Skip to main content

Documentation Index

Fetch the complete documentation index at: https://hackwithmike.com/llms.txt

Use this file to discover all available pages before exploring further.

Introduction


I passed the OffSec Web Expert (OSWE) exam a while back, and I promised to write something on it - so here it is. OSWE is a 48-hour proctored exam with 2 targets. Each target has 1 user flag for authentication bypass, and 1 root flag for remote code execution (RCE). Obtaining 3 out of 4 flags is required to pass. Each target also comes with 2 machines: a target machine with the actual flags, and a debug machine that holds an exact copy of the source code and the application. Do note that you cannot download the source code off the debugging box to your own machine. Most analysis and review will be performed on the debugging machine. Per target, you are expected to produce a single Python exploit script that chains together both the auth-bypass and RCE vulnerabilities. Since there are already a lot of great OSWE write-ups on the course structure and exam-day experience, the rest of this blog will focus more on my methodology and preparation. Here are a few references that helped me along the way: One more tip for you: pay close attention to the comments on the slow exam environment - I experienced the same and ended up using SSH, grep commands, and eyeballing for most of my code review.

The Methodology


The OSWE / AWAE course focuses heavily on exploitation techniques for the introduced vulnerabilities. By the time you sit the exam, you should already have a bunch of scripts and helpers ready, such as blind SQLi extractors, XSS token-theft payloads, reverse shell handlers, etc. The actual challenge of the exam is to find bugs in an unfamiliar codebase under time pressure, and to triage exploitable vulnerabilities from rabbitholes. A concatenated SQL query is a good lead, but it can also be a dead end if the input was cast to an integer upstream, or if it is being properly sanitised by a strong filter. On the other hand, custom sanitisers are always worth investigating, as the implementation can be incomplete or misconfigured. From a pure exam perspective, two ideas drive my whole approach: splitting your work into two tracks - Auth-bypass & RCE, and hunting by features & endpoints.

Two Tracks: Auth-bypass and RCE

As mentioned, each target requires an authentication bypass to get to the app admin account for the user flag, and an RCE for the root flag. Treat them as separate searches - each is usually abused through different features and vuln classes.

Authentication Bypass

The Auth-bypass track is always about attacking the authentication logic. You can trick the server into believing you are someone else, or have a higher privilege (e.g., admin=true), or break the authentication flow to skip the checks, or simply get your hands into the valid credentials. Start by understanding how the application authenticates users and assigns roles. Here are some example questions worth asking:
  • Does the app use session tokens to authenticate & authorize its users? If so, how are they implemented? (e.g., Cookies? Authentication Header? Custom headers?)
  • Say if the app uses cookies for authentication, are the cookies properly protected? Is httponly set to prevent XSS from extracting the cookie?
  • Is role assignment exposed in the client-side? (e.g., something like role=admin in cookies / headers). If so, are they properly validated?
  • How are the session tokens (and other related tokens like password reset, temporary login codes) generated, stored, and checked? Are they vulnerable to extraction from database (SQLi), or are they predictable?
  • etc.

Remote-Code Execution

On the other hand, the RCE track is about identifying where the server may parse or process our input as server-side code. The usual vectors are deserialization, server-side template injection (SSTI), custom command wrappers, file upload to an executable path, SQL injection, etc. From an exam perspective, this is easier to scope: since the RCE is expected after Auth-bypass, focus on functions and endpoints that are exposed to the admin user only. It can be something like:
  • An admin-only dashboard that contains a command wrapper;
  • An editing function that normal users are restricted from using;
  • A file upload function for administrative tasks;
  • An SQL query that only the admin user is accessible;
  • etc.
Using the “admin-only” logic, if an upload function behaves exactly the same for both regular users and admin users, then it is less likely to be the intended RCE vector for OSWE. Keeping the two tracks separate stops you from getting distracted by the amount of code. Start with Auth-bypass, and keep the RCE hunt limited to admin-accessible features only.
Vulnerability chaining is a must for the OSWE exam (and also in real-world hunting), so always ask - “what does this vulnerability unlock next?”. A file read vuln can lead to leaking of environment variables, which give further access to other services that expose another vulnerablity, etc.

Hunt by Features and Endpoints

Since we have both the source code and a working application, treat it like a grey-box test: interact with the application like a regular user, list every accessible feature and endpoint, then map them back to the source code. Using the two-track methodology, here are some features & endpoints worth looking at:

Pre-admin (Auth-bypass)

  • Login and registration
  • Password reset
  • Profile and account update
  • Any user-input areas (e.g., blog post, comments, feedback forms, URL parameters, etc.)
  • File upload and download (e.g., profile picture, blog post images, attachments, etc.)
  • Any functions that likely pull data from the database (e.g., search function, blog post filtering, etc.)
  • etc.

Post-admin (RCE)

  • Admin dashboard
  • File import and export
  • File upload and download
  • Content Templates
  • User management panel
  • Database management panel
  • Background and cron jobs
  • System command / function runners
  • etc.
Most importantly, trace the user input from source to sink. Ask yourself - where does it enter (source)? What transformations happen? Which security checks run before the dangerous operation? Where does it reach eventually (sink)?

The Preparation


With the methodology, we can then prepare for the exam accordingly. Know the impact of each vuln class, have search patterns ready, and prepare helper scripts that were battle-tested in labs.

Vulnerability Classes by Tracks

Following the two-track approach, I classified each vulnerability class by their impacts. If it helps with becoming admin, it goes into the Auth-bypass track. If it helps turn admin access into code execution, it goes into the RCE track.

Pre-admin (Auth-bypass)

For the pre-admin track, the goal is to reach the administrator context, steal or forge a privileged session, or otherwise make the application treat you as the admin user. Here is how to think about the pre-admin bugs:
Impact: Data extraction, auth bypass, token theft
  • It may leak admin password hashes, active sessions, reset tokens, signing secrets, etc. Sometimes the login query itself can also be bypassed directly.

Impact: Account takeover
  • Check the reset token is predictable, reusable, leaked, or not properly tied to a user.

Post-admin (RCE)

For the post-admin track, the bug only becomes interesting once the feature is reachable from the admin context or clearly depends on data the admin can create. The main question is whether the vuln can actually become code execution:
Impact: Direct command execution
  • This is the cleanest RCE way - look out for filters & bypass though.
  • Pro-tip: Validate it with a quick wget or curl command to your controlled server to confirm if the command is actually being executed.

Impact: Database-level file write or command execution
  • Some databases can write files, load extensions, execute commands, or leak credentials for another service. That is where SQLi becomes more than data theft.
There is naturally some overlap between the two lists. SQLi, XXE, SSRF, and traversal can all be either pre-admin or post-admin depending on where they are reachable and what they expose. The key is not to see it as a rigid framework, but a mental map helps you quickly prioritize your effort during the exam.

Search Patterns

Have grep patterns ready for the languages you might see will make your life way easier. I usually start by spamming a few grep searchs, open the interesting-looking files, then trace the input properly from route -> controller -> helper/model/sink. Here are a few examples:
# Routes / auth checks
grep -rn "Route::\|->connect\|->get\|->post\|Router::" --include="*.php" .
grep -rn "beforeFilter\|isAuthorized\|checkAccess\|allow(" --include="*.php" .

# SQLi / auth-bypass leads
grep -rn "mysqli_query\|->query(\|->exec(\|PDO" --include="*.php" .
grep -rn "\"[[:space:]]*\.[[:space:]]*\$_\|'[[:space:]]*\.[[:space:]]*\$_\|SELECT.*\$" --include="*.php" .

# RCE / file / parsing sinks
grep -rn "eval(\|assert(\|call_user_func\|create_function" --include="*.php" .
grep -rn "exec(\|shell_exec(\|system(\|passthru(\|popen(\|proc_open(" --include="*.php" .
grep -rn "unserialize(\|__wakeup\|__destruct\|__toString" --include="*.php" .
grep -rn "move_uploaded_file\|file_put_contents\|\$_FILES\|include(\|require(" --include="*.php" .
grep -rn "DOMDocument\|simplexml_load\|XMLReader\|xml_parse\|LIBXML_NOENT" --include="*.php" .

Helpers and AI in Prep

As is the case for all OffSec exams, conversational AI tools are banned during the exam. However, that doesn’t mean you can’t use them before the exam for preparation. I used LLMs heavily during prep to make sure I covered the areas I was weaker in, such as Java and PHP. Here is an example of what my prompt looked like. Always tweak the prompt around - different lengths, structures, wordings, and focuses - until you find something useful:
LLM Prompt
Generate a white-box/grey-box vulnerability cheatsheet for [LANGUAGE] using the following structure:

1. **Language Overview** – structure, routing logic, key features, important syntax/functions
2. **Initial Recon** – high-value files, entry points, and areas to prioritize during code review
3. **Auth Bypass** – hunting strategies, relevant vuln classes, exploitation techniques (include cross-language techniques where applicable, and variants beyond what the course explicitly covers)
4. **RCE** – same scope as above; include technique variants (e.g., for deserialization: XML, BinaryFormatter, etc.)
5. **White-box Hunting Tips** – language-specific tips, grep patterns, static analysis tricks

Notes:
- Assume white-box access with a live app and optional dynamic debugger (grey-box where useful)
- Reference course syllabus topics where applicable
- Include relevant techniques not explicitly in the syllabus
I also had it assist me in creating most of my helper snippets. However, LLMs sometimes love to overcomplicate things. It once built me a highly sophisticated custom HTTP session handler, basically a huge requests wrapper with extra steps, while all I needed was one simple line of requests.Session().get(). Definitely know your basics, so that you can call out the slop when needed. Here are some helper snippets worth having ready and tested before exam day:
  • Blind SQLi extractor with parallel worker threads (I built a very handy one!)
  • Token brute-forcer
  • Web server that can both serve payloads and receive callbacks (e.g., handling XSS callbacks, serving DTDs, etc.)
  • Reverse shell handler with separate send and receive threads
  • Argparse skeleton for new exploit scripts (all the flags & parameters for your final exploit)
  • Modular PoC structure that you can easily plug in and remove the above snippets
One advanced tip I have is to spend time figuring out what to hardcode into the final Python script. For example, if you need to upload a binary file / ZIP file for your exploit, you can’t really “attach” that file alongside your Python script as a bundle. To solve this, I simply encode the file to Base64, embed the Base64 string into the script, then decode it during runtime. As long as the file size isn’t too big, this is usually the cleanest way to handle attachments. The other example is XXE exploits - I would hardcode the DTDs and XML payloads in my scripts. While the official guide notes that you can start a Netcat listener and web server before executing the script, I prefer building that into the script so it works smoothly for the examiner. Do note that some tools, such as phpggc, may require dynamic inputs like target IPs or ports, so this trick may not always work gracefully. In that case, I prefer writing a webshell to a reachable location for simplicity. My own helpers and PoC templates are in my GitHub repo: https://github.com/hkm67/OSWE-Notes. Feel free to reference and adapt them to your needs!

Closing Notes


Once again, thank you for reading till the end. The methodology here is purely from my personal experience and way of thinking, so I know it may not be as intuitive to everyone. I tried my best to make it make sense, but please feel free to reach out if you have any questions or recommendations - my inbox is always open! (Tho sometimes I may reply a bit slow haha)
Last modified on May 26, 2026