利用Google工具栏命令实现XSS攻击的技术分析

本文详细分析了Google工具栏存在的两个XSS漏洞,包括利用navigateto命令和自定义按钮参数实现攻击的技术细节,涉及IE浏览器特殊命令执行和CSRF令牌绕过方法。

利用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()函数:

1
<body onload="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给了我日语消息和漏洞猎人的插图。太可爱了! 今年我将继续报告漏洞。非常感谢!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计