使用WEBRTC进行端口扫描

时间:2018-06-10 08:26:23

标签: javascript browser port

我试图在我的localhost上使用JS从浏览器运行端口扫描。 我已经尝试了各种方法,包括超时检查,建议做很多帖子。

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

有人可以帮忙吗?

感谢。

2 个答案:

答案 0 :(得分:2)

没有这样的方法。 WebRTC使用STUN进行同意,以避免允许您构建端口扫描程序。见the security considerations

答案 1 :(得分:0)

有几种方法可以完成基于浏览器的端口扫描。但是通常,它是某种形式的定时攻击,它使浏览器加载一些不存在的资源并测量响应。这里有些例子。一个使用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>

在这里,我们将使用一种称为turnscan的最新webrtc方法(仅基于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

还有其他技术,但我将让您搜索其余技术。