resources: simplify default script; document API better
This commit is contained in:
parent
a4eedcbc26
commit
1b77c0daa6
1 changed files with 205 additions and 12 deletions
|
@ -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,<?php,/bin/bash")
|
||||
end)
|
||||
|
||||
-- Called for each new connection
|
||||
eris.on("connection", function(ctx)
|
||||
eris.inc_counter("total_connections")
|
||||
eris.debug("New connection from " .. ctx.ip)
|
||||
|
||||
-- You can reject connections by returning false
|
||||
-- This example checks a blocklist
|
||||
local blocklist = eris.get_state("manual_blocklist") or ""
|
||||
if blocklist:find(ctx.ip) then
|
||||
eris.info("Rejecting connection from manually blocked IP: " .. ctx.ip)
|
||||
return false
|
||||
end
|
||||
|
||||
return true -- accept the connection
|
||||
end)
|
||||
|
||||
-- Called when generating a response
|
||||
eris.on("response_gen", function(ctx)
|
||||
eris.inc_counter("total_responses")
|
||||
|
||||
-- Generate a unique traceable token for this request
|
||||
local token = eris.gen_token("ERIS-")
|
||||
|
||||
-- Add some believable but fake honeytokens based on the request path
|
||||
local enhanced_content = ctx.content
|
||||
|
||||
if ctx.path:find("wp%-") then
|
||||
-- For WordPress paths
|
||||
enhanced_content = enhanced_content
|
||||
.. "\n<!-- WordPress Debug: "
|
||||
.. token
|
||||
.. " -->"
|
||||
.. "\n<!-- WP_HOME: http://stop.crawlingmysite.com/wordpress -->"
|
||||
.. "\n<!-- DB_USER: wp_user_"
|
||||
.. math.random(1000, 9999)
|
||||
.. " -->"
|
||||
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<!-- Server: Apache/2.4.41 (Ubuntu) -->"
|
||||
.. "\n<!-- Debug-Token: "
|
||||
.. token
|
||||
.. " -->"
|
||||
.. "\n<!-- Environment: staging -->"
|
||||
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<!-- DEBUG: " .. honeytoken .. " -->"
|
||||
result = result .. "\n<div style='display:none'>Server ID: " .. token .. "</div>"
|
||||
-- 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<!-- WordPress Debug Token: " .. token .. " -->\n"
|
||||
elseif response_type == "api" then
|
||||
enhanced = enhanced:gsub('"status": "[^"]+"', '"status": "warning"')
|
||||
enhanced = enhanced:gsub('"message": "[^"]+"', '"message": "API token: ' .. token .. '"')
|
||||
else
|
||||
enhanced = enhanced .. "\n<!-- Debug token: " .. token .. " -->\n"
|
||||
end
|
||||
|
||||
return result
|
||||
return enhanced
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue