【问题标题】:Port Scanning using WEBRTC使用 WEBRTC 进行端口扫描
【发布时间】:2018-11-19 18:25:04
【问题描述】:

我正在尝试在我的本地主机上使用 JS 从我的浏览器运行端口扫描。 我尝试了各种方法来做到这一点,包括超时检查推荐的帖子数量。

我知道有一种方法可以使用 WebRTC 扫描主机上的特定端口,但找不到任何相关文档。

有人可以帮忙吗?

谢谢。

【问题讨论】:

    标签: javascript browser port


    【解决方案1】:

    没有这样的方法。 WebRTC 使用 STUN 来获得同意,其中包括避免允许您构建端口扫描器。见the security considerations

    【讨论】:

    • WebRTC 用于获取您的 IP - 从那里它可以开始在该子网内执行扫描
    【解决方案2】:

    有几种方法可以完成基于浏览器的端口扫描。但通常情况下,它是某种形式的定时攻击,通过使浏览器加载一些不存在的资源并测量响应。这里有些例子。一个使用 img 标签,另一个使用 webrtc。

    这里我们将使用一个假的img标签方法:

    /* The scanner needs these global variables for an ugly hack. */
    var last_scanobj_index = 0;
    var scanobjs = {};
    
    function PortScanner(ip, port) {
    
        this.ip = ip;
        this.port = port;
        this.on_open_or_closed = null;
        this.on_stealthed = null;
        this.start_time = null;
        this.timed_out = null;
        this.total_time = null;
    
        this.run = function () {
            /* Check that the client gave us all the callbacks we need. */
            if (this.on_open_or_closed == null) {
                alert("Please set the on_open_or_closed callback!");
            }
            if (this.on_stealthed == null) {
                alert("Please set the on_stealthed callback!");
            }
    
            /* Save this object in the global directory (UGLY HACK). */
            var our_scanobj_index = last_scanobj_index;
            last_scanobj_index++;
            scanobjs[our_scanobj_index] = this;
    
            /* Record the starting time. */
            this.start_time = (new Date()).getTime();
    
            /* Create the div to load the image, passing our object's index into
                the global directory so that it can be retrieved. */
            document.getElementById("testdiv").innerHTML = '<img src="http://' + ip + ':' + port +
                '" alt="" onerror="error_handler(' + our_scanobj_index + ');" />';
    
            // XXX: What's the right way to do this in JS?
            var thiss = this;
            setTimeout(
                function () {
                    /* This will be non-null if the event hasn't fired yet. */
                    if (scanobjs[our_scanobj_index]) {
                        scanobjs[our_scanobj_index] = null;
                        thiss.timed_out = true;
                        thiss.on_stealthed();
                    }
                },
                10000
            );
        }
    }
    
    function error_handler(index) {
        /* Get the PortScanner object back. */
        var thiss = scanobjs[index];
    
        /* If it's null, the scan timed out. */
        if (thiss == null) {
            return;
        }
        /* Set it to null so the timeout knows we handled it. */
        scanobjs[index] = null;
        thiss.timed_out = false;
    
        /* Measure the amount of time it took for the load to fail. */
        thiss.total_time = (new Date()).getTime() - thiss.start_time;
    
        /* Call the appropriate callback. */
        if (thiss.total_time < 1500) {
            thiss.on_open_or_closed();
        } else {
            thiss.on_stealthed();
        }
    }
    
    function custom_scan(form) {
        var ip = form.custom_ipaddr.value;
        var port = form.custom_port.value;
        var ip_addr_re = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
    
        var match = ip_addr_re.exec(ip);
        if (match == null) {
            alert("That isn't a valid IPv4 address.");
            return;
        }
    
        if (match[1] > 255 || match[2] > 255 || match[3] > 255 || match[4] > 255) {
            alert("That isn't a valid IPv4 address.");
        }
    
        port = parseInt(port);
        if (isNaN(port) || port < 0 || port > 65535) {
            alert("Bad port number");
        }
    
        document.getElementById("custom_button").disabled = true;
        document.getElementById("custom_result").innerHTML = "Scanning... This will take up to 10 seconds.";
    
        var scanner = new PortScanner(ip, port);
    
        scanner.on_stealthed = function () {
            if (scanner.timed_out) {
                document.getElementById("custom_result").innerHTML = "Case 2 (no response after 10s).";
            } else {
                document.getElementById("custom_result").innerHTML = "Case 2 (" + this.total_time + " ms).";
            }
            document.getElementById("custom_button").disabled = false;
        }
    
        scanner.on_open_or_closed = function () {
            document.getElementById("custom_result").innerHTML = "Open (" + this.total_time + " ms)."
            document.getElementById("custom_button").disabled = false;
        }
    
        scanner.run();
    }
    
    /* This variable keeps track of which 192.168.1 IP to scan next. */
    var current_octet;
    var stop;
    
    function lan_scan(form) {
        document.getElementById("lan_button").disabled = true;
        document.getElementById("lan_button_stop").disabled = false;
    
        /* Skip .1 since it might visibly prompt for a password. */
        current_octet = 2;
        stop = false;
    
        var scanner = new PortScanner("192.168.1." + current_octet, 80);
        scanner.on_stealthed = lan_on_stealthed;
        scanner.on_open_or_closed = lan_on_open_or_closed;
        scanner.run();
    
        document.getElementById("lan_results").innerHTML = "Scanning... <br />";
    }
    
    function lan_stop(form) {
        stop = true;
        document.getElementById("lan_button").disabled = false;
        document.getElementById("lan_button_stop").disabled = true;
    }
    
    function lan_on_stealthed() {
        var res_div = document.getElementById("lan_results");
        res_div.innerHTML += "192.168.1." + current_octet + ": ";
        if (this.timed_out) {
            res_div.innerHTML += "Closed (no response after 10 seconds). <br />";
        } else {
            res_div.innerHTML += "Closed (" + this.total_time + " ms). <br />";
        }
    
        current_octet += 1;
    
        if (stop || current_octet >= 255) {
            res_div.innerHTML += "Done. <br />";
            document.getElementById("lan_button").disabled = false;
            document.getElementById("lan_button_stop").disabled = true;
            return;
        }
    
        var scanner = new PortScanner("192.168.1." + current_octet, 80);
        scanner.on_stealthed = lan_on_stealthed;
        scanner.on_open_or_closed = lan_on_open_or_closed;
        scanner.run();
    }
    
    function lan_on_open_or_closed() {
        var res_div = document.getElementById("lan_results");
        res_div.innerHTML += "192.168.1." + current_octet + ": ";
        res_div.innerHTML += "Port Open (" + this.total_time + " ms). <br />";
    
        current_octet += 1;
    
        if (stop || current_octet >= 255) {
            res_div.innerHTML += "Done. <br />";
            document.getElementById("lan_button").disabled = false;
            document.getElementById("lan_button_stop").disabled = true;
            return;
        }
    
        var scanner = new PortScanner("192.168.1." + current_octet, 80);
        scanner.on_stealthed = lan_on_stealthed;
        scanner.on_open_or_closed = lan_on_open_or_closed;
        scanner.run();
    }
    /*(function () {
      PortScanner('192.168.50.50', 80)
      document.getElementById('result').innerHTML = "Hello"
    })()
    */
    <p>
            <strong>Local Network Scan (img method)</strong>
        </p>
    
        <form>
            <input type="button" id="lan_button" value="Scan 192.168.1.* port 80" onclick="lan_scan(this.form);" />
            <input type="button" id="lan_button_stop" value="Stop Scan" onclick="lan_stop(this.form);" disabled="disabled"/>
        </form>
    
        <div id="lan_results" style="padding-top: 10px;"></div>
    
        <p>
            <strong>Custom Scan</strong>
        </p>
    
        <form>
            <table>
                <tr>
                    <td>IP Address:&nbsp;&nbsp;</td>
                    <td><input type="text" name="custom_ipaddr" value="192.168.1.1"></input></td>
                </tr>
                <tr>
                    <td>Port:</td>
                    <td><input type="text" name="custom_port" value="80"></input></td>
                </tr>
                <tr>
                    <td></td>
                    <td style="text-align: right;">
                        <input type="button" value="Scan" id="custom_button" onclick="custom_scan(this.form);" />
                    </td>
                </tr>
            </table>
        </form>
    
        <div id="custom_result"></div>
    
    </div>
    
    <div id="testdiv" style="visibility: hidden"></div>

    这里我们将使用最近的 webrtc 方法,称为 turnscan(仅限基于 Chrome 的浏览器):

    var ports = [21, 22, 23, 25, 53, 80, 443, 445, 5900, 8080];
    var target = "192.168.1.1";
    
    address_div = document.createElement('div');
    address_div.id = target;
    address_div.innerHTML = target;
    document.getElementById("hosts").appendChild(address_div);
    
    var scan_array = [];
    for (i = 0; i < ports.length; i++) {
      probe_address = "turn:" + target + ":" + ports[i] + "?transport=tcp";
      scan_array.push({
        urls: probe_address,
        credential: "lobster",
        username: "albino"
      });
    
      port_div = document.createElement('div');
      port_div.id = ports[i]
      port_div.innerHTML = "&nbsp;&nbsp;&nbsp;-> Port " + ports[i] + " - ?"
      document.getElementById(target).appendChild(port_div);
    }
    
    var port_scan = new RTCPeerConnection({
      iceServers: scan_array,
      iceCandidatePoolSize: 0
    });
    port_scan.createDataChannel('', {
      reliable: false
    });
    
    port_scan.onicecandidateerror = function(e) {
      if (e.url == null) {
        return;
      }
    
      url_split = e.url.split(":");
      port_split = url_split[2].split("?");
    
      if (e.hostCandidate != "0.0.0.x:0") {
        document.getElementById(port_split[0]).innerHTML = "&nbsp;&nbsp;&nbsp;-> Port " + port_split[0] + " - <b><i>Open</i><b>"
      } else {
        document.getElementById(port_split[0]).innerHTML = "&nbsp;&nbsp;&nbsp;-> Port " + port_split[0] + " - Closed"
      }
    }
    
    setTimeout(function() {
      if (port_scan.iceGatheringState === "gathering") {
        port_scan.close();
      }
    }, 60000);
    
    port_scan.onicegatheringstatechange = function(e) {
      if (port_scan.iceGatheringState == "complete") {
        port_scan.close();
      }
    }
    
    port_scan.createOffer(function(offerDesc) {
        port_scan.setLocalDescription(offerDesc);
      },
      function(e) {
        console.log("Create offer failed callback.");
      });
    <html>
    
      <body>
        <div id="hosts">
        </div>
      </body>
    
    </html>

    一些参考链接:

    https://portswigger.net/research/exposing-intranets-with-reliable-browser-based-port-scanning

    https://defuse.ca/in-browser-port-scanning.htm

    https://github.com/jacob-baines/turnscan.js

    还有其他技术,但我会让你去寻找其余的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多