.. | ||
README.md |
shellcode
Every once in a while, you'll need to run some shellcode.
Before jumping into how to do things in Python with pwntools, it's worth exploring the command-line tools as they can really make life easy!
asm
This command line tool does what it says on the tin.
$ asm nop
90
$ asm 'mov eax, 0xdeadbeef'
b8efbeadde
There are a few output formats to choose from. By default, the tool writes hex-encoded output to stdout if it's a terminal. If it's a pipe or file, it will instead just write the binary data.
phd
is a command that comes with pwntools which is very similar to xxd
, but includes highlighting of printable ASCII values, NULL bytes, and some other special values.
$ asm nop -f hex
90
$ asm nop -f string
'\x90'
$ asm nop | phd
00000000 90 │·│
00000001
Different architectures and endianness values can be selected as well, as long as you have an appropriate version of binutils
installed. See the installation page for more information.
$ asm -c arm nop
00f020e3
$ asm -c powerpc nop
60000000
$ asm -c mips nop
00000000
Pwntools is also aware of most common constants, and resolves them in a context-sensitive manner.
$ asm 'push SYS_execve'
6a0b
$ asm -c amd64 'push SYS_execve'
6a3b
disasm
Disasm is the counterpart to asm
.
$ asm 'push eax' | disasm
0: 50 push eax
$ asm -c arm 'bx lr' | disasm -c arm
0: e12fff1e bx lr
shellcraft
Shellcraft is the command-line interface to the shellcode library that comes with Pwntools. To get a list of all avialable shellcode, just use the shellcraft
command by itself.
$ shellcraft
aarch64.linux.accept
aarch64.linux.access
aarch64.linux.acct
...
Many of the shellcraft templates are just syscall wrappers, designed to make shellcode easier. A few of them -- in particular sh
, dupsh
, and echo
-- are compact implementations of common shellcode for execve
, dup2
ing file descriptors, and writing a string to stdout
.
Like the asm
tool, shellcraft
has multiple output modes.
$ shellcraft i386.linux.sh
6a68682f2f2f73682f62696e89e331c96a0b5899cd80
$ shellcraft i386.linux.sh -fasm
/* push '/bin///sh\x00' */
push 0x68
push 0x732f2f2f
push 0x6e69622f
/* call execve('esp', 0, 0) */
mov ebx, esp
xor ecx, ecx
push 0xb
pop eax
cdq /* Set edx to 0, eax is known to be positive */
int 0x80
Debugging Shellcode
Invariably, you'll want to debug your shellcode, or just experiment with a small snippet. Pwntools makes this super easy!
Emitting ELF files
The first option is to emit an ELF file which contains the shellcode, and load it in GDB manually.
$ shellcraft i386.linux.sh -f elf > sh
$ asm 'mov eax, 1; int 0x80' -f elf > exit
$ chmod +x sh exit
$ strace ./exit
execve("./exit", ["./exit"], [/* 94 vars */]) = 0
_exit(0) = ?
$ echo 'echo Hello!' | strace -e execve ./sh
execve("./sh", ["./sh"], [/* 94 vars */]) = 0
execve("/bin///sh", [0], [/* 0 vars */]) = 0
Hello!
Some of the commands may take options, and all of them should be documented. shellcraft
will also resolve any constants it knows about.
$ shellcraft i386.linux.echo -?
Writes a string to a file descriptor
Arguments:
string(str): Message to print
sock: File descriptor. Default is ebp.
$ shellcraft i386.linux.echo "Hello, world" STDOUT_FILENO
686f726c64686f2c20776848656c6c6a015b89e16a0c5a6a0458cd80
$ shellcraft i386.linux.mov eax SYS_execve -fasm
push 0xb
pop eax
$ shellcraft i386.linux.mov eax SYS_execve
6a0b58
Launching GDB
Instead of emitting an ELF and launching GDB manually, you can just jump straight into GDB.
$ shellcraft i386.linux.sh --debug
$ asm 'mov eax, 1; int 0x80;' --debug