247CTF - The Encrypted Password

The encrypted password

Challenge prompt:

You won't find the admin's secret password in this binary. We even encrypted it with a secure one-time-pad. Can you still recover the password?

1. Quick dynamic check with ltrace

The retained ltrace excerpt shows the input and comparison calls. Its strcmp string is a tracer-truncated display, not Python or a complete executable source listing.

1
2
3
4
$ ltrace ./encrypted_password
puts("Enter the secret password:")
fgets("arst\\n", 33, stdin)
strcmp("arst\\n", "141c85ccfb2ae19d8d8c224c4e403dce"...)

This already hints that the expected secret is a printable 32-byte string.

2. Or debug in debugger (pwndbg)

The retained debugger excerpt uses a breakpoint at strcmp (0x555555400930); this address depends on the loaded executable and ASLR mapping.

1
2
3
4
5
pwndbg> b *0x555555400930
pwndbg> r
► 0x555555400930 call strcmp@plt
s1: 0x7fffffffdf00 ◂— 0x500000000a
s2: 0x7fffffffded0 ◂— '141c85ccfb2ae19d8d8c224c4e403dce'

At compare time, s2 contains the final password candidate.

3. Or reverse logic in IDA

Relevant decompiled logic:

1
2
3
4
5
6
7
8
9
10
11
12
strcpy(s, "875e9409f9811ba8560beee6fb0c77d2");
*(_QWORD *)s2 = 0x5A53010106040309LL;
v8 = 0x5C585354500A5B00LL;
v9 = 0x555157570108520DLL;
v10 = 0x5707530453040752LL;

for (i = 0; i < strlen(s); ++i)
s2[i] ^= s[i];

fgets(s1, 33, stdin);
if (!strcmp(s1, s2))
printf("You found the flag!\\n247CTF{<flag-redacted>}\\n", s2);

The excerpt records the XOR construction and comparison. fgets(s1, 33, stdin) can read exactly 32 bytes before the terminating NUL, leaving a typed newline unread; the 32-byte candidate should be supplied without an extra newline in the compared buffer. The original executable is unavailable, so the comparison path has not been rerun.

Reconstruct the secret with Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import struct

chunks = [
0x5A53010106040309,
0x5C585354500A5B00,
0x555157570108520D,
0x5707530453040752,
]

s2_bytes = b"".join(struct.pack("<Q", chunk) for chunk in chunks)
key = b"875e9409f9811ba8560beee6fb0c77d2"
if len(s2_bytes) != len(key):
raise ValueError("XOR operands must both contain 32 bytes")
password = bytes(value ^ mask for value, mask in zip(s2_bytes, key))

print(password.decode("ascii"))

Flag

247CTF{[flag redacted]}