flag format: FLAG{...} solve challenge rồi viết ch...
Tạo vào: 29 tháng 5, 2026
Tạo vào: 29 tháng 5, 2026
flag format: FLAG{...}
solve challenge rồi viết cho tôi 1 file md hướng dẫn giải lại chi tiết gồm lệnh và script đã dùng
bash -lc cat > /mnt/data/solve_challenge.md <<'MD'
textFLAG{V0l4t1l3_Br0ws3r_St4t3}
Challenge gồm 2 artifact:
memory_artifact.txt: kết quả strings từ memory browser, chứa JWT/resume token, signature fragment, request id đang active và nonce.traffic.pcap: lưu lượng HTTP. Response /api/secret được gzip + chunked, bên trong là JSON chứa ciphertext AES-256-CBC.Từ memory xác định stream đúng là req-live-4821 vì:
textwindow.__TRACE__={"candidateRequestIds":["req-archive-1138","req-telemetry-2244","req-live-4821"],"active":"req-live-4821"} sessionStorage["recoveryNonce"]="nonce-ephemeral-browser-9f3c71" IndexedDB:volatile-auth:{"sigFragment":"c2lnbmF0dXJl","traceRef":"req-live-4821"}
sigFragment base64 decode ra signature, vì vậy token đầy đủ là:
text<resumeToken>.c2lnbmF0dXJl
Key AES được derive bằng SHA-256 từ chuỗi:
text<full_jwt>|req-live-4821|nonce-ephemeral-browser-9f3c71
Ciphertext trong JSON có dạng IV || ciphertext, 16 byte đầu là IV.
bashfile /mnt/data/memory_artifact.txt /mnt/data/traffic.pcap head -n 40 /mnt/data/memory_artifact.txt strings -a /mnt/data/traffic.pcap | grep -E 'FLAG|flag|GET|POST|HTTP|token|nonce|req-|Authorization|Cookie|websocket|gzip|chunk|jwt|eyJ' -n
Kết quả đáng chú ý trong pcap:
textGET /api/archive HTTP/1.1 X-Request-ID: req-archive-1138 Transfer-Encoding: chunked Content-Encoding: gzip GET /api/telemetry HTTP/1.1 X-Request-ID: req-telemetry-2244 Transfer-Encoding: chunked Content-Encoding: gzip GET /api/secret HTTP/1.1 X-Request-ID: req-live-4821 Transfer-Encoding: chunked Content-Encoding: gzip
Lưu thành extract_http.py:
python#!/usr/bin/env python3 import struct import socket import gzip from pathlib import Path def parse_pcap(path): data = Path(path).read_bytes() magic = data[:4] endian = '<' if magic == b'\xd4\xc3\xb2\xa1' else '>' *_, linktype = struct.unpack(endian + 'HHiiii', data[4:24]) off = 24 streams = {} while off + 16 <= len(data): _ts_sec, _ts_usec, incl_len, _orig_len = struct.unpack(endian + 'IIII', data[off:off + 16]) off += 16 pkt = data[off:off + incl_len] off += incl_len # traffic.pcap là Linux cooked capture v2, linktype 276. if linktype != 276 or len(pkt) < 20: continue proto = struct.unpack('!H', pkt[0:2])[0] if proto != 0x0800: continue ip = pkt[20:] if len(ip) < 20: continue ihl = (ip[0] & 0x0f) * 4 if ip[9] != 6: # TCP continue total_len = struct.unpack('!H', ip[2:4])[0] src = socket.inet_ntoa(ip[12:16]) dst = socket.inet_ntoa(ip[16:20]) tcp = ip[ihl:total_len] if len(tcp) < 20: continue sport, dport, seq, _ack, off_flags = struct.unpack('!HHIIH', tcp[:14]) tcp_header_len = (off_flags >> 12) * 4 body = tcp[tcp_header_len:] if body: streams.setdefault((src, sport, dst, dport), []).append((seq, body)) return {k: b''.join(chunk for _, chunk in sorted(v)) for k, v in streams.items()} def dechunk(body): out = b'' i = 0 while True: j = body.find(b'\r\n', i) if j < 0: break size_line = body[i:j].split(b';', 1)[0] try: size = int(size_line, 16) except ValueError: break i = j + 2 if size == 0: break out += body[i:i + size] i += size + 2 return out for stream, payload in parse_pcap('/mnt/data/traffic.pcap').items(): if not payload.startswith(b'HTTP/1.1'): continue header, _, body = payload.partition(b'\r\n\r\n') headers = header.decode('latin1').split('\r\n') request_id = next((h.split(': ', 1)[1] for h in headers if h.lower().startswith('x-request-id:')), '') if b'Transfer-Encoding: chunked' in header: body = dechunk(body) if b'Content-Encoding: gzip' in header: body = gzip.decompress(body) print(f'=== {stream} RID={request_id} ===') print(body.decode('utf-8', 'replace'))
Chạy:
bashpython3 extract_http.py
Output quan trọng:
json{"type":"encrypted_flag","algorithm":"AES-256-CBC","stream":"live","request_id":"req-live-4821","data":"4FJ8/vLJ5Tf84E1j6Ee2imsCxno4ARV2+7byPofRBHCGbPFGElbYYuiejakKXlTY"}
Lưu thành solve.py:
python#!/usr/bin/env python3 import base64 import hashlib from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes resume_token = ( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' 'eyJ1c2VyIjoiYW5hbHlzdCIsInNlc3Npb24iOiJlcGhlbWVyYWwiLCJpYXQiOjE3MDAwMDAwMDB9' ) sig_fragment = 'c2lnbmF0dXJl' request_id = 'req-live-4821' nonce = 'nonce-ephemeral-browser-9f3c71' enc_b64 = '4FJ8/vLJ5Tf84E1j6Ee2imsCxno4ARV2+7byPofRBHCGbPFGElbYYuiejakKXlTY' full_jwt = f'{resume_token}.{sig_fragment}' key_material = f'{full_jwt}|{request_id}|{nonce}' key = hashlib.sha256(key_material.encode()).digest() raw = base64.b64decode(enc_b64) iv = raw[:16] ct = raw[16:] cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) pt = cipher.decryptor().update(ct) + cipher.decryptor().finalize() pad = pt[-1] if not 1 <= pad <= 16 or pt[-pad:] != bytes([pad]) * pad: raise ValueError('Invalid PKCS#7 padding') flag = pt[:-pad].decode() print(flag)
Chạy:
bashpython3 solve.py
Kết quả:
textFLAG{V0l4t1l3_Br0ws3r_St4t3}
Có thể decode sigFragment như sau:
bashpython3 - <<'PY' import base64 print(base64.urlsafe_b64decode('c2lnbmF0dXJl' + '===').decode()) PY
Output:
textsignature
MD ls -l /mnt/data/solve_challenge.md
Thought for 6m 10s
Đã giải ra flag:
textFLAG{V0l4t1l3_Br0ws3r_St4t3}
Mình đã tạo file hướng dẫn chi tiết tại đây: solve_challenge.md
Nguồn memory artifact đã dùng: (memory_artifact.txt)