Commit f3b881c7 authored by Edvard Rejthar's avatar Edvard Rejthar

Webextensions fully replaced Addon-SDK

parent f7bd1155
.idea
__pycache__
*.pem
\ No newline at end of file
*.pem
/firefox-mdmaug-extension/nbproject
{
"abort_on_missing": false,
"check_memory": false,
"enable_e10s": false,
"is-sdk-bundled": false,
"jetpackID": "mdmaug@jetpack",
"loader": "addon-sdk/lib/sdk/loader/cuddlefish.js",
"main": "main",
"mainPath": "mdmaug/main",
"manifest": {
"mdmaug/main": {
"docsSHA256": null,
"jsSHA256": "497a1082ce489b39d8f17e63e14015b7f3ea023f4af555ccc15ef740d6f003e7",
"moduleName": "main",
"packageName": "mdmaug",
"requirements": {
"chrome": "chrome",
"sdk/base64": "sdk/base64",
"sdk/page-mod": "sdk/page-mod",
"sdk/tabs": "sdk/tabs",
"sdk/self": "sdk/self",
"sdk/tabs/utils": "sdk/tabs/utils",
"sdk/timers": "sdk/timers",
"sdk/ui/button/action": "sdk/ui/button/action",
"sdk/window/utils": "sdk/window/utils"
},
"sectionName": "lib"
}
},
"metadata": {
"addon-sdk": {
"description": "Add-on development made easy.",
"keywords": [
"javascript",
"engine",
"addon",
"extension",
"xulrunner",
"firefox",
"browser"
],
"license": "MPL 2.0",
"name": "addon-sdk"
},
"mdmaug": {
"author": "Edvard Rejthar",
"description": "mdmaug csirt.cz detection tool",
"license": "MPL 2.0",
"main": "main",
"name": "mdmaug",
"version": "0.1"
}
},
"name": "mdmaug",
"parseable": false,
"preferencesBranch": "mdmaug@jetpack",
"sdkVersion": "1.17",
"staticArgs": {},
"verbose": false
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --><RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>mdmaug@jetpack</em:id>
<em:version>0.1</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
<!-- Firefox -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>26.0</em:minVersion>
<em:maxVersion>30.0</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>mdmaug</em:name>
<em:description>mdmaug csirt.cz detection tool</em:description>
<em:creator>Edvard Rejthar</em:creator>
</Description>
</RDF>
\ No newline at end of file
/*
* Prepisuje hackery vyuzivane funkce jako unescape nebo eval a bonzuje to vys.
* */
//window.opener
//document.location
//unescape
//*******
// Prepsat nebezpecne funkce
//*******
//squawk - bonznout
mdmaugSquawk = function(cmd, message) {
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': JSON.stringify({'cmd': cmd, 'message': message})}));
};
//mdmaugWrapper - man in the middle nebezpečných funkcí
mdmaugWrapper = function (fn) {
var swap = fn;
return function () {
mdmaugSquawk(swap.name, arguments);
return swap.apply(null, arguments);
};
};
unescape = mdmaugWrapper(unescape);
//Eval
//X kupodivu se mi nepodarilo funkci napsat jako jeden wrapper:
//X mdmaugDeepWrapper = function (fn) {var swap = fn;return function () {detail = JSON.stringify({'cmd': swap.name, 'message': arguments});document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': detail}));if (arguments[0].indexOf("arguments.callee") != -1) {arguments[0] = arguments[0].replace("arguments.callee", arguments.callee.caller.name);}return swap.apply(null, arguments);};};
//X eval2 = mdmaugDeepWrapper(eval);
//X funkci model z firebugu: mdmaugWrapper = function(fn){var swap = fn;return function(){console.log("start",swap.name);arguments[0]= arguments[0].replace("arguments.callee",arguments.callee.caller.name); return swap.apply(null, arguments);};function jooa(a) {console.log("RESULT",eval2(b));}jooa();
evalClone = unsafeWindow.eval;
eval = function (cmd) {
mdmaugSquawk("eval", cmd);
if (arguments.length > 0) {
if (arguments[0].indexOf("arguments.callee") != -1) {
arguments[0] = arguments[0].replace("arguments.callee", arguments.callee.caller.name);//"0"); // arguments.callee.caller
}
}
return evalClone(cmd);
};
document.write = function(str) {
mdmaugSquawk("document.write", str);
document.getElementsByTagName("html")[0].innerHTML= str;//simuluje chovani
};
// Upichnout funkce do stranky
exportFunction(unescape, unsafeWindow, {defineAs: "unescape"});
exportFunction(eval, unsafeWindow, {defineAs: "eval"});
exportFunction(evalClone, unsafeWindow, {defineAs: "evalClone"});
exportFunction(document.write, unsafeWindow, {defineAs: "document.write"});
unsafeWindow.addEventListener("DOMContentLoaded", function() {
unsafeWindow.addEventListener("DOMContentLoaded", function () {
alert('got cnn');
});
unsafeWindow.location.replace('http://cnn.com');
});
// Listener - prebira zpravy od nebezpecnych funkci a propaguje je vzhuru do main.js
var target = document.getElementsByTagName("html")[0];
target.addEventListener('mdmaug_spy', function (e) {
detail = JSON.parse(e.detail);
if (Object.keys(detail.message).length == 1 && detail.message["0"]) {
detail.message = detail.message["0"];
}
if (detail.message) {
self.postMessage({href: document.location.href, cmd: detail.cmd, message: detail.message});
}
}, false, true);
/*
* Prepisuje hackery vyuzivane funkce jako unescape nebo eval a bonzuje to vys.
* */
//window.opener
//document.location
//unescape
//*******
// Prepsat nebezpecne funkce
//*******
//mdmaugWrapper
mdmaugWrapper = function(fn){
var swap = fn;
return function(){
alert(swap.name);
alert(arguments);
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'message': swap.name}));
return swap.apply(null, arguments);
};
};
unescape = mdmaugWrapper(unescape);
mdmaugArgumentsWrapper = function(fn){
var swap = fn;
return function(){
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'cmd': swap.name, 'message': arguments}));
arguments[0]= arguments[0].replace("arguments.callee",arguments.callee.caller.name);
return swap.apply(null, arguments);
};
};
eval = mdmaugArgumentsWrapper(eval);
/*//unescape
unescapeClone = unsafeWindow.unescape;
unescape = function(str) { //XXX take decodeURI(Component)!!!!
return unescapeClone(str);
};*/
/*
evalClone = unsafeWindow.eval;
eval = function(cmd) {
//alert("eval " + cmd);
//document.getElementsByTagName("html")[0].setAttribute("mdmaug","eval: " + cmd); // + Math.floor(Math.random(10)*10000)
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': 'eval:' + cmd}));
if (arguments.length > 0) {
if(arguments[0].indexOf("arguments.callee") != -1) {
//vyskytuje se arguments.callee, ktereho neumime prohnat evalem
// Co vsechno muze utocnik s nim delat -> muze ho priradit: eval('a=arguments.callee; b')
// Muze ho returnovat: eval('arguments.callee')
// Kombinace.
// Zatim to delame tak, ze ho nahradime nulou (kdyby byl prirazovat) a vratime ho (je v arguments.callee.caller), ale zbytek cmd evaluujeme
// Tato metoda půjde rozšířit podle toho, jak se zjistí, že se viry chovají. Mohu si postupně psát takový vlastní eval.
arguments[0] = arguments[0].replace("arguments.callee",arguments.callee.caller.name);//"0"); // arguments.callee.caller
//evalClone(arguments[0]);
//return arguments.callee.caller;
}
}
//cmd = cmd.replace("arguments.callee",""); // arguments.callee.caller
return evalClone(cmd);
};
*/
exportFunction(unescape, unsafeWindow, {defineAs: "unescape"});
/*exportFunction(unescapeClone, unsafeWindow, {defineAs: "unescapeClone"});
exportFunction(eval, unsafeWindow, {defineAs: "eval"});
exportFunction(evalClone, unsafeWindow, {defineAs: "evalClone"});
*/
var target = document.getElementsByTagName("html")[0];
target.addEventListener('mdmaug_spy', function (e) {
//alert(e.detail);
console.error("prijem", e);
alert(e.pokus);
alert(e.message[0]);
//console.error("JOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO " + e.detail);
self.postMessage({href: document.location.href, cmd: e.cmd, detail: e.message});
}, false, true);
/*window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
observer = new MutationObserver(function(mutation) {
alert("mutation ");
alert(target.getAttribute("mdmaug"));
alert("END");
}),
// configuration of the observer:
config = {
attributes: true // this is to watch for attribute changes.
};
// pass in the element you wanna watch as well as the options
observer.observe(target, config);
// later, you can stop observing
// observer.disconnect();
*/
\ No newline at end of file
/*
* Prepisuje hackery vyuzivane funkce jako unescape nebo eval a bonzuje to vys.
* */
//window.opener
//document.location
//unescape
//*******
// Prepsat nebezpecne funkce
//*******
//mdmaugWrapper
mdmaugWrapper = function (fn) {
var swap = fn;
return function () {
alert(swap.name);
alert(arguments[0]);
detail = JSON.stringify({'cmd': swap.name, 'message': arguments});
//{'cmd': swap.name, 'message': arguments, 'pokus': "joo"} {'cmd': , 'message':}
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': detail}));
alert("arguments");
return swap.apply(null, arguments);
};
};
mdmaugDeepWrapper = function (fn) {
var swap = fn;
return function () {
detail = JSON.stringify({'cmd': swap.name, 'message': arguments});
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': detail}));
args = arguments;
alert("Args:");
if (args[0].indexOf("arguments.callee") != -1) {
args[0] = args[0].replace("arguments.callee", arguments.callee.caller.name);
}
alert(args[0]());
alert(swap.apply(null, args));
alert(args[0]);
return swap.apply(null, args);
};
};
eval = mdmaugDeepWrapper(eval);
unescape = mdmaugWrapper(unescape);
/*//unescape
unescapeClone = unsafeWindow.unescape;
unescape = function(str) { //XXX take decodeURI(Component)!!!!
return unescapeClone(str);
};*/
/*
evalClone = unsafeWindow.eval;
eval = function(cmd) {
//alert("eval " + cmd);
//document.getElementsByTagName("html")[0].setAttribute("mdmaug","eval: " + cmd); // + Math.floor(Math.random(10)*10000)
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': 'eval:' + cmd}));
if (arguments.length > 0) {
if(arguments[0].indexOf("arguments.callee") != -1) {
//vyskytuje se arguments.callee, ktereho neumime prohnat evalem
// Co vsechno muze utocnik s nim delat -> muze ho priradit: eval('a=arguments.callee; b')
// Muze ho returnovat: eval('arguments.callee')
// Kombinace.
// Zatim to delame tak, ze ho nahradime nulou (kdyby byl prirazovat) a vratime ho (je v arguments.callee.caller), ale zbytek cmd evaluujeme
// Tato metoda půjde rozšířit podle toho, jak se zjistí, že se viry chovají. Mohu si postupně psát takový vlastní eval.
arguments[0] = arguments[0].replace("arguments.callee",arguments.callee.caller.name);//"0"); // arguments.callee.caller
//evalClone(arguments[0]);
//return arguments.callee.caller;
}
}
//cmd = cmd.replace("arguments.callee",""); // arguments.callee.caller
return evalClone(cmd);
};
*/
exportFunction(unescape, unsafeWindow, {defineAs: "unescape"});
//exportFunction(unescapeClone, unsafeWindow, {defineAs: "unescapeClone"});
exportFunction(eval, unsafeWindow, {defineAs: "eval"});
// exportFunction(evalClone, unsafeWindow, {defineAs: "evalClone"});
var target = document.getElementsByTagName("html")[0];
target.addEventListener('mdmaug_spy', function (e) {
detail = JSON.parse(e.detail);
if (Object.keys(detail.message).length == 1 && detail.message["0"]) {
detail.message = detail.message["0"];
}
if (detail.message) {
self.postMessage({href: document.location.href, cmd: detail.cmd, message: detail.message});
}
}, false, true);
/*
* Prepisuje hackery vyuzivane funkce jako unescape nebo eval a bonzuje to vys.
* */
//window.opener
//document.location
//unescape
unescapeClone = unsafeWindow.unescape;
unescape = function(str) { //XXX take decodeURI(Component)!!!!
document.getElementsByTagName("html")[0].dispatchEvent(new CustomEvent("mdmaug_spy", {'detail': 'unescape:' + str}));
return unescapeClone(str);
};
exportFunction(unescape, unsafeWindow, {defineAs: "unescape"});
exportFunction(unescapeClone, unsafeWindow, {defineAs: "unescapeClone"});
exportFunction(eval, unsafeWindow, {defineAs: "eval"});
exportFunction(evalClone, unsafeWindow, {defineAs: "evalClone"});
var target = document.getElementsByTagName("html")[0];
target.addEventListener('mdmaug_spy', function (e) {
//alert(e.detail);
//console.error("JOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO " + e.detail);
self.postMessage({href: document.location.href,detail: e.detail});
}, false);
/*window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
observer = new MutationObserver(function(mutation) {
alert("mutation ");
alert(target.getAttribute("mdmaug"));
alert("END");
}),
// configuration of the observer:
config = {
attributes: true // this is to watch for attribute changes.
};
// pass in the element you wanna watch as well as the options
observer.observe(target, config);
// later, you can stop observing
// observer.disconnect();
*/
\ No newline at end of file
{"name": "firefox_mdmaug_writer", "description": "Firefox disk writer", "path": "/opt/mdmaug/mdmaug/bin/firefox_mdmaug_writer.py", "type": "stdio", "allowed_extensions": [ "mdmaug@csirt.cz" ] }
......@@ -19,7 +19,7 @@ cd $DIR
# mariadb setup
systemctl start mariadb.service
mysql -u root < mdmaug-installation.sql # populate db
mysql -uroot -e "CREATE USER 'mdmaug'@'localhost' IDENTIFIED BY 'fidFDSs676'; GRANT ALL PRIVILEGES ON mdmaug. * TO 'mdmaug'@'localhost';" # new user
mysql -uroot -e "CREATE USER \"mdmaug\"@\"localhost\" IDENTIFIED BY \"fidFDSs676\"; GRANT ALL PRIVILEGES ON mdmaug. * TO \"mdmaug\"@\"localhost\";" # new user
# adding user the server will be run under
useradd -m -d $DESTINATION mdmaug
......@@ -44,8 +44,9 @@ done
# adopt all files to the new user
chown mdmaug:mdmaug -R $DESTINATION
# make the new user able to use the display (needed on Ubuntu 17.10 at least)
# make the new user able to use the display (needed on Ubuntu 17.10 at least; after every restart :( not sure what to do)
xhost +local:mdmaug
# Writer from Firefox to the disk
echo "{\"name\": \"firefox_mdmaug_writer\", \"description\": \"Firefox disk writer\", \"path\": \"$DESTINATION/mdmaug/bin/firefox_mdmaug_writer.py\", \"type\": \"stdio\", \"allowed_extensions\": [ \"mdmaug@csirt.cz\" ] }" > $DESTINATION/.mozilla/native-messaging-hosts/firefox_mdmaug_writer.json
......@@ -20,6 +20,8 @@ Scans a website for a sign of a parasite hosts or commands.
* You may put ```03 1,7,13,19 * * * ~/mdmaug-launch``` in ```crontab -e``` of user mdmaug.
* We are using Python3.6+
### Troubleshooting
* Analysis stopped working after restart? Maybe you need to launch `xhost +local:mdmaug` command from a common user shell after every system restart :( I'm not sure.
## What is done to Firefox profiles?
We want no block nor safebrowsing warning. If you created the profiles manually, you'd use ```firefox -P```, the profiles names being: 0,1...
......
# This file was created by https://github.com/mozilla/web-ext
# Your auto-generated extension ID for addons.mozilla.org is:
mdmaug@csirt.cz
\ No newline at end of file
# MDMaug extension
How to build a new version of this? Go to the extension folder first.
Test it:
`web-ext run --bc --verbose -u http://localhost/redirect/http://example.com`
Sign it:
1. Change version in `manifest.json`
2. `web-ext sign --api-key <from addons.mozilla.org> --api-secret <the same>`
3. Newly generated file rename to `mdmaug@csirt.cz.xpi`
4. Move it to `.mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/`
// *****
// Mdmaug extension
// *****
console.log("Mdmaug extension - background page starts");
var firefox_mdmaug_writer = browser.runtime.connectNative("firefox_mdmaug_writer");// connects with firefoxwriter.py
var spyFiles = []; // list of spy files (file-exists check is not recomended by Mozilla)
browser.runtime.onMessage.addListener(function (message) {
// Screenshot saver
if (message.screenshot) {
append_to_file("screenshot.base64", message.screenshot);
browser.windows.getCurrent().then((windowInfo) => {
// quit browser
browser.windows.remove(windowInfo.id);
});
return;
}
// Spy file listener
var file = url2filename(message.href, "spy");
var contents = message.cmd + ": " + JSON.stringify(message.message) + "\n\n\n";
if (spyFiles.indexOf(file) === -1) {
spyFiles.push(file);// file will be created
var contents = message.href + " spy" + "\n" + contents; // pouze na 1. radek souboru patri puvodni url
}
append_to_file(file, contents);
console.log("Appenden spyfile", file);
});
/**
* traffic listener
*/
let trafficBlacklist = ["http://www.google.com/adsense/", "https://fbstatic-a.akamaihd.net/rsrc.php", "http://clients1.google.com/ocsp", "https://safebrowsing-cache.google.com/safebrowsing/", "https://safebrowsing.google.com/safebrowsing/", "https://tiles.services.mozilla.com/", "http://localhost/redirect/"];
browser.webRequest.onBeforeRequest.addListener(
function (details) {
// log resources that we want
console.log("On before event now!", details.url);
if (startsWithArray(details.url, trafficBlacklist)) { // we ignore EX. safebrowsing which is loaded on every page
return;
}
//console.log(details);
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let header = details.url + " " + details.type + "\n";
let filename = url2filename(details.url, "tmp");
append_to_file(filename, header);
filter.ondata = event => {
let data = decoder.decode(event.data, {stream: true});
//console.log("event", event, data);
append_to_file(filename, data);
filter.write(event.data);
};
filter.onstop = event => {
filter.disconnect();
};
return {};
},
{urls: ["<all_urls>"], types: ["beacon", "csp_report", "main_frame", "object_subrequest", "script", "sub_frame", "web_manifest", "websocket", "xbl", "xml_dtd", "xmlhttprequest", "xslt", "other"]},
["blocking"] // "requestBody"
);
/**
* startsWithArray
*/
function startsWithArray(value, values) {
for (var i = 0; i < values.length; i++) {//blacklist veleznamych domen
if (value.startsWith(values[i])) {
return true;
}
}
return false;
}
/**
* Returns nice filename from any url url2filename
*/
function url2filename(url, extension = "tmp") {
return url.replace(/[^a-z0-9]/gi, '-').replace(/-+/, '-').substring(0, 50).toLowerCase() + "." + extension
}
/**
* Log to file
* @param {string} filename
* @param {string} text
*/
function append_to_file(filename, text) {
console.log("Appending", filename);
firefox_mdmaug_writer.postMessage({"filename": filename, "text": text});
}
\ No newline at end of file
{
"description": "MDMaug scanner",
"manifest_version": 2,
"name": "MDMaug",
"version": "1.0.0rc1",
"homepage_url": "https://gitlab.labs.nic.cz/csirt/mdmaug/",
"icons": {
"48": "icons/cznic.png"
},
"applications": {
"gecko": {
"id": "mdmaug@csirt.cz"
}
},
"background": {
"scripts": [
"main.js"
]
},
"permissions": [
"activeTab",
"tabs",
"nativeMessaging",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"run_at": "document_start",
"js": [
"spy.js"
]
}
]
}
/*******
* Overwrites commonly abused functions, such as unescape or eval and denunciates this up.
* */
//window.opener
//document.location
//unescape
if (window.location.href.indexOf("http://localhost/redirect/") === 0) {
// kdyz zacina na "localhost/redirect/", je to jen presmerovani
// Protoze se prvni nacitana stranka zacne nacitat rychleji , nez tento addon, prvni request na root neprojde mym snifferem.
// (Nedelo se to vzdy, jen casto (!). Zřejmě vnitřní procesy FF, nějaký heartbeat.)
//Tento blok kodu se v 'tabs.on(ready)' obsas nespustil (!). Davam ho mimo
window.location = window.location.href.substr(26);
}
/**
* Functions that squawks the information up to the background page.
* @param {type} cmd Function name.
* @param {type} message Parameter of the rogue function.
* @returns {undefined}
*/
var mdmaugSquawk = function (cmd, message) {