chrome-error://chromewebdata/的利用

今天发现一个很有趣的东西,利用chrome-error://chromewebdata 来判断页面。想研究一下原理

1. 用chrome-error://chromewebdata 来进行 端口扫描

在chrome 里面比如访问http://127.0.0.1:8888 这个端口并没有开,chrome 会显示 refuse, 在console 里面看location == 'chrome-error://chromewebdata'.但是地址栏不变。在地址栏里面加# 这个时候页面会重载。因为地址栏和location 并不一样。所以会重载, 如果这127.0.0.1:8888端口开了,页面显示正常,location 和 地址栏一致。如果再加个#并不会 页面重载,利用这个差异可以进行端口判断。

如果需要批量的话,整个页面不可能一直重载把,即不能动 top-frame ,这个时候需要插入一个iframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<iframe name="test" src > </iframe>
<script>

f = document.getElementsByName('test')[0];

f.onload = () =>{console.log("1111111")};

f.src = "http://127.0.0.1:80";

a = document.createElement('a');

a.target = f.name;

a.href = f.src + "#";

</script>

http://127.0.0.1:80 这个页面显示正常,所以只会console.log 一次 ,如果 换成 http://127.0.0.1:8888 没有开启的端口。这个时候会显示两次 console.log。利用这个差异就可以批量检测端口。当然目标网站如果 X-Frame-Options with deny 会影响结果。一个简单的port 扫描如下:

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
30
<iframe name="test" src="" ></iframe>
<script>
var URL = 'http://127.0.0.1:';
var port = 70;
var limit = 10000;
var urlarr = [];
var f = document.getElementsByName('test')[0];
function scan(i){
if(i > limit) return;
var where = URL+i+"/";
console.log(where);
var calls = 0;
f.onload = () =>{
calls++;
f(calls>1){
clearTimeout(timer);
scan(i+1);
return;
}
var a = document.createElement('a');
a.target = f.name;
a.href = f.src+'#'
a.click();
a = null;
}
f.src = where;
timer = setTimeout(()=>{urlarr.push(i);scan(i+1);},2000);
}
scan(port);
</script>

setTimeout 需根据请求响应的时间调整。本地跑的很快。

2. ssrf

当然出现chrome-error://chromewebdata/ 不只仅仅是访问refuse 时会出现,触发csp,触发xss auditor 都会出现。其实关键在于 地址栏 和 location 的值不一致时候 对于 url+"#"的处理,一致时就不会重载。不一致就会触发页面刷新。

在353C CTF filemanager 中就利用了 xss auditor 让页面出现 chrome-error://chromewebdata/。题目因为存在xsrf 存在无法直接xss。体外话,其实找xsrf 的token 也可以用相似的侧信道,我在有些go 的框架里面注意到,关于xsrf的token 字符串比较都是需要用 subtle.ConstantTimeCompare ,并不是简单的 token == expect,用来防止时序攻击,比较字符串时,有可能因为字符串不一样 返回的时间有所不同。

chrome-error://chromewebdata/ 是用来验证页面一个不错的法子。当然有一定的局限型,必须是可以连续的验证的

1
2
3
4
5
6
7
8
9
10
<?php
$password = @$_GET["password"];
if($password==='admin'){
echo "you get it." ;
echo "<script>var a='aaaaaa';</script>";
}else{
echo "guess error!" ;
echo "<script>var b='bbbbbb';</script>";

}

这样的情况下不行 只有唯一情况 页面不一样,并具有有连续的性。无法验证

===的RHS 换成 strpos('admin',$password); 就可以用这种方式。在某些ssrf 中可能有奇效。记录一下。

永远不说放弃,努力再努力,终会如愿以偿!