MISC-长虹守卫
ISCC2026 WriteUp 提交模板
MISC-长虹守卫
解题思路
1.解压
解压后发现有这几个文件

2.分析txt文档

发现后面有一段base64
解码:

KEYMAT:AURORA-ER|flight=LX-517|syn=<EVT_A_UTC>|idl=<EVT_B_UTC>|a2=<EVT_C_UTC>
ALGO:SHA256|XOR|CTR
REASM:SEQ_ORDER|frag=3
IDRULE:idx26_applied_to_idx>=27_only
UTC:local+date_corr-timezone
NOTE:EVT_A=TCP_SYN_SENT,EVT_B=IDL_CROSS,EVT_C=ANOMALY_MARKER_A2
可以看到KEYMAT后面,有:
syn=<EVT_A_UTC>:SYN 握手时间取自事件 A 的 UTC 标准时间戳idl=<EVT_B_UTC>:空闲交叉时间取自事件 B 的 UTC 时间戳a2=<EVT_C_UTC>:A2 异常标记时间取自事件 C 的 UTC 时间戳
EVT_A: TCP_SYN_SENT
EVT_B: IDL_CROSS
EVT_C: marker=A2
3.分析流量包

也没几个包,发现这个后面与串hex
CIPH:6bcc4445589479de64236b4761bca7d66107ef6fb8cf966f9046a68caa36906c2201d29d53c6
根据提示:
DATE_CORR=-1DAY;bug=FDR-227(date_not_applied)
must_apply_DATE_CORR=-1DAY from idx>=0026
IDRULE:idx26_applied_to_idx>=27_only
UTC:local+date_corr-timezone
这几句合起来说明:
- 飞机东向跨越 +180 -> -180 时,本地日期应该回退一天
- 但飞参记录器有 bug,这个修正没有正常应用
- 更麻烦的是,提示又说这个规则可能只对 idx>=27 生效,也就是 idx26 这条 EVT_B 本身怎么解释存在歧义
所以为了稳妥,脚本对每个关键事件都同时尝试两种解释:
- date_corr = 0:假设这条日志的本地日期没修
- date_corr = -1:假设这条日志应该减一天再转 UTC
然后按提示里的公式去算候选 epoch:
UTC = local + date_corr - timezone
写脚本计算,得到:
ISCC{b8c4acc9fcfd685af25d69106dc9b59d}
Exp
import base64
import hashlib
import itertools
import re
import struct
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
LOG_PATH = BASE_DIR / "LX517.txt"
TRACE_PATH = BASE_DIR / "LX517.pcap"
FLAG_RE = re.compile(rb"ISCC\{[0-9a-fA-F]{32}\}")
@dataclass(frozen=True)
class FlightMarker:
row_id: int
local_stamp: datetime
latitude_deg: float
longitude_deg: float
code: str
memo: str
def scan_manifest(raw_log: str) -> str:
for fragment in re.findall(r"[A-Za-z0-9+/=]{80,}", raw_log):
try:
decoded_text = base64.b64decode(fragment).decode("utf-8")
except Exception:
continue
if "KEYMAT:" in decoded_text and "ALGO:" in decoded_text:
return decoded_text
raise RuntimeError("unable to locate embedded manifest")
def read_markers(raw_log: str) -> list[FlightMarker]:
markers = []
for row_text in raw_log.splitlines():
if not re.match(r"^\d{4},", row_text):
continue
columns = row_text.split(",", 9)
if len(columns) != 10:
continue
markers.append(
FlightMarker(
row_id=int(columns[0]),
local_stamp=datetime.strptime(columns[1], "%Y-%m-%d %H:%M:%S"),
latitude_deg=float(columns[2]),
longitude_deg=float(columns[3]),
code=columns[8],
memo=columns[9],
)
)
return markers
def guess_zone_hours(longitude_deg: float) -> list[int]:
candidates = {int(round(longitude_deg / 15))}
if longitude_deg > 150:
candidates.update({12, 13, 14})
if longitude_deg < -150:
candidates.update({-10, -11, -12})
return sorted(candidates)
def utc_epoch_variants(marker: FlightMarker) -> list[int]:
epochs = set()
for zone_hours, day_delta in itertools.product(
guess_zone_hours(marker.longitude_deg),
(0, -1),
):
shifted_local = marker.local_stamp + timedelta(days=day_delta)
utc_stamp = shifted_local - timedelta(hours=zone_hours)
epochs.add(int(utc_stamp.replace(tzinfo=timezone.utc).timestamp()))
return sorted(epochs)
def decode_capture_endian(global_header: bytes) -> str:
magic = global_header[:4]
if magic == b"\xd4\xc3\xb2\xa1":
return "<"
if magic == b"\xa1\xb2\xc3\xd4":
return ">"
raise RuntimeError("unsupported pcap magic")
def slice_tcp_appdata(trace_file: Path) -> list[bytes]:
capture = trace_file.read_bytes()
if len(capture) < 24:
return []
byte_order = decode_capture_endian(capture[:24])
app_chunks = []
cursor = 24
while cursor + 16 <= len(capture):
_ts_sec, _ts_usec, included_len, _original_len = struct.unpack(
byte_order + "IIII",
capture[cursor : cursor + 16],
)
cursor += 16
frame = capture[cursor : cursor + included_len]
cursor += included_len
if len(frame) < 14:
continue
if struct.unpack("!H", frame[12:14])[0] != 0x0800:
continue
ipv4_packet = frame[14:]
if len(ipv4_packet) < 20 or ipv4_packet[0] >> 4 != 4:
continue
header_len = (ipv4_packet[0] & 0x0F) * 4
total_len = struct.unpack("!H", ipv4_packet[2:4])[0]
if ipv4_packet[9] != 6 or len(ipv4_packet) < total_len:
continue
tcp_segment = ipv4_packet[header_len:total_len]
if len(tcp_segment) < 20:
continue
payload_offset = (tcp_segment[12] >> 4) * 4
app_data = tcp_segment[payload_offset:]
if app_data:
app_chunks.append(app_data)
return app_chunks
def recover_cipher_blob(trace_file: Path) -> bytes:
merged_payload = b"".join(slice_tcp_appdata(trace_file))
located = re.search(rb"CIPH:([0-9a-fA-F]+)", merged_payload)
if located is None:
located = re.search(rb"CIPH:([0-9a-fA-F]+)", trace_file.read_bytes())
if located is None:
raise RuntimeError("ciphertext marker not found")
return bytes.fromhex(located.group(1).decode())
def apply_counter_xor(cipher_blob: bytes, material_text: str) -> bytes:
block_total = (len(cipher_blob) + 31) // 32
stream = bytearray()
encoded_material = material_text.encode()
for counter in range(block_total):
stream.extend(
hashlib.sha256(
encoded_material + struct.pack(">I", counter)
).digest()
)
return bytes(left ^ right for left, right in zip(cipher_blob, stream))
def pick_relevant_markers(markers: list[FlightMarker]):
syn_markers = [item for item in markers if item.code == "EVT_A"]
idl_markers = [item for item in markers if item.code == "EVT_B"]
anomaly_markers = [
item
for item in markers
if item.code == "EVT_C"
and ("marker=A2" in item.memo or "marker=X9" in item.memo)
]
return syn_markers, idl_markers, anomaly_markers
def fill_material_template(
template_text: str,
syn_epoch: int,
idl_epoch: int,
anomaly_epoch: int,
) -> str:
return (
template_text.replace("<EVT_A_UTC>", str(syn_epoch))
.replace("<EVT_B_UTC>", str(idl_epoch))
.replace("<EVT_C_UTC>", str(anomaly_epoch))
)
def run() -> None:
raw_log = LOG_PATH.read_text(encoding="utf-8", errors="ignore")
manifest = scan_manifest(raw_log)
markers = read_markers(raw_log)
cipher_blob = recover_cipher_blob(TRACE_PATH)
template_match = re.search(r"^KEYMAT:(.+)$", manifest, re.MULTILINE)
if template_match is None:
raise RuntimeError("key material template missing")
material_template = template_match.group(1).strip()
syn_markers, idl_markers, anomaly_markers = pick_relevant_markers(markers)
attempt_count = 0
for syn_marker, idl_marker, anomaly_marker in itertools.product(
syn_markers,
idl_markers,
anomaly_markers,
):
epoch_triplets = itertools.product(
utc_epoch_variants(syn_marker),
utc_epoch_variants(idl_marker),
utc_epoch_variants(anomaly_marker),
)
for syn_epoch, idl_epoch, anomaly_epoch in epoch_triplets:
material_text = fill_material_template(
material_template,
syn_epoch,
idl_epoch,
anomaly_epoch,
)
attempt_count += 1
candidate_flag = apply_counter_xor(cipher_blob, material_text)
if FLAG_RE.fullmatch(candidate_flag):
print("hint:")
print(manifest)
print("ciphertext:", cipher_blob.hex())
print("keymat:", material_text)
print("flag:", candidate_flag.decode())
print("tried:", attempt_count)
return
raise RuntimeError(f"flag not found after {attempt_count} attempts")
if __name__ == "__main__":
run()

浙公网安备 33010602011771号