客户端信息刺探

2018/10/10 安全 xss 10534 words views

继续学习《XSS 攻击剖析与防御》,在这里主要总结一下 客户端信息刺探 的相关技术的应用。

主要来自《XSS 攻击剖析与防御》

0x01 JavaScript 实现端口扫描

JavaScript 可对用户本地网络中的主机进行端口扫描,从而确定可被利用的服务。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JavaScript 扫描端口</title>
</head>
 
<body>
<form>
    <label for="target">target</label>
    <input type="text" name="target" value="www.baidu.com" /><br />
    <label for="port">port</label>
    <input type="text" name="port" value="80" /><br />
    <label for="timeout">timeout</label>
    <input type="text" name="timeout" value="1000" /><br />
    <label for="result">result</label>
    <textarea name="result" id="result" cols="50" rows="10"></textarea><br />
    <input type="button" value="scan" onclick="scan(this.form)" />
</form>
<script>
	var AttackAPI = {
	    PortScanner: {}
	};
	AttackAPI.PortScanner.scanPort = function (callback, target, port, timeout) {
	    var timeout = (timeout == null)?100:timeout;
	    var img = new Image();
	    img.onerror = function () {
	        if (!img) {
		            return;
		        }
		    img = undefined;
		    callback(target, port, 'open');
		    };
		    img.onload = img.onerror;
		    img.src = 'http://' + target + ':' + port;
		 
		    setTimeout(function () {
		        if (!img) {
		            return;
		        }
		        img = undefined;
		        callback(target, port, 'closed');
		    }, timeout);
		};
		AttackAPI.PortScanner.scanTarget = function (callback, target, ports, timeout) {
		    for (index = 0; index < ports.length; index++) {
		        AttackAPI.PortScanner.scanPort(callback, target, ports[index], timeout);
		    }
		};
		 
		var result = document.getElementById('result');
		var callback = function (target, port, status) {
		    result.value += target + ':' + port + ' ' + status + "\n";
		};
		var scan = function (form) {
		    result.value = "";
		    AttackAPI.PortScanner.scanTarget(callback, form.target.value, form.port.value.split(','), form.timeout.value);
		};

</script>
</body>
</html> 

原理的关键点就是新建一个 Image 对象,将 src 设成目标网页 target:port,如果目标在使用这个端口那么就会发生 load 或者 error 事件。这就足以使脚本判断目标网址是否在使用查询端口了。

这里我对于原理并没有深入的探究,先留个坑在这里 ⭐️

参考:
https://www.gnucitizen.org/blog/javascript-port-scanner/

0x02 截获剪贴板内容

1.只在 IE 浏览器中可用

<html>
	<head>
		<meta charset="utf-8">
		<title>Test</title>
	</head>
	<body>
		<form id="test" action="test.php" method="post">
			<div id="someData">
				<textarea rows="4" cols="40" name="test">
				</textarea>
			</div>
			<input type="button" value="复制到剪贴板" onclick="setClipboard()">
			<input type="button" value="查看剪贴板内容" onclick="readClipboard()">
			<input type="button" value="清除" onclick="window.clipboardData.clearData('text');">
		</form>
		<script>
			function readClipboard(){
				alert(window.clipboardData.getData('Text'));
			}
			function setClipboard(){
				var t = document.getElementById("someData").innerText;
				window.clipboardData.setData('text', t);
			}
		</script>
	</body>
</html>

2.在 chrome 浏览器中

<html>
	<head>
		<meta charset="utf-8">
		<title>Test</title>
	</head>
	<body>
		<input id="test" value="123">
		<script>
		test.onpaste=function(e){
		    e = e || event;
		    var clipboardData = e.clipboardData || window.clipboardData;
		    var s = clipboardData.getData('text');
		    alert(s);
		    return false;
		}
		</script>
	</body>
</html>

在 chrome 里限制 JavaScript 代码访问剪贴板内容,但是这里在 paste 事件触发时我们是可以获取到剪贴板里面的内容的(在 click 事件被触发时是不能获取到剪贴板内容的),因此可以通过上面的代码获取到剪贴板的内容。

下面这段代码可以修改剪贴板里的内容

<html>
	<head>
		<meta charset="utf-8">
		<title>Test</title>
	</head>
	<body>
		<input type="text" value="test" >
		<script>
			 document.addEventListener('copy', function(e){
			    // 设置信息,实现复制
			    e.clipboardData.setData('text/plain', 'Hello, world!');
			    e.preventDefault(); 
			});
		</script>
	</body>
</html>

e.clipboardData: 只能通过 document 上的copy/paste/cut 事件来获取

以上的代码只在特定的浏览器里面试过,别的浏览器效果怎样尚未测试。

3.参考

http://www.dengzhr.com/js/1056
https://www.cnblogs.com/xiaohuochai/p/5882902.html
https://juejin.im/entry/59140bd1128fe1005ca0e9f7

0x03 获取客户端 IP 地址

以下代码对浏览器的兼容性并不好,需要具体情况具体对待

1.仅在 IE 上可行(获取内网 IP)

环境: winXP

<!--在 IE6 中测试成功,在 IE11 中测试失败-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JavaScript获取客户端IP</title>
</head>
 
<body>
<script type="text/javascript" language="javascript">
<!--
function GetLocalIPAddress()
{
     var obj = null;
     var rslt = "";
     try
     {
         obj = new ActiveXObject("rcbdyctl.Setting");
         rslt = obj.GetIPAddress;
         obj = null;
     }
     catch(e)
     {
         //异常发生
     }
     
    return rslt;
}
 
document.write("你的IP是:" + GetLocalIPAddress());
//-->
</script>
</body>
</html> 

环境: win7 32位

<!--在 IE11 中测试成功-->
<html>
<head><title>WMI Scripting HTML</title>
<meta content="text/html; charset=utf-8">
<script>
function GetAdapterInfo() {
 
	var locator = new ActiveXObject ("WbemScripting.SWbemLocator");
	var service = locator.ConnectServer("."); //连接本机服务器
	var properties = service.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=TRUE");
	//查询使用SQL标准
	var e = new Enumerator (properties);
    var msg="";
	for (;!e.atEnd();e.moveNext ())
	{
		var p = e.item ();
		msg+="Caption:" + p.Caption + " "; //网卡描述,也可以使用Description
		msg+="IP:" + p.IPAddress(0) + " ";//IP地址为数组类型,子网俺码及默认网关亦同
		msg+="MAC:" + p.MACAddress + " "; //网卡物理地址
	}
          return msg;
 
}
alert( GetAdapterInfo());
</script>
<body>
</body>
</html>

2.获取 IE 外网 IP

<!--在 IE6 和 IE11 上均能成功-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JavaScript获取客户端IP</title>
</head>
 
<body>
<script type="text/javascript" language="javascript">
xml = new ActiveXObject("Microsoft.XMLHTTP");
xml.open("GET", "http://2018.ip138.com/ic.asp", false);
xml.send();
kk = xml.ResponseText;
i = kk.indexOf("[");
ie = kk.indexOf("]");
ip = kk.substring(i+1, ie);
document.write("你的 IP 地址是:" + ip);
</script>
</body>
</html> 


IE 上其它的玩法

<!--在 IE11 中测试成功-->
<HTML>
<HEAD>
<META charset="utf-8">
<TITLE>WMI Scripting HTML</TITLE>
</HEAD>
<BODY>
<script language=javascript>
var WshShell =new ActiveXObject("WScript.Shell");
document.write("计算机名 = "+ WshShell.ExpandEnvironmentStrings("%COMPUTERNAME%")+"<br/>");
document.write("登录用户名 = "+ WshShell.ExpandEnvironmentStrings("%USERNAME%")+"<br/>");
</script>
</BODY>
</HTML>

在线测试各种浏览器兼容性:https://www.browserling.com/internet-explorer-testing

参考:
Mac测试ie兼容性

3. chrome 上获取客户端 IP (获取公网 IP)

获取客户端公网 IP

<html>
	<head>
		<meta content="text/html" charset="utf-8">
		<script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_1c4228b8.js"></script>
		<title>Test</title>
	</head>
	<body>	
		<script> 
			$(document).ready(function () {
			    $.getJSON("http://jsonip.com/?callback=?", function (data) {
			        console.log(data);
			        alert(data.ip);
			    });
			});
		</script>
	</body>
</html>


下面这段代码调用现成的接口甚至可以获取客户端的精确位置,之后要做什么全凭你的想象力了……

<html>
	<head>
		<meta content="text/html" charset="utf-8">
		<script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_1c4228b8.js"></script>
		<title>Test</title>
	</head>
	<body>	
		<script> 
			$(document).ready(function () {
				$.getJSON('https://ipapi.co/json/', function(data) {
				  console.log(JSON.stringify(data, null, 2));
				});
			});
		</script>
	</body>
</html>

这里有个坐标反查的网站:百度坐标反查

4.使用 WebRTC 获取客户端 IP

对于客户端在内网的 IP 地址可以使用 WebRTC,这里我直接贴出两个现成的代码,因为对于 WebRTC 我并不熟悉.(下面的代码在 IE 上无法使用,我只测试 chrome 了,是成功的)

<html>
	<head>
		<meta content="text/html" charset="utf-8">
		<title>Test</title>
	</head>
	<body>	
		<script> 
			var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})

			/*Usage example*/
			findIP.then(ip => document.write('your ip: ', ip)).catch(e => console.error(e))
		</script>
	</body>
</html>
<html>
	<head>
		<meta content="text/html" charset="utf-8">
		<title>Test</title>
	</head>
	<body>	
		<h1> Demo retrieving Client IP using WebRTC </h1>
		<script> 
			function findIP(onNewIP) { //  onNewIp - your listener function for new IPs
			  var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; //compatibility for firefox and chrome
			  var pc = new myPeerConnection({iceServers: []}),
			    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]) onNewIP(ip);
			    localIPs[ip] = true;
			  }
			  pc.createDataChannel(""); //create a bogus data channel
			  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); // create offer and set local description
			  pc.onicecandidate = function(ice) { //listen for candidate events
			    if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
			    ice.candidate.candidate.match(ipRegex).forEach(ipIterate);
			  };
			}


			var ul = document.createElement('ul');
			ul.textContent = 'Your IPs are: '
			document.body.appendChild(ul);

			function addIP(ip) {
			  console.log('got ip: ', ip);
			  var li = document.createElement('li');
			  li.textContent = ip;
			  ul.appendChild(li);
			}

			findIP(addIP);
		</script>
	</body>
</html>

参考:
How to get client’s IP address using JavaScript?
JS获取IP、MAC和主机名的几种方法

Search

    Table of Contents