发一下许久之前写的宽字节注入,引用部分sql注入天书
尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如gbk,作为自己默认的编码类型。也有一些cms为了考虑老用户,所以出了gbk和utf-8两个版本。
我们就以gbk字符编码为示范,拉开帷幕。gbk是一种多字符编码,具体定义自行百度。但有一个地方尤其要注意:
通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。
当将页面编码保存为gbk时输出2,utf-8时输出3。除了gbk以外,所有ANSI编码都是2个字节。ansi只是一个标准,在不用的电脑上它代表的编码可能不相同,比如简体中文系统中ANSI就代表是GBK。
原理详解
SQL语句是 SELECT * FROM news WHERE tid=’{KaTeX parse error: Expected 'EOF', got '}' at position 3: id}̲',就是根据文章的id把文章从…id的值转义。这是通常cms中对sql注入进行的操作,只要我们的输入参数在单引号中,就逃逸不出单引号的限制,无法注入。
那么怎么逃过addslashes的限制?众所周知addslashes函数产生的效果就是,让’变成’,让引号变得不再是“单引号”,只是一撇而已。一般绕过方式就是,想办法处理’前面的\:
1.想办法给\前面再加一个\(或单数个即可),变成\’,这样\被转义了,‘逃出了限制
2.想办法把\弄没有。
我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。如果我们输入%df’看会怎样:
为什么从刚才到现在,只是在’也就是%27前面加了一个%df就报错了?
这就是mysql的特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的\也就是%5c变成了一个汉字“運”,而’逃逸了出来。因为两个字节代表一个汉字,所以我们可以试试%df%df%27:
不报错了。因为%df%df是一个汉字,%5c%27不是汉字,仍然是’。
那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以:
%a1%5c他可能不是汉字,但一定会被mysql认为是一个宽字符,就能够让后面的%27逃逸了出来
宽字节注入
原理用addslashes函数将’前面加
gbk编码为2个字符作为汉字,通常有’/防止sql注入一般有两种思路
1、%df 吃掉 \ 具体的原因是 urlencode(‘) =%5c%27,我们在%5c%27 前面添加%df,形 成%df%5c%27,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此 事%df%5c 就是一个汉字,%27 则作为一个单独的符号在外面,同时也就达到了我们的目的。
%df%5c%27 构成 “運”’
也就是一个汉字叫一个 ’ ,这样我们就可以sql注入
http://127.0.0.1/sqli-labs/Less-32/?id=-1%df%27union%20select%201,user(),3–+
2、将 \’ 中的 \ 过滤掉,例如可以构造 %%5c%5c%27 的情况,后面的%5c 会被前面的%5c 给注释掉。这也是 bypass的一种方法。
% 中**写大于128的ascii就可以,这样与之前的构成一个汉字,或者写%df注释掉了%df
!!!!!!!!!!注意addslashes将’替换成’
例如:
?id=-1%aa%df%df%27union%20select%201,user(),3–+
%aa///’
%aa/ 构成汉字
//两个注释
最后逃逸出来’
也可以
?id=-1%df%df%df%27union%20select%201,user(),3–+
’ 也可以逃逸出来’