zoukankan      html  css  js  c++  java
  • sqli-宽字节注入

    0x0 背景

    1. 当某字符的大小为一个字节时,称其字符为窄字节.
    2. 当某字符的大小为两个字节时,称其字符为宽字节.
    3. 所有英文默认占一个字节,汉字占两个字节
    4. 常见的宽字节编码:GB2312,GBK,GB18030,BIG5,Shift_JIS等等

    0x1 宽字节注入原理

     

    程序员为了防止sql注入,对用户输入中的单引号(’)进行处理,在单引号前加上斜杠()进行转义,这样被处理后的sql语句中,单引号不再具有‘作用’,仅仅是‘内容’而已,换句话说,这个单引号无法发挥和前后单引号闭合的作用,仅仅成为‘内容‘

    【再举个例子,要找某位名字里带单引号的用户,搜索的时候,就要让单引号成为内容去搜索,而不能起到其他作用】

    而安全测试人员要绕过这个转义处理,使单引号发挥作用,有两个思路:

    1. 让斜杠()失去作用
    2. 让斜杠()消失

    第一个思路就是借鉴程序员的防范思路,对斜杠()转义,使其失去转义单引号的作用,成为‘内容’

    第二个思路就是宽字节注入

     

    当使用宽字节编码,如:GBK时,两个连在一起的字符会被认为是汉字,我们可以在单引号前加一个字符,使其和斜杠()组合被认为成汉字,从未达到让斜杠消失的目的,进而使单引号发挥作用

    注意:前一个字符的Ascii要大于128,两个字符才能组合成汉字

    0x2 注入方法

    0x21 黑盒

     

     

    可以看到,在发现单引号被转义后,当我们加了%df后,sql语句报错,说明单引号发挥了作用,斜杠与%df组合

    0x22白盒

     

    1.gbk编码

     

    2.单引号被替换成’

     

    3.php内置函数addslashes进行转义(lesson33)

     

    4.mysql_real_escape_string

    这个mysql内置的函数可以把sql语句中字符串的特殊字符进行转义,同时考虑连接的字符集,可以用来解决宽字节注入,但某些场景仍不行,因为程序没有指定php连接mysql的字符集。

    如果要使用这个函数防御,要在执行sql语句之前调用一下mysql_set_charset函数,设置当前连接的字符集为gbk,再调用mysql_real_escape_string来过滤用户输入

    0x23 sqlmap

    需要注意的是,对于宽字节注入场景,直接

    python sqlmap.py -u "http://localhost/sqli-labs-master/Less-32/?id=1"

    是找不到注入的

     

    必须得

    python sqlmap.py -u "http://localhost/sqli-labs-master/Less-32/?id=1%df%27"

    还可以加些参数:

    --threads 10 //如果你玩过 msfconsole的话会对这个很熟悉 sqlmap线程最高设置为10

    --level 3 //sqlmap默认测试所有的GET和POST参数,当--level的值大于等于2的时候也会测试HTTP Cookie头的值,当大于等于3的时候也会测试User-Agent和HTTP Referer头的值。最高可到5

    --risk 3 // 执行测试的风险(0-3,默认为1)risk越高,越慢但是越安全

    ----search //后面跟参数 -D -T -C 搜索列(S),表(S)和或数据库名称(S) 如果你脑子够聪明,应该知道库列表名中可能会有ctf,flag等字样,结果有时候题目就是这么耿直对吧?

    //我最后还是没成功用sqlmap注入

    0x3防御

    借鉴内容:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html

    在0x22.3中我们说到了一种修复方法,就是先调用mysql_set_charset函数设置连接所使用的字符集为gbk,再调用mysql_real_escape_string来过滤用户输入。

    这个方式是可行的,但有部分老的cms,在多处使用addslashes来过滤字符串,我们不可能去一个一个把addslashes都修改成mysql_real_escape_string。我们第二个解决方案就是,将character_set_client设置为binary(二进制)。

    只需在所有sql语句前指定一下连接的形式是二进制:

    SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

    这几个变量是什么意思?

    当我们的mysql接受到客户端的数据后,会认为他的编码是character_set_client,然后会将之将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。

    然后,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。

    所以,我们将character_set_client设置成binary,就不存在宽字节或多字节的问题了,所有数据以二进制的形式传递,就能有效避免宽字符注入。

    比如,我们的phithon内容管理系统v2.0版本更新如下:

     

    已经不能够注入了:

     

    在我审计过的代码中,大部分cms是以这样的方式来避免宽字符注入的。这个方法可以说是有效的,但如果开发者画蛇添足地增加一些东西,会让之前的努力前功尽弃。

    0x4总结

    在逐渐国际化的今天,推行utf-8编码是大趋势。如果就安全性来说的话,我也觉得使用utf-8编码能够避免很多多字节造成的问题。

    不光是gbk,我只是习惯性地把gbk作为一个典型的例子在文中与大家说明。世界上的多字节编码有很多,特别是韩国、日本及一些非英语国家的cms,都可能存在由字符编码造成的安全问题,大家应该有扩展性的思维。

    总结一下全文中提到的由字符编码引发的安全问题及其解决方案:

    1. gbk编码造成的宽字符注入问题,解决方法是设置character_set_client=binary。
    2. 矫正人们对于mysql_real_escape_string的误解,单独调用set names gbk和mysql_real_escape_string是无法避免宽字符注入问题的。还得调用mysql_set_charset来设置一下字符集。
    3. 谨慎使用iconv来转换字符串编码,很容易出现问题。只要我们把前端html/js/css所有编码设置成gbk,mysql/php编码设置成gbk,就不会出现乱码问题。不用画蛇添足地去调用iconv转换编码,造成不必要的麻烦。

    参考文档:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html

  • 相关阅读:
    LA3523 二分图和点双连通分量的综合性质及证明
    LA4127计算几何+离散化+点覆盖
    LA 4728凸包算法-旋转卡壳的直径
    UVA 11168凸包+距离公式
    UVA 10652凸包+面的旋转
    UVA10969计算几何+交叉圆形成的圆弧长
    LA3485二分+求解积分方程+辛普森算法计算积分
    LA5009三分法
    UVA10341幂函数零点的通解分析
    UVA11524构造系数数组+高斯消元解异或方程组
  • 原文地址:https://www.cnblogs.com/diligenceday/p/12324329.html
Copyright © 2011-2022 走看看