argp's blog

advisories

FreeBSD kernel NFS client local vulnerabilities

by argp on May.23, 2010, under advisories

census ID: census-2010-0001
CVE ID: CVE-2010-2020
Affected Products: FreeBSD 8.0-RELEASE, 7.3-RELEASE, 7.2-RELEASE
Class: Improper Input Validation (CWE-20)
Remote: No
Discovered by: Patroklos Argyroudis

We have discovered two improper input validation vulnerabilities in the FreeBSD kernel’s NFS client-side implementation (FreeBSD 8.0-RELEASE, 7.3-RELEASE and 7.2-RELEASE) that allow local unprivileged users to escalate their privileges, or to crash the system by performing a denial of service attack.

Details

FreeBSD is an advanced operating system which focuses on reliability and performance. More information about its features can be found here.

FreeBSD 8.0-RELEASE, 7.3-RELEASE and 7.2-RELEASE employ an improper input validation method in the kernel’s NFS client-side implementation. Specifically, the first vulnerability is in function nfs_mount() (file src/sys/nfsclient/nfs_vfsops.c) which is reachable from 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.

The function nfs_mount() employs an insufficient input validation method for copying data passed in a structure of type nfs_args from userspace to kernel. Specifically, the file handle buffer to be mounted (args.fh) and its size (args.fhsize) are completely user-controllable. The unbounded copy operation is in file src/sys/nfsclient/nfs_vfsops.c (the excerpts are from 8.0-RELEASE):

1094
1095
1096
1097
1098
1099
if (!has_fh_opt) {
      error = copyin((caddr_t)args.fh, (caddr_t)nfh,
           args.fhsize);
    if (error) {
         goto out;
      }

The declaration of the variables args and nfh is at:

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
static int
nfs_mount(struct mount *mp)
{
        struct nfs_args args = {
            .version = NFS_ARGSVERSION,
            .addr = NULL,
            .addrlen = sizeof (struct sockaddr_in),
            .sotype = SOCK_STREAM,
            .proto = 0,
            .fh = NULL,
            .fhsize = 0,
            .flags = NFSMNT_RESVPORT,
            .wsize = NFS_WSIZE,
            .rsize = NFS_RSIZE,
            .readdirsize = NFS_READDIRSIZE,
            .timeo = 10,
            .retrans = NFS_RETRANS,
            .maxgrouplist = NFS_MAXGRPS,
            .readahead = NFS_DEFRAHEAD,
            .wcommitsize = 0,                   /* was: NQ_DEFLEASE */
            .deadthresh = NFS_MAXDEADTHRESH,    /* was: NQ_DEADTHRESH */
            .hostname = NULL,
            /* args version 4 */
            .acregmin = NFS_MINATTRTIMO,
            .acregmax = NFS_MAXATTRTIMO,
            .acdirmin = NFS_MINDIRATTRTIMO,
            .acdirmax = NFS_MAXDIRATTRTIMO,
        };
        int error, ret, has_nfs_args_opt;
        int has_addr_opt, has_fh_opt, has_hostname_opt;
        struct sockaddr *nam;
        struct vnode *vp;
        char hst[MNAMELEN];
        size_t len;
        u_char nfh[NFSX_V3FHMAX];

This vulnerability can cause a kernel stack overflow which leads to privilege escalation on FreeBSD 7.3-RELEASE and 7.2-RELEASE. On FreeBSD 8.0-RELEASE the result is a kernel crash/denial of service due to the SSP/ProPolice kernel stack-smashing protection which is enabled by default. Versions 7.1-RELEASE and earlier do not appear to be vulnerable since the bug was introduced in 7.2-RELEASE. In order to demonstrate the impact of the vulnerability we have developed a proof-of-concept privilege escalation exploit. A sample run of the exploit follows:

[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)

The second vulnerability exists in the function mountnfs() that is called from function nfs_mount():

1119
1120
error = mountnfs(&args, mp, nam, args.hostname, &vp,
    curthread->td_ucred);

The function mountnfs() is reachable from the mount(2) and nmount(2) system calls by unprivileged users. As with the nfs_mount() case above, this requires the sysctl(8) variable vfs.usermount to be set to a non-zero value.

The file handle to be mounted (argp->fh) and its size (argp->fhsize) are passed to function mountnfs() from function nfs_mount() and are user-controllable. These are subsequently used in an unbounded bcopy() call (file src/sys/nfsclient/nfs_vfsops.c):

1219
bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);

The above can cause a kernel heap overflow when argp->fh is bigger than 128 bytes (the size of nmp->nm_fh) since nmp is an allocated item on the Universal Memory Allocator (UMA, the FreeBSD kernel’s heap allocator) zone nfsmount_zone (again from src/sys/nfsclient/nfs_vfsops.c):

1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
static int
mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
    char *hst, struct vnode **vpp, struct ucred *cred)
{
        struct nfsmount *nmp;
        struct nfsnode *np;
        int error;
        struct vattr attrs;
 
        if (mp->mnt_flag & MNT_UPDATE) {
                nmp = VFSTONFS(mp);
                printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
                free(nam, M_SONAME);
                return (0);
        } else {
                nmp = uma_zalloc(nfsmount_zone, M_WAITOK);

This kernel heap overflow can lead on FreeBSD 8.0-RELEASE, 7.3-RELEASE and 7.2-RELEASE to privilege escalation and/or a kernel crash/denial of service attack. Similarly to the first vulnerability, FreeBSD 7.1-RELEASE and earlier versions do not appear to be vulnerable. We have developed a proof-of-concept DoS exploit to demonstrate the vulnerability. Furthermore, we have also developed a privilege escalation exploit for this second vulnerability which will not be released at this point.

FreeBSD has released an official advisory and a patch to address both vulnerabilities. All affected parties are advised to follow the upgrade instructions included in the advisory and patch their systems.

Leave a Comment :, , , , , , more...

Monkey HTTPd improper input validation vulnerability

by argp on Dec.14, 2009, under advisories

census ID: census-2009-0004
Affected Products: Monkey web server versions ≤ 0.9.2.
Class: Improper Input Validation (CWE-20), Incorrect Calculation (CWE-682)
Remote: Yes
Discovered by: Patroklos Argyroudis

We have discovered a remotely exploitable “improper input validation” vulnerability in the Monkey web server that allows an attacker to perform denial of service attacks by repeatedly crashing worker threads that process HTTP requests.

Details

Monkey is a fast, efficient, small and easy to configure HTTP/1.1 compliant web server. It has been designed to be scalable with low memory and CPU consumption. More information about its features can be found here.

Monkey (up to and including version 0.9.2) employs an insufficient input validation method for handling HTTP requests with invalid connection headers. Specifically, the vulnerability is in the calculation for the end of the request body buffer related to newline characters in function Request_Find_Variable() in the file src/request.c:

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
char *Request_Find_Variable(char *request_body,  char *string)
{
   int pos_init_var=0, pos_end_var=0;
   char *var_value = 0;
 
   /* Existe *string en request_body ??? */        
   if (strstr2(request_body, string) == NULL)
       return NULL;
 
   pos_init_var = str_search(request_body, string, strlen(string));
   pos_end_var = str_search(request_body+pos_init_var, "\n", 1) - 1;
 
   if(pos_init_var<=0 || pos_end_var<=0){
       return  NULL;   
   }
 
   pos_init_var += strlen(string) + 1;
   pos_end_var = (unsigned int) (pos_init_var  + pos_end_var) - (strlen(string) +1);
 
   var_value = m_copy_string(request_body, pos_init_var, pos_end_var);
 
   return (char *) var_value;
}

With a specially crafted request body the pos_init_var integer can take the value 0x1c (28 in decimal) and the pos_end_var integer can take the value 0x1a (26 in decimal). Then in the m_copy_string() function, the calculation for the unsigned integer size in line 428 (file src/utils.c) leads to a signedness bug and m_copy_string() returns NULL (line 438, file src/utils.c):

423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
char *m_copy_string(const char *string, int pos_init, int pos_end)
{
   unsigned int size, bytes;
   char *buffer=0;
 
   size = (unsigned int) (pos_end &mdash; pos_init ) + 1;
   if(size<=2) size=4;
 
   buffer = M_malloc(size);
 
   if(!buffer){
       return NULL;
   }
 
   if(pos_end>strlen(string) || (pos_init > pos_end)){
       return NULL;
   }

This causes Request_Find_Variable() to return NULL (line 344, file src/request.c) and this to be used in the strstr2() call at line 345 of file src/request.c:

344
345
346
347
sr->connection = Request_Find_Variable(request_body, RH_CONNECTION);
if((strstr2(sr->connection,"Keep-Alive"))!=NULL){
    sr->keep_alive=VAR_ON;
}

This vulnerability can allow an attacker to perform denial of service attacks by repeatedly crashing Monkey worker threads that process HTTP requests. We have developed a proof-of-concept exploit to demonstrate the vulnerability.

The maintainer of Monkey has been contacted and a new version of the web server (0.9.3) has been released that addresses this issue. All affected parties are advised to upgrade to the latest version available.

Leave a Comment :, , , , , , more...

CoreHTTP web server off-by-one buffer overflow vulnerability

by argp on Dec.02, 2009, under advisories

census ID: census-2009-0003
CVE ID: CVE-2009-3586
Affected Products: CoreHTTP web server versions ≤ 0.5.3.1.
Class: Improper Input Validation (CWE-20), Failure to Constrain Operations within the Bounds of a Memory Buffer (CWE-119)
Remote: Yes
Discovered by: Patroklos Argyroudis

We have discovered a remotely exploitable “improper input validation” vulnerability in the CoreHTTP web server that leads to an off-by-one stack buffer overflow. The vulnerability can lead to denial of service attacks against the web server and potentially to the remote execution of arbitrary code with the privileges of the user running the server.

Details

CoreHTTP is a minimalist web server focusing on speed and size. More information about its features can be found here.

CoreHTTP (up to and including version 0.5.3.1) employs an insufficient input validation method for handling HTTP requests with invalid method names and URIs. Specifically, the vulnerability is an off-by-one buffer overflow in the sscanf() call at file src/http.c line numbers 45 and 46:

45
46
sscanf(parentsprock->buffer,
       "%" PATHSIZE_S "[A-Za-z] %" PATHSIZE_S "s%*[ \t\n]", req, url);

The buffers req and url are declared to be of size 256 bytes (PATHSIZE) and the sscanf() call writes 256 bytes (PATHSIZE_S) to these buffers without NULL terminating them.

Note that this is not vulnerability CVE-2007-4060 in which the same sscanf() call contained no bounds check at all.

This vulnerability can lead to denial of service attacks against the CoreHTTP web server and potentially to the remote execution of arbitrary code with the privileges of the user running the server. We have developed a proof-of-concept exploit to demonstrate the vulnerability.

To address the problem we propose the following unofficial patch (download it from here), since CoreHTTP’s author has not released an official fix yet:

--- corehttp/src/common.h.orig  2009-12-01 09:29:18.000000000 +0200
+++ corehttp/src/common.h       2009-12-01 09:31:47.000000000 +0200
@@ -36,7 +36,7 @@
 #define BUFSIZE                2048
 #define BUFSIZE_S      "2048"
 #define PATHSIZE       256
-#define PATHSIZE_S     "256"
+#define PATHSIZE_S     "255"
 #define        SETSIZE         16
 
 #ifndef GLOBALS_DEFINED
Leave a Comment :, , , , , , more...

Linux kernel SUNRPC off-by-two buffer overflow

by argp on Dec.01, 2009, under advisories

census ID: census-2009-0005
Affected Products: Linux kernel versions from 2.6.32 to 2.6.32-rc7.
Class: Off-by-two stack buffer overflow.
Discovered by: Patroklos Argyroudis

We have found an off-by-two stack buffer overflow in the Linux kernel SUNRPC implementation. Linux kernel versions from 2.6.32 to 2.6.32-rc7 are affected.

Details

There is an off-by-two stack buffer overflow in function rpc_uaddr2sockaddr() of file net/sunrpc/addr.c in the Linux kernel SUNRPC implementation. It was introduced in commit a02d692611348f11ee1bc37431a883c3ff2de23e.

The function rpc_uaddr2sockaddr() that is used to convert a universal address to a socket address takes as an argument the size_t variable uaddr_len (the length of the universal address string). The stack buffer buf is declared in line 315 to be of size RPCBIND_MAXUADDRLEN. If the passed argument uaddr_len is equal to RPCBIND_MAXUADDRLEN then the condition of line 319 is false and then at lines 324 and 325 there are two out-of-bounds assignments:

312: size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
313:                           struct sockaddr *sap, const size_t salen)
314: {
315:        char *c, buf[RPCBIND_MAXUADDRLEN];
            ...
319:        if (uaddr_len > sizeof(buf))
320:            return 0;
            ...
324:        buf[uaddr_len] = '\n';
325:        buf[uaddr_len + 1] = '\0';
            ...
363: }
364: EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);

Since the function rpc_uaddr2sockaddr() is declared as an EXPORT_SYMBOL_GPL function it can be used by kernel modules and potentially be reachable by user input. The bug was reported and fixed in 2.6.32-rc8 (commit 1e360a60b24ad8f8685af66fa6de10ce46693a4b).

Leave a Comment :, , , , , more...


Search

Use the form below to search the blog: