2020: rgbctf: five fives - 5225225
This commit is contained in:
parent
bf6ebc4719
commit
26f7857bbc
|
@ -0,0 +1,70 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.security.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Scanner in = new Scanner(System.in);
|
||||
|
||||
System.out.println("Welcome to the Five Fives Lotto!");
|
||||
System.out.println("Generating seed...");
|
||||
|
||||
//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);
|
||||
|
||||
System.out.println("Yesterday's numbers were: ");
|
||||
for (int i = 0; i != 5; i++) {
|
||||
System.out.print((r.nextInt(5) + 1) + " ");
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int[] nums = new int[5];
|
||||
for (int a = 0; a != 5; a++) {
|
||||
nums[a] = r.nextInt(5) + 1;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void outputFlag() {
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader("flag.txt"));
|
||||
System.out.println(in.readLine());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error reading flag. Please contact admins.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
# 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: <Main.java>
|
||||
|
||||
## 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`.
|
Loading…
Reference in New Issue