THM: Bookstore

After several hospital appointments, I finally had time for another CTF. This time I picked Bookstore on TryHackMe, rated as medium and focused on API enumeration — exactly my thing. Web pentesting is what I enjoy most at the moment, and although I might try bug bounties in the future, that’s still a different league and not something I feel fully ready for yet.

This machine turned out to be a nice combination of API fuzzing, source code analysis, and Local File Inclusion (LFI).

NMAP

A quick port scan revealed three open ports:

Port 5000 immediately stood out — Werkzeug usually means Flask.

HTTP (80)

Browsing to port 80 showed a generic web page with no real functionality.

  • gobuster: no useful directories
  • ffuf: no subdomains
  • Burp Suite while browsing revealed requests going to:

That looked far more interesting than the static site.

API Enumeration (5000)

Navigating to port 5000 gave me a basic page.

I immediately ran Gobuster:

  • /api
  • /console

Visiting /console showed me a Flask debug console protected by a PIN.

I could brute-force it… but before going down that route, I decided to enumerate the API properly first.

Visiting /api returned actual API documentation.

This confirmed I was in the right place. I grabbed a wordlist for fuzzing from GitHub and started attacking /api/v2. Nothing stood out at first, so I tried older versions.

The API allowed parameters like:

  • id
  • author
  • published

So I fuzzed parameter names to see if something unexpected would pop up.

One command always crashed the server: show Checking the response in Burp showed:

The error message filename not defined immediately suggested a possible LFI vulnerability, so I decided to verify it:

After digging through HTML source and failing to extract more useful files manually, I turned to HackTricks — and found two powerful file paths:

  • /proc/self/cmdline
  • /proc/self/environ

That last file ended up giving me the PIN I needed to unlock the console.

Going back to /console, I entered the PIN and gained access to the Python execution console.

I spawned a reverse shell with this one-liner:

Shell access achieved:

Privilege Escalation

First thing I did after getting a shell was run LinPEAS to get a better overview of the system and spot any obvious privilege escalation vectors. One file immediately stood out in the results:

Checking its permissions showed something interesting:

The file was owned by root and executable. Running it launched some kind of custom binary, so rather than blindly executing it further, I decided to inspect it first.

Reverse engineering the binary

I downloaded the file to my Kali machine and opened it in Ghidra. Reverse engineering is not my strongest skill, so this took me a bit longer than expected — but it was a good learning moment. Eventually I discovered the following logic:

The program calculates a value using this expression:

So the “mystery value” was just a simple XOR operation. I quickly decoded it in Python:

Output:

Root access

At this point I simply ran the binary again and used the decoded value as input.

While this wasn’t a traditional privilege escalation like abusing sudo permissions or misconfigured cronjobs, it was a great hands-on exercise in reverse engineering and understanding how binaries hide secrets. That alone made this part worth it.

Learning notes

API Enumeration

  • Always enumerate versioned endpoints: /v1, /v2, /beta, /old.
  • Try parameter fuzzing, not just paths — logic bugs often live in parameters.
  • Read API docs carefully; they often expose more than intended.
  • If v2 looks secure, try v1 — backwards compatibility usually means weaker validation.

Error Handling

  • Treat error messages as information disclosure.
  • Messages like filename not defined often indicate internal file handling.
  • Application crashes during requests usually mean poor input validation.
  • Always test parameters hinted by error output.

Reverse Engineering (Privilege Escalation)

  • Download suspicious binaries and analyze locally.
  • Start with:
    • strings
    • Ghidra or IDA
  • Focus on:
    • auth checks
    • hardcoded values
    • XOR routines
    • input validation
  • Decode logic offline before executing anything on the target.
  • Simple obfuscation (XOR) = low-hanging fruit.