对 ping0.cc 利用 WebRTC 静默上报用户真实 IP 的分析

来源: https://www.nodeseek.com/post-674661-1

观前提醒:
本篇仅分析了一个接口,不知道接口有什么作用,更不知道这个接口如何影响封控值和共享人数,仅作为风险提醒与数据参考。
不要访问本文的任何链接。

最近刷到了ICMP不可达喵的帖子 历时两个月的ping0实验终于有了结果,正好没什么意思,简单做一个小分析。

首先使用 Reqable 工具抓包,先找可疑请求(即请求体中含有 IP 的请求)。

结果非常 Amazing 啊,发现一请求如下(省略请求头):

POST https://ping0.cc/ip/peer HTTP/2

{

“ip”: “xxx.xxx.xxx.xxx”, # IP 地址
“size”: “879-769” # 浏览器窗口大小
}





---


返回: HTTP/2 204

看了下启动器,是由 https://cdn.ping0.cc/js/check.js 启动的。

下载下来,发现经过 jsjiami.com.v7 混淆,一般吧,在 AI 时代没啥好说的。

这个方法原文如下:

'peer'() {
    const _0x240196 = _0x35e62e,
        _0x4a0fc3 = {
            'qnArj': function (_0x1b0c8c, _0x599205) {
                return _0x1b0c8c === _0x599205;
            },
            'CfeTI': _0x240196(0x2a1, '&]9^'),
            'uxcbk': function (_0x47aa75, _0xb926d0) {
                return _0x47aa75 === _0xb926d0;
            },
            'saKfi': _0x240196(0x1bf, 'l5GL'),
            'KxNbH': function (_0x3ad146, _0x30d0ae) {
                return _0x3ad146 + _0x30d0ae;
            },
            'Ahaer': _0x240196(0x208, 'EHcf'),
            'FCfGW': _0x240196(0x23f, 'p7Wb'),
            'gpjRN': function (_0x1758b5, _0x5b3737) {
                return _0x1758b5 === _0x5b3737;
            },
            'DrvIp': _0x240196(0x2a8, 'H@6r')
        },
        _0x213f70 = window[_0x4a0fc3[_0x240196(0x2b7, 'H)5x')]];
    if (_0x4a0fc3[_0x240196(0x1ef, '2RVF')](_0x213f70, undefined)) {
        this[_0x240196(0x1c9, 'nGax')] = window[_0x240196(0x1a3, '[1jt')];
        return;
    }
    const _0x475906 = new _0x213f70({
        'iceServers': [{
            'urls': _0x4a0fc3[_0x240196(0x2b6, 'fr9d')]
        }]
    });
    _0x475906[_0x240196(0x239, 'M0YP')] = _0x365e93 => {
        const _0x507ee3 = _0x240196;
        if (_0x365e93[_0x507ee3(0x1ad, 'YS0[')]) {
            if (_0x4a0fc3[_0x507ee3(0x1f1, '4Qn*')](_0x4a0fc3[_0x507ee3(0x2a7, 'tqEz')], _0x4a0fc3[_0x507ee3(0x29a, 'J^P0')])) {
                const _0x22ec76 = _0x365e93[_0x507ee3(0x1c7, 'nGax')][_0x507ee3(0x2b1, 'H)5x')][_0x507ee3(0x1ff, 'ni%P')](' ')[0x4];
                if (_0x4a0fc3[_0x507ee3(0x252, '3LK)')](_0x22ec76[_0x507ee3(0x1a5, '[1jt')](_0x4a0fc3[_0x507ee3(0x248, '#IR7')]), -0x1) && !this[_0x507ee3(0x2a3, '$aHF')](_0x22ec76)) {
                    const _0x13b720 = _0x4a0fc3[_0x507ee3(0x1e0, '*qsc')](_0x4a0fc3[_0x507ee3(0x28c, 'l5GL')](window[_0x507ee3(0x1e1, '[1jt')], '-'), window[_0x507ee3(0x2b3, 'iMDv')]);
                    axios[_0x507ee3(0x1d3, '4Qn*')](_0x4a0fc3[_0x507ee3(0x23e, 'ZAzr')], {
                        'ip': _0x22ec76,
                        'size': _0x13b720
                    });
                }
            } else _0x2588e5[_0x507ee3(0x213, 'SZ(Q')](_0x390073);
        }
    }, _0x475906[_0x240196(0x1b6, 'f01U')]({
        'offerToReceiveAudio': !![]
    })[_0x240196(0x1b2, 'H)5x')](_0x2c7a44 => _0x475906[_0x240196(0x24b, 'J^P0')](_0x2c7a44));
}

反混淆清理一下,变成这样:

peer() {
    const RTCPeerConnection = window.RTCPeerConnection;

    if (RTCPeerConnection === undefined) {
        this.newaddr = window.ip;
        return;
    }

    const pc = new RTCPeerConnection({
        iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
    });

    pc.onicecandidate = (event) => {
        if (event.candidate) {
            // 死代码分支(混淆器添加的永真条件)
            if (true) {
                // 从 candidate 字符串中提取第5个字段(IP地址)
                const ip = event.candidate.candidate.split(' ')[4];

                // 检查:包含点号(IPv4)且不是保留地址
                if (ip.indexOf('.') !== -1 && !this.isreserve(ip)) {
                    // 构造 size 参数
                    const size = window.innerWidth + '-' + window.innerHeight;

                    // POST 上报
                    axios.post('/ip/peer', { ip: ip, size: size });
                }
            }
        }
    };

    // 触发 ICE 候选收集
    pc.createOffer({ offerToReceiveAudio: true })
        .then(offer => pc.setLocalDescription(offer));
}

是不是一眼就知道这段代码在干嘛了,利用 WebRTC 技术绕过代理,获取用户的真实公网 IP 地址,并结合浏览器的窗口尺寸信息,将其发送到后端服务器。

那么这段逻辑在什么时候会触发呢?

Vue的 created() hook

只要你打开就静默发生捏。

你要是让我评价这段行为在干嘛,我只能说你都收集浏览器大小了作为指纹了,那还说啥了,难道收集浏览器大小是为了帮你检查一下 WebRTC 有没有 leak?


本篇内容仅供参考,可以自己读一下源码,不长。

本篇内容的任何观点仅代表作者个人看法,并非客观事实,仅供参考。


二编:
用过的大佬们也不用那么焦虑哇,你如果有好好开着 TUN 一点事没有的,不会泄漏你的IP。
就是会收集你的浏览器视图大小作为指纹,可能用于封控值和共享人数的判断,脏掉你的IP(

个人平语:

chrome和 firfox 均有 WebRTC 插件可控制是否绕过代理