一次排序注入的深入研究

发布时间 2023-11-13 15:37:23作者: cha0s32

最近看到一个大佬的渗透报告,里面有一个排序注入的利用。太久没有手工注入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语句,主要用于从数据库中检索特定条件下的分页数据。让我详细解释一下:

  1. 最内层子查询 (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)),这是一个日期比较,根据条件选取符合要求的记录。
  2. 第二层子查询 (Second Subquery):
    • 这个查询对最内层的结果进行排序,ORDER BY 17表示按照第17列排序。
  3. 最外层子查询 (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一把梭,有就有,没有就没有了哈哈哈。