网通用户访问VeryCD等P2P网站被劫持的分析和解决方案

今天总算闲了下来,随手把前几天VeryCD被劫持的一些分析记录和解决方法整理出来。相信这份资料对个人站长来说非常有参考价值。

顺便推荐一下Caoz写的一篇文章,希望大家都能了解做网站背后的辛酸:由做站长的艰辛说起

====
话说VeryCD等网站被劫持的第二天,劫持还在继续。我闲着无聊在QQ群里胡扯,被Dash和xdanger逮到。正好我非常荣幸的是北京网通用户,这个伟大的任务就只能交给我了。

先用正常方式访问一下VeryCD,得到下面的结果

Sam@Bogon:~$ curl -v -H www.verycd.com * About to connect() to x.x.x.x port 80 (#0) *   Trying x.x.x.x... connected * Connected to x.x.x.x (x.x.x.x) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.verycd.com > < HTTP/1.1 200 OK < Content-Type: text/html;charset=gb2312 < Content-Length:182 < <html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>warn</title></head><frameset cols="100"><frame src="http://www.baidu.com"/></frameset></html> * Connection #0 to host x.x.x.x left intact * Closing connection #0 Sam@Bogon:~$

可以发现返回的结果直接被劫持并替换。并不像一般的挂马等行为是在网页内容的最前或者最后部分插入劫持代码。

之后直接输入VeryCD的IP,返回的结果是VeryCD的squid服务器默认页面,说明IP并没有成为劫持的判断标准。应该是VeryCD的域名或者网页中某个特征导致劫持设备对内容进行替换。(此处省略结果)

既然域名是判断的标准之一,那么就可以尝试替换HTTP协议中Host的办法来测试

(1) Sam@Bogon:~$ curl -v -H 'Host: www.veryc.com' www.verycd.com * About to connect() to www.verycd.com port 80 (#0) *   Trying x.x.x.x... connected * Connected to www.verycd.com (x.x.x.x) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.veryc.com > < HTTP/1.1 200 OK (略) (2) Sam@Bogon:~$ curl -v -H 'Host: verycd.com' www.verycd.com * About to connect() to www.verycd.com port 80 (#0) *   Trying x.x.x.x... connected * Connected to www.verycd.com (x.x.x.x) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: verycd.com > < HTTP/1.1 200 OK < Content-Type: text/html;charset=gb2312 < Content-Length:182 < <html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>warn</title></head><frameset cols="100"><frame src="http://www.baidu.com"/></frameset></html> * Connection #0 to host www.verycd.com left intact * Closing connection #0 Sam@Bogon:~$ (3) Sam@Bogon:~$ curl -v -H 'Host: www.veryc.com' www.verycd.com/verycd.com * About to connect() to www.verycd.com port 80 (#0) *   Trying x.x.x.x... connected * Connected to www.verycd.com (x.x.x.x) port 80 (#0) > GET /verycd.com HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.veryc.com > < HTTP/1.1 200 OK (略) (3) Sam@Bogon:~$ curl -v -H 'Host: w.verycd.com' www.verycd.com * About to connect() to www.verycd.com port 80 (#0) *   Trying x.x.x.x... connected * Connected to www.verycd.com (x.x.x.x) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: w.verycd.com > < HTTP/1.1 200 OK (略)

例子中,分别用了4种测试方法
1为发送一个主机头为www.veryc.com的请求到verycd的服务器,可以看到数据正常返回,没有被劫持
2为发送了一个主机头为verycd.com的请求到verycd的服务器,可以看到数据被劫持了
3为发送了一个主机头为www.veryc.com,使用GET方式获取/verycd.com文件的请求到verycd的服务器,可以看到数据正常返回,没有被劫持
4为发送一个主机头为w.verycd.com的请求到verycd的服务器,可以发现数据没有被劫持

通过上面的结论可以看出,用于劫持的设备只对域名的host部分做判断。

我们再来一个有趣的测试:如果把host发送到网通的bbn.com.cn去会怎样呢?

Sam@Bogon:~$ curl -v -H "Host: www.vercd.com" www.bbn.com.cn * About to connect() to www.bbn.com.cn port 80 (#0) *   Trying 202.106.195.131... connected * Connected to www.bbn.com.cn (202.106.195.131) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.vercd.com > < HTTP/1.1 200 OK < Date: Sat, 08 Nov 2008 13:33:06 GMT < Server: Apache/2.0.59 (Unix) DAV/2 < Last-Modified: Thu, 06 Nov 2008 07:21:36 GMT < ETag: "73c63-119c6-259cc000" < Accept-Ranges: bytes < Content-Length: 72134 < Content-Type: text/html < Set-Cookie: BIGipServerweb_pool=107325632.20480.0000; path=/ < <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> (略)

可以看到,什么事情都不会发生。这说明劫持设备应该是在北京网通出口上。

为了证实设备就在北京网通的出口上,我分别用北京不同线路的机器进行了测试,发现访问均一切正常。但某小ISP租用了网通的出口,出现了被劫持的情况。
为了再证实我的猜想,我在一台位于北京某不受影响的ISP的服务器上分别装了pptpd和rinetd,先测试使用VPN链接到此服务器pptpd,所有数据包通过此服务器发送,访问VeryCD.com,一切正常,数据没有被劫持。
然后再把本机的hosts指向此服务器,通过服务器的rinetd对数据包进行转发至VeryCD的服务器,发现数据包被劫持。
结论:加密后的数据不会被劫持。

我再到外部随便找了一台服务器,此服务器跟VeryCD无任何关系,也不位于同一物理位置,结果如下

Sam@Bogon:~$ curl -v -H 'Host: www.verycd.com' server.outside * About to connect() to server.outside port 80 (#0) *   Trying x.x.x.x... connected * Connected to server.outside (x.x.x.x) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.verycd.com > < HTTP/1.1 200 OK < Content-Type: text/html;charset=gb2312 < Content-Length:182 < <html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>warn</title></head><frameset cols="100"><frame src="http://www.baidu.com"/></frameset></html> * Connection #0 to host server.outside left intact * Closing connection #0

分析到了这一步,事情已经非常明朗了:
在北京网通的出口,被人有意或者无意放置了一套类似于GFW的设备用于劫持所有在列表内的P2P网站。我个人更加愿意相信这是网通在测试新设备。因为很明显,劫持后返回的数据使用了一个警告(warn)的标题,劫持者对于这些被劫持的网站的流量有一个很清晰的认识,并没有自己使用服务器来支撑这些流量(根据我掌握的数据,这些网站的流量,就算是静态的html文件也需要十几台服务器做支撑),而是不带任何用于分成或者统计的代码跳转到百度(百度用于统计和分成的代码是tn=xxxx)。(被劫持的第三天有部分流量被分到information.com,直接把information.com弄挂了)。
至于百度也是有苦难言。白白来了这么多无效流量,消耗资源不说,还要背上一个骂名。据我所知,出事后百度也在到处找方式接触受害网站了解情况。

====
解决方法:
根据上面的结论,这件事情的解决方法有下面几种:
1.更换域名,跟劫持者耗。对网站所有者来说低成本,但会造成大量用户不知道新域名而流失。但可以借助百度贴吧来解决。
2.使用BGP协议,更改北京网通用户到网站服务器之间的路由,跳过劫持设备。缺点是成本太高,BGP协议可以被网通人为忽略。
3.在劫持设备以内放置一台分流服务器,分流服务器使用VPN或者别的加密链路链接至主服务器进行数据交换。这样用户使用非加密链接链接至分流服务器,劫持设备无法进行劫持。
4.网站使用ssl,用户和网站之间数据均经过加密,劫持设备无法截取。

====
课外作业:
既然这套设备类似GFW,众所周知GFW是双向的,不知道这套设备怎样呢?带着这个疑问,我做了一个课外实验,让外省的朋友使用上面的测试方法访问我的机器

curl -vIH "Host: www.verycd.com" http://124.64.1xx.xx/ * About to connect() to 124.64.1xx.xx port 80 (#0) *   Trying 124.64.1xx.xx... connected * Connected to 124.64.1xx.xx (124.64.1xx.xx) port 80 (#0) > HEAD / HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Accept: */* > Host: www.verycd.com > < HTTP/1.1 200 OK HTTP/1.1 200 OK < Date: Thu, 06 Nov 2008 15:28:27 GMT Date: Thu, 06 Nov 2008 15:28:27 GMT < Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l < Last-Modified: Mon, 24 Sep 2007 05:23:06 GMT Last-Modified: Mon, 24 Sep 2007 05:23:06 GMT < ETag: "29d84-17ef-43adad0ba6280" ETag: "29d84-17ef-43adad0ba6280" < Accept-Ranges: bytes Accept-Ranges: bytes < Content-Length: 6127 Content-Length: 6127 < MS-Author-Via: DAV MS-Author-Via: DAV < Content-Type: text/html Content-Type: text/html

可以看到,这套设备真不咋地,不支持反向过滤。

====
又及:
在测试的过程中,我发现连续发送N个请求出去,总有几个漏网之鱼,能正确返回数据。这说明了啥?
1.设备是旁路的,失败的截取不会影响到正常的数据传输
2.设备要么是性能有缺陷,要么有防ddos的功能。我更加愿意相信前者。
3.不管设备是性能有缺陷还是能防ddos,我相信一点:在大量数据的攻击下,设备肯定会失去部分作用。