0x00 前言

参考学蚁致用的文章:【热剩饭】获取代理池背后攻击者的真实IP

0x01 WebRTC

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

WebRTC支持发送UDP请求。

WebRTC相关API参考:https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API

0x02 通过WebRTC获取代理池中攻击者真实IP

基本原理

攻击者一般都喜欢使用Socks5类型的代理池来隐藏自己的真实IP。Socks5协议本身是支持UDP协议的,但是大多数的代理客户端并没有去实现。

因此,如果攻击者使用的Socks5类型代理只是转发所有的TCP请求而不支持UDP请求,那么就可以在网页上发起一个UDP请求从而获取到攻击者的真实出口IP。

Demo

WebRTC支持UDP协议,而且在大多数浏览器中都是默认开启的。

即使Socks5代理支持UDP协议,但是WebRTC并不会走代理,因为其设计之初就是为了点对点通信。

webrtc.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
Remote Addr: <?=$_SERVER['REMOTE_ADDR']?>
<hr>
<h3>WebRTC</h3>
<h4>Your local IP addresses:</h4>
<ul id="localip"></ul>
<h4>Your public IP addresses:</h4>
<ul id="publicip"></ul>
<h4>Your IPv6 addresses:</h4>
<ul id="ipv6"></ul>
<iframe id="rtc_iframe" sandbox="allow-same-origin" style="display: none"></iframe>
<script>
//get the IP addresses associated with an account
function getIPs(callback){
var ip_dups = {};
//compatibility for firefox and chrome
var RTCPeerConnection = window.RTCPeerConnection
|| window.mozRTCPeerConnection
|| window.msRTCPeerConnection
|| window.webkitRTCPeerConnection;
var useWebKit = !!window.webkitRTCPeerConnection;
//bypass naive webrtc blocking using an iframe
if(!RTCPeerConnection){
var win = document.getElementById("rtc_iframe").contentWindow;
RTCPeerConnection = win.RTCPeerConnection
|| win.mozRTCPeerConnection
|| win.msRTCPeerConnection
|| win.webkitRTCPeerConnection;
useWebKit = !!win.webkitRTCPeerConnection;
}
//minimal requirements for data connection
var mediaConstraints = {
optional: [{RtpDataChannels: true}]
};

var servers = {
iceServers: [
{
urls: [
'stun:stun.l.google.com:19302?transport=udp',
'stun:stun1.l.google.com:19302?transport=udp',
'stun:stun2.l.google.com:19302?transport=udp',
'stun:stun3.l.google.com:19302?transport=udp',
'stun:stun4.l.google.com:19302?transport=udp',
"stun:stun.ekiga.net?transport=udp",
"stun:stun.ideasip.com?transport=udp",
"stun:stun.rixtelecom.se?transport=udp",
"stun:stun.schlund.de?transport=udp",
"stun:stun.stunprotocol.org:3478?transport=udp",
"stun:stun.voiparound.com?transport=udp",
"stun:stun.voipbuster.com?transport=udp",
"stun:stun.voipstunt.com?transport=udp",
"stun:stun.voxgratia.org?transport=udp"
]
}
]
};
//construct a new RTCPeerConnection
var pc;
try {
pc = new RTCPeerConnection(servers, mediaConstraints);
} catch (e) {
return
}
function handleCandidate(candidate){
//match just the IP address
var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
var ip_addr = ip_regex.exec(candidate)[1];
//remove duplicates
if(ip_dups[ip_addr] === undefined)
callback(ip_addr);
ip_dups[ip_addr] = true;
}
//listen for candidate events
pc.onicecandidate = function(ice){
//skip non-candidate events
if(ice.candidate)
handleCandidate(ice.candidate.candidate);
};

//create a bogus data channel
pc.createDataChannel("bl");
//create an offer sdp
try {
pc.createOffer().then(function(result) {
pc.setLocalDescription(result);
});
} catch (e) {
pc.createOffer().then(function(result) {
pc.setLocalDescription(result, function(){}, function(){});
}, function() {});
}
//wait for a while to let everything done
setTimeout(function(){
//read candidate info from local description
var lines = pc.localDescription.sdp.split('\n');

lines.forEach(function(line){
if(line.indexOf('a=candidate:') === 0)
handleCandidate(line);
});
}, 1000);
}
//insert IP addresses into the page
getIPs(function(ip){
var li = document.createElement("li");
li.textContent = ip;
//local IPs
if (ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/))
document.getElementById("localip").appendChild(li);
//IPv6 addresses
else if (ip.match(/^[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}$/))
document.getElementById("ipv6").appendChild(li);
//assume the rest are public IPs
else
document.getElementById("publicip").appendChild(li);
});
</script>
</body>
</html>

使用Socks5代理访问,成功获取到真实出口IP:

云函数代理池测试

待测试分析…

红蓝对抗借鉴

红队

  • 专用打点浏览器,禁掉WebRTC功能:
    • Chrome:在Chrome应用商店里,安装一个名为WebRTC Leak Prevent的扩展,然后选择Disable non-proxied UDP(force proxy)即可。
    • Firefox:在浏览器上输入about:config,之后搜索media.peerconnection.enabled,找到它后双击,将其改成false即可。
  • 改用VPN;
  • 禁掉了WebRTC后,推荐用热点,再挂代理池;

蓝队

  • 外网打点页面嵌入,如WAF拦截页面;
  • 蜜罐页面嵌入;
  • 不仅局限于WebRTC,研究其他基于UDP协议的功能;