← Back to Writeups
CUSTOMMediumpwn

httpsec

XESXOR9/2/20263 min read
#pwn#custom#medium#reverse_engineering#route_recovery#token_validation_reversal

httpsec

Platform: spbctf | Category: pwn | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-06-08 | Status: Solved Techniques: reverse_engineering, route_recovery, token_validation_reversal

Summary

Task: a network-exposed ELF implements a tiny custom HTTP server with a hidden protected route instead of an obvious crash bug. Solution: reverse the parser and auth logic, recover the required /secret/ path and valid 8-byte X-Auth token _kR8hVQS, then request the route to receive the flag.

httpsec — spbctf

Description

No organizer description was preserved in the task files.

The target service was http://109.233.56.90:11544/ and the provided binary was httpsec.elf. Initial probing showed GET / returning Welcome to our fast web-server, while unknown routes returned No such route.

Analysis

At first glance this looked like a small HTTP-facing pwn service: the ELF is amd64 PIE with NX enabled, no canary, and partial RELRO. That naturally suggests a parser bug, but reversing showed the intended solve was logic recovery rather than memory corruption. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The key functions were:

  • 0x19f3 — per-connection HTTP parser
  • 0x138d — main route and auth handler
  • 0x199e — header lookup helper
  • 0x1327 — prefix-compare helper

The parser splits the request line with strtok() into global method, path, and version pointers. The path is truncated at ?, so query-string tricks do not change routing. Then up to 16 headers are parsed into a table of (name, value) pairs.

Route handling is simple:

  1. Exact GET / returns Welcome to our fast web-server.
  2. Any path with prefix /secret/ and method GET enters the secret handler.
  3. Everything else returns No such route. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The secret handler looks up the X-Auth header with the helper at 0x199e.

  • Missing header -> 403 Forbidden / Missing auth token
  • Wrong length (!= 8) -> 403 Forbidden / Bad auth token
  • Correct length -> custom arithmetic/XOR validation

Reversing the checker showed that the token test is fully reversible. One valid token is:

text
_kR8hVQS

Sending GET /secret/ with X-Auth: _kR8hVQS returns:

text
Flag: spbctf{REDACTED}

So the important conclusion is that this was a hidden-route plus custom-auth reversing task packaged as a pwn service, not a memory-corruption exploit. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Brief dead ends worth noting:

  • common route fuzzing found nothing beyond /
  • Host-header and similar HTTP tricks did not affect routing
  • the initial memory-corruption hypothesis was killed by reversing the real control flow

Solution

  1. Probe the service and record the two visible behaviors: / works and unknown paths return No such route.
  2. Inspect httpsec.elf with checksec; note the pwn-style mitigations but avoid assuming a bug exists.
  3. Reverse the request parser at 0x19f3 and the main handler at 0x138d.
  4. Recover the hidden route condition: method must be GET and path must have prefix /secret/.
  5. Reverse the secret handler and identify the required X-Auth header.
  6. Follow the 8-byte arithmetic/XOR checker and solve it, yielding _kR8hVQS.
  7. Send a valid request and read the flag from the response. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
python
#!/usr/bin/env python3

import socket

HOST = "109.233.56.90"
PORT = 11544
TOKEN = "_kR8hVQS"

request = (
    "GET /secret/ HTTP/1.1\r\n"
    f"Host: {HOST}:{PORT}\r\n"
    f"X-Auth: {TOKEN}\r\n"
    "Connection: close\r\n"
    "\r\n"
)

with socket.create_connection((HOST, PORT), timeout=5) as sock:
    sock.sendall(request.encode())
    data = b""
    while True:
        chunk = sock.recv(4096)
        if not chunk:
            break
        data += chunk

print(data.decode(errors="replace"))

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Expected response:

text
HTTP/1.1 200 OK

Flag: spbctf{REDACTED}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍