Lab 02 - Program Analysis

Supporting files

Lab archive - Password: lab-02

Old location: http://elf.cs.pub.ro/oss/res/labs/lab-02.tar.gz

Exercises

1. Where do they live?

In this exercise you will be validating some truths about executables and processes in linux.

  1. Copy the following to a file: live.c

    #include <stdio.h>
    #include <stdlib.h>
    
    int iAmGlobalVar = 55;
    int iAmUninit[100] ;
    
    int foo(int a) {
        int g = 90 * a;
        static int iAmStatic;
        printf("address of g, a variable in foo\'s stack frame %p\n", &g);
        return 0;
    }
    
    int main() {
        int x = 42;
    
        printf("Hello world\n");
        printf("address of x, a variable in main\'s stack frame %p\n", &x);
        x = foo(0);
    
        int *m = malloc(10000);
        printf("an address in the heap: %p\n", m);
    
        int *n = malloc(10000);
        printf("another address in the heap: %p\n", n);
    
        printf("foo\'s address: %p\n", foo );
        while(1);
    
        return 0;
    }
    
  2. Now we will create two versions of the executable. One that uses the Position Indendent Executable (PIE) option and one that does not: Create the no PIE first using the no-pieoption:

    clang -o livenopie live.c
    
  3. ... and now the PIE version the -pieoption:

    clang -o live live.c  -pie
    
  4. Validate that the executables are different using md5sum:

    md5sum live livenopie
    
  5. Is the file command able to tell the difference between the PIE and non-PIE versions?

    file live livenopie
    
  6. Validate that both executables work, by running each of them. The hex addresses that they print might be a little different, but we will learn why in further steps. Since they have a while(1); each will stay running until you do a CTRL-C

  7. The main difference between the PIE and non-PIE versions is that:

  8. In the non-PIE version, the addresses of the functions are established in the executable and the loader will use the instrutions in exactly those addresses.
  9. In the PIE version, the addresses of the functions are offsets to be used by the loader once it chooses (perhaps randomly) the base address where it wants to load the text.
  10. We will validate that difference between PIE/non-PIE in the next section. But first, use objdump to determine the address of the function foo both in the live and livenopie binaries.

ASLR and PIE

  1. Address Space Layout Randomization (ASLR) is a computer security technique which involves randomly positioning the base address of an executable and the position of libraries, heap, and stack, in a process's address space. Linux has this featured turned on by default. Some more information: https://blog.morphisec.com/aslr-what-it-is-and-what-it-isnt/

  2. If you had sudo priviledges in your computer you could turn off the ASLR in linux by issuing the following command:

    echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
    

    However, since you are a simple mortal in oscar.ccom.uprrp.edu we will only be able to switch ASLR on/off as we debug the program.

    GDB turns off ASLR by default to make the process of debugging easier.

  3. With ASLR off, everytime that you run an executable, it will be assigned the same base addresses in virtual memory for the stack, heap, and text (program instructions).

  4. using gdb, run live several times and register the output of the program, e.g. the messages displayed by the printf in the program

  5. using, run livenopieseveral times and register the output of the program

    Make an observation in your report about what you observed in terms of the addresses.

  6. The following two steps will be done in the shell (outside of gdb, where ASLR is ON by default)

    1. Run live several times. What do you notice about the various addresses printed in the program?

    2. Run livenopie several times. What do you notice about the various addresses printed in the program? Comment about which addresses differ between runs and which stay the same.

Another way of monitoring the addresses layout of programs

  1. run ./live & outside of gdb. (the & leaves the program executing in the background and lets you know its process ID). Linux allows you to see the memory map of your process by looking at the file /proc/<PID>/maps. Here a sample run in my computer.

    $ ./live &
    [2] 1479
    Hello world
    stack 0x7ffe1b272744
    stack in foo 0x7ffe1b272724
    heap 0: 0x557e4e49a420
    heap 1 : 0x557e4e49cb40
    foo's address: 0x557e4c688850
    
    $ cat /proc/1479/maps
    557e4c688000-557e4c689000 r-xp 00000000 08:02 9863938 etc....
    

    To kill the ./live process: kill (process number)) (kill 1479 in this example)

  2. In your report, present the output of the map, the output of the program and explain how each address printed by the program corresponds to the correct area in the map. For example, in the previous output the statement foo's address: 0x557e4c688850 can be verified to be an address in the renge 557e4c688000-557e4c689000 presented in the map file.

2. stripped

Someone has given us a stripped binary called stripped. Let's run it and give it a brief view:

$ ./stripped
Hello, there!
I am looping, looping, looping, looping, looping,
$ file ./stripped
./stripped:  ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

The executable file is stripped, so we can't rely on any symbol information to look at it. Take a look at the result of the command nm stripped and validate that it has no symbols.

However, stripped is a small executable, so we can try to reverse engineer it by hand. To do that, answer the following questions:

3. stripped, re-loaded

Looking more carefully at our stripped binary, we notice that there is one string that it never prints out:

$ strings -t x stripped
    154 Hello, there!
    162 I am looping,
    171 All done!
    17c .shstrtab
    186 .text
    18c .data

The string All done! is at offset 0x171 in the binary, that is equivalent to 0x600171` in the loaded program.

$ objdump -d stripped -M intel
00000000004000b1 <h>:
  4000b1:   ba 0a 00 00 00          mov    edx,0xa
  4000b6:   48 be 71 01 60 00 00    movabs rsi,0x600171
  4000bd:   00 00 00
  4000c0:   e8 75 00 00 00          call   0x40013a
  4000c5:   c3                      ret

This means that the function that does the print (0x4000b1) is never reached! Why? The reason is that the program exits before doing that.

Find the call to the exit function that occurs at run-time exactly before this print and manually replace it with NOP instructions using the hex editor of your choice. At the end the program should display the following:

./stripped
Hello, there!
I am looping, looping, looping, looping, looping, looping, looping, looping, looping, looping, looping, looping,
All done!

Note that the program should still exit cleanly!


Hint: the NOP instruction has opcode 0x90, so just replace all the bytes of the offending call instruction with that


4. Smash the Stack

Download level01 from Smash the stack and solve it using gdb. Break on main, step through the execution and figure out what it does and how to crack it.

    $ scp level1@io.netgarage.org:/levels/level01 . # Password is level1

5. GDB

Run the bash_login executable. The executable gets input from the user and evaluates it against a static condition. If it succeeds it then calls a password_accepted function that prints out a success message and spawns a shell.

Your task is to use GDB to force the executable to call the password_accepted function.

Gather as much info about the executable as possible through the techniques you have learned in previous sessions. Think of modifying registers for forcing the executable to call the function (there is more than one way of doing this).

Note: you do NOT need to find out the password for this excercise, just manipulate the program dynamically to make it call the password_accepted function. In your report, comment about your process.

Deliverables

Turn in a writeup through Moodle (online.upr.edu). Make sure to answer the questions asked throughout the instructions.