diff options
Diffstat (limited to 'rules')
-rw-r--r-- | rules/misc.lua | 2 | ||||
-rw-r--r-- | rules/regexp/headers.lua | 18 | ||||
-rw-r--r-- | rules/regexp/misc.lua | 88 |
3 files changed, 102 insertions, 6 deletions
diff --git a/rules/misc.lua b/rules/misc.lua index 03aa5a3a9..a01b8ecd1 100644 --- a/rules/misc.lua +++ b/rules/misc.lua @@ -457,7 +457,7 @@ local aliases_id = rspamd_config:register_symbol{ local addr = task:get_from(type)[1] local na,tags = rspamd_lua_utils.remove_email_aliases(addr) if na then - task:set_from(type, addr) + task:set_from(type, addr, 'alias') task:insert_result('TAGGED_FROM', 1.0, fun.totable( fun.filter(function(t) return t and #t > 0 end, tags))) end diff --git a/rules/regexp/headers.lua b/rules/regexp/headers.lua index 7abf52bb0..5ee848018 100644 --- a/rules/regexp/headers.lua +++ b/rules/regexp/headers.lua @@ -464,12 +464,13 @@ reconf['FORGED_MUA_OPERA_MSGID'] = { group = 'mua' } --- Detect forged Mozilla Mail/Thunderbird/Seamonkey headers +-- Detect forged Mozilla Mail/Thunderbird/Seamonkey/Postbox headers -- Mozilla based X-Mailer local user_agent_mozilla5 = 'User-Agent=/^\\s*Mozilla\\/5\\.0/H' local user_agent_thunderbird = 'User-Agent=/^\\s*(Thunderbird|Mozilla Thunderbird|Mozilla\\/.*Gecko\\/.*(Thunderbird|Icedove)\\/)/H' local user_agent_seamonkey = 'User-Agent=/^\\s*Mozilla\\/5\\.0\\s.+\\sSeaMonkey\\/\\d+\\.\\d+/H' -local user_agent_mozilla = string.format('(%s) & !(%s) & !(%s)', user_agent_mozilla5, user_agent_thunderbird, user_agent_seamonkey) +local user_agent_postbox = [[User-Agent=/^\s*Mozilla\/5\.0\s\([^)]+\)\sGecko\/\d+\sPostboxApp\/\d+(?:\.\d+){2,3}$/H]] +local user_agent_mozilla = string.format('(%s) & !(%s) & !(%s) & !(%s)', user_agent_mozilla5, user_agent_thunderbird, user_agent_seamonkey, user_agent_postbox) -- Mozilla based common Message-ID template local mozilla_msgid_common = 'Message-ID=/^\\s*<[\\dA-F]{8}\\.\\d{1,7}\\@([^>\\.]+\\.)+[^>\\.]+>$/H' local mozilla_msgid_common_sec = 'Message-ID=/^\\s*<[\\da-f]{8}-([\\da-f]{4}-){3}[\\da-f]{12}\\@([^>\\.]+\\.)+[^>\\.]+>$/H' @@ -514,6 +515,19 @@ reconf['FORGED_MUA_SEAMONKEY_MSGID_UNKNOWN'] = { description = 'Forged mail pretending to be from Mozilla Seamonkey but has forged Message-ID', group = 'mua' } +-- Summary rule for forged Postbox Message-ID header +reconf['FORGED_MUA_POSTBOX_MSGID'] = { + re = string.format('(%s) & (%s) & !(%s) & !(%s)', user_agent_postbox, mozilla_msgid_common, mozilla_msgid, unusable_msgid), + score = 4.0, + description = 'Forged mail pretending to be from Postbox but has forged Message-ID', + group = 'mua' +} +reconf['FORGED_MUA_POSTBOX_MSGID_UNKNOWN'] = { + re = string.format('(%s) & !((%s) | (%s)) & !(%s) & !(%s)', user_agent_postbox, mozilla_msgid_common, mozilla_msgid_common_sec, mozilla_msgid, unusable_msgid), + score = 2.5, + description = 'Forged mail pretending to be from Postbox but has forged Message-ID', + group = 'mua' +} -- Message id validity diff --git a/rules/regexp/misc.lua b/rules/regexp/misc.lua index 642a02e21..ece856c96 100644 --- a/rules/regexp/misc.lua +++ b/rules/regexp/misc.lua @@ -65,14 +65,15 @@ local my_victim = [[/(?:victim|prey)/{words}]] local your_webcam = [[/webcam/{words}]] local your_onan = [[/(?:mast[ur]{2}bati(?:on|ng)|onanism|solitary)/{words}]] local password_in_words = [[/^pass(?:(?:word)|(?:phrase))$/i{words}]] -local btc_wallet_address = [[/^[13][0-9a-zA-Z]{25,34}$/{words}]] +local btc_wallet_address = [[/^[13][1-9A-Za-z]{25,34}$/]] local wallet_word = [[/^wallet$/{words}]] local broken_unicode = [[has_flag(bad_unicode)]] +local list_unsub = [[header_exists(List-Unsubscribe)]] reconf['LEAKED_PASSWORD_SCAM'] = { - re = string.format('%s & (%s | %s | %s | %s | %s | %s | lua:check_data_images)', + re = string.format('%s{words} & (%s | %s | %s | %s | %s | %s | %s | lua:check_data_images)', btc_wallet_address, password_in_words, wallet_word, - my_victim, your_webcam, your_onan, broken_unicode), + my_victim, your_webcam, your_onan, broken_unicode, list_unsub), description = 'Contains password word and BTC wallet address', functions = { check_data_images = function(task) @@ -94,3 +95,84 @@ reconf['LEAKED_PASSWORD_SCAM'] = { score = 7.0, group = 'scams' } + +-- Special routine to validate bitcoin wallets +-- Prepare base58 alphabet +local fun = require "fun" +local off = 0 +local base58_dec = fun.tomap(fun.map( + function(c) + off = off + 1 + return c,(off - 1) + end, + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")) + +local id = rspamd_config:register_symbol{ + name = 'LEAKED_PASSWORD_SCAM_VALIDATED', + callback = function(task) + local rspamd_re = require "rspamd_regexp" + local hash = require "rspamd_cryptobox_hash" + + if task:has_symbol('LEAKED_PASSWORD_SCAM') then + -- Perform BTC wallet check (quite expensive) + local wallet_re = rspamd_re.create_cached(btc_wallet_address) + local seen_valid = false + for _,tp in ipairs(task:get_text_parts()) do + + local words = tp:get_words('raw') or {} + + for _,word in ipairs(words) do + if wallet_re:match(word) then + -- We have something that looks like a BTC address + local bytes = {} + for i=1,25 do bytes[i] = 0 end + -- Base58 decode loop + fun.each(function(ch) + local acc = base58_dec[ch] or 0 + for i=25,1,-1 do + acc = acc + (58 * bytes[i]); + bytes[i] = acc % 256 + acc = math.floor(acc / 256); + end + end, word) + -- Now create a validation tag + local sha256 = hash.create_specific('sha256') + for i=1,21 do + sha256:update(string.char(bytes[i])) + end + sha256 = hash.create_specific('sha256', sha256:bin()):bin() + + -- Compare tags + local valid = true + for i=1,4 do + if string.sub(sha256, i, i) ~= string.char(bytes[21 + i]) then + valid = false + end + end + + if valid then + task:insert_result('LEAKED_PASSWORD_SCAM_VALIDATED', 1.0, word) + seen_valid = true + end + end + end + end + + if not seen_valid then + task:insert_result('LEAKED_PASSWORD_SCAM_INVALID', 1.0) + end + end + end, + score = 0.0, + group = 'scams' +} + +rspamd_config:register_symbol{ + type = 'virtual', + name = 'LEAKED_PASSWORD_SCAM_INVALID', + parent = id, + score = 0.0, +} + +rspamd_config:register_dependency('LEAKED_PASSWORD_SCAM_VALIDATED', + 'LEAKED_PASSWORD_SCAM')
\ No newline at end of file |