Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved detection and protection against business email compromise (BEC) such as CEO fraud #1269

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 97 additions & 1 deletion modules/imap/handler_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,21 @@ public function process() {
$msg['server_id'] = $form['imap_server_id'];
$msg['server_name'] = $details['name'];
$msg['folder'] = $form['folder'];
$msgs[] = $msg;
$uid = $msg['uid'];
$part = true;
$max = 87;
$msg_struct = $imap->get_message_structure($uid);
$struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $part));
$msg_struct_current = array_shift($struct);
$msg_text = $imap->get_message_content($uid, $part, $max, $msg_struct_current);
// remove line 858 to 863 when https://github.com/cypht-org/cypht/pull/1241 is merged

$isValid = $this->validationMessage($msg['to'], $msg['subject'], $msg_text, $imap, $this->cache, $form['imap_server_id']);
if ($isValid) {
$msgs[] = $msg;
} else {
$msgs = [];
}
}
if ($imap->selected_mailbox) {
$imap->selected_mailbox['detail']['exists'] = $total;
Expand All @@ -868,6 +882,72 @@ public function process() {
$this->out('do_not_flag_as_read_on_open', $this->user_config->get('unread_on_open_setting', false));
}
}
public function validationMessage($email, $subject, $msg, $imap, $cache, $imap_server_id) {
// 1. Check Suspicious Terms or Requests
$suspiciousTerms = explode(",", $this->user_config->get("ceo_suspicious_terms_setting"));
if ($this->detectSuspiciousTerms($msg, $suspiciousTerms) || $this->detectSuspiciousTerms($subject, $suspiciousTerms)) {
// 2. check ceo_rate_limit
$amount = $this->extractAmountFromEmail($msg);
$amountLimit = $this->user_config->get("ceo_rate_limit_setting");
if ($amount > $amountLimit) {
// 3. Check Sender's Email Address
$folder = "Suspicious emails";
if (!count($imap->get_mailbox_status($folder))) {
$imap->create_mailbox($folder);
}
$server_id = $imap_server_id ."_". bin2hex($folder);

if ($this->user_config->get("ceo_use_trusted_contact_setting")) {
$contacts = $this->get('contact_store');
$contact_list = $contacts->getAll();
$existingEmails = array_map(function($c){
return $c->value('email_address');
},$contact_list);
if (!$this->isValidateAddrEmail(array_values($existingEmails), $email)) {
// 4. action to execute implement here
imap_move_same_server($server_id, "move", $cache, $folder);
}
} else {
// 4. action to execute implement here
imap_move_same_server($server_id, "move", $cache, $folder);
}
return false;
}
return true;
}
}
private function detectSuspiciousTerms($msg, $suspiciousTerms) {
foreach ($suspiciousTerms as $phrase) {
if (stripos($msg, $phrase) !== false) {
return true;
}
}

return false;
}
private function detectUnusualAmount($normalLimit, $amount) {
if ($amount > $normalLimit) {
return true;
}
return false;
}
private function isValidateAddrEmail($trustedDomain, $email) {
foreach ($trustedDomain as $e) {
if ($email === $e) {
return true;
}
}
return false;
}
private function extractAmountFromEmail($emailBody) {
$pattern = '/\b\d+(?:,\d+)?\.?\d*\s*(?:USD|dollars?|US\$?|EUR|euros?|€|JPY|yen|¥|GBP|pounds?|£|CAD|CAD\$|AUD|AUD\$)/i';

preg_match_all($pattern, $emailBody, $matches);

if (count($matches[0]) > 0) {
return $matches[0][0];
}
}
}

/**
Expand Down Expand Up @@ -2194,3 +2274,19 @@ function process_move_messages_in_screen_email_enabled_callback($val) { return $
process_site_setting('move_messages_in_screen_email', $this, 'process_move_messages_in_screen_email_enabled_callback', true, true);
}
}

/**
* Process setting_ceo_detection_fraud in the settings page
* @subpackage core/handler
*/
class Hm_Handler_process_setting_ceo_detection_fraud extends Hm_Handler_Module {
public function process() {
function process_ceo_use_trusted_contact_callback($val) { return $val; }
function process_ceo_suspicious_terms_callback($val) { return $val; }
function process_ceo_rate_limit_callback($val) { return $val; }

process_site_setting('ceo_use_trusted_contact', $this, 'process_ceo_use_trusted_contact_callback');
process_site_setting('ceo_suspicious_terms', $this, 'process_ceo_suspicious_terms_callback');
process_site_setting('ceo_rate_limit', $this, 'process_ceo_rate_limit_callback');
}
}
37 changes: 37 additions & 0 deletions modules/imap/output_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -1470,3 +1470,40 @@ protected function output() {
return $res;
}
}
class Hm_Output_setting_ceo_detection_fraud extends Hm_Output_Module {
protected function output() {
$settings = $this->get('user_settings', array());
$ceo_use_trusted_contact = "checked";
$ceo_suspicious_terms = "wire transfer, urgent, account details, payment instruction";
$ceo_rate_limit = "100";
if (array_key_exists('ceo_use_trusted_contact', $settings)) {
if ($settings['ceo_use_trusted_contact']) {
$ceo_use_trusted_contact = "checked";
} else {
$ceo_use_trusted_contact = "";
}
}

if (array_key_exists('ceo_suspicious_terms', $settings) && $settings['ceo_suspicious_terms']) {
if ($settings['ceo_suspicious_terms']) {
$ceo_suspicious_terms = $settings['ceo_suspicious_terms'];
}
}
if (array_key_exists('ceo_rate_limit', $settings) && $settings['ceo_rate_limit']) {
if ($settings['ceo_rate_limit']) {
$ceo_rate_limit = $settings['ceo_rate_limit'];
}
}

$res = '<tr class="general_setting"><td><label for="ceo_use_trusted_contact">'.
$this->trans('CEO fraud: Use Trusted Contacts as Valid emails').
'</label></td><td><input class="form-check-input" type="checkbox" role="switch" id="ceo_use_trusted_contact" name="ceo_use_trusted_contact" '. $ceo_use_trusted_contact .' ></td></tr>';
$res .= '<tr class="general_setting"><td><label for="ceo_suspicious_terms">'.
$this->trans('CEO fraud: Suspicious Phrases or Requests(separate by ",")').
'</label></td><td><textarea class="form-control form-control-sm w-auto" role="switch" id="ceo_suspicious_terms" name="ceo_suspicious_terms">'. $ceo_suspicious_terms .'</textarea></td></tr>';
$res .= '<tr class="general_setting"><td><label for="ceo_rate_limit">'.
$this->trans('CEO fraud: Rate-Limit or Monitor Unusual Requests').
'</label></td><td><input class="form-control form-control-sm w-auto" type="number" min="0" role="switch" id="ceo_rate_limit" name="ceo_rate_limit" value="'. $ceo_rate_limit .'" ></td></tr>';
return $res;
}
}
5 changes: 5 additions & 0 deletions modules/imap/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
add_handler('settings', 'process_auto_advance_email_setting', true, 'imap', 'date', 'after');
add_handler('settings', 'process_first_time_screen_emails_per_page_setting', true, 'imap', 'date', 'after');
add_handler('settings', 'process_setting_move_messages_in_screen_email', true, 'imap', 'process_first_time_screen_emails_per_page_setting', 'after');
add_handler('settings', 'process_setting_ceo_detection_fraud', true, 'imap', 'process_setting_move_messages_in_screen_email', 'after');
add_output('settings', 'imap_server_ids', true, 'imap', 'page_js', 'before');
add_output('settings', 'start_sent_settings', true, 'imap', 'end_settings_form', 'before');
add_output('settings', 'sent_since_setting', true, 'imap', 'start_sent_settings', 'after');
Expand All @@ -62,6 +63,7 @@
add_output('settings', 'imap_auto_advance_email', true, 'imap', 'imap_pagination_links', 'after');
add_output('settings', 'first_time_screen_emails_per_page_setting', true, 'imap', 'imap_auto_advance_email', 'after');
add_output('settings', 'setting_move_messages_in_screen_email', true, 'imap', 'first_time_screen_emails_per_page_setting', 'after');
add_output('settings', 'setting_ceo_detection_fraud', true, 'imap', 'default_sort_order_setting', 'after');

/* compose page data */
add_output('compose', 'imap_server_ids', true, 'imap', 'page_js', 'before');
Expand Down Expand Up @@ -438,5 +440,8 @@
'tag_id' => FILTER_DEFAULT,
'first_time_screen_emails' => FILTER_VALIDATE_INT,
'move_messages_in_screen_email' => FILTER_VALIDATE_BOOLEAN,
'ceo_use_trusted_contact' => FILTER_VALIDATE_BOOLEAN,
'ceo_suspicious_terms' => FILTER_DEFAULT,
'ceo_rate_limit' => FILTER_VALIDATE_INT,
)
);