Skip to content

ModSecurity 3.x inspectFile operator does not pass FILES_TMPNAMES parameter to lua engine #2204

Closed
@kadirerdogan

Description

@kadirerdogan

The problem occurs because current implementation (v3) of the inspectFile operator does not pass FILES_TMPNAMES parameter to lua engine.

bool InspectFile::evaluate(Transaction *transaction, const std::string &str) {
    if (m_isScript) {
        return m_lua.run(transaction); 
    } else {
    ...

This function should pass "str" parameter to lua engine as return m_lua.run(transaction,str);
And also there should be some changes in src/engine/lua.h and src/engine/lua.cc file accordingly. The fix should not effect other script calls like exec action

Modsecurity v2 does not hit this problem so i have used a similar method to fix the bug in v3. I am planning to make a pull request.

I have tested the fix for below rules with below lua scripts and it works as intended

SecRule FILES_TMPNAMES "@inspectFile /usr/local/nginx/scanfile.lua" "id:1001,phase:2,t:none,log,auditlog,deny"
  
SecRule REQUEST_METHOD "@streq POST" "id:1002,exec:/usr/local/nginx/luatest.lua"

luatest.lua:

function main()
        m.log(1,"modsec lua exec action test ");
end

scanfile.lua:

function fsize(filename)
   file = io.open(filename,"r")
   local current = file:seek()
   local size = file:seek("end")
   file:seek("set",current)
   file:close()
   return size
end

function main(filename)

        m.log(1,"Inspection for "..filename);

   -- Configure paths
   local clamdscan  = "/usr/bin/clamdscan"
   local clamscan  = "/usr/bin/clamscan"

   -- failoverOnClamdFailure: failover to clamscan if clamdscan report an error
   local failoverOnClamdFailure = true

   -- fail (and block) if clamdscan (and clamscan) fails
   local failOnError = false

   -- local var
   local agent = "clamdscan"

   -- Skip empty items because if clamd is not working and you
   -- use the clamscan agent an empty file can take about 12 secs 
   -- to be analyzed
   if fsize(filename) == 0 then
     m.log(1, "[scanav skipped, file " .. filename .." size is zero]")
     return nil
   end

   -- The system command we want to call with fdpass flag to 
   -- do not incur in a permission issue
   local cmd = clamdscan .. " --fdpass --stdout --no-summary"

   -- Run the command and get the output
   local f = io.popen(cmd .. " " .. filename .. " || true")
   local l = f:read("*a")
   f:close()

   -- Check the output for the FOUND or ERROR strings which indicate
   -- an issue we want to block access on
   local isVuln = string.find(l, "FOUND")
   local isError = string.find(l, "ERROR")
  -- If clamdscan fails and you want failover to the traditional clamscan...
   if isError and failoverOnClamdFailure then
     -- Try to use the clamscan program
     m.log(1, "[clamdscan fails (" .. l .. "), failover to clamscan]")
     agent = "clamscan"
     cmd = clamscan .. " --stdout --no-summary"
     f = io.popen(cmd .. " " .. filename .. " || true")
     l = f:read("*a")
     f:close()
     isVuln = string.find(l, "FOUND")
     isError = string.find(l, "ERROR")
   end

   if isVuln then
     m.log(1, "[" .. agent .. " scanner message: " .. l .. "]\n")
     return "Virus Detected"
   elseif isError and failOnError then
     -- is a error (not a virus) a failure event?
     m.log(1, "[" .. agent .. " scanner message: " .. l .. "]\n")
     return "Error Detected"
   else
     return nil
   end
end

virussample.txt

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

Metadata

Metadata

Assignees

Labels

3.xRelated to ModSecurity version 3.x

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions