一次排序注入的深入研究
最近看到一个大佬的渗透报告,里面有一个排序注入的利用。太久没有手工注入SQL了,一时间看得有点懵,花了点时间研究了一下,并记录成这篇博客。由于设计到真实生产系统,截图就不多给了,直接口头表述。如果有不清楚的,还请见谅。
存在SQL注入的接口存在一个sortField参数,传入值为0,会报错,响应包回显SQL查询语句
SELECT * FROM (
SELECT TMP_PAGE.*,ROWNUM ROW_ID FROM (
SELECT * FROM (
SELECT a.id as "id",a.xxx as "xxx",……(反正有很多列) FROM
FROM wl a
LEFT JOIN t_user u
ON u.id=a.sszh WHERE jgzt="1" and (
YXQX="-1" or time > ADD_MONTHS(sysdate,0-YXQX*12)
)
ORDER BY 0
))
TMP_PAGE)
WHERE ROW_ID <= ? AND ROW_ID >?
该sortField参数会传到ORDER BY语句到后面,即ORDER BY {sortField}
此时记录一下ORDER BY 0 的响应包,稍后进行进一步注入的时候会用到
因为看不到这个查询语句在干啥?我把它丢进了GPT分析,分析结果如下:
这个查询语句是一个复杂的Oracle SQL语句,主要用于从数据库中检索特定条件下的分页数据。让我详细解释一下:
- 最内层子查询 (Innermost Subquery):
- 这个查询从
wl
表中选择了一系列列。 - 使用了
LEFT JOIN
将该表与t_user
表关联,连接条件是u.id = a.sszh
。 - WHERE子句包括条件
jgzt="1"
,表示选取状态为"1"的记录。 - 还有一个复杂的条件,
(YXQX="-1" or time > ADD_MONTHS(sysdate, 0 - YXQX * 12))
,这是一个日期比较,根据条件选取符合要求的记录。
- 这个查询从
- 第二层子查询 (Second Subquery):
- 这个查询对最内层的结果进行排序,
ORDER BY 17
表示按照第17列排序。
- 这个查询对最内层的结果进行排序,
- 最外层子查询 (Outermost Subquery):
- 使用
ROWNUM
给每一行结果分配一个行号,并将这个行号作为ROW_ID
的别名。 - 然后通过外部的
SELECT
语句,筛选出ROW_ID
在指定范围内的记录,实现分页效果。
- 使用
关于order by 注入,更多的可能关注这篇文章ORDER BY 注入,这里就不多讲原理了。
因为是渗透测试报告,我没有机会手动进行测试,只能通过口头了解知道该系统对逗号进行了过滤。
针对该过滤,大佬使用了参数污染,基本原理如下:
若参数名一致,服务器可能有几种处理情况:
1. 将其拼接在一起
2. 第二个参数值覆盖第一个参数值
针对该原理使用payload 为:
sortField=decode(substring(user&sortField=1&sortField=1)&sortField=chr(103)&sortField=(1/0)&sortField=0)
首先先解释一下各类函数的作用:
- substring 截取字符串,第一个参数为字符串,第二个为start值,第三个为length值
- decode 通常用于在查询中进行条件性的值转换,通常格式为
DECODE(expression, search1, result1, search2, result2, ..., default_result)
其中 expression
是需要比较的值,search1
, search2
, ... 是要匹配的条件,result1
, result2
, ... 是匹配到相应条件时返回的结果,default_result
是当没有条件匹配时返回的默认结果。
而 &
则是使用同参数名来给函数传参,最后服务器处理的结果会是:(返回包里也有)
ORDER BY
DECODE(
SUBSTRING(
user,1,1
),chr(103),1/0,0
)
语句的结果就是:
取user
的第一个字母,若跟chr(103)匹配,则产生一个除零报错,若不匹配,则跟ORDER BY 0产生同样的错误(这就是为什么我让大家把前面ORDER BY 0的错误记下来)
总结:大佬的思路就是牛!我SQL注入就是SQLMAP一把梭,有就有,没有就没有了哈哈哈。