APIs Are Everywhere
Modern web applications don’t just serve HTML pages. Behind the UI, there’s usually a set of APIs (Application Programming Interfaces) that handle the actual logic: authentication, data retrieval, user management, file operations.
These APIs are often less protected than the web UI. The frontend might enforce input validation and access controls, but the API behind it might not.
If the frontend says “you can’t do that,” the API might disagree.
REST API Basics
Most web APIs follow the REST (Representational State Transfer) pattern.
Key characteristics:
- Endpoints are URLs that represent resources:
/api/users,/api/books - HTTP methods define the action: GET (read), POST (create), PUT (update), DELETE (remove)
- Data is usually JSON:
{"username": "admin", "password": "secret"} - Versioned paths:
/api/v1/users,/api/v2/users
The API Path Convention
API paths are usually predictable:
/api/version/resource For example:
/api/v1/users- list all users/api/v1/users/admin- specific user/api/v1/users/admin/password- specific property/api/v2/books/search- search functionality
Predictable naming is your advantage. If you find
/api/v1/users, you can guess that/api/v1/booksand/api/v1/adminprobably exist too.
Discovering APIs with Gobuster
You can’t test APIs you haven’t found. Gobuster has a powerful pattern feature for API discovery.
Creating a Pattern File
APIs are versioned. Create a pattern file that appends version numbers to every wordlist entry:
echo '{GOBUSTER}/v1' > pattern.txt
echo '{GOBUSTER}/v2' >> pattern.txtThe {GOBUSTER} placeholder gets replaced with each word from the wordlist.
Running the Scan
gobuster dir -u http://10.10.10.50:5001 -w /usr/share/wordlists/dirb/big.txt -p pattern.txtThis might discover:
/api/v1/books(Status: 200)/api/v1/users(Status: 200)/console(Status: 200)
Each of these is a thread to pull.
Interacting with APIs using curl
curl is your command-line API client. It’s on every system and gives you full control over HTTP requests.
Basic GET Request
curl -i http://10.10.10.50:5002/api/v1/usersThe -i flag includes response headers, which reveal server software, content types, and more.
POST Request with JSON
curl -d '{"username":"admin","password":"test"}'
-H 'Content-Type: application/json'
http://10.10.10.50:5002/api/v1/users/login-dsends data in the request body-Hsets a header (here, telling the server we’re sending JSON)
Changing the HTTP Method
curl -X PUT
-H 'Content-Type: application/json'
-H 'Authorization: Bearer eyJ...'
-d '{"password":"pwned"}'
http://10.10.10.50:5002/api/v1/users/admin/passwordThe -X flag overrides the default method (GET) with any method you want.
HTTP Methods Matter
The same endpoint can behave completely differently depending on the HTTP method you use.
What Each Method Does
| Method | Purpose | When to try it |
|---|---|---|
| GET | Read data | Always, it’s the default |
| POST | Create something new | Login forms, registration, uploads |
| PUT | Replace/update existing data | Changing passwords, updating profiles |
| PATCH | Partial update | Same as PUT but for single fields |
| DELETE | Remove something | Account deletion, file removal |
Reading Error Messages
Error responses tell you more than you think:
| Response | What it really means |
|---|---|
404 Not Found | Endpoint doesn’t exist |
405 Method Not Allowed | Endpoint exists, wrong method |
401 Unauthorized | Endpoint exists, need credentials |
403 Forbidden | Endpoint exists, insufficient privileges |
400 Bad Request | Endpoint exists, wrong parameters |
A 405 is better than a 404. It confirms the endpoint is real. Try a different method.
The API Exploitation Chain
Finding one endpoint leads to finding more. Each discovery feeds the next step.
A Real Attack Flow
Here’s how API enumeration leads to full compromise:
- Brute-force API paths with Gobuster patterns → find
/api/v1/users - GET
/api/v1/users→ returns a list of usernames including “admin” - Brute-force
/api/v1/users/admin/→ discover/emailand/passwordsub-paths - POST to
/loginwith wrong password → error says “Password is not correct” (confirms the username is valid) - POST to
/registerwith"admin": truein the JSON → creates an admin account - Login with new account → get a JWT token
- PUT to
/api/v1/users/admin/passwordwith the JWT → change the real admin’s password
Full admin takeover, no exploit code needed. Just curl and creative enumeration.
JWT Tokens
Many APIs use JSON Web Tokens (JWT) for authentication. After a successful login, the server returns a token. You include it in subsequent requests:
curl -H 'Authorization: Bearer eyJhbGciOiJ...'
http://10.10.10.50:5002/api/v1/users/adminJWTs are base64-encoded and have three parts separated by dots. You can decode them to see the payload:
echo 'eyJhbGciOiJ...' | base64 -dThis reveals the username, role, and expiration. Sometimes the role can be tampered with if the server doesn’t validate the signature properly.
Common API Vulnerabilities
| Vulnerability | What to look for |
|---|---|
| Broken access control | Can you access other users’ data by changing the ID? |
| Mass assignment | Does the registration endpoint accept "admin": true? |
| Excessive data exposure | Does the API return more fields than the UI shows? |
| Missing rate limiting | Can you brute-force the login endpoint? |
| Method confusion | Does PUT work where POST is rejected? |
| Verbose errors | Do error messages reveal valid usernames or internal paths? |
APIs trust the client more than they should. The frontend may enforce rules, but the API often doesn’t. Always test the API directly with curl or Burp, bypassing the UI entirely.
Practice Boxes
- Nibbles - Web enumeration leading to CMS admin exploitation
- Bashed - Directory brute-forcing reveals a hidden web shell
- Pickle Rick - Source code inspection and command injection
- Blunder - Web app enumeration and CMS exploitation