'Overwrite RTCPeerConnection callback 'onicecandidate'

I am trying to spoof ip address leaked from WebRTC, so I want to override 'onicecandidate' callback function but the code below does not work, I cannot figure out why.

  Object.defineProperty(RTCPeerConnection.prototype, 'onicecandidate', {
    set: function (eventHandler) {

        console.log('hook set');

        this._onicecandidateEventHandler = eventHandler;
        this._onicecandidate = function (event) {

            console.log('hook');

            this._onicecandidateEventHandler.apply(this, arguments);
        };


    },
    get: function () {
        return this._onicecandidate;
    }

})

The code above supposed to hook the receiver function assigned by the "fingerprinting script".

A example of fingerprinting script is like this :

    function findIP() {
        var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
        var pc = new myPeerConnection({iceServers: [{urls: "stun:stun.l.google.com:19302"}]}),
        noop = function() {},
        localIPs = {},
        ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g,
        key;

        function ipIterate(ip) {
            if (!localIPs[ip]) {console.log('got ip: ', ip);}
            localIPs[ip] = true;
        }

        pc.createDataChannel("");

        pc.createOffer(function(sdp) {
            sdp.sdp.split('\n').forEach(function(line) {
                if (line.indexOf('candidate') < 0) return;
                line.match(ipRegex).forEach(ipIterate);
            });
            pc.setLocalDescription(sdp, noop, noop);
        }, noop);

        pc.onicecandidate = function(ice) {
            if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
            ice.candidate.candidate.match(ipRegex).forEach(ipIterate);
        };
    }

As you can see: the method to get your real ip from webRTC is trying to estisibale a connection then set a callback on 'onicecandidate' event, the event information contains the real Ip information.

What I'd like to do is to override 'set' function of 'onicecandidate' assignment so it will be replaced by my own hook function and after "alter" the ip address the hook will call the real receiver set by the fingerprint script.

In my tests : I can observed, after executed my code from console, the RTCPeerConnection.prototype has been override, if I assigned a function to RTCPeerConnection.onicecandidate , the console will print "hook set", so appeared that override is success, also if I called RTCPeerConnection.onicecandidate(xxx) mannullay, both my hook function and original function is executed, it works as expected . However this code is not working when I used in the real fingerprint script like I pasted the above. The onicecandidate event are never fired after the override applied.

I am a beginner for javascript, hope someone can explain my confusion .

Thank you in advance.



Solution 1:[1]

Without commenting on why this doesn't work, this alone won't help you against scripts that use addEventListener('icecandidate').

adapter.js contains a "wrapPeerConnectionEvent" helper function which handles both variants. With that helper it becomes quite a simple task:

wrapPeerConnectionEvent(window, 'icecandidate', (e) => {
  if (e.candidate) {
    const parts = e.candidate.candidate.split(' ');
    parts[4] = '127.0.0.1'; // replace the real ip with 127.0.0.1
    e.candidate.candidate = parts.join(' ');   
  }
  return e;
});

See https://jsfiddle.net/krgz5qu1/ for a full example. Note that you may need to take care of the ip in the relAddr field of server-reflexive and relay candidates as well.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Philipp Hancke