Support #8534
openLua detect rule: args["buffer"] is always empty in match() - buffer content inaccessible
Description
In Suricata 8.0.0, when using a Lua script as a detect keyword (lua:buffer.lua) placed after a sticky buffer (e.g., base64_data;lua:buffer.lua;), the args table passed to match() is always empty. Setting needs["buffer"] = true in init() does not populate args["buffer"].
Looking at the source code (detect-lua.c), DetectLuaMatchBuffer() correctly pushes buffer data into the args table, but it appears to never be called. Only DetectLuaMatch() is invoked, which passes an empty table.
Steps to reproduce:
function init(args)
return {["buffer"] = true}
end
function match(args)
for k, v in pairs(args) do
print(k .. "=" .. type(v))
end
return 1
end
With rule: alert http any any -> any any (...; base64_data;lua:test.lua; ...)
Output: empty (no keys in args table).
Question: Is this a known limitation or a bug? Will a future version restore the ability for Lua detect scripts to access the current inspection buffer via args["buffer"], similar to older Suricata versions?
Currently the only workaround is to use suricata.http / suricata.packet libraries, which always return the full transaction/packet data regardless of buffer position.
PA Updated by Philippe Antoine 24 days ago
- Status changed from New to Feedback
I think this is because of base64_data which is getting obsolete
Could you instead try more modern transform from_base64 ?
Are you working on raw tcp stream ? Or on a http sticky buffer ?
JC Updated by jghs chha 23 days ago
Philippe Antoine wrote in #note-1:
I think this is because of
base64_datawhich is getting obsoleteCould you instead try more modern transform
from_base64?
Are you working on raw tcp stream ? Or on a http sticky buffer ?
yep! working both on raw tcp and http sticky buffer not possible, not just here with base64_data.
JC Updated by jghs chha 23 days ago · Edited
It would be even better if you could give me a buffer.lua script that works well in the HTTP sticky buffer area or TCP. Below is a roundabout strategy I wrote using AI analysis, but it is not perfect and will print all content instead of the specified buffer content.
local packet = require("suricata.packet")
local http = require("suricata.http")
function init(args)
local needs = {}
needs["packet"] = true
return needs
end
function setup()
end
function match(args)
local tx = http.get_tx()
if tx then
-- request
local req_line = tx:request_line()
if req_line then
print("Request line: " .. tostring(req_line))
end
local req_headers = tx:request_headers_raw()
if req_headers then
print("Request headers:\n" .. tostring(req_headers))
end
local req_body = tx:request_body()
if req_body then
for i, chunk in ipairs(req_body) do
print("Request body chunk[" .. i .. "]: " .. tostring(chunk))
end
end
-- response
local resp_line = tx:response_line()
if resp_line then
print("Response line: " .. tostring(resp_line))
end
local resp_headers = tx:response_headers_raw()
if resp_headers then
print("Response headers:\n" .. tostring(resp_headers))
end
local resp_body = tx:response_body()
if resp_body then
for i, chunk in ipairs(resp_body) do
print("Response body chunk[" .. i .. "]: " .. tostring(chunk))
end
end
end
-- TCP payload
local p = packet.get()
if p then
local payload = p:payload()
if payload and #payload > 0 then
print("TCP payload (" .. #payload .. " bytes): " .. payload)
end
end
return 1
end
PA Updated by Philippe Antoine 20 days ago · Edited
In Suricata 8.0, (unlike to 7 and before) the init function should not ask for the buffer anymore, see https://docs.suricata.io/en/suricata-8.0.4/rules/lua-detection.html
You should get it directly from the http lib or so
cc @Jason Ish