Load-time Hacking using LD_PRELOAD

1,889 views
1,681 views

Published on

An approach for load-time hacking using LD_PRELOAD is presented.

We discuss a simple, yet intriguing, strategy for overcoming the limitations discussed in Part 1 (i.e., the first publication given in the reference) of reverse engineering and exploitation using LD_PRELOAD, a dynamic linking technique. In particular, we relax the need for exit(1) in the main function. The essence of the technique is that both the stack pointer (esp) and the base frame pointer (ebp) are carefully adjusted when the wrapper to the library function is called. The proposed solution allows us to safely return to libc after dynamically modifying the control flow in the wrapper to (library) functions.

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,889
On SlideShare
0
From Embeds
0
Number of Embeds
52
Actions
Shares
0
Downloads
16
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Load-time Hacking using LD_PRELOAD

  1. 1. DharmalingamGanesan (dganesan@fc-md.umd.edu) Itzik Kotler (xorninja@gmail.com) 1
  2. 2. int main(int argc, char **argv) { char passwd[] = "foobar"; if (argc < 2) { printf("usage: %s <given-password>n", argv[0]); return 0; } if (!strcmp(passwd, argv[1])) { printf("Green light!n"); return 1; } printf("Red light!n"); return 0; } 2  What if you do not know the passwd? Reference: Reverse Engineering with LD_PRELOAD by Itzik Kotler
  3. 3. /* * strcmp, Fixed strcmp function -- Always equal! */ int strcmp(const char *s1, const char *s2) { printf("S1 eq %sn", s1); printf("S2 eq %sn", s2); // ALWAYS RETURN EQUAL STRINGS! return 0; } 3
  4. 4.  gcc -fPIC -c strcmp-hijack.c -o strcmp-hijack.o  gcc -shared -o strcmp-hijack.so strcmp-hijack.o  ./strcmp-target redbull  Output: “Red light!”  Attack using LD_PRELOAD  LD_PRELOAD="./strcmp-hijack.so" ./strcmp-target redbull  Output: “Green light!” 4
  5. 5. /* * cerberus.c, Impossible statement */ #include <stdio.h> int main(int argc, char **argv) { int a = 13, b = 17; if (a != b) { printf("Sorry!n"); return 0; } printf("On a long enough timeline," " the survival rate for everyone drops to zeron"); exit(1); } 5 Can we avoid “Sorry” and print the “On a long…”? [~]$ ./cerberus On a long enough timeline, the survival rate for everyone drops to zero
  6. 6. 080483d4 <main>: 80483d4: 55 push %ebp 80483d5: 89 e5 mov %esp,%ebp 80483d7: 83 e4 f0 and $0xfffffff0,%esp 80483da: 83 ec 20 sub $0x20,%esp 80483dd: c7 44 24 18 0d 00 00 movl $0xd,0x18(%esp) 80483e4: 00 80483e5: c7 44 24 1c 11 00 00 movl $0x11,0x1c(%esp) 80483ec: 00 80483ed: 8b 44 24 18 mov 0x18(%esp),%eax 80483f1: 3b 44 24 1c cmp 0x1c(%esp),%eax 80483f5: 74 13 je 804840a <main+0x36> 80483f7: c7 04 24 f0 84 04 08 movl $0x80484f0,(%esp) 80483fe: e8 ed fe ff ff call 80482f0 <puts@plt> 8048403: b8 00 00 00 00 mov $0x0,%eax 8048408: eb 11 jmp 804841b <main+0x47> 804840a: c7 04 24 f8 84 04 08 movl $0x80484f8,(%esp) 8048411: e8 da fe ff ff call 80482f0 <puts@plt> 8048416: b8 01 00 00 00 mov $0x1,%eax 804841b: c9 leave 804841c: c3 ret 6 Note: puts is used for printf
  7. 7.  Create our own “puts” wrapper  Update the return address after the first puts  Transfer control to the second puts  Embed assembly code and adjust the ESP! 7
  8. 8. /* Pointer to the original puts call */ static int (*_puts)(const char *str) = NULL; int puts(const char *str) { if (_puts == NULL) { _puts = (int (*)(const char *str)) dlsym(RTLD_NEXT, "puts"); // Hijack the RET address and modify it to <main+xx> __asm__ __volatile__ ( "movl 0x4(%ebp), %eax n" "addl $7, %eax n" "movl %eax, 0x4(%ebp)" ); return 1; } __asm__ __volatile__ ( "addl $28, %%esp n“ “ jmp *%0 n" : : "g" (_puts) : "%esp" ); return -1; } 8 • Why add 7 to eax? • 0x804840a – 0x8048403 • Why add 28 to esp? • Answered in next slides
  9. 9. 00000000 <printf>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 18 sub $0x18,%esp 6: a1 00 00 00 00 mov 0x0,%eax b: 85 c0 test %eax,%eax d: 75 2a jne 39 <printf+0x39> f: b8 00 00 00 00 mov $0x0,%eax 14: 89 44 24 04 mov %eax,0x4(%esp) 18: c7 04 24 ff ff ff ff movl $0xffffffff,(%esp) 1f: e8 fc ff ff ff call 20 <printf+0x20> 24: a3 00 00 00 00 mov %eax,0x0 29: 8b 45 04 mov 0x4(%ebp),%eax 2c: 83 c0 0f add $0xf,%eax 2f: 89 45 04 mov %eax,0x4(%ebp) 32: b8 01 00 00 00 mov $0x1,%eax 37: eb 00 jmp 39 <printf+0x39> 39: c9 leave 3a: c3 ret 9 Esp got adjusted: 4 bytes (push %ebp) 0x18 bytes (sub $0x18, %esp) Total: 0x18 + 4 = 24 + 4 = 28
  10. 10.  Create a shared lib of the wrapper:  gcc -c -m32 megatron.c -o megatron.o –ldl  gcc -shared -o megatron.so megatron.o -m32 –ldl  export LD_PRELOAD=./megatron.so [~]$ ./cerberus On a long enough timeline, the survival rate for everyone drops to zero 10
  11. 11.  The main function uses exit(1)  If we replace it by return(1) and run: [~]$ gcc -o cerberus cerberus.c -m32 [~]$ [~]$ export LD_PRELOAD=./megatron.so [~]$ [~]$ ./cerberus On a long enough timeline, the survival rate for everyone drops to zero ^C [~]$ 11 Why the program is not terminating?
  12. 12. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP ESP Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP ESP EBP (main)96 Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP ESP EBP (main)96 (a). Just before the 2nd printf. (b). In the wrapper puts. (c). After pointers rewinding. 12 100 96 92 88 84 80 76 52 80 76 100 96 92 88 84 80 100 96 92 88 84
  13. 13. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of puts (wrapper) 76 ESP EBP Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of puts (wrapper) 76 ESP EBP EIP (d). Inside the real puts. (e). After returning from real puts. 13 76 76 100 96 92 88 84 80 100 96 92 88 84 *80
  14. 14.  Control comes back to main and will try to run return 1:  mov %ebp, %esp  pop %ebp  Pop %eip (or ret) 14
  15. 15. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of puts (wrapper) 76 ESP EBP 15 76 100 96 92 88 76 80 mov %ebp, %esp 84
  16. 16. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of puts (wrapper) 76EBP ESP 16 76 100 96 92 88 80 pop %ebp 84
  17. 17. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of puts (wrapper) 76EBP EIP 17 76 100 96 92 88 84 ret: pop %eip ESP • Now EIP points to leave-ret sequence! • Never ending because EBP of mains is lost *80
  18. 18.  We lost main’s EBP along the way  There is an infinite loop when the control comes to main  mov %ebp, %esp  pop %ebp  Ret (or pop %eip)  Program is not able to return to libc  Fix:Why not restore the EBP! 18
  19. 19. OLD __asm__ __volatile__ ( "addl $28, %%esp n“ "jmp *%0 n" : : "g" (_puts) : "%esp" ); NEW __asm__ __volatile__ ( "addl $24, %%esp n" "popl %%ebp n" "jmp *%0 n" : : "g" (_puts) : "%esp" ); 19
  20. 20. [~]$ export LD_PRELOAD=./megatron.so [~]$ [~]$ ./cerberus On a long enough timeline, the survival rate for everyone drops to zero [~]$ [~]$ echo $? 1 20
  21. 21. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP ESP EBP (main) Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP, ESP EBP (main) (a). In the wrapper puts. (b). After ESP rewinding. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printfESP EBP (main) (c). After pop EBP. EBP 21 76 100 96 92 88 84 80 52 76 100 96 92 88 84 80 52 76 100 96 92 88 84 80 52
  22. 22. Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of main (96) ESP EBP Ret2libc EBP (libc) 17 13 Ptr to printf input str ret address after printf EBP of main ESP EBP EIP (d). Inside the real puts. (e). After returning from real puts. 22 76 100 96 92 88 84 80 52 76 76 100 96 92 88 84 *80 52
  23. 23.  LD_PRELOAD is a powerful way to hack  Key idea:Wrapper to library functions  Collect data such as input arguments!  Modify control flow dynamically  ESP and EBP rewinding is the core concept  Try it out yourself  Things to keep in mind:  Number of byte adjustments in your wrapper 23
  24. 24.  Itzik Kotler  Reverse Engineering with LD_PRELOAD  http://securityvulns.com/articles/reveng/  Dharma Ganesan and Itzik Kotler  Reverse Engineering with LD_PRELOAD (Part 11)  Article to be published 24

×