第十届御网杯网络安全大赛WriteUp

admin 2026-07-01 04:59:45 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文档详细记录了第十届御网杯网络安全大赛的解题过程,涵盖WEB和PWN两大方向。WEB部分包括贪吃蛇前端数据伪造、PHP反序列化漏洞利用、目录穿越绕过、FlaskSSTI注入与Session伪造;PWN部分涉及基础栈溢出、ret2text后门利用、栈可执行Shellcode注入等技术。文档提供了完整的漏洞分析、解题步骤和EXP代码,具有实战参考价值。 综合评分: 85 文章分类: CTF,WEB安全,二进制安全,实战经验,漏洞分析


解题步骤

  1. 解压 image_04.zip,获取 image_04.png。
  2. 读取 PNG 结构,IEND 块后残留 64 字节数据,为隐写密文。
  3. 密文结构:4 字节填充 + 4 字节 seed + XOR 密文。
  4. 用 seed 初始化 LCG,生成随机数与密文异或,得到 Base62 字符串。
  5. Base62 转字节,UTF-8 解码得到 flag。

完整 EXP

#!/usr/bin/env python3
import argparse
import string
import struct
import zipfile
from pathlib import Path

# LCG参数
A = 1664525
C = 1013904223
MASK = 0xFFFFFFFF
# Base62字符集
B62 = string.digits + string.ascii_lowercase + string.ascii_uppercase

# 读取ZIP中的PNG
def get_png_data(zip_file: Path):
    with zipfile.ZipFile(zip_file, 'r') as zf:
        png_list = [n for n in zf.namelist() if n.lower().endswith('.png')]
        if not png_list:
            raise RuntimeError("No PNG inside archive")
        target_name = png_list[0]
        return target_name, zf.read(target_name)

# 截取IEND块后的数据
def cut_after_iend(data: bytes) -> bytes:
    if not data.startswith(b'\x89PNG\r\n\x1a\n'):
        raise RuntimeError("Not a valid PNG file")
    offset = 8
    data_len = len(data)
&nbsp; &nbsp; while offset + 8 <= data_len:
&nbsp; &nbsp; &nbsp; &nbsp; chunk_len = struct.unpack('>I', data[offset:offset+4])[0]
&nbsp; &nbsp; &nbsp; &nbsp; chunk_type = data[offset+4:offset+8]
&nbsp; &nbsp; &nbsp; &nbsp; offset += 8 + chunk_len + 4
&nbsp; &nbsp; &nbsp; &nbsp; if chunk_type == b'IEND':
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return data[offset:]
&nbsp; &nbsp; raise RuntimeError("IEND chunk missing")

# LCG解密
def lcg_decrypt(raw: bytes):
&nbsp; &nbsp; if len(raw) < 8:
&nbsp; &nbsp; &nbsp; &nbsp; raise RuntimeError("Trailer data too short")
&nbsp; &nbsp; seed = int.from_bytes(raw[4:8], 'big')
&nbsp; &nbsp; cur = seed
&nbsp; &nbsp; out = bytearray()
&nbsp; &nbsp; for b in raw[8:]:
&nbsp; &nbsp; &nbsp; &nbsp; cur = (A * cur + C) & MASK
&nbsp; &nbsp; &nbsp; &nbsp; out.append(b ^ (cur & 0xFF))
&nbsp; &nbsp; return seed, bytes(out)

# Base62解码
def b62_decode(s: str) -> bytes:
&nbsp; &nbsp; num = 0
&nbsp; &nbsp; for c in s:
&nbsp; &nbsp; &nbsp; &nbsp; num = num * 62 + B62.index(c)
&nbsp; &nbsp; byte_cnt = (num.bit_length() + 7) // 8
&nbsp; &nbsp; return num.to_bytes(byte_cnt, 'big')

# 解析文件
def parse_file(zip_path: Path):
&nbsp; &nbsp; png_name, png_buf = get_png_data(zip_path)
&nbsp; &nbsp; tail = cut_after_iend(png_buf)
&nbsp; &nbsp; seed, dec_buf = lcg_decrypt(tail)
&nbsp; &nbsp; b62_str = dec_buf.rstrip(b'\x00').decode('ascii')
&nbsp; &nbsp; flag = b62_decode(b62_str).decode('utf-8')
&nbsp; &nbsp; return {
&nbsp; &nbsp; &nbsp; &nbsp; 'zip_path': str(zip_path),
&nbsp; &nbsp; &nbsp; &nbsp; 'png_name': png_name,
&nbsp; &nbsp; &nbsp; &nbsp; 'png_size': len(png_buf),
&nbsp; &nbsp; &nbsp; &nbsp; 'tail_size': len(tail),
&nbsp; &nbsp; &nbsp; &nbsp; 'seed_hex': f"0x{seed:08x}",
&nbsp; &nbsp; &nbsp; &nbsp; 'b62_str': b62_str,
&nbsp; &nbsp; &nbsp; &nbsp; 'flag': flag
&nbsp; &nbsp; }

# 扫描目标文件
def scan_targets(input_list: list[str]) -> list[Path]:
&nbsp; &nbsp; if not input_list:
&nbsp; &nbsp; &nbsp; &nbsp; input_list = [str(Path(__file__).parent.resolve())]
&nbsp; &nbsp; paths = []
&nbsp; &nbsp; for item in input_list:
&nbsp; &nbsp; &nbsp; &nbsp; p = Path(item)
&nbsp; &nbsp; &nbsp; &nbsp; if p.is_dir():
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paths += sorted(p.glob('*.zip'))
&nbsp; &nbsp; &nbsp; &nbsp; else:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paths.append(p)
&nbsp; &nbsp; return paths

# 主运行
def run():
&nbsp; &nbsp; parser = argparse.ArgumentParser()
&nbsp; &nbsp; parser.add_argument('targets', nargs='*')
&nbsp; &nbsp; args = parser.parse_args()
&nbsp; &nbsp; file_list = scan_targets(args.targets)
&nbsp; &nbsp; if not file_list:
&nbsp; &nbsp; &nbsp; &nbsp; print("[!] No ZIP files found")
&nbsp; &nbsp; &nbsp; &nbsp; return
&nbsp; &nbsp; for fp in file_list:
&nbsp; &nbsp; &nbsp; &nbsp; try:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res = parse_file(fp)
&nbsp; &nbsp; &nbsp; &nbsp; except Exception as e:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[!] {fp}: {str(e)}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue
&nbsp; &nbsp; &nbsp; &nbsp; print(f" &nbsp; &nbsp;Flag: {res['flag']}\n")

if __name__ == "__main__":
&nbsp; &nbsp; run()

关键截图

flag

flag{memory_dump_analysis}

19、签到题 – 损坏的压缩包|Base64 解码

题目:data.txt,内容为 Base64 字符串

考点:基础 Base64 解码

解题步骤

  1. 打开 data.txt,内容:a2Jzdg==
  2. 直接 Base64 解码,得到 flag。

关键截图

flag

flag{kbsv}

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:赛查查 《第十届御网杯网络安全大赛 Write Up》

    评论:0   参与:  0