Rating:
---
## Solver
```python
#!/usr/bin/env python3
import socket, ssl, hashlib, ast, re, sys, time
HOST = "nitwit.challs.pwnoh.io"
PORT = 1337
CONNECT_TIMEOUT = 15
READ_TIMEOUT = 2.5
POST_SEND_READ_LOOPS = 40
def h(x: bytes) -> bytes:
return hashlib.sha256(x).digest()
def chain(x: bytes, t: int) -> bytes:
for _ in range(t):
x = h(x)
return x
def int_to_vec_buggy(m: int, vec_len: int, base: int = 16):
digits = [0] * vec_len
i = vec_len - 1
while m > 0:
digits[i] = m % base
m //= base
i -= 1
return digits
def df_vec(msg_bytes: bytes):
d = 15
n0 = 64
n1 = 2
m_int = int.from_bytes(msg_bytes, "big")
m_vec = int_to_vec_buggy(m_int, n0, 16)
c = d * n0 - sum(m_vec)
c_vec = int_to_vec_buggy(c, n1, 16)
return m_vec + c_vec
TOKEN_RE = re.compile(rb"""b(['"])(?:\\.|(?!\1).)*\1""", re.S)
def extract_sig_list(buf: bytes, expect: int = 66):
sig = []
for m in TOKEN_RE.finditer(buf):
lit = m.group(0).decode("ascii", "strict")
try:
sig.append(ast.literal_eval(lit))
except Exception:
continue
if len(sig) == expect:
return sig
return None
FLAG_RE = re.compile(rb'(?i)(flag\{[^}]+\}|pwnoh\{[^}]+\}|pwn\{[^}]+\})')
def main():
m0 = b"\x00" * 32
m_new = b"admin" + b"\xff" * 23 + b"\x40" + b"\x00" * 3
assert len(m_new) == 32
s_old = df_vec(m0)
s_new = df_vec(m_new)
for i, (a, b) in enumerate(zip(s_old, s_new)):
if b < a:
raise RuntimeError(f"delta negative at idx {i}: {b} < {a}")
ctx = ssl.create_default_context()
with socket.create_connection((HOST, PORT), timeout=CONNECT_TIMEOUT) as raw:
with ctx.wrap_socket(raw, server_hostname=HOST) as s:
s.settimeout(CONNECT_TIMEOUT)
buf = b""
while b">>> " not in buf:
chunk = s.recv(8192)
if not chunk:
break
buf += chunk
sys.stdout.write(chunk.decode(errors="ignore"))
sys.stdout.flush()
s.sendall((m0.hex() + "\n").encode())
data = b""
sig = None
while True:
chunk = s.recv(8192)
if not chunk:
break
data += chunk
sys.stdout.write(chunk.decode(errors="ignore"))
sys.stdout.flush()
if sig is None:
sig = extract_sig_list(data, expect=66)
if sig is not None and (b">>> " in data):
break
if sig is None or len(sig) != 66:
raise RuntimeError(f"[x] Failed to parse signature list (got {0 if sig is None else len(sig)})")
s.sendall((m_new.hex() + "\n").encode())
data2 = b""
while b">>> " not in data2:
chunk = s.recv(8192)
if not chunk:
break
data2 += chunk
sys.stdout.write(chunk.decode(errors="ignore"))
sys.stdout.flush()
forged = [chain(sig[i], s_new[i] - s_old[i]) for i in range(len(s_new))]
payload = repr(forged) + "\n"
s.sendall(payload.encode())
s.settimeout(READ_TIMEOUT)
full = b""
got_flag = None
for _ in range(POST_SEND_READ_LOOPS):
try:
chunk = s.recv(8192)
if not chunk:
break
full += chunk
sys.stdout.write(chunk.decode(errors="ignore"))
sys.stdout.flush()
m = FLAG_RE.search(full)
if m:
got_flag = m.group(1).decode(errors="ignore")
break
except socket.timeout:
continue
if got_flag:
print("\n[+] FLAG:", got_flag)
else:
time.sleep(0.2)
try:
while True:
chunk = s.recv(8192)
if not chunk:
break
full += chunk
sys.stdout.write(chunk.decode(errors="ignore"))
sys.stdout.flush()
m = FLAG_RE.search(full)
if m:
print("\n[+] FLAG:", m.group(1).decode(errors="ignore"))
break
except Exception:
pass
if __name__ == "__main__":
main()
```
## Output:
```text
FLAG: bctf{i_f0rg0t_h0w_t0_r3ad_m4th_n0t4t10n}
```