Funded by Emerging Threats, I’ve been working on giving the lua scripts access to flowvars.
Currently only “flowvars” are done, “flowints” will be next. Please review the code at:
https://github.com/inliniac/suricata/tree/dev-lua-flowvar
Pcre based flowvar capturing is done in a post-match fashion. If the rule containing the “capture” matches, the var is stored in the flow.
For lua scripting, this wasn’t what the rule writers wanted. In this case, the flowvars are stored in the flow regardless of a rule match.
The way a script can start using flowvars is by first registering which one it needs access to:
function init (args) local needs = {} needs["http.request_headers.raw"] = tostring(true) needs["flowvar"] = {"cnt"} return needs end
More than one can be registered, e.g.:
needs["flowvar"] = {"cnt", "somevar", "anothervar" }
The maximum is 15 per script. The order of the vars matters. As Suricata uses id’s internally, to use the vars you have to use id’s as well. The first registered var has id 0, 2nd 1 and so on:
function match(args) a = ScFlowvarGet(0); if a then print ("We have an A: " .. (a)) a = tostring(tonumber(a)+1) print ("A incremented to: " .. (a)) ScFlowvarSet(0, a, #a) else print "Init A to 1" a = tostring(1) ScFlowvarSet(0, a, #a) end print ("A is " .. (a)) if tonumber(a) == 23 then print "Match!" return 1 end return 0 end
You can also use a var:
function init (args) local needs = {} needs["http.request_headers.raw"] = tostring(true) needs["flowvar"] = {"blah", "cnt"} return needs end local var_cnt = 1 function match(args) a = ScFlowvarGet(var_cnt); if a then print ("We have an A: " .. (a)) a = tostring(tonumber(a)+1) print ("A incremented to: " .. (a)) ScFlowvarSet(var_cnt, a, #a) else print "Init A to 1" a = tostring(1) ScFlowvarSet(var_cnt, a, #a) end print ("A is " .. (a)) if tonumber(a) == 23 then print "Match!" return 1 end return 0 end
Flowvars are set at the end of the rule’s inspection, so after the script has run.
When multiple stores are done from the script and/or pcre, the last match will win. So if order matters, rule priority can be used to control inspection order.
Thoughts, comments, and code review highly welcomed at the oisf-devel list.
Pingback: Suricata Lua scripting flowint access | Inliniac
Pingback: More on Suricata lua flowints | Inliniac
If you could add a rule that would set the flowvar, and acctually work with the above luajit script, it would be great.
Just as an example, I cant access the ua flowvar set with this:
alert http any any -> any any (msg:”LUAJIT Set HTTP flowvar (ua)”; content:”User-Agent: “; pcre:”/(?P.*)\r\n/Ri”; luajit:test.lua; sid:1;)
test.lua:
—-8<—-
function init (args)
local needs = {}
needs["flowvar"] = {"ua"}
return needs
end
function match(args)
a = ScFlowvarGet(0);
local l = io.open("/tmp/luajit-test.log", "a")
if a then
l:write("We got flowvar ua: " .. (a) .. "\n")
return 1
else
l:write("We did not get any ua flowvar :(\n")
return 0
end
end
return 0
—-8<—-
This will always write that it did not get any ua flowvar 😦
So a working example of the whole stack would be great!