mobile solve
This commit is contained in:
96
2026/insomnihack/web/Exfailtrator/solve.py
Normal file
96
2026/insomnihack/web/Exfailtrator/solve.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Solve script for DNS 0x20 exfiltration challenge.
|
||||
|
||||
The webshell exfiltrates data via DNS by:
|
||||
1. base64-encoding the content (with + and / replaced by -)
|
||||
2. prepending a 3-char MD5 checksum
|
||||
3. performing a DNS_A lookup for: {base64}.{checksum}.{attacker_domain}
|
||||
|
||||
DNS 0x20 encoding preserves the case of query labels in the response,
|
||||
meaning the mixed-case payload in the DNS log IS the original base64.
|
||||
|
||||
However, intermediate resolvers may have corrupted some letter cases,
|
||||
so we reconstruct the correct capitalisation by:
|
||||
- splitting the payload into groups of 4 base64 characters
|
||||
- trying all case variants per group
|
||||
- keeping only variants that decode to printable ASCII
|
||||
- finding the combination whose MD5[:3] matches the checksum in the log
|
||||
"""
|
||||
|
||||
import base64
|
||||
from hashlib import md5
|
||||
from itertools import product
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paste the data label and checksum from the 0x20-encoded DNS log entry here
|
||||
# ---------------------------------------------------------------------------
|
||||
PAYLOAD = "Su5tE1QwdDRSBHLfBJn2zXjFAgFWcdNUzWQTAxjSLtfLodhjMtUzfq"
|
||||
CHECKSUM = "190" # first 3 hex chars of md5(flag)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def reverse_strtr(s: str) -> str:
|
||||
"""The PHP replaces + and / with -. Reverse where possible (no-op if no dashes)."""
|
||||
# If there are no dashes the base64 had neither + nor /, nothing to do.
|
||||
# If there ARE dashes we'd need to try both — handled by the case-brute-force below.
|
||||
return s
|
||||
|
||||
|
||||
def case_variants(group: str):
|
||||
"""Yield every capitalisation variant of a base64 group that decodes to printable ASCII."""
|
||||
letter_positions = [(i, c) for i, c in enumerate(group) if c.isalpha()]
|
||||
for bits in product([True, False], repeat=len(letter_positions)):
|
||||
candidate = list(group)
|
||||
for (idx, _), upper in zip(letter_positions, bits):
|
||||
candidate[idx] = candidate[idx].upper() if upper else candidate[idx].lower()
|
||||
s = "".join(candidate)
|
||||
padding = "=" * ((4 - len(s) % 4) % 4)
|
||||
try:
|
||||
decoded = base64.b64decode(s + padding)
|
||||
if all(32 <= b < 127 for b in decoded): # printable ASCII only
|
||||
yield s, decoded
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def solve(payload: str, checksum: str) -> str:
|
||||
payload = reverse_strtr(payload)
|
||||
|
||||
# Split into groups of 4 (standard base64 block size)
|
||||
groups = [payload[i:i+4] for i in range(0, len(payload), 4)]
|
||||
|
||||
# Collect valid byte candidates for each group
|
||||
group_candidates = []
|
||||
for i, g in enumerate(groups):
|
||||
cands = list(case_variants(g))
|
||||
if not cands:
|
||||
raise ValueError(f"No printable-ASCII candidate found for group {i} ({g!r})")
|
||||
group_candidates.append([dec for _, dec in cands])
|
||||
print(f" group[{i:02d}] {g!r:6s} → {[dec for _, dec in cands]}")
|
||||
|
||||
print(f"\nSearching {' × '.join(str(len(c)) for c in group_candidates)} combinations "
|
||||
f"for MD5[:3] == {checksum!r} …\n")
|
||||
|
||||
# Enumerate combinations and check MD5 checksum
|
||||
for combo in product(*group_candidates):
|
||||
candidate_bytes = b"".join(combo)
|
||||
if md5(candidate_bytes).hexdigest()[:3] == checksum:
|
||||
return candidate_bytes.decode()
|
||||
|
||||
raise ValueError("No combination matched the checksum — check PAYLOAD / CHECKSUM values.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("DNS 0x20 Exfiltration — Solve Script")
|
||||
print("=" * 60)
|
||||
print(f"Payload : {PAYLOAD}")
|
||||
print(f"Checksum : {CHECKSUM}\n")
|
||||
print("Candidate bytes per base64 group (printable ASCII filter):")
|
||||
|
||||
flag = solve(PAYLOAD, CHECKSUM)
|
||||
|
||||
print("=" * 60)
|
||||
print(f"FLAG: {flag}")
|
||||
print("=" * 60)
|
||||
Reference in New Issue
Block a user