Find the Password (medium)
附件是一个要求输入密码的控制台程序:它把输入字符求和当 XOR key 来解密
encrypted.enc,只有算出的校验和命中目标值才把解密出的口令回显出来。
附件含 Windows 版
app7win.zip(app7win.exe)和 Linux 版
app7unix.tar.gz(ELF app7unix),以及加密文件
encrypted.enc(480 字节)。程序把输入字符逐字节求和得到
key,用 key XOR encrypted.enc 的前 5
字节、边解边累加校验和;当校验和等于 0xdca 时,用
printf("Congratulations, The password is '%s'")
把解密结果当作口令打印出来。
Solution
Recon:
file unix/app7unix win/app7win.exe work/encrypted.enc →
app7unix 是
ELF 64-bit LSB pie executable, x86-64, not stripped,app7win.exe
是
PE32 executable for MS Windows 4.00 (console), Intel i386, 3 sections,encrypted.enc
是 data。
strings -a unix/app7unix 里有
Please enter the password:、encrypted.enc、Failed to open encrypted.enc、An error occured、Congratulations, The password is '%s'、Invalid Password,还残留源文件名
app7win.c:Linux 版和 Windows 版来自同一份源码。
#!/usr/bin/env python3 """Recover the HTS Application 7 password from encrypted.enc. app7win.exe reads the first 5 bytes of encrypted.enc, XORs each of them with a 32-bit key derived from the login input (key = sum of the signed input bytes, the trailing newline included), accumulates the *full* 32-bit XOR results into a checksum, and prints "The password is '%s'" only when that checksum equals 0xdca. Reproducing the checksum lets us solve for the single key that passes the gate; the same key turns encrypted.enc into the plaintext password. """ MASK = 0xffffffff TARGET = 0xdca# cmp [checksum],0xdca in main enc = open("encrypted.enc", "rb").read(5)
defchecksum(key): """Windows build: sum of (byte ^ key) as full 32-bit values.""" total = 0 for b in enc: total = (total + (b ^ key)) & MASK return total
deftransform(raw, key): """Per byte: repeat {buf = buf>>1 | ((buf&1)<<7)} key times, then += 3.""" out = bytearray() for v in raw: for _ inrange(key): v = (v >> 1) | (0x80if v & 1else0) out.append((v + 3) & 0xff) returnbytes(out)
defmain(): key = next(k for k inrange(1 << 20) if checksum(k) == TARGET) print(f"checksum {TARGET:#x} reached with key = {key} ({key:#x})") raw = bytes((b ^ key) & 0xfffor b in enc) print(f"encrypted.enc[:5] ^ key = {raw.hex()}") pw = transform(raw, key) print(f"plaintext password = {pw.decode()!r}") # any login whose signed-byte sum (newline included) equals key passes the gate print(f"login input needs signed-byte sum {key} (newline adds 10)")
if __name__ == "__main__": main()
1 2 3 4 5
$ cd <hts-workspace>/challenges/hts-app/app7/work && cp ../solve.py . && uv run python solve.py checksum 0xdca reached with key = 753 (0x2f1) encrypted.enc[:5] ^ key = c0bcc8c4c2 plaintext password = 'caged' login input needs signed-byte sum 753 (newline adds 10)