SLIDE 1 a single gadget weird machine
Framing Signals a return to portable shellcode
Erik Bosman and Herbert Bos
Highlights of Dutch Cyber Security Research
SLIDE 2
memory corruption, the problem that just won't go away
25+ years after the morris worm and still going strong
1
SLIDE 3
stack buffer overflow stack sp
return addr buffer
2
SLIDE 4
stack buffer overflow stack sp
return addr buffer
2
SLIDE 5
stack buffer overflow stack sp
return addr buffer
2
SLIDE 6
stack buffer overflow stack sp
return addr buffer
2
SLIDE 7
stack buffer overflow stack sp
return addr buffer
2
SLIDE 8
stack buffer overflow stack sp
return addr buffer
2
SLIDE 9 stack sp
return addr buffer
3
SLIDE 10 stack sp
return addr buffer
code
3
SLIDE 11 return oriented programming
stack
return addr buffer
code
gadgets
3
SLIDE 12 return addr buffer
code
return addr return addr
gadgets
3
SLIDE 13 Return Oriented Programming
- dependent on available gadgets
- non-trivial to program
- chains may differ greatly between
different binaries
4
SLIDE 14 Sigreturn Oriented Programming
- minimal number of gadgets
- constructing shellcode by
chaining system calls
- easy to change functionality of
shellcode
(gadgets are always present)
5
SLIDE 15
unix signals stack sp
6
SLIDE 16
unix signals stack sp
6
SLIDE 17
unix signals stack sp
ucontext siginfo
6
SLIDE 18
unix signals stack sp
ucontext sigreturn siginfo
6
SLIDE 19
unix signals stack sp
ucontext sigreturn siginfo good: kernel agnostic about signal handlers
6
SLIDE 20
unix signals stack sp
ucontext sigreturn siginfo bad: kernel agnostic about signal handlers (we can fake 'em)
6
SLIDE 21 two gadgets
- call to sigreturn
- syscall & return
7
SLIDE 22
forged signal frame sigreturn
8
SLIDE 23
forged signal frame sigreturn program counter
8
SLIDE 24
forged signal frame sigreturn program counter stack pointer
8
SLIDE 25
sigreturn program counter stack pointer RAX RDX R10 R8 R9 RDI RSI ... ...
8
SLIDE 26
sigreturn program counter stack pointer syscall number arg3 arg4 arg5 arg6 arg1 arg2 ... ...
8
SLIDE 27
sigreturn syscall & return stack pointer syscall number arg3 arg4 arg5 arg6 arg1 arg2 ... ...
8
SLIDE 28
sigreturn syscall & return next sigframe syscall number arg3 arg4 arg5 arg6 arg1 arg2 ... ...
8
SLIDE 29
syscall(...) next
9
SLIDE 30
socket() bind() listen() accept() execve() 10
SLIDE 31 SROP exploit on x86-64
An exploit which does not make use
- f any gadgets in the target program
- control over the stack
- a known writable memory location
(*any* location, and we don't need to write there beforehand)
11
SLIDE 32 two gadgets
- call to sigreturn
- syscall & return
12
SLIDE 33 two gadgets
- call to sigreturn: RAX = 15 + syscall
- syscall & return
12
SLIDE 34
- ne gadget
- RAX = 15
- syscall & return
12
SLIDE 35 [vsyscall]
ffffffffff600000 48 c7 c0 60 00 00 00 0f 05 c3 cc cc cc cc cc cc gettimeofday() fffffffffff60010 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc * ffffffffff600400 48 c7 c0 c9 00 00 00 0f 05 c3 cc cc cc cc cc cc time() ffffffffff600410 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc * ffffffffff600800 48 c7 c0 35 01 00 00 0f 05 c3 cc cc cc cc cc cc getcpu() ffffffffff600810 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc * ffffffffff601000
0f05 syscall c3 return
13
SLIDE 36
socket() bind() listen() accept() execve() 14
SLIDE 37
socket() bind() listen() accept() execve() 14
SLIDE 38
read(fd, buffer, 1024) RAX RDI RSI RDX
x64 syscall ABI
15
SLIDE 39
read(fd, buffer, 1024) = 1024 RAX RDI RSI RDX
x64 syscall ABI
15
SLIDE 40
read(fd, buffer, 1024) = 1024 RAX RDI RSI RDX RAX
x64 syscall ABI
15
SLIDE 41
read() = 306 (syncfs) fsyncfs() = 0 (read) read() = 15 (sigreturn) sigreturn() execve() 16
SLIDE 42
CVE-2012-5976 (asterisk)
17
SLIDE 43 On some systems SROP gadgets are randomised, on others, they are not
Operating system Gadget Memory map Linux i386 sigreturn [vdso] Linux < 3.11 ARM sigreturn [vectors] Linux < 3.3 x86-64 syscall & return [vsyscall] Linux ≥ 3.3 x86-64 syscall & return Libc Linux x86-64 sigreturn Libc FreeBSD 9.2 x86-64 sigreturn 0x7ffffffff000 Mac OSX x86-64 sigreturn Libc iOS ARM sigreturn Libsystem iOS ARM syscall & return Libsystem 0xffff0000 0xffffffffff600000
18
SLIDE 44 On some systems SROP gadgets are randomised, on others, they are not
Operating system Gadget Memory map Linux i386 sigreturn [vdso] Linux < 3.11 ARM sigreturn [vectors] Linux < 3.3 x86-64 syscall & return [vsyscall] Linux ≥ 3.3 x86-64 syscall & return Libc Linux x86-64 sigreturn Libc FreeBSD 9.2 x86-64 sigreturn 0x7ffffffff000 Mac OSX x86-64 sigreturn Libc iOS ARM sigreturn Libsystem iOS ARM syscall & return Libsystem 0xffff0000 0xffffffffff600000
non-ASLR :-( android
18
SLIDE 45
questions?
19
SLIDE 46
questions?
27
SLIDE 47 mitigation:
It may be useful to disable vsyscall vsyscall=emulate (default from Linux 3.3 onward)
vsyscall=none
SLIDE 49
stack canary stack sp
return addr buffer
SLIDE 50
stack canary stack sp
return addr buffer
SLIDE 51
sigreturn program counter stack pointer RAX RDX R10 R8 R9 RDI RSI ... ...
SLIDE 52
sigreturn program counter stack pointer RAX RDX R10 R8 R9 RDI RSI ... ...
SLIDE 54 mitigation:
- Signal frame canaries
- Counting signals in progress
SLIDE 55
CVE-2012-5976 (asterisk)
stack sp stack sp
SLIDE 56
CVE-2012-5976 (asterisk)
stack sp stack sp alloca
SLIDE 57
CVE-2012-5976 (asterisk)
stack sp stack sp alloca
SLIDE 58 dispatch jmp dispatch load CODE jump cond jump P = P + c *P = *P + c *P=getchar() putchar(*P) store exit
SLIDE 59
code = open("/proc/self/mem",O_RDWR); p = open("/proc/self/mem",O_RDWR); a = open("/proc/self/mem",O_RDWR);
SLIDE 60
code = open("/proc/self/mem",O_RDWR); p = open("/proc/self/mem",O_RDWR); a = open("/proc/self/mem",O_RDWR); instruction dispatch: read(code, &ucontext.sp, sizeof(long));
SLIDE 61
code = open("/proc/self/mem",O_RDWR); p = open("/proc/self/mem",O_RDWR); a = open("/proc/self/mem",O_RDWR); instruction dispatch: read(code, &ucontext.sp, sizeof(long)); pointer ops: p++ -> lseek(p, 1, SEEK_CUR);
SLIDE 62
code = open("/proc/self/mem",O_RDWR); p = open("/proc/self/mem",O_RDWR); a = open("/proc/self/mem",O_RDWR); instruction dispatch: read(code, &ucontext.sp, sizeof(long)); pointer ops: p++ -> lseek(p, 1, SEEK_CUR); addition: lseek(a, &identity_table_x2, SEEK_SET); lseek(a, val1, SEEK_SET); lseek(a, val2, SEEK_SET); read(a, dest, 1);