在Chrome中使用WebRTC ICE服务器进行端口扫描(一)

很早就有使用浏览器扫描LAN这种操作了。也有许多使用XHR请求WebSocket纯HTML来发现和识别LAN设备的工具。但是在这篇文章中,我将介绍一种使用WebRTC ICE服务器的新扫描技术。它速度很快,并且与其他方法不同的是:它绕过了阻止的端口列表。唯一的缺点是:它仅在受害者使用Chrome时有效。

首先给大家看一个概念简介的视频。视频中我正在扫描的是192.168.88.0/24网络。

https://www.youtube.com/watch?v=M6lBVhkzUmM&feature=emb_title

(因为“网络”选项卡可见,所以您看不到任何被记录的请求。)

您也可以跳过简介部分,直接进入代码演示页面。

什么是ICE服务器?

正如我所说,扫描时要用到WebRTC ICE服务器。ICE服务器是WebRTC RTCPeerConnection用于自发现、NAT遍历或中继的STUNTURN服务器。服务器列表可以传递到RTCPeerConnection的构造函数中。下图是提供给一台Google公共STUN服务器的构造函数示例:

var rtc = new RTCPeerConnection({
    iceServers:[{“urls”:”stun:stun.l.google.com:19302”}]
});

当上述RTCPeerConnection进入ICE gathering state时,它将尝试连接到提供的服务器。

协议事项

ICE服务器可以绑定到UDP或TCP端口。但是除非另有指示,否则Chrome会仅尝试通过UDP进行通信。下图是Wireshark的屏幕截图,图中显示的是Chrome发送到不存在的TURN服务器的数据包。内容都是UDP。

如果您了解ICE服务器URLs,就可以强制Chrome通过TCP进行访问。但是传递给RTCPeerConnection构造函数的URL必须符合RFC 7064(STUN)或RFC 7065(TURN)。 TURN URI方案如下:

详情见https://tools.ietf.org/html/rfc7065#section-3.1

对于扫描而言,最重要的是可选的“?transport =”字段。通过使用以“?transport = tcp”结尾的TURN URI,我们可以强制Chrome使用基于TCP的ICE。

现在我们掌握了一种可以使用我们选择的任何IP和端口来启动TCP连接的方法。但是我们扫描的所有主机大都不是TURN服务器,那我们该如何确定主机是否还存在呢?

确定主机是否存在

下图是JSFiddle生成的256 TURN URI,用于查找192.168.[0–255].1范围内仍存在的主机地址。

var brute_array = [];
for (i = 0; i < 256; i++) {
  brute_address = "turn:192.168." + i + ".1:445?transport=tcp";
  brute_array.push({
    urls: brute_address,
    credential: "lobster",
    username: "albino"
  });
}

var rtc_brute = new RTCPeerConnection({
  iceServers: brute_array,
  iceCandidatePoolSize: 0
});
rtc_brute.createDataChannel('', {
  reliable: false
});
rtc_brute.onicecandidateerror = function(e) {
  if (e.url == null) {
    return;
  }

  url_split = e.url.split(":");
  host_div = document.createElement('div');
  host_div.id = url_split[1];
  host_div.innerHTML = url_split[1];
  document.getElementById('hosts').appendChild(host_div);
}

// trigger the gathering of ICE candidates
rtc_brute.createOffer(function(offerDesc) {
  rtc_brute.setLocalDescription(offerDesc);
}, function(e) {
  console.log("Create offer failed callback.");
<html>

  <body>
    <div id="hosts">
    </div>
  </body>

</html>
192.168.10.1
192.168.13.1
192.168.15.1
192.168.16.1
192.168.32.1
192.168.33.1
192.168.35.1
192.168.50.1
192.168.65.1
192.168.69.1
192.168.132.1
192.168.67.1
192.168.68.1
192.168.133.1
192.168.134.1
192.168.135.1
192.168.136.1
192.168.137.1
192.168.138.1
192.168.139.1
192.168.140.1
192.168.141.1
192.168.142.1
192.168.143.1
192.168.144.1
192.168.145.1
192.168.146.1
192.168.147.1
192.168.148.1
192.168.149.1
192.168.150.1
192.168.151.1
192.168.152.1
192.168.153.1
192.168.154.1
192.168.155.1
192.168.156.1
192.168.157.1
192.168.158.1
192.168.159.1
192.168.160.1
192.168.161.1
192.168.162.1
192.168.163.1
192.168.164.1
192.168.165.1
192.168.166.1
192.168.167.1
192.168.168.1
192.168.169.1
192.168.170.1
192.168.171.1
192.168.172.1
192.168.173.1
192.168.174.1
192.168.175.1
192.168.176.1
192.168.177.1
192.168.178.1
192.168.179.1
192.168.180.1
192.168.181.1
192.168.182.1
192.168.73.1
192.168.30.1
192.168.76.1
192.168.72.1
192.168.74.1
192.168.75.1
192.168.96.1
192.168.97.1
192.168.99.1
192.168.98.1
192.168.94.1
192.168.70.1
192.168.183.1
192.168.201.1
192.168.199.1
192.168.200.1
192.168.195.1
192.168.196.1
192.168.202.1
192.168.203.1
192.168.204.1
192.168.205.1
192.168.206.1
192.168.207.1
192.168.208.1
192.168.209.1
192.168.210.1
192.168.211.1
192.168.212.1
192.168.213.1
192.168.214.1
192.168.215.1
192.168.216.1
192.168.217.1
192.168.218.1
192.168.219.1
192.168.220.1
192.168.221.1
192.168.222.1
192.168.223.1
192.168.224.1
192.168.225.1
192.168.226.1
192.168.227.1
192.168.228.1
192.168.229.1
192.168.230.1
192.168.231.1
192.168.232.1
192.168.233.1
192.168.234.1
192.168.235.1
192.168.236.1
192.168.237.1
192.168.238.1
192.168.239.1
192.168.240.1
192.168.241.1
192.168.242.1
192.168.243.1
192.168.244.1
192.168.245.1
192.168.246.1
192.168.247.1
192.168.248.1
192.168.249.1
192.168.250.1
192.168.251.1
192.168.252.1
192.168.253.1
192.168.254.1
192.168.255.1
192.168.0.1
192.168.1.1
192.168.2.1
192.168.3.1
192.168.4.1
192.168.5.1
192.168.6.1
192.168.7.1
192.168.8.1
192.168.9.1
192.168.11.1
192.168.12.1
192.168.14.1
192.168.17.1
192.168.18.1
192.168.19.1
192.168.20.1
192.168.21.1
192.168.22.1
192.168.23.1
192.168.24.1
192.168.25.1
192.168.26.1
192.168.27.1
192.168.28.1
192.168.29.1
192.168.31.1
192.168.34.1
192.168.36.1
192.168.37.1
192.168.38.1
192.168.39.1
192.168.40.1
192.168.41.1
192.168.42.1
192.168.43.1
192.168.44.1
192.168.45.1
192.168.46.1
192.168.47.1
192.168.48.1
192.168.49.1
192.168.51.1
192.168.52.1
192.168.53.1
192.168.54.1
192.168.55.1
192.168.56.1
192.168.57.1
192.168.58.1
192.168.59.1
192.168.60.1
192.168.61.1
192.168.62.1
192.168.63.1
192.168.64.1
192.168.66.1
192.168.71.1
192.168.77.1
192.168.78.1
192.168.79.1
192.168.80.1
192.168.81.1
192.168.82.1
192.168.83.1
192.168.84.1
192.168.85.1
192.168.86.1
192.168.87.1
192.168.88.1
192.168.89.1
192.168.90.1
192.168.91.1
192.168.92.1
192.168.93.1
192.168.95.1
192.168.100.1
192.168.101.1
192.168.102.1
192.168.103.1
192.168.104.1
192.168.105.1
192.168.106.1
192.168.107.1
192.168.108.1
192.168.109.1
192.168.110.1
192.168.111.1
192.168.112.1
192.168.113.1
192.168.114.1
192.168.115.1
192.168.116.1
192.168.117.1
192.168.118.1
192.168.119.1
192.168.120.1
192.168.121.1
192.168.122.1
192.168.123.1
192.168.124.1
192.168.125.1
192.168.126.1
192.168.127.1
192.168.128.1
192.168.129.1
192.168.130.1
192.168.131.1
192.168.184.1
192.168.185.1
192.168.186.1
192.168.187.1
192.168.188.1
192.168.189.1
192.168.190.1
192.168.191.1
192.168.192.1
192.168.193.1
192.168.194.1
192.168.197.1
192.168.198.1

icecandidateerror事件生成,则确定该主机地址“存在(active)”。如果主机以某种形式拒绝连接,Chrome将生成错误事件。理想情况是:在Chrome发送初始消息后,主机通过RST或快速地拒绝了连接。尽管服务器保持连接打开,但错误事件仍需要30秒钟才能生成。

这就是为什么JSFiddle要使用端口445进行扫描。我曾遇到过SMB完成了TCP握手,然后在Chrome的非SMB流量之后关闭了连接。实际上445也是一种不切实际的选择,因为它更有可能会安装Windows盒子。

如果Chrome没有响应,则不会生成该事件。这可能是由于防火墙忽略了不常见的入站请求。或者实际上没有可用的主机。

我遇到过的唯一一个极端情况是:发送ICMP响应作为回复。这会导致Chrome生成icecandidateerror,它与处于active状态的主机没有区别。

原文地址:https://medium.com/tenable-techblog/using-webrtc-ice-servers-for-port-scanning-in-chrome-ce17b19dd474

文章作者:Jacob Baines

填写常用邮箱,接收社区更新

WebRTC 中文社区由

运营