Skip to main content

Insecure Direct Object Reference (IDOR)

Insecure Direct Object References (IDOR) is a security vulnerability that occurs when an application allows users to directly access or modify objects (such as files, database records, or URLs) based on user-supplied input, without sufficient access controls. This means that if a user changes a parameter value (like an ID) in a URL or API request, they might be able to access or manipulate data that they aren’t authorized to see or modify.

Vulnerable Code​

Look at the code snippet below, any logged-in user can access other users’ data by changing the user_id parameter in the URL.

To fix this, we need to check if the logged-in user owns the requested data.

<?php
// Assume user is already authenticated

// Get user ID from URL (e.g., profile.php?user_id=3)
$user_id = $_GET['user_id'];

// Fetch user data without checking ownership
$conn = new mysqli("localhost", "root", "", "users_db");
$result = $conn->query("SELECT * FROM users WHERE id = $user_id");

if ($result->num_rows > 0) {
$user = $result->fetch_assoc();
echo "Name: " . $user['name'] . "<br />";
echo "Email: " . $user['email'] . "<br />";
}
?>

MUST have Burp Extension​

Autorize is an extension aimed at helping the penetration tester to detect authorization vulnerabilities, one of the more time-consuming tasks in a web application penetration test.

Short Note

Following color and their meaning when using this extension:

  1. Bypassed! - Red color
  2. Enforced! - Green color
  3. Is enforced??? (please configure enforcement detector) - Yellow color

Testing Methodology ​

Numeric Value Parameter ​

Increment and decrement these values to access sensitive information.

  • Decimal value: 287789, 287790, 287791, ...
  • Hexadecimal: 0x4642d, 0x4642e, 0x4642f, ...
  • Unix epoch timestamp: 1695574808, 1695575098, ...

Common Identifiers Parameter​

Some identifiers can be guessed like names and emails, they might grant you access to customer data.

  • Name: john, doe, john.doe, ...
  • Role: customer, admin, moderator, ...
  • Email: email@gmail.com
  • Base64 encoded value: ZW1haWxAZ21haWwuY29tCg==

Weak Pseudo Random Number Generator ​

  • UUID/GUID v1 can be predicted if we know the time they were created: 95f6e264-bb00-11ec-8833-00155d01ef00
  • MongoDB Object Ids are generated in a predictable manner: 5ae9b90a2c144b9def01ec37
    • a 4-byte value representing the seconds since the Unix epoch
    • a 3-byte machine identifier
    • a 2-byte process id
    • a 3-byte counter, starting with a random value
info

Useful tool: https://github.com/andresriancho/mongo-objectid-predict

  • By default it predicts future OID than provided one.
  • Using --backward flag, it predicts previous/older OIDs.
  • --counter-diff 100 will generate 100 OIDs only around passed OIDs.
# mongo-objectid-predict cheatsheet
# Basic usage (predict forward ObjectIds)
python2 mongo-objectid-predict 6985ac948cbf4900093753c2

# Predict older ObjectIds (eg: find admin created before user)
python2 mongo-objectid-predict --backward 6985ac948cbf4900093753c2

# Increase guessing range (counter offset)
python2 mongo-objectid-predict --counter-diff 100 6985ac948cbf4900093753c2

# Generate multiple ObjectIds per counter value
python2 mongo-objectid-predict --per-counter 3 6985ac948cbf4900093753c2

# Wide backward prediction (common IDOR case)
python2 mongo-objectid-predict --backward --counter-diff 200 6985ac948cbf4900093753c2

# Generate many ObjectIds and save to file
python2 mongo-objectid-predict --counter-diff 1000 6985ac948cbf4900093753c2 > objectids.txt

# Stealthy low-noise prediction
python2 mongo-objectid-predict --backward --counter-diff 50 --per-counter 1 6985ac948cbf4900093753c2

# Fuzz predicted ObjectIds against API
ffuf -w objectids.txt -u https://target/api/user/FUZZ

Hashed Parameter​

Sometimes we see websites using hashed values to generate a random user id or token, like sha1(username), md5(email), ...

  • MD5: 098f6bcd4621d373cade4e832627b4f6
  • SHA1: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
  • SHA2: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Wildcard Parameter ​

Send a wildcard (*, %, ., _) instead of an ID, some backend might respond with the data of all the users.

  • GET /api/users/* HTTP/1.1
  • GET /api/users/% HTTP/1.1
  • GET /api/users/_ HTTP/1.1
  • GET /api/users/. HTTP/1.1

IDOR Tips ​

  • Change the HTTP request: POST → PUT
  • Change the content type: XML → JSON
  • Transform numerical values to arrays: {"id":19} → {"id":[19]}
  • Use Parameter Pollution: user_id=hacker_id&user_id=victim_id