Not so FastCGI!

Published: 2020-06-05
Last Updated: 2020-06-05 08:27:17 UTC
by Remco Verhoef (Version: 1)
2 comment(s)

This past month, we've seen some new and different scans targeting tcp ports between 8000 and 10,000. The first occurrence was on 30 April 2020 and originated from ip address and containing payload:



After this initial scan, the next similar scans used a different ip address (, but within 5 hours from the first occurrence we received a different payload:



It is clear that the payload is trying to exploit something PHP related, but it was not immediately obvious what service was being targeted. After Googling around for a while, I could identify the payload as being targeting fastcgi. Fastcgi can run using both unix sockets (named pipes on Windows) and tcp sockets. Apparently they are scanning for publicly available, incorrect configured fastcgi sockets.

Now that we know what to look at, we can dive into the source code of FastCGI to validate the protocol being used. The FastCGI code can be found at the PHP repository.

Looking at the source code and function fcgi_read_request, we can recognise the header and structure being used. Eg the first header contains the FCGI_BEGIN_REQUEST type, with FCGI_RESPONDER role. The following header consists of the type FCGI_PARAMS, with several variables being defined.

PHP_VALUE allow_url….
SCRIPT_FILENAME /usr/bin/phar.phar
SCRIPT_NAME /usr/bin/phar.phar

Next, it will send a FCGI_PARAMS to end the send of parameters, and send the header with type FCGI_STDIN.

The PHP_VALUE variable consists of php directives causing the base64 encoded script to be automatically parsed before the main file (

Using my favorite swiss army knife CyberChef, we can decode the base64 encoded script easily (recipe From Base64) and beautify the code (recipe Generic Code Beautify), resulting in the following php script:

<?php if (function_exists('error_reporting'))  {

if (function_exists('ini_set'))  {
    @ini_set('error_reporting', 0);
    @ini_set('error_log', NULL);
    @ini_set('log_errors', 0);

if ($___ ==  = "/usr/bin/phar.phar")  {
    echo"<span style='display:none'>".md5('lohpidr')."</span>";


After setting up some configuration to prevent error reporting and error logging, it will validate if the code is being executed with the script name set to /usr/bin/phar.phar. If this is the case, a non-browser visible (hidden by css) will be returned, containing the md5 hash of lohpidr, which results in the hash 58d4c1968bd824ac7ac95da61a462919.

Since the 27th of May, we now see the same payload occurring with a different originating ip address It is interesting to see is that the netblock owner of the first ( and last ( ip address is Virtual Machine Solutions LLC, the middle ( is owned by SpectraIP B.V. We don't see any other traffic from these hosts within our honeypot network.


Please share your ideas, comments and/or insights, with me via social media, @remco_verhoef or email, remco.verhoef at dutchsec dot com. Have a great day!

Remco Verhoef (@remco_verhoef)
ISC Handler - Founder of DutchSec


Keywords: honeypot php
2 comment(s)


good one, Remco.

Diary Archives