# B01lers CTF 2020
After a long hiatus playing any CTFs, I had a lot of fun getting back into theswing of things by playing b01lers CTF, put on by Purdue University.Unfortunately, I only had the time to look at three of the easier pwningchallenges, and solve two of those.
## Pwn 100 - Department of Flying Vehicles
> Dave ruined the code for the DFV starship registry system. Please help fix it.>> `nc pwn.ctf.b01lers.com 1001`  > [dfv](dfv/dfv)  > Author: nsnc
This is appears to be a simple keygen/reversing challenge:
```$ ./dfvDave has ruined our system. He updated the code, and now he even has trouble checking his own liscense!If you can please make it work, we'll reward you!
Welcome to the Department of Flying Vehicles.Which liscense plate would you like to examine? > EATDUSTError.```
But when we disassemble it:
![main function of dfv in Binary Ninja](pics/dfv-main.png)
At address `0xabe`, we see that our string is XORed with`'\x11\x0f\xdcI\xd6\xd5\x04\x10'` (let's call this value `xor`) and then ataddress `0xac2` the first 8 bytes are compared to `'R@\x93\x05\x92\x94R\x10'`(let's call this value `key`). Equivalently, our input is compared to `xor ^key`, which equals `COOLDAV\0`. If our string matches this value, thenexecution continues to a branch were it is possible to reach `sub_96a`, whichprints `flag.txt`. If, on the other hand, our string does not match at all, thenthe program exits without printing the flag.
So we know that our input string must be `"COOLDAV"` if we want to print theflag. Is that all there is to this challenge? A simple XORed string? No! This isa _100_ point challenge. It better take more than 5 minutes to solve!
If we examine the block starting at `0xad6`, we will see that our same input is`strncmp`'d with `"COOLDAV"`, and then `sub_96a` is called if our string __doesnot match__ with `"COOLDAV"`. So, what can we deduce? We know that our stringmust _not_ match `"COOLDAV"`, but _must_ match `"COOLDAV"`. These twoconstraints are logical inverses of each other, so requiring both would beunsatisfiable. In short, the challenge is unsolvable. The end. Thanks for awonderful CTF Purdue!
Wait, let's look closer at that `xor` at `0xabe`. Looking at the disassembly, wecan see that `xor` and `key` both live in memory (indeed, there is no versionof the [`xor` instruction on AMD64](https://www.felixcloutier.com/x86/xor) thatcan encode a 64-bit immediate operand). In fact, they both live on the stack.Hmm, if only there were a way to overwrite those two values...
![A closer inspection of instructions 0xab5..0xabe](pics/dfv-closer.png)
Oh, now what's that? A call to `gets`? The[dangerous](https://stackoverflow.com/q/1694036/1529586),[unsafe](https://cwe.mitre.org/data/definitions/242.html), and[deprecated](https://github.com/bminor/glibc/blob/e4a399921390509418826e8e8995d2441f29e243/libio/stdio.h#L571-L582)`gets`?! Well, now that we know we have a buffer overflow on the stack, weshould be able to overwrite `xor` or `key`, or both! This will allow us to givean input string that does not match `"COOLDAV"`, and by changing `xor` and`key`, it can match `xor ^ key`. So we need to choose an `s`, `xor`, and `key`,such that `s ^ xor == key` and `s != "COOLDAV"`. Solving the challenge is assimple as sending each in order. See [sol.py](dfv/sol.py) for the full solution.
## Pwn 100 - Meshuggah 2.0
> Dave escaped security, but only by crashing directly into an asteroid. Don't worry, he's still alive, but he's going to need a new starship>> `nc pwn.ctf.b01lers.com 1003`  > [meshuggah](meshuggah/meshuggah)  > Author: maczilla
When we visit the Used ~~Car~~ Starship Dealer, they inform us of an ongiongsale: one starship at any time will be 90% off, but it is up to us to identifyit. For accountability, they kinda provide us with the first three starships ofthe day that were sold at 90% off, and then we are asked which starship we wouldlike to buy.
```Welcome to the Used Car Dealership, we hope you are ready for the insane savings ahead of you!Here are the first three starships which were purchased today for an incredible 90% savings. Each starship costs a mere 10 credits when on sale, but we only put one on sale at a time
1. Meshuggah-15083166962. Meshuggah-19084842463. Meshuggah-340538234
I don't even know how Meshuggah comes up with their model names, but I don't care because everyone buys them
Which model starship would you like to buy? 420Thats gonna be an expensive one... Glad you're buying from me! And please come back after that one breaks down.```
![main function of meshuggah in Binary Ninja](pics/meshuggah-main.png)
`main` is simple enough: `srand(time(NULL) + 2)`, `list_purchases()`, then it givesus 1000 money, then calls `buy_starship` 92 times. If we're able to make 92purchases without go bankrupt, then it will print the flag; otherwise it justexits.
![list_previous_purchases function of meshuggah in Binary Ninja](pics/meshuggah-list-previous.png)
`list_previous_purchases` prints out the first three random numbers returned by `rand()`.
![buy_starship function of meshuggah in Binary Ninja](pics/meshuggah-buy.png)
`buy_starship` asks us to choose a starship by number, then produces a randomnumber using `rand()`. If our two numbers match, they sell us the starshipfor 10 money; otherwise they sell it for 100 money.
We start with 1000 money, and we need to make 92 purchases. If we pull this offperfectly, guessing the right number every single time, then we'll wind upspending 920 (92 * 10). Now it's apparent to me why 92: if we guess wrong evenonce, we would have to spend 1010 money to purchase 92 starships. It's set up sothat we have to perfectly guess all 92 starships.
Normally, this would be extremely hard. `rand()` returns an `int`, which on mostsystems is a 32-bit number, making it about a 1-in-4-billion chance to correctlyguess any one number, let alone 92 of them. Fortunately, we have two tricks upour sleeve:
1. We are given the first three numbers that come out of the PRNG, so instead of   making a 1-in-4-billion chance guess 92 times, we can search through all the   possible seeds (again, on most systems a 32-bit number) and find the one(s)   that produce a PRNG sequence that matches the first three given to us.2. The way that they are seeding the PRNG is very important. Since they are   seeding it with `time(NULL) + 2`, if we can guess the system time, then we   can figure out the seed. This is a serious flaw, and corresponds to [CWE   337](https://cwe.mitre.org/data/definitions/337.html)
(1) alone would be very inefficient (on my machine it would take about an hour),and it's not guaranteed to give just one result. But when we combine it with(2), there might only be a few seeds that we have to search, due to anyuncertainty in the system time.
So, to wrap up, we need to collect the three initial PRNG values leaked to us.Then we try seeds that are near `time(NULL) + 2` until we find one that producesa sequence that starts with those three numbers. Then, using that seed, we sendthe next 92 numbers to the target. See [sol.py](meshuggah/sol.py) for the fullsolution.