前言
在帮电信的客户测试项目的过程中,发现一处 SQL 注入漏洞。
数据库类型是 oracle,该处功能点是用来查询用户的。
查询 1 时,输出无结果。
查询 a 时,输出有结果
测试过程
第一次测试
第一次测试是毫无过滤手法的。
通过 sqlmap 可以正常的获取数据。
第二次测试
这次复测,正确来说是第三次复测,通过项目经理得知,该项目,客户已经找了另外一个公司帮助复测。
因此我这次复测是第三次,但实际上是我的第二次测试。
使用第一次测试的 payload 可以发现,该 payload 已经无法正常使用了。开始想办法让它 SQL 语句报错,看看 SQL 语句是怎么写的。
测试后发现使用’
和)
可以使语句报错。
familyName
参数的值,是在 instr
函数中,这是一个字符串查找函数。
大概看了一下相关概念和使用案例,明白了这个函数怎么使用。
这里使用在线的 oracle 运行工具进行语句和 payload 调试。
https://livesql.oracle.com/apex/f?p=590:1000
通过报错语句、构造一个类似的伪查询 SQL 语句
select user from dual where instr(user,'A')>0
这里的 A
也就可以是我们通过发包传入的 payload
。
那么通过闭合,在使用逻辑运算符就可以去进行SQL注入了。
假设 payload 是 A')>0 OR instr(user,'A
。
此时在数据包中构造一个类似的 payload
,并且尝试注入。
当我的值都是 1
时,查询结果应该是为空的,但是正常回显了数据。说明插入的字符串中有字符串被过滤了。
此时尝试寻找是哪个关键字被过滤了。
最后确定是逻辑运算符 and
和 or
被过滤。
此时把 or
删掉,看看 instr
有没有被过滤
可以发现 instr
没有过滤
ByPass过程
尝试编码绕过
测试 payload 是 1')>0 or instr(cscp_user.username,'1
当插入语句被成功执行时,预期应该是返回数据是空。
并且其他可被识别的编码绕过均失败。
尝试大小写绕过
大小写失败
尝试双写绕过
绕过失败,OrRr
被没有按预期变成 or
在网上查了很多相关资料,也并未找到能够代替逻辑运算符的方法。
此时想到了字符拼接
即将 or
拆分成 o
和 r
,然后通过||
符号连接。
但是实际上经过测试后发现,这个返回的是一条记录,而不是一个简单的字符串,因此没办法拼接。
峰回路转,成功 bypass
难受啊、正在迷茫的时候。
突然发现了一个有意思的东西。
当我把 0
和 OR
中间的空格删除后发现,OR
的颜色没变,说明 SQL
还是把它当作了一个逻辑运算符。
这里我尝试执行一下这个语句。
发现结果被正常的输出,所以大胆猜测 0or
和 0 or
的执行效果是一样的,这应该是 oracle
的啥特性
,可以忽略空格。
这里我来在数据包中尝试注入。
测试发现,结果已经达到了预期值
查询 a 时,返回也有记录
注:这里被测站点使用的查询语句中 instr 实际上有多个,我要考虑完美闭合,即闭合左边的 instr,还不能忽略掉右边的),所以 payload 里面才会有一个 instr。为什么这么操作,是因为测试发现,通过注释,是无法闭合语句的。
这里尝试获取数据。
但是这里有几个概念要清楚。
oracle
数据库中,查询用户是可以直接用 user
来查的,and
比 or
的优先级高,因此and
先执行。
构造一个这样的 payload
:
1')>0or length(user)=10and instr(cscp_user.username,'a
通过前面分析可知,a
代表有数据,因此 instr
和 length(user)
两个是先执行的,这里是判断当前用户长度是否是 10
,如果是 10
,并且 instr
中的 string2
是 a
,回显有数据即and
左右两边都是 true
,因此查询有数据。
开始发包
回显有数据,说明当前用户长度是 10
。
接下来可以通过 left
,substr
这类关键字去截取字符串,既可以成功注入到当前的用户名称了。
如果 left
和 substr
被过滤,可以使用 like
进行绕过。
即 user like ‘%’
通过通配符去匹配。
这里也就 bypass 成功,这里开发只是做了黑名单校验,因此开发祭天,法力无边。哈哈哈,开发要挨打了。
总结
SQL注入绕过没技巧,主要得通过页面回显去判断拦截类型,并且要需要本地调试自己的payload能否正常运行。
后续就是,由于第二天是国庆,下午是和甲方开发玩了一下午,她边修我边绕,最后下班了,我就没绕了,也算是一次比较有趣的bypass经历,毕竟是真实的实战对抗。