2026第十届御网杯网络安全大赛线上赛 区域赛WP (MISC和Crypto)(详解-思路-脚本)

芜湖~

题目没有之前那么好玩 有些题目能找到原型

线上赛莫名其妙人性化 中午把网站停了 给选手吃饭时间 没想到

不过 这次不管是附件题 还是web题 每个IP的flag都不一样 挺好的

以下是我自己的一些思路和解析 有什么问题或者建议随时都可以联系我

目录

芜湖~

MISC

签到题-损坏的压缩包

迷宫

幻影

[Base64 编码 + 异或加密](#Base64 编码 + 异或加密)

这里有两种解决方法

元老级工具了

脚本

像素中的秘密

脚本解读

[加油各位( •̀ ω •́ )y 期待与君再相逢](#加油各位( •̀ ω •́ )y 期待与君再相逢)


MISC

签到题-损坏的压缩包

dGFoZw==

base64解码

flag{tahg}

迷宫

附件只有一个压缩包

根据题目提示直接解压

layer1 → data2 → secret3 → hidden4 → .config → user → backup5

先用十六进制编辑器查看内容

后面30没有用

ZWE2MzJjNjYwNmJlY2Q5ZTQ2YzFkMzkyZjhiMGU2ZGE==

一看就是base64

直接Base64 解码

ea632c6606becd9e46c1d392f8b0e6da

flag{ea632c6606becd9e46c1d392f8b0e6da}

幻影

依然只有一个zip的附件

只有个bin的文件

老规矩不能直接打开的文件 先看一下源代码

看到这里其实 提示已经非常明显了 这里逐行分析一下

  • 第一行的Rar!:没用干扰信息(但你要知道没有试出来的)。
  • 第二行的提示:REMEMBER: FLAG IS HIDDEN IN BASE64 PLUS XOR! 核心提示!

    翻译过来就是:flag 藏在「Base64 编码 + 异或加密」里!很多小白一开始会看错,把XOR看成X,以为 x 是文件名的 04,其实不是,这里的XOR是加密算法的名字!

  • 第三行的假 flag:FAKE FLAG: flag{00000000-0000-0000-0000-000000000000}
  • 第四行的警告:DO NOT TRUST THIS ONE. 这行是提醒你!上面那个全是 0 的 flag 是假的!用来迷惑你的!不要信它!
  • 最后一行的乱码一样的字符串:+fP++OT+qvup/f6mqrL7/Pmusqv6/K6y/f36qbL5rPum/an9+6qpqqri 真正的明=密文

Base64 编码 + 异或加密

先进行Base64 编码 在进行异或解密

这里有两种解决方法

元老级工具了

CyberChefThe Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysishttps://gchq.github.io/CyberChef/

拿到flag

flag{a5d6ba95-dcf1-4ec1-bbe6-f3d9b6bd5655}

脚本

python 复制代码
import base64

# 1. 读取我们提取到的加密字符串
encrypted_str = "+fP++OT+qvup/f6mqrL7/Pmusqv6/K6y/f36qbL5rPum/an9+6qpqqri"
encrypted_bytes = encrypted_str.encode('ascii')

# 2. 暴力破解所有可能的密钥x(0~255)
for x in range(256):
    try:
        # 先把加密字符串做Base64解码
        padding = 4 - len(encrypted_bytes) %4
        if padding <4:
            eb = encrypted_bytes + b'='*padding
        else:
            eb = encrypted_bytes
        decoded = base64.b64decode(eb, validate=False)
        # 然后每个字节异或密钥x,解密
        temp = bytes([b ^ x for b in decoded])
        # 转成字符串,看看是不是flag
        res = temp.decode('utf-8', errors='replace')
        if 'flag{' in res:
            print(f"找到真正的Flag啦!密钥x={x}")
            print(f"最终Flag:{res}")
            break
    except:
        continue

也可以得到flag

flag{a5d6ba95-dcf1-4ec1-bbe6-f3d9b6bd5655}

像素中的秘密

只看题目 像素 而且又在 高级里面 就知道又要破脚本里面

附件下载 只有一个图片 不怕附件多 就怕附件只有一个

正常分析 在源代码里面 发现IEND 块后残留 64 字节数据

这是一个正常的思路

读取 PNG 文件,提取 IEND 块后数据,拆分出种子用 LCG 异或解密得到 Base62 字符串,解码后转为 UTF-8 文本即为 flag。、

脚本解读

python 复制代码
# 导入必要的模块
# string:提供字符串相关工具(如数字/字母字符集)
# struct:用于解析二进制数据(处理PNG块结构、字节序)
# Path:更便捷的文件路径处理(判断文件是否存在、读取文件)
import string
import struct
from pathlib import Path

# ===================== 核心解密参数配置 =====================
# LCG(线性同余生成器)参数 - 该类MISC题的通用标准参数
# A:乘法因子(multiplier),CTF中最常见的Java/glibc标准值
A = 1664525
# C:增量(increment),与A配套的标准值
C = 1013904223
# MASK:32位无符号整数掩码,确保计算结果在32位范围内
MASK = 0xFFFFFFFF

# Base62字符集(CTF通用顺序:数字→小写字母→大写字母)
# Base62是一种编码方式,比Base64少了+和/,常用于隐写题
B62 = string.digits + string.ascii_lowercase + string.ascii_uppercase


# ===================== 核心功能函数 =====================
def cut_after_iend(png_data: bytes) -> bytes:
    """
    核心功能:遍历PNG文件结构,找到IEND结束块,返回其之后的所有残留数据
    PNG文件结构:文件头(8字节) + 多个块(长度+类型+数据+CRC) + IEND块
    IEND块是PNG的最后一个块,隐写数据通常藏在IEND之后
    """
    # 第一步:校验PNG文件头(固定为\x89PNG\r\n\x1a\n),排除非PNG文件
    if not png_data.startswith(b'\x89PNG\r\n\x1a\n'):
        raise RuntimeError("❌ 不是有效的PNG文件(文件头校验失败)")

    # offset:当前遍历到的字节偏移量,初始跳过8字节文件头
    offset = 8
    # data_len:PNG文件总字节长度
    data_len = len(png_data)

    # 循环遍历所有PNG块,直到找到IEND块
    # 每次循环至少需要8字节(4字节长度 + 4字节块类型)
    while offset + 8 <= data_len:
        # 解析当前块的长度(PNG块长度为大端字节序,用>I解析)
        chunk_len = struct.unpack('>I', png_data[offset:offset + 4])[0]
        # 解析当前块的类型(如IHDR/IDAT/IEND)
        chunk_type = png_data[offset + 4:offset + 8]

        # 移动偏移量到下一个块:8字节(长度+类型) + 块数据长度 + 4字节CRC校验位
        offset += 8 + chunk_len + 4

        # 找到IEND块(PNG的结束块),返回其后的所有数据
        if chunk_type == b'IEND':
            print(f"✅ 找到IEND块,偏移位置: 0x{offset:08x}")  # 打印十六进制偏移,方便调试
            return png_data[offset:]

    # 遍历完所有块仍未找到IEND,说明文件损坏或非标准PNG
    raise RuntimeError("❌ 未找到PNG的IEND结束块")


def lcg_decrypt(raw_data: bytes) -> tuple[int, bytes]:
    """
    核心功能:用LCG算法解密IEND后的残留数据
    数据结构约定:4字节填充(无用) + 4字节seed(种子) + 剩余为XOR密文
    返回值:(提取到的seed, 解密后的字节数据)
    """
    # 校验数据长度:至少需要8字节(4填充+4seed),否则无法解密
    if len(raw_data) < 8:
        raise RuntimeError(f"❌ 尾部数据过短(仅{len(raw_data)}字节),至少需要8字节")

    # 提取seed:跳过前4字节填充,取4-8字节,按大端字节序转整数
    # 大端字节序(big-endian)是网络/文件存储的通用方式
    seed = int.from_bytes(raw_data[4:8], 'big')
    print(f"✅ 提取到seed: 0x{seed:08x} (十进制: {seed})")  # 打印十六进制+十进制seed,方便调试

    # cur_seed:当前LCG生成器的种子值,初始为提取的seed
    cur_seed = seed
    # decrypted:存储解密后的字节数据,用bytearray更高效
    decrypted = bytearray()

    # 遍历8字节后的所有密文字节,逐字节异或解密
    for idx, b in enumerate(raw_data[8:]):
        # 执行LCG公式:下一个种子 = (A*当前种子 + C) % 2^32(用MASK实现)
        cur_seed = (A * cur_seed + C) & MASK
        # 异或解密:密文字节 ^ LCG生成值的低8位(只取最后1字节)
        dec_byte = b ^ (cur_seed & 0xFF)
        # 将解密后的字节加入结果
        decrypted.append(dec_byte)

    # 返回seed和解密后的字节数据(bytearray转bytes)
    return seed, bytes(decrypted)


def b62_decode(b62_str: str) -> bytes:
    """
    核心功能:将Base62字符串解码为原始字节数据
    Base62解码原理:字符串→大整数→字节数组(大端)
    """
    # 初始化解码后的整数为0
    num = 0
    # 遍历Base62字符串的每个字符,逐位计算整数
    for c in b62_str:
        try:
            # 核心公式:num = num * 62 + 字符在B62中的索引
            num = num * 62 + B62.index(c)
        except ValueError:
            # 字符不在B62字符集中,解码失败
            raise RuntimeError(f"❌ Base62字符串包含非法字符: {c}(仅支持0-9/a-z/A-Z)")

    # 计算需要的字节数:确保至少1字节(避免num=0时返回空)
    # bit_length():整数的二进制位数,+7//8 是向上取整到字节数
    byte_count = max((num.bit_length() + 7) // 8, 1) if num > 0 else 1
    # 将整数转为大端字节序的字节数组
    return num.to_bytes(byte_count, 'big')


# ===================== 主函数(一键解密) =====================
def main(png_path: str = "image_10.png"):
    """
    主函数:整合所有步骤,一键解密PNG文件中的flag
    参数:png_path - PNG文件路径,默认值为同目录的image_10.png
    """
    # 将字符串路径转为Path对象,方便文件操作
    png_file = Path(png_path)
    # 检查文件是否存在,不存在则提示并退出
    if not png_file.exists():
        print(f"❌ 未找到文件: {png_path}")
        return

    # 第一步:读取PNG文件的二进制数据
    with open(png_file, 'rb') as f:  # 'rb'以二进制模式读取,避免编码问题
        png_data = f.read()
    print(f"✅ 读取PNG文件成功,文件大小: {len(png_data)} 字节")

    # 第二步:提取IEND块后的残留数据(捕获异常,避免程序崩溃)
    try:
        tail_data = cut_after_iend(png_data)
        print(f"✅ IEND后提取到 {len(tail_data)} 字节残留数据")
    except Exception as e:
        print(e)  # 打印具体错误信息
        return

    # 第三步:用LCG算法解密残留数据(捕获异常)
    try:
        seed, dec_buf = lcg_decrypt(tail_data)
        # 去除解密后数据末尾的空字节(\x00),并转为ASCII字符串
        b62_str = dec_buf.rstrip(b'\x00').decode('ascii')
        print(f"✅ LCG解密完成,Base62字符串: {b62_str}")
    except Exception as e:
        print(e)
        return

    # 第四步:Base62解码得到最终flag(捕获异常)
    try:
        flag_bytes = b62_decode(b62_str)
        # 将字节数据转为UTF-8字符串(flag的标准编码)
        flag = flag_bytes.decode('utf-8')
        # 格式化输出flag,增强可读性
        print("\n" + "=" * 50)
        print(f"🎉 最终Flag: {flag}")
        print("=" * 50)
    except Exception as e:
        print(e)
        return


# ===================== 程序入口 =====================
if __name__ == "__main__":
    """
    程序入口:直接运行脚本时,调用main函数
    默认解密同目录下的image_10.png,无需传参
    """
    main()

运行脚本

✅ 读取PNG文件成功,文件大小: 245 字节
✅ 找到IEND块,偏移位置: 0x000000b5
✅ IEND后提取到 64 字节残留数据
✅ 提取到seed: 0x69cb3446 (十进制: 1774924870)
✅ LCG解密完成,Base62字符串: 16vPI4pqYkxFvJHGGgssbbrGLF7Zqg1YN

==================================================
🎉 最终Flag: flag{final_flag_png_lcg}
==================================================

加油各位( •̀ ω •́ )y 期待与君再相逢

相关推荐
zzzsde2 小时前
【Linux】线程同步和互斥(5):线程池的实现&&线程安全
linux·运维·服务器·开发语言·算法·安全
消失的旧时光-19432 小时前
企业认证与安全体系(五):Spring Security + JWT + Redis 企业级认证实战
redis·安全·spring·spring security·jwt
x-cmd2 小时前
[260531] OpenClaw 五月月报:模型接入大爆发、安全重构、手机端终于能当主控台用了 [特殊字符]
安全·ai·智能手机·重构·x-cmd·openclaw
国科安芯2 小时前
ASM232S电气特性与TIA/EIA-232-F及ITU V.28标准符合性深度分析
单片机·嵌入式硬件·算法·安全·架构
Rain5092 小时前
mini-cc 权限安全:给 AI 戴上枷锁
前端·人工智能·安全·架构·node.js·ai编程
Lethehong2 小时前
第十届御网杯网络安全大赛 - Wp
网络安全
ylscode2 小时前
微软发布针对 Windows 11 的 KB5089573 补丁,以修复“周二补丁日”安装问题
windows·安全·microsoft·安全威胁分析
鹿鸣天涯3 小时前
网规第三版:第9章网络安全部署案例
网络·安全·web安全·软考·网络规划设计师
深邃-3 小时前
【Web安全】-10-网站关键信息收集:目录扫描的概念,工具目录扫描(内含御剑,FindSomething安装链接),网站服务器收集,操作系统判断
运维·服务器·安全·web安全·http·网络安全