]]
local exports = {}
-local rspamd_logger = require "rspamd_logger"
local lua_util = require "lua_util"
--[[
exports.check_html_text_mismatch = function(task, fuzzy_results)
local html_matches = {}
local text_matches = {}
-
+
-- Separate HTML and text fuzzy matches
for _, res in ipairs(fuzzy_results or {}) do
if res.type == 'html' then
table.insert(text_matches, res)
end
end
-
+
-- Phishing scenario: high text match but low/no HTML match
if #text_matches > 0 and #html_matches == 0 then
local max_text_score = 0
max_text_score = res.score
end
end
-
+
-- High text match but no HTML match = suspicious
if max_text_score > 0.7 then
return max_text_score * 0.5, string.format(
max_text_score)
end
end
-
+
-- Inverse scenario: HTML match but no text match
-- (Could be template with varying content - less suspicious)
if #html_matches > 0 and #text_matches == 0 then
max_html_score = res.score
end
end
-
+
-- This is expected for newsletters/notifications
lua_util.debugm('fuzzy_html', task,
'HTML match (%.2f) without text match - likely template variation',
max_html_score)
end
-
+
return 0, nil
end
if not html_fuzzy_result then
return 0, nil
end
-
+
-- High HTML match = known template
if html_fuzzy_result.score > 0.8 then
-- Check if text is suspicious
html_fuzzy_result.score)
end
end
-
+
return 0, nil
end
This indicates possible template reuse for phishing.
]]
-local rspamd_logger = require "rspamd_logger"
local lua_util = require "lua_util"
local N = 'fuzzy_html_phishing'
local function check_fuzzy_mismatch(task)
local fuzzy_results = task:get_mempool():get_variable('fuzzy_result')
-
+
if not fuzzy_results then
return false
end
-
- -- Collect results by type
- local text_matches = {}
- local html_matches = {}
-
- for _, hash_result in ipairs(fuzzy_results) do
- local symbol = tostring(hash_result)
- -- Parse fuzzy result format: "flag:hash:prob:type"
- -- This is simplified - actual parsing depends on result format
-
- -- For now, check mempool variables set by fuzzy_insert_result
- -- We need to enhance fuzzy_check to expose result types
- end
-
+
-- Get fuzzy check symbols from task results
local fuzzy_symbols = task:get_symbols_all()
local has_text_fuzzy = false
local has_html_fuzzy = false
local text_score = 0
local html_score = 0
-
+
for _, sym in ipairs(fuzzy_symbols) do
if sym.name:match('FUZZY.*TEXT') or sym.name == 'R_FUZZY_HASH' then
has_text_fuzzy = true
html_score = math.max(html_score, sym.score or 0)
end
end
-
+
-- Scenario 1: Text matches legitimate but no HTML match
-- This could indicate phishing with copied text but fake HTML/CTA
if has_text_fuzzy and not has_html_fuzzy and text_score > 5.0 then
text_score)
return true
end
-
+
-- Scenario 2: HTML matches but text doesn't (less suspicious)
-- This is common for newsletters/notifications with varying content
if has_html_fuzzy and not has_text_fuzzy and html_score > 8.0 then
html_score)
-- Could add negative score or just log
end
-
+
return false
end
}
-- Register callback
-local id = rspamd_config:register_symbol{
+rspamd_config:register_symbol{
name = 'FUZZY_HTML_PHISHING_CHECK',
type = 'callback',
callback = check_fuzzy_mismatch,