Exploiting. Part 1: Applications¶
We discuss exploiting concents and then focus on application exploiting (i.e. runtime/binary application exploiting).
- Slides for this session:
Cheatsheet¶
Before you start, enable support for x32 binaries with:
# allow the execution of x32 binaries on x64 Linux
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
# also allow the compilation of x32 binaries on x64 Linux
sudo apt-get install gcc-multilib
To disassemble a binary, use:
objdump -M intel -d <name-of-the-binary> | less
To disassemble a raw shellcode, use:
objdump -D -b binary -m i386 -M intel <file-containing-raw-shellcode>
Compute a payload, write it to a file and then send the payload to a binary:
python3 -c 'import sys; sys.stdout.buffer.write(b"<your-payload>")' > /tmp/payload
cat /tmp/payload - | ./<vulnerable-binary>
Same outcome, without writing the payload to the file:
cat <((python3 -c 'import sys; sys.stdout.buffer.write(b"<your-payload>")')) - | ./<vulnerable-binary>
To send the payload to a remote server, use:
cat <((python3 -c 'import sys; sys.stdout.buffer.write(b"<your-payload>")')) - | nc <IP> <PORT>
Caution: Use sys.stdout.buffer.write()
instead of print()
when working with raw bytes in Python3
.
For details, see this stackoverflow question.
Lab Key Takeaways¶
x32 Linux system call convention: place the system call number in
eax
, then its arguments, in order, inebx
,ecx
,edx
,esi
,edi
, andebp
, then invokeint 0x80
.On x32 Linux, function call parameters are pushed on the stack from the rightmost to the leftmost as they appear in C code.
On x32 Linux, system call parameters are copied into registers (they are not pushed into registers).
Based on points 2 and 3 above: on x32 Linux function calling convention is different than system call calling convention.
x64 Linux system call convention: place the system call number in
rax
, then its arguments, in order, inrdi
,rsi
,rdx
,r10
,r8
, andr9
, then invokesyscall
.On x64 Linux, the x64 Linux function call convention states that parameters are pushed into
rdi
,rsi
,rdx
,rcx
,r8
,r9
respectively.Based on points 5 and 6 above: in terms of parameter order on x64, the only difference between function calling and syscall calling is the overlap between
r10
andrcx
. See the question about r10 and rcx registers.A list of both x32 and x64 syscalls is Linux system call convention.
Tasks¶
Download the session task archive.
Open the session task archive and access the
buffer-overflow/
subfolder. Exploit thevuln
executable to jump to thewarcraft()
,diablo()
and thenstarcraft()
functions, one at a time. When callingstarcraft()
you are only interested in printing the message via theputs()
call.The steps are:
Use
nm
orobjdump
to find the addresses ofwarcraft()
,diablo()
and theputs()
call inside ofstarcraft()
.Identify the location and the length of the buffer overflow.
Craft payloads to exploit the buffer overflow.
Send each payload to the binary.
Open the session task archive and access the
shellcode/
subfolder. Thehello-shellcode/vuln
binary is compiled fromhello-shellcode/vuln.c
usingmake
. Thegen-hello-shellcode/
subdirectory contains boilerplate code to help you easily compile shellcodes.See the assembly source code in
gen-hello-shellcode/shellcode.S
, and then usemake
to assemble it as a raw file calledshellcode.bin
. You can disassemble the raw file by usingobjdump -D -b binary -m i386 -M intel shellcode.bin
and see that it matchesshellcode.S
. You can list the contents ofshellcode.bin
in hexadecimal by usingmake print
.Your goal is to write shellcodes in
asm
, assemble the shellcodes and send the shellcodes to thevuln
binary.At each subchallenge, perform the following:
Craft your shellcode inside the right asm source file.
Compile and print your shellcode.
Send the raw shellcode to the
vuln
binary to exploit it.
The subchallenges are:
The
gen-hello-shellcode/shellcode-mundi.S
file is a copy ofgen-hello-shellcode/shellcode.S
. Update thegen-hello-shellcode/shellcode-mundi.S
shellcode to writeSalut, Mundi!
to standard output. Then compile the shellcode withmake print-mundi
and send it to thevuln
binary.Now make the
vuln
binary exit properly (without printing Segmentation fault) after running your shellcode. To do so, update thegen-hello-shellcode/print-exit-shellcode.S
source to also runexit(0)
after printingSalut, Mundi!
. Then compile the shellcode withmake print-exit-print
and send it to thevuln
binary.The system call ID of
exit()
is on the Linux system calls page or inside of/usr/include/asm/unistd_32.h
. The system call ID is stored in theeax
register and parameters are stored inebx
,ecx
,edx
,esi
andedi
.Check information on Linux system calls and Linux system call convention.
Printing is boring. Spawning shells is fun. Create a new shellcode that spawns a shell. To do so, update the
gen-hello-shellcode/execve-shellcode.S
shellcode to spawn a shell by runningexecve("/bin/sh", 0, 0)
. Then compile the shellcode withmake execve-print
and then send it to thevuln
binary.If you are out of ideas for the shellcode, take a look at this one. Check a more complicated one if things are too easy. For the curious, more fun shellcodes are found on shell-storm.org.
After you get a working shellcode, test the same payload on the remote server. Use
nc
alongsidepython3
to generate and send the payload to the remote server. The address is141.85.224.104:30000
.For a better understanding of what the execve shellcode does, go through the article Demystifying the Execve Shellcode (Stack Method).
(BONUS) Create a shellcode that reads a fixed-length message from standard input and then prints it and exits properly. Update the
gen-hello-shellcode/read-print-exit-shellcode.S
source to read a fixed length string onto the stack and print it to standard output. Then compile the shellcode withmake read-print-exit-print
and send it to thevuln
binary.
Open the session task archive and access the
ret-to-libc/
subfolder. Your goal is to create shells by callingsystem()
. Do this in three different ways:Call
system("/bin/bash")
from functionenroth()
.Comment out
enroth()
and callsystem("sh")
using the call tosystem()
in functionerathia()
and thesh
string already in the executable.Also comment out
erathia()
and callsystem("sh")
by using the address ofsystem()
in the standard C library. Disable ASLR by usingecho 0 | sudo tee /proc/sys/kernel/randomize_va_space
.
Open the session task archive and access the
integer-overflow/
subfolder. Provide the proper input to theintover
executable to create a shell. Craft a working payload locally and then submit it to the remote server. The address is141.85.224.104:30001