利用Google工具栏命令实现XSS攻击
在这篇文章中,我将分享在toolbar.google.com上发现的两个XSS漏洞。这些漏洞于2015年6月发现,现已被修复。
这些漏洞有些特殊,只能在安装了Google工具栏的IE浏览器上利用。IE的Google工具栏有一些特殊命令,可以通过toolbar.google.com的Web界面执行。
例如,您可以从以下地址找到命令:http://toolbar.google.com/fixmenu
1
2
3
4
5
6
7
8
9
10
11
12
|
<script language="JavaScript"> <!--
function command(s) {
window.location = 'http://toolbar.google.com/command?key=' + document.googleToken + s;
}
function fixMenu() {
command('&fixmenu=1');
alert(document.all['restartmessage'].innerText)
}
// -->
</script>
....
<input type=button onclick='javascript:fixMenu()' value="Reset IE's Toolbar menu">
|
点击页面上的按钮可以重置工具栏设置。命令是如何执行的?让我们看看command()函数。
1
|
window.location = 'http://toolbar.google.com/command?key=' + document.googleToken + s;
|
通常,通过此代码我们会跳转到"http://toolbar.google.com/command?…"。但在安装了Google工具栏的IE上,导航到"http://toolbar.google.com/command"被视为特殊命令。要执行命令,需要在查询字符串中放入命令名称。如您在上面的页面中所见,fixmenu=1与重置设置相关联。
document.googleToken用于CSRF令牌。document.googleToken是由Google工具栏设置的随机值。如果令牌不正确,命令执行将失败。toolbar.google.com是唯一可以访问该令牌的域。
检查工具栏命令
首先,为了找到命令,我探索了toolbar.google.com上的内容和工具栏的二进制文件。然后,我注意到了navigateto命令。顾名思义,navigateto命令用于导航。当我在toolbar.google.com上的IE开发者控制台中放入以下脚本时,它确实起作用了。它带我去了example.com。
(注意:此命令似乎在最新的Google工具栏中已被移除)
1
|
location="http://toolbar.google.com/command?key="+document.googleToken+"&navigateto=http://example.com/"
|
我还测试了javascript: URL。
1
|
location="http://toolbar.google.com/command?key="+document.googleToken+"&navigateto=javascript:alert(1)"
|
然后我得到了一个警报对话框!但现在高兴还为时过早,因为我们无法从外部页面知道document.googleToken。换句话说,如果攻击者能够获取document.googleToken,它就直接成为XSS漏洞。
XSS第一部分
我浏览了toolbar.google.com域的资源,并找到了以下页面:
http://toolbar.google.com/dc/dcuninstall.html(WebArchive)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<script language="JavaScript"> <!--
function command(s) {
window.location = 'http://toolbar.google.com/command?key=' + document.googleToken + s;
}
function OnYes() {
var path = document.location.href.substring(0,document.location.href.lastIndexOf("/") + 1);
command("&uninstall-dc=anyway&DcClientMenu=false&EnableDC=false&navigateto=" + path + "dcuninstalled.html");
// window.location=path + "dcuninstallfailed.html";
}
// -->
</script>
...
<script language="JavaScript"> <!--
document.write('<button default class=button name=yes ');
document.write('onclick="OnYes(); ">Uninstall Google Compute</button>');
// -->
</script>
|
该页面有一个可以执行命令的按钮。如果单击按钮,它会通过OnYes()函数调用command("&uninstall-dc=anyway&DcClientMenu=false&EnableDC=false&navigateto=" + path + “dcuninstalled.html”);。
让我们先不管命令细节,看看path变量。path变量由以下行设置:
1
|
var path = document.location.href.substring(0,document.location.href.lastIndexOf("/") + 1);
|
它切割location.href以用作命令字符串。我相信编码人员期望以下粗体字符串:
https://toolbar.google.com/dc/dcuninstall.html
但这段代码不好。如果URL在查询或哈希中有/,它将切割意外的URL字符串。
https://toolbar.google.com/dc/dcuninstall.html?xxx/yyy
那么,如果我们放入以下字符串会发生什么?
https://toolbar.google.com/dc/dcuninstall.html?&navigateto=javascript:alert(1)//
此URL被分配给path变量,并用于命令字符串的一部分,如下所示:
http://toolbar.google.com/command?key=[TOKEN]&uninstall-dc=anyway&DcClientMenu=false&EnableDC=false&navigateto=https://toolbar.google.com/dc/dcuninstall.html?&navigateto=javascript:alert(1)//dcuninstalled.html
此命令中有两个navigateto。在这种情况下,似乎后面的字符串被用作命令。因此,该命令将我们导航到javascript:alert(1)//dcuninstalled.html!!
通过这种方式,我实现了XSS而无需知道document.googleToken。
XSS第二部分
之后,我发现了另一个有趣的页面:
https://toolbar.google.com/buttons/edit/index.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
30
31
32
|
<script language=JavaScript>
<!--
document.custom_button_uid = "";
function command(s) {
window.location = "http://toolbar.google.com/command?key=" +
document.googleToken + s;
}
function Load() {
var url = window.document.URL.toString();
var url_pieces = url.split("?");
if (url_pieces.length > 1) {
var params = url_pieces[1].split("&");
var i = 0;
for (i = 0; i < params.length; i++) {
param_pieces = params[i].split("=");
if (param_pieces.length == 2 &&
param_pieces[0] == "custom_button_uri" &&
param_pieces[1].length > 0) {
document.custom_button_uid = unescape(param_pieces[1]);
}
}
}
if (document.custom_button_uid != "") {
action.innerHTML = document.forms[0].edit_mode_title.value;
command("&custom-button-load=" + document.custom_button_uid);
}
}
....
// -->
</script>
<body onload="Load()">
|
让我们看看这段代码。
首先,调用Load()函数:
Load()函数将document.URL字符串设置为url变量:
1
|
var url = window.document.URL.toString();
|
查询被分解,并取出参数名称和值。然后,如您在下文粗体字符串中所见,代码尝试查找custom_button_uri参数。如果找到该参数,它将参数值分配给document.custom_button_uid变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var url_pieces = url.split("?");
if (url_pieces.length > 1) {
var params = url_pieces[1].split("&");
var i = 0;
for (i = 0; i < params.length; i++) {
param_pieces = params[i].split("=");
if (param_pieces.length == 2 &&
param_pieces[0] == "custom_button_uri" &&
param_pieces[1].length > 0) {
document.custom_button_uid = unescape(param_pieces[1]);
}
}
}
|
document.custom_button_uid变量传递给command()函数:
1
2
3
4
|
if (document.custom_button_uid != "") {
action.innerHTML = document.forms[0].edit_mode_title.value;
command("&custom-button-load=" + document.custom_button_uid);
}
|
这意味着用户输入通过custom_button_uri查询参数传递到命令中。
让我们再次查看赋值部分:
1
|
document.custom_button_uid = unescape(param_pieces[1]);
|
幸运的是,custom_button_uri值通过了unescape()方法!这意味着我们可以放入URL编码的&和=,如下所示:
https://toolbar.google.com/buttons/edit/index.html?custom_button_uri=%26navigateto%3Djavascript:alert(document.domain)
最终,命令字符串为:
http://toolbar.google.com/command?key=[TOKEN]&custom-button-load=&navigateto=javascript:alert(document.domain)
完成!
奖励
我通过Google VRP报告了这些漏洞,并获得了$3133.7 × 2的奖励。
找到并理解未记录的命令并不容易,但这是一段有趣的时光。
最后,我想介绍一下去年从Google收到的节日礼物。
(您可以从以下链接找到过去的礼物:Chromebook、Nexus 10、Nexus 5、Moto 360)
它是USB Armory、Bug Bountopoly和明信片!
Google安全团队的Stephen给了我日语消息和漏洞猎人的插图。太可爱了!
今年我将继续报告漏洞。非常感谢!