Sql注入-Oracle

Sql注入-Oracle
Att@ckxu项目中师傅交的一个漏洞,研究了一下
原查询请求
/SWSService/swthweb/searchData?page=1&size=5&sort=fileTime&order=desc&productionModule=5&productionType=5&productionCode=13&startTime=2025-07-03&endTime=2025-07-08 |
注入点:sort
sort
参数通常直接拼接到ORDER BY
子句,而ORDER BY
不能使用参数化查询(?
绑定变量),因此容易成为注入点。- 许多开发者错误地认为
ORDER BY
是安全的,不会做严格过滤。
根据查询请求,猜测查询语句
SELECT * FROM production_data |
order by后的字段为可控
攻击思路
确定存在注入
当输入sort=fileTime,发现返回的内容的确是按照fileTime字段来排序的
当输入sort=1,返回的内容顺序和sort=fileTime不同
至此,说明sort的值可控,并且能够带入查询,可能存在sql注入
进一步确认:
尝试子查询:sort=fileTime,(select+1)
页面返回500,说明后端尝试执行子查询但失败(漏洞存在,盲注)
如果返回200,说明子查询被执行并且成功返回(可以直接执行任意sql语句)
确定为盲注
判断数据库类型
Oracle
sort=fileTime,decode(1,1,1,0) → 如果正常,确认Oracle
MySQL
sort=fileTime,IF(1=1,1,0) → 测试条件函数
SQL Server
sort=fileTime,IIF(1=1,1,0) → 测试条件函数
三条语句执行完毕之后,只有第一条语句可以正常查询,说明数据库为Oracle(支持Oracle数据库函数)
盲注函数验证
以下是常见数据库的延迟函数及用法:
数据库 | 睡眠函数 | 示例用法 | 备注 |
---|---|---|---|
Oracle | DBMS_PIPE.RECEIVE_MESSAGE |
DBMS_PIPE.RECEIVE_MESSAGE('a',5) |
需权限,通常可用。 |
MySQL | SLEEP() |
SLEEP(5) |
直接支持,最常用。 |
PostgreSQL | pg_sleep() |
pg_sleep(5) |
单位是秒,支持小数(如0.5)。 |
SQL Server | WAITFOR DELAY |
WAITFOR DELAY '0:0:5' |
参数为时间字符串(时:分:秒)。 |
SQLite | 无内置函数,可模拟 | 1=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(100000000/2)))) |
因为确定了是Oracle数据库,使用Oracle数据库的睡眠函数
当使用DBMS_PIPE.RECEIVE_MESSAGE
函数,成功延迟
获取数据库信息
攻击者最终构造的Payload:
sort=fileTime,1/decode(REGEXP_SUBSTR(user,'.',4,1),'s',1,0) |
已知可以用布尔和时间盲注
1. 整体结构
- 目的:通过除法错误实现 布尔盲注(Boolean-Based Blind SQLi),探测
user
字段的第4个字符是否为's'
。 - 执行逻辑:
- 提取
user
列的第4个字符。 - 用
decode
判断该字符是否为's'
。 - 通过
1/0
触发错误,观察页面是否返回500。
- 提取
2. 函数逐层解析
(1) REGEXP_SUBSTR(user,'.',4,1)
- 作用:从
user
列的值中提取第4个字符。user
:目标列名(可能是数据库用户或应用用户字段)。'.'
:正则表达式,匹配任意单个字符。4
:从第4个字符开始提取。1
:提取1个字符。
- 示例:
- 若
user='admin'
,则返回'm'
(第4个字符)。 - 若
user='system'
,则返回's'
。
- 若
(2) decode(..., 's', 1, 0)
- 作用:Oracle的条件判断函数,类似
IF-THEN-ELSE
。- 语法:
decode(值, 条件1, 结果1, 条件2, 结果2, ..., 默认值)
。 - 这里:若提取的字符是
's'
,返回1
;否则返回0
。
- 语法:
(3) 1/decode(...)
- 关键攻击点:
- 若字符是
's'
:decode
返回1
→1/1=1
(正常排序,页面正常返回)。 - 若字符不是
's'
:decode
返回0
→1/0
(除零错误,页面返回500)。
- 若字符是
为什么一定要用1/
这里的1/就是为了返回500,
布尔盲注要找到返回200和500的两种请求所触发的方式,有的时候可能是值为0,有的时候可能是无法运算
也就是说,这里sort的参数值并不是常规的1或0,(1或0都可以正常查询,这里的500是因为不能够查询,所以返回500)
相比于之前的,这里是构造出让参数的运算值报错,导致500;而不是参数的运算值为0,导致500
Oracle不支持布尔运算符,只支持算数运算符,并且get请求的参数要考虑它的URL编码问题
另一个payload:
sort=fileTime,(exp(291-(decode(REGEXP_SUBSTR(user,'.',4,1),'s',1,0)))) |
exp()就是运算次方,能正常运算返回200,不能正常运算返回500