Top Banner
function hooking for osx and linux joe damato @joedamato timetobleed.com
127

Function hooking for OSX and Linux

Nov 19, 2014

Download

Documents

ice799

Talk from Defcon 18
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Function hooking for OSX and Linux

function hooking for osx and linux

joe damato@joedamato

timetobleed.com

Page 2: Function hooking for OSX and Linux

slides are ontimetobleed.com

Page 3: Function hooking for OSX and Linux

(free jmpesp)

Page 4: Function hooking for OSX and Linux

i’m not a security researcher.

call me a script kiddie: @joedamato

Page 5: Function hooking for OSX and Linux
Page 6: Function hooking for OSX and Linux

laughinglarry.com

Page 7: Function hooking for OSX and Linux

slayerinc.com

Page 8: Function hooking for OSX and Linux

dbgrady.files.wordpress.com

assembly is in att syntax

Page 9: Function hooking for OSX and Linux

WTF is an ABI ?

Page 10: Function hooking for OSX and Linux

WTF is an Application Binary

Interface ?

Page 11: Function hooking for OSX and Linux

alignment

thomasgroup.com

Page 12: Function hooking for OSX and Linux

calling convention

arianlim.wordpress.com

Page 13: Function hooking for OSX and Linux

object file and library formats

tandemfs.org

Page 14: Function hooking for OSX and Linux

hierarchy of specs

Page 15: Function hooking for OSX and Linux

topatoco.com

Page 16: Function hooking for OSX and Linux

System V ABI (271 pages)

System V ABI AMD64 Architecture Processor Supplement (128 pages)

System V ABI Intel386 Architecture Processor Supplement (377 pages)

MIPS, ARM, PPC, and IA-64 too!

Page 17: Function hooking for OSX and Linux

mac osx x86-64 calling convention

based on

System V ABI AMD64 Architecture ! ! ! Processor Supplement

Page 18: Function hooking for OSX and Linux

gregs-wines.com

Page 19: Function hooking for OSX and Linux

alignment

thomasgroup.com

Page 20: Function hooking for OSX and Linux

end of argument area must be aligned on a 16byte boundary.

and $0xfffffffffffffff0, %rsp

Page 21: Function hooking for OSX and Linux

calling convention

arianlim.wordpress.com

Page 22: Function hooking for OSX and Linux

• function arguments from left to right live in:%rdi, %rsi, %rdx, %rcx, %r8, %r9

• that’s for INTEGER class items.

• Other stuff gets passed on the stack (like on i386).

• registers are either caller or callee save

Page 23: Function hooking for OSX and Linux

object file and library formats

tandemfs.org

Page 24: Function hooking for OSX and Linux

steverubel.typepad.com

Page 25: Function hooking for OSX and Linux

ELF Objects

en.wikipedia.org

Page 26: Function hooking for OSX and Linux

ELF Objects• ELF objects have headers

• elf header (describes the elf object)

• program headers (describes segments)

• section headers (describes sections)

• libelf is useful for wandering the elf object extracting information.

• the executable and each .so has its own set of data

Page 27: Function hooking for OSX and Linux

ELF Object sections• .text - code lives here

• .plt - stub code that helps to “resolve” absolute function addresses.

• .got.plt - absolute function addresses; used by .plt entries.

• .debug_info - debugging information

• .gnu_debuglink - checksum and filename for debug info

Page 28: Function hooking for OSX and Linux

ELF Object sections

• .dynsym - maps exported symbol names to offsets

• .dynstr - stores exported symbol name strings

• .symtab - maps symbol names to offsets

• .strtab - symbol name strings

• more sections for other stuff.

Page 29: Function hooking for OSX and Linux

vanachteren.net

Page 30: Function hooking for OSX and Linux

Mach-O Objects

developer.apple.com

Page 31: Function hooking for OSX and Linux

Mach-O Objects• Mach-O objects have load commands

• header (describes the mach-o object)

• load commands (describe layout and linkage info)

• segment commands (describes sections)

• dyld(3) describes some apis for touching mach-o objects

• the executable and each dylib/bundle has its own set of data

Page 32: Function hooking for OSX and Linux

Mach-O sections

• __text - code lives here

• __symbol_stub1 - list of jmpq instructions for runtime dynamic linking

• __stub_helper - stub code that helps to “resolve” absolute function addresses.

• __la_symbol_ptr - absolute function addresses; used by symbol stub

Page 33: Function hooking for OSX and Linux

Mach-O sections

• symtabs do not live in a segment, they have their own load commands.

• LC_SYMTAB - holds offsets for symbol table and string table.

• LC_DYSYMTAB - a list of 32bit offsets into LC_SYMTAB for dynamic symbols.

Page 34: Function hooking for OSX and Linux

blog.makezine.com

Page 35: Function hooking for OSX and Linux

nm

000000000048ac90 t Balloc

0000000000491270 T Init_Array

0000000000497520 T Init_Bignum

000000000041dc80 T Init_Binding

000000000049d9b0 T Init_Comparable

000000000049de30 T Init_Dir

00000000004a1080 T Init_Enumerable

00000000004a3720 T Init_Enumerator

00000000004a4f30 T Init_Exception

000000000042c2d0 T Init_File

0000000000434b90 T Init_GC

% nm /usr/bin/ruby

symbol “value”

symbol names

Page 36: Function hooking for OSX and Linux

objdump% objdump -D /usr/bin/ruby

offsets opcodes instructions helpful metadata

Page 37: Function hooking for OSX and Linux

readelf% readelf -a /usr/bin/ruby

This is a *tiny* subset of the data available

Page 38: Function hooking for OSX and Linux

otool% otool -l /usr/bin/ruby

This is a *tiny* subset of the data available

Page 39: Function hooking for OSX and Linux

nerve.com

Page 40: Function hooking for OSX and Linux

strip• You can strip out whatever sections you

want....

• but your binary may not run.

• you need to leave the dynamic symbol/string tables intact or dynamic linking will not work.

Page 41: Function hooking for OSX and Linux

bassfishin.com

Page 42: Function hooking for OSX and Linux

Calling functions

callq *%rbx

callq 0xdeadbeef

other ways, too...

Page 43: Function hooking for OSX and Linux

anatomy of a call412d16: e8 c1 36 02 00 callq 4363dc # <a_function>

412d1b: .....

address of this instruction

call opcode32bit displacement to the target function from the next instruction.

(objdump output)

Page 44: Function hooking for OSX and Linux

anatomy of a call412d16: e8 c1 36 02 00 callq 4363dc # <a_function>

412d1b: .....

412d1b = 4363dc + 000236c1

(x86 is little endian)

(objdump output)

Page 45: Function hooking for OSX and Linux

Hook a_function

Overwrite the displacement so that all calls to a_function actually call a different function instead.

It may look like this:int other_function() { /* do something good/bad */

/* be sure to call a_function! */ return a_function();}

Page 46: Function hooking for OSX and Linux

codez are easy/* CHILL, it’s fucking psuedo code */

while (are_moar_bytes()) { curr_ins = next_ins; next_ins = get_next_ins(); if (curr_ins->type == INSN_CALL) { if ((hook_me - next_ins) == curr_ins->displacement) { /* found a call hook_me!*/ rewrite(curr_ins->displacement, (replacement_fn - next_ins)); return 0; } }}

... right?.....

Page 47: Function hooking for OSX and Linux

lemur.com

Page 48: Function hooking for OSX and Linux

32bit displacement• overwriting an existing call with another call

• stack will be aligned

• args are good to go

• can’t redirect to code that is outside of:

• [rip + 32bit displacement]

• you can scan the address space looking for an available page with mmap, though...

Page 49: Function hooking for OSX and Linux

Doesn’t work for all

calling a function that is exported by a dynamic library works differently.

Page 50: Function hooking for OSX and Linux

How runtime dynamic linking works (elf)

0x7ffff7afd6e6

.got.plt entryInitially, the .got.plt entry contains the address of the instruction after

the jmp.

Page 51: Function hooking for OSX and Linux

How runtime dynamic linking works (elf)

0x7ffff7afd6e6

.got.plt entryAn ID is stored and the rtld is

invoked.

Page 52: Function hooking for OSX and Linux

How runtime dynamic linking works (elf)

0x7ffff7b34ac0

.got.plt entryrtld writes the address of

rb_newobj to the .got.plt entry.

Page 53: Function hooking for OSX and Linux

How runtime dynamic linking works (elf)

0x7ffff7b34ac0

.got.plt entryrtld writes the address of

rb_newobj to the .got.plt entry.

calls to the PLT entry jump immediately to rb_newobj now

that .got.plt is filled in.

Page 54: Function hooking for OSX and Linux

rs.tacklewarehouse.com

Page 55: Function hooking for OSX and Linux

Hook the GOT

Redirect execution by overwriting all the .got.plt entries for rb_newobj in each DSO with a handler function instead.

Page 56: Function hooking for OSX and Linux

0xdeadbeef

.got.plt entryVALUE other_function() { new_obj = rb_newobj(); /* do something with new_obj */ return new_obj;}

Hook the GOT

NO, it isn’t. other_function() lives in it’s own DSO, so its calls to rb_newobj() use the .plt/.got.plt in its own DSO.

As long as we leave other_function()‘s DSO unmodified, we’ll avoid an infinite loop.

WAIT... other_function() calls rb_newobj() isn’t that an infinite loop?

Page 57: Function hooking for OSX and Linux

vanachteren.net

Page 58: Function hooking for OSX and Linux

tlaneve.files.wordpress.com

Page 59: Function hooking for OSX and Linux

elf

mach-o

me

Page 60: Function hooking for OSX and Linux

what else is left?

inline functions.

Page 61: Function hooking for OSX and Linux

add_freelist• Can’t hook because add_freelist is inlined:

static inline voidadd_freelist(p) RVALUE *p;{ p->as.free.flags = 0; p->as.free.next = freelist; freelist = p;}

• The compiler has the option of inserting the instructions of this function directly into the callers.

• If this happens, you won’t see any calls.

Page 62: Function hooking for OSX and Linux

So... what now?• Look carefully at the code:

static inline voidadd_freelist(p) RVALUE *p;{ p->as.free.flags = 0; p->as.free.next = freelist; freelist = p;}

• Notice that freelist gets updated.

• freelist has file level scope.

• hmmmm......

Page 63: Function hooking for OSX and Linux

A (stupid) crazy idea• freelist has file level scope and lives at some

static address.

• add_freelist updates freelist, so...

• Why not search the binary for mov instructions that have freelist as the target!

• Overwrite that mov instruction with a call to our code!

• But... we have a problem.

• The system isn’t ready for a call instruction.

Page 64: Function hooking for OSX and Linux

alignment

thomasgroup.com

Page 65: Function hooking for OSX and Linux

calling convention

arianlim.wordpress.com

Page 66: Function hooking for OSX and Linux

Isn’t ready? What?• The 64bit ABI says that the stack must be

aligned to a 16byte boundary after any/all arguments have been arranged.

• Since the overwrite is just some random mov, no way to guarantee that the stack is aligned.

• If we just plop in a call instruction, we won’t be able to arrange for arguments to get put in the right registers.

• So now what?

Page 67: Function hooking for OSX and Linux

jmp

• Can use a jmp instruction.

• Transfer execution to an assembly stub generated at runtime.

• recreate the overwritten instruction

• set the system up to call a function

• do something good/bad

• jmp back when done to resume execution

Page 68: Function hooking for OSX and Linux

picasaweb.google.com/lh/photo/-R3BPlqOq8MfQGFTduIqCA

Page 69: Function hooking for OSX and Linux

checklist• save and restore caller/callee saved

registers.

• align the stack.

• recreate what was overwritten.

• arrange for any arguments your replacement function needs to end up in registers.

• invoke your code.

• resume execution as if nothing happened.

Page 70: Function hooking for OSX and Linux

this instruction updates the freelist and comes from add_freelist:

Can’t overwrite it with a call instruction because the state of the system is not ready for a function call.

The jmp instruction and its offset are 5 bytes wide.Can’t grow or shrink the binary, so insert 2 one byte

NOPs.

Page 71: Function hooking for OSX and Linux

shortened assembly stub

Page 72: Function hooking for OSX and Linux

shortened assembly stub

Page 73: Function hooking for OSX and Linux

shortened assembly stub

Page 74: Function hooking for OSX and Linux

shortened assembly stub

Page 75: Function hooking for OSX and Linux

shortened assembly stub

Page 76: Function hooking for OSX and Linux

shortened assembly stub

Page 77: Function hooking for OSX and Linux

shortened assembly stub

Page 78: Function hooking for OSX and Linux

shortened assembly stub

void handler(VALUE freed_object) { mark_object_freed(freed_object); return;}

Page 79: Function hooking for OSX and Linux

shortened assembly stub

Page 80: Function hooking for OSX and Linux

and it actually works.

gem install memprofhttp://github.com/ice799/memprof

Page 81: Function hooking for OSX and Linux

listverse.files.wordpress.com

Page 82: Function hooking for OSX and Linux

Sample Outputrequire 'memprof'Memprof.startrequire "stringio"StringIO.newMemprof.stats

108 /custom/ree/lib/ruby/1.8/x86_64-linux/stringio.so:0:__node__ 14 test2.rb:3:String 2 /custom/ree/lib/ruby/1.8/x86_64-linux/stringio.so:0:Class 1 test2.rb:4:StringIO 1 test2.rb:4:String 1 test2.rb:3:Array 1 /custom/ree/lib/ruby/1.8/x86_64-linux/stringio.so:0:Enumerable

Page 83: Function hooking for OSX and Linux

a web-based heap visualizer and leak analyzermemprof.com

Page 84: Function hooking for OSX and Linux

memprof.coma web-based heap visualizer and leak analyzer

Page 85: Function hooking for OSX and Linux

a web-based heap visualizer and leak analyzermemprof.com

Page 86: Function hooking for OSX and Linux

memprof.coma web-based heap visualizer and leak analyzer

Page 87: Function hooking for OSX and Linux

memprof.coma web-based heap visualizer and leak analyzer

Page 88: Function hooking for OSX and Linux

memprof.coma web-based heap visualizer and leak analyzer

Page 89: Function hooking for OSX and Linux

community.devexpress.com

Page 90: Function hooking for OSX and Linux

config.middleware.use(Memprof::Tracer)

{ "time": 4.3442,

"rails": { "controller": "test", "action": "index" },

"request": { "REQUEST_PATH": "/test,, "REQUEST_METHOD": "GET" },

total time for request

rails controller/action

request env info

Page 91: Function hooking for OSX and Linux

"mysql": { "queries": 3, "time": 0.00109302 },

"gc": { "calls": 8, "time": 2.04925 },

config.middleware.use(Memprof::Tracer)

8 calls to GC2 secs spent in GC

3 mysql queries

Page 92: Function hooking for OSX and Linux

"objects": { "created": 3911103, "types": { "none": 1168831, "object": 1127, "float": 627, "string": 1334637, "array": 609313, "hash": 3676, "match": 70211 } }}

config.middleware.use(Memprof::Tracer)

3 million objs created

lots of strings

lots of arrays

regexp matches

object instances

1 million method calls

Page 93: Function hooking for OSX and Linux

smiley-faces.org

Page 94: Function hooking for OSX and Linux

mindfulsecurity.com

Page 95: Function hooking for OSX and Linux

evil liveshttp://github.com/ice799/memprof/tree/dnw

• makes ruby faster!11!!1

• hooks read syscall

• looks for magic cookie (JOE)

• turns off GC

• Ruby is fast.

Page 96: Function hooking for OSX and Linux

it makes ruby faster!!1!

look a bullshit benchmark!

Page 97: Function hooking for OSX and Linux

it makes ruby faster!!1!#NORMAL RUBY!!!!11!!

[joe@mawu:/Users/joe/code/defcon/memprof/ext]% ab -c 10 -n 200 http://blah:4567/hi/JOE

Benchmarking blah (be patient)Completed 100 requestsCompleted 200 requestsFinished 200 requests

Concurrency Level: 10Time taken for tests: 7.462 secondsComplete requests: 200Failed requests: 0Write errors: 0Requests per second: 26.80 [#/sec] (mean)Time per request: 373.108 [ms] (mean)Time per request: 37.311 [ms] (mean, across all concurrent requests)

Page 98: Function hooking for OSX and Linux

it makes ruby faster!!1!# fast0r RUBY!!!11!111[joe@mawu:/Users/joe/code/defcon]% ab -c 10 -n 200 http://blah:4567/hi/JOE

Benchmarking blah (be patient)Completed 100 requestsCompleted 200 requestsFinished 200 requests

Concurrency Level: 10Time taken for tests: 6.594 secondsComplete requests: 200Failed requests: 0Write errors: 0Requests per second: 30.33 [#/sec] (mean)Time per request: 329.708 [ms] (mean)Time per request: 32.971 [ms] (mean, across all concurrent requests)

Page 99: Function hooking for OSX and Linux

you can do anything

• this example is stupid, but you can do anything.

• hook read/write and phone home with data.

• fork a backdoor when a specific cookie is seen

• whatever

Page 100: Function hooking for OSX and Linux

break.com

Page 101: Function hooking for OSX and Linux

zanyvideos.com

Page 102: Function hooking for OSX and Linux

injectso

• written by Shaun Clowes

• injects libraries into running processes using ptrace(2).

• super clever hack!

Page 103: Function hooking for OSX and Linux

hockeydrunk.com

Page 104: Function hooking for OSX and Linux

injecting live processes

• ptrace(2)

• allows you to view and modify the register set and address space of another process

• permissions on memory are ignored

Page 105: Function hooking for OSX and Linux

fucking injectso, how does it work?

• attach to target process using ptrace

• save a copy of a small piece of the program stack.

• save a copy of the register set

• create a fake stack frame with a saved return address of 0

Page 106: Function hooking for OSX and Linux

fucking injectso, how does it work?• set register set to point at dlopen

• rip = &dlopen

• rdi = dso name

• rsi = mode

• let er rip, waitpid and it’ll segfault on return to 0.

• restore stack, register set, resume as normal.

Page 107: Function hooking for OSX and Linux

ptrace evil dso• remote allocating

memory is a pain in the ass.

• generating segfaults in running processes might be bad (core dumps, etc).

• binary patching is hard, doing it with ptrace is harder.

• getting the user to use your library might be hard.

• already running processes will need to be killed first.

• need to poison each time app is started.

• binary patching is hard.

Page 108: Function hooking for OSX and Linux

realmofraven.com

Page 109: Function hooking for OSX and Linux

combine ‘em

• use injectso hack to load an evil dso

• evil dso will take it from there

Page 110: Function hooking for OSX and Linux

64bit injectso port• ported by Stealth

• http://c-skills.blogspot.com/2007/05/injectso.html

• i did some trivial cleanup and put the codez on github

• http://github.com/ice799/injectso64

• tested it on 64bit ubuntu VM, works.

Page 111: Function hooking for OSX and Linux

injectso +

evil-binary-patching-dso

customdynamics.com

Page 112: Function hooking for OSX and Linux

customdynamics.com

Page 113: Function hooking for OSX and Linux

buycostumes.com

Page 114: Function hooking for OSX and Linux

emeraldinsight.com

Page 115: Function hooking for OSX and Linux

how to defend against it• NX bit - call mprotect

• strip debug information - mostly prebuilt binaries

• statically link everything - extremely large binaries

• put all .text code in ROM - maybe?

• don’t load DSOs at runtime - no plugins, though

• disable ptrace - no gdb/strace.

• check /proc/<pid>/maps - word.

Page 116: Function hooking for OSX and Linux

slashgear.com

Page 117: Function hooking for OSX and Linux

my future research: exploring alternative

binary formats.

Page 118: Function hooking for OSX and Linux

slayerinc.com

Page 119: Function hooking for OSX and Linux

globalhealthandfitness.com

Page 120: Function hooking for OSX and Linux

alignment

thomasgroup.com

Page 121: Function hooking for OSX and Linux

calling convention

arianlim.wordpress.com

Page 122: Function hooking for OSX and Linux

object file and library formats

tandemfs.org

Page 124: Function hooking for OSX and Linux

tallteacher.files.wordpress.com

Page 126: Function hooking for OSX and Linux

leopard has a pe loader?

handle = dlopen("./procexp.exe", RTLD_NOW | RTLD_FIRST );

steven-edwardss-imac:temp sedwards$ ./a.outdlopen(./procexp.exe, 258): Library not loaded: WS2_32.dll Referenced from: /Users/sedwards/Library/ApplicationSupport/CrossOver/Bottles/winetest/drive_c/windows/temp/procexp.exe Reason: image not found

Page 127: Function hooking for OSX and Linux

cfs2.tistory.com