Sql注入-Oracle

项目中师傅交的一个漏洞,研究了一下

原查询请求

/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
WHERE productionModule = 5
AND productionType = 5
AND productionCode = 13
AND fileTime BETWEEN '2025-07-03' AND '2025-07-08'
ORDER BY fileTime DESC
LIMIT 5 OFFSET 0; -- (page=1, size=5)

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函数,成功延迟

image-20250717170117352

image-20250717170211790

获取数据库信息

攻击者最终构造的Payload:

sort=fileTime,1/decode(REGEXP_SUBSTR(user,'.',4,1),'s',1,0)

已知可以用布尔和时间盲注

1. 整体结构

  • 目的:通过除法错误实现 布尔盲注(Boolean-Based Blind SQLi),探测 user 字段的第4个字符是否为 's'
  • 执行逻辑
    1. 提取 user 列的第4个字符。
    2. decode 判断该字符是否为 's'
    3. 通过 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 返回 11/1=1(正常排序,页面正常返回)。
    • 若字符不是 's'decode 返回 01/0(除零错误,页面返回500)。

image-20250717183007159

为什么一定要用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