From 1b77c0daa61bddc975ec23386c97d502af0be462 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Fri, 2 May 2025 07:40:28 +0300 Subject: [PATCH] resources: simplify default script; document API better --- resources/default_script.lua | 217 +++++++++++++++++++++++++++++++++-- 1 file changed, 205 insertions(+), 12 deletions(-) diff --git a/resources/default_script.lua b/resources/default_script.lua index 90f0966..f2f51fd 100644 --- a/resources/default_script.lua +++ b/resources/default_script.lua @@ -1,17 +1,210 @@ -function generate_honeytoken(token) - local token_types = { "API_KEY", "AUTH_TOKEN", "SESSION_ID", "SECRET_KEY" } - local prefix = token_types[math.random(#token_types)] - local suffix = string.format("%08x", math.random(0xffffff)) - return prefix .. "_" .. token .. "_" .. suffix -end +--[[ +Eris Default Script +This script demonstrates how to use the Eris Lua API to customize +the tarpit's behavior, and will be loaded by default if no other +scripts are loaded. + +Available events: +- connection: When a new connection is established +- request: When a request is received +- response_gen: When generating a response +- response_chunk: Before sending each response chunk +- disconnection: When a connection is closed +- block_ip: When an IP is being considered for blocking +- startup: When the application starts +- shutdown: When the application is shutting down +- periodic: Called periodically + +API Functions: +- eris.debug(message): Log a debug message +- eris.info(message): Log an info message +- eris.warn(message): Log a warning message +- eris.error(message): Log an error message +- eris.set_state(key, value): Store persistent state +- eris.get_state(key): Retrieve persistent state +- eris.inc_counter(key, [amount]): Increment a counter +- eris.get_counter(key): Get a counter value +- eris.gen_token([prefix]): Generate a unique token +- eris.timestamp(): Get current Unix timestamp +--]] + +-- Called when the application starts +eris.on("startup", function(ctx) + eris.info("Initializing default script") + + -- Initialize counters + eris.inc_counter("total_connections", 0) + eris.inc_counter("total_responses", 0) + eris.inc_counter("blocked_ips", 0) + + -- Initialize banned keywords + eris.set_state("banned_keywords", "eval,exec,system,shell," + .. "\n" + .. "\n" + elseif ctx.path:find("phpunit") or ctx.path:find("eval") then + -- For PHP exploit attempts + -- Turns out you can just google "PHP error log" and search random online forums where people + -- dump their service logs in full. + enhanced_content = enhanced_content + .. "\nPHP Notice: Undefined variable: _SESSION in /var/www/html/includes/core.php on line 58\n" + .. "Warning: file_get_contents(): Filename cannot be empty in /var/www/html/vendor/autoload.php on line 23\n" + .. "Token: " + .. token + .. "\n" + elseif ctx.path:find("api") then + -- For API requests + local fake_api_key = + string.format("ak_%x%x%x", math.random(1000, 9999), math.random(1000, 9999), math.random(1000, 9999)) + + enhanced_content = enhanced_content + .. "{\n" + .. ' "status": "warning",\n' + .. ' "message": "Test API environment detected",\n' + .. ' "debug_token": "' + .. token + .. '",\n' + .. ' "api_key": "' + .. fake_api_key + .. '"\n' + .. "}\n" + else + -- For other requests + enhanced_content = enhanced_content + .. "\n" + .. "\n" + .. "\n" + end + + -- Track which honeytokens were sent to which IP + local honeytokens = eris.get_state("honeytokens") or "{}" + local ht_table = {} + + -- This is a simplistic approach - in a real script, you'd want to use + -- a proper JSON library to handle this correctly + if honeytokens ~= "{}" then + -- Simple parsing of the stored data + for ip, tok in honeytokens:gmatch('"([^"]+)":"([^"]+)"') do + ht_table[ip] = tok + end + end + + ht_table[ctx.ip] = token + + -- Convert back to a simple JSON-like string + local new_tokens = "{" + for ip, tok in pairs(ht_table) do + if new_tokens ~= "{" then + new_tokens = new_tokens .. "," + end + new_tokens = new_tokens .. '"' .. ip .. '":"' .. tok .. '"' + end + new_tokens = new_tokens .. "}" + + eris.set_state("honeytokens", new_tokens) + + return enhanced_content +end) + +-- Called before sending each chunk of a response +eris.on("response_chunk", function(ctx) + -- This can be used to alter individual chunks for more deceptive behavior + -- For example, to simulate a slow, unreliable server + + -- 5% chance of "corrupting" a chunk to confuse scanners + if math.random(1, 100) <= 5 then + local chunk = ctx.content + if #chunk > 10 then + local pos = math.random(1, #chunk - 5) + chunk = chunk:sub(1, pos) .. string.char(math.random(32, 126)) .. chunk:sub(pos + 2) + end + return chunk + end + + return ctx.content +end) + +-- Called when deciding whether to block an IP +eris.on("block_ip", function(ctx) + -- You can override the default blocking logic + + -- Check for potential attackers using specific patterns + local banned_keywords = eris.get_state("banned_keywords") or "" + local user_agent = ctx.user_agent or "" + + -- Check if user agent contains highly suspicious patterns + for keyword in banned_keywords:gmatch("[^,]+") do + if user_agent:lower():find(keyword:lower()) then + eris.info("Blocking IP " .. ctx.ip .. " due to suspicious user agent: " .. keyword) + eris.inc_counter("blocked_ips") + return true -- Force block + end + end + + -- For demonstration, we'll be more lenient with 10.x IPs + if ctx.ip:match("^10%.") then + -- Only block if they've hit us many times + return ctx.hit_count >= 5 + end + + -- Default to the system's threshold-based decision + return nil +end) + +-- The enhance_response is now legacy, and I never liked it anyway. Though let's add it here +-- for the sake of backwards compatibility. function enhance_response(text, response_type, path, token) - local result = text - local honeytoken = generate_honeytoken(token) + local enhanced = text - -- Add some fake sensitive data - result = result .. "\n" - result = result .. "\n
Server ID: " .. token .. "
" + -- Add token as a comment + if response_type == "php_exploit" then + enhanced = enhanced .. "\n/* Token: " .. token .. " */\n" + elseif response_type == "wordpress" then + enhanced = enhanced .. "\n\n" + elseif response_type == "api" then + enhanced = enhanced:gsub('"status": "[^"]+"', '"status": "warning"') + enhanced = enhanced:gsub('"message": "[^"]+"', '"message": "API token: ' .. token .. '"') + else + enhanced = enhanced .. "\n\n" + end - return result + return enhanced end