mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-11-20 02:57:12 +03:00
Fixed files overwriting in installer; added OWASP CRS.
This commit is contained in:
798
iis/ModSecurityIIS/owasp_crs/lua/advanced_filter_converter.lua
Normal file
798
iis/ModSecurityIIS/owasp_crs/lua/advanced_filter_converter.lua
Normal file
@@ -0,0 +1,798 @@
|
||||
#!/opt/local/bin/lua
|
||||
local rex = require "rex_pcre"
|
||||
local B = require "bit"
|
||||
|
||||
function main()
|
||||
|
||||
function dec2hex(nValue)
|
||||
if type(nValue) == "string" then
|
||||
nValue = String.ToNumber(nValue);
|
||||
end
|
||||
nHexVal = string.format("%X", nValue);
|
||||
sHexVal = nHexVal.."";
|
||||
return sHexVal;
|
||||
end
|
||||
|
||||
function hex2dec (arg)
|
||||
local dec = {}
|
||||
for str in string.gfind(arg, "%w%w") do
|
||||
local str = '0X'..str
|
||||
table.insert(dec, tonumber(str))
|
||||
end
|
||||
|
||||
return unpack(dec)
|
||||
end
|
||||
|
||||
function explode ( seperator, str )
|
||||
local pos, arr = 0, {}
|
||||
for st, sp in function() return string.find( str, seperator, pos, true ) end
|
||||
do
|
||||
table.insert( arr, string.sub( str, pos, st-1 ) );
|
||||
pos = sp + 1;
|
||||
end
|
||||
table.insert( arr, string.sub( str, pos ) );
|
||||
return arr
|
||||
end
|
||||
|
||||
|
||||
function oct2dec(octstr)
|
||||
local i, len, num;
|
||||
|
||||
num = 0;
|
||||
i = 0;
|
||||
octstr = string.reverse(octstr);
|
||||
len = string.len(octstr);
|
||||
|
||||
if (len > 11) then
|
||||
return 1;
|
||||
end
|
||||
|
||||
for str in string.gfind(octstr, "%w") do
|
||||
number = tonumber(str);
|
||||
if((number < 0) or (number > 7)) then
|
||||
num = 0;
|
||||
return 0;
|
||||
end
|
||||
|
||||
i = tonumber(i);
|
||||
num_shr = B.lshift(number ,(i*3));
|
||||
num = B.bor(num,num_shr);
|
||||
i = i + 1;
|
||||
end
|
||||
return num;
|
||||
end
|
||||
|
||||
|
||||
function str_split_unique(data)
|
||||
a = {}
|
||||
b = {}
|
||||
-- use table to eliminate duplicates
|
||||
for i=1,string.len(data) do
|
||||
v = string.sub(data,i,i)
|
||||
a[v] = v
|
||||
end
|
||||
-- insert into ordered array and sort
|
||||
for k,v in pairs(a) do
|
||||
table.insert(b,k)
|
||||
end
|
||||
table.sort(b)
|
||||
return b
|
||||
end
|
||||
|
||||
function str_split(data)
|
||||
a = {}
|
||||
for i=1,string.len(data) do
|
||||
a[i] = string.sub(data,i,i)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
-- character table string
|
||||
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
-- base64 decoding
|
||||
function base64decode(data)
|
||||
data = string.gsub(data, '[^'..b..'=]', '')
|
||||
return (data:gsub('.', function(x)
|
||||
if (x == '=') then return '' end
|
||||
local r,f='',(b:find(x)-1)
|
||||
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
|
||||
return r;
|
||||
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
|
||||
if (#x ~= 8) then return '' end
|
||||
local c=0
|
||||
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
|
||||
return string.char(c)
|
||||
end))
|
||||
end
|
||||
|
||||
function urldecode(s)
|
||||
return (string.gsub (string.gsub (s, "+", " "),
|
||||
"%%(%x%x)",
|
||||
function (str)
|
||||
return string.char (tonumber (str, 16))
|
||||
end ))
|
||||
end
|
||||
|
||||
function urlencode(s)
|
||||
return (string.gsub (s, "%W",
|
||||
function (str)
|
||||
return string.format ("%%%02X", string.byte (str))
|
||||
end ))
|
||||
end
|
||||
|
||||
function strip_tags(h)
|
||||
local newstr = rex.gsub(h, "<(\/?)(\\w+)[^\>]*>", "%2", nil, 0, 0);
|
||||
return newstr
|
||||
end
|
||||
|
||||
function hexdecode(s)
|
||||
s = string.gsub(s, "%%(%x%x)", function (h)
|
||||
return string.char(tonumber(h, 16))
|
||||
end)
|
||||
return s
|
||||
end
|
||||
|
||||
function sql_hexdecode(s)
|
||||
s = string.gsub(s, "(%x%x)", function (h)
|
||||
return string.char(tonumber(h, 16))
|
||||
end)
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
--[[ Retrieve all ARGS parameters from ModSec
|
||||
|
||||
urlDecodeUni, htmlEntityDecode and jsDecode can be used here with the initial
|
||||
extraction of data since they are able to decode any inline value vs.
|
||||
other transformation functions which will attempt to decode the entire
|
||||
string value. For those situations, we must create our own Lua functions
|
||||
]]
|
||||
|
||||
local args = {};
|
||||
args = m.getvars("ARGS", {"none"});
|
||||
|
||||
-- Only run checks if ARGS are present
|
||||
if (#args == "0") then
|
||||
m.log(4, "# of ARGS: " ..#args.. ".");
|
||||
return nil;
|
||||
end
|
||||
|
||||
|
||||
-- Place ARGS data into key/value pairs for inspection
|
||||
for k,v in pairs(args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
original_value = value;
|
||||
m.log(4, "Arg Name: " ..name.. " and Arg Value: " ..value.. ".");
|
||||
|
||||
--[[ Start Converter code ]]
|
||||
|
||||
--[[ Make sure the value to normalize and monitor doesn't contain
|
||||
possibilities for a regex DoS.]]
|
||||
-- remove obvious repetition patterns
|
||||
value = rex.gsub(value, "(?:(.{2,})\\1{32,})|(?:[\-+=|@\\s]{128,})", "x", nil, 0, 0);
|
||||
m.log(4, "Remove repetition patterns: " .. value .. "");
|
||||
|
||||
--[[ Check for comments and erases them if available ]]
|
||||
-- check for existing comments
|
||||
if rex.match(value, "(?ms:(?:\\<!\-|\-\->|\\/\\*|\\*\\/|\\/\\/\\W*\\w+\\s*$)|(?:\-\-[^\\-]*\-))", 1) then
|
||||
converted = rex.gsub(value, "(?ms:(?:(?:<!)(?:(?:\-\-(?:[^\\-]*(?:\-[^\\-]+)*)\-\-\\s*)*)(?:>))|(?:(?:\\/\\*\\/*[^\\/\\*]*)+\\*\\/)|(?:\-\-[^\\-]*\-))", ";", nil, 0, 0);
|
||||
value = (value .. "\n" .. converted);
|
||||
m.log(4, "Check for Existing Comments: " .. value .. "");
|
||||
end
|
||||
|
||||
-- make sure inline comments are detected and converted correctly
|
||||
value = rex.gsub(value, "(?m:(<\\w+)\\/+(\\w+=?))", "%1/%2", nil, 0, 0);
|
||||
m.log(4, "Remove Inline Comments1: " .. value .. "");
|
||||
value = rex.gsub(value, "(?m:[^\\\\:]\\/\\/(.*)$)", "/**/%1", nil, 0, 0);
|
||||
m.log(4, "Remove Inline Comments2: " .. value .. "");
|
||||
|
||||
--[[ Strip newlines ]]
|
||||
-- check for inline linebreaks
|
||||
value = rex.gsub(value, "\\\\(r|n|f|t|v)", ";", nil, 0, 0);
|
||||
m.log(4, "Check for inline linebreaks: " .. value .. "");
|
||||
-- replace replacement characters regular spaces
|
||||
value = string.gsub(value, "<EFBFBD>", ' ', nil, 0, 0);
|
||||
m.log(4, "Replace replacement chars: " .. value .. "");
|
||||
-- convert real linebreaks
|
||||
value = rex.gsub(value, "(?m:[\\r\\n\\f\\t\\v])", " ", nil, 0, 0);
|
||||
m.log(4, "Convert real linebreaks: " .. value .. "");
|
||||
|
||||
--[[ Checks for common charcode pattern and decodes them ]]
|
||||
function convertFromJSCharcode(value)
|
||||
|
||||
local matches, matches2, matches3;
|
||||
local changed = 0;
|
||||
local sum = 0;
|
||||
local chr = 0;
|
||||
local converted = "";
|
||||
local tmp_value = value;
|
||||
|
||||
-- check if value matches typical charCode pattern
|
||||
|
||||
for line in rex.gmatch(tmp_value, "(?ms:(?:[\\d+-=\/\* ]+(?:\\s?,\\s?[\\d+-=\/\* ]+)){4,})", 0, 0)
|
||||
do
|
||||
if(matches ~= nil) then
|
||||
matches = matches .. "," .. line;
|
||||
else
|
||||
matches = line;
|
||||
end
|
||||
end
|
||||
|
||||
if(matches ~= nil) then
|
||||
|
||||
matches = rex.gsub(matches,"(\\s)", "");
|
||||
matches = rex.gsub(matches,"(\\w+=)", "");
|
||||
|
||||
str = explode(",",matches);
|
||||
|
||||
for i=1, table.getn(str) do
|
||||
|
||||
chr = str[i];
|
||||
|
||||
if(string.len(str[i]) > 0) then
|
||||
|
||||
chr = rex.gsub(chr,"(?s:\\W0)", "");
|
||||
|
||||
if(chr ~= nil) then
|
||||
|
||||
for line2 in rex.gmatch(chr, "(\\d*[+-\/\* ]\\d+)",0, 0)
|
||||
do
|
||||
if(matches2 ~= nil) then
|
||||
matches2 = matches2 .. "" .. line2;
|
||||
else
|
||||
matches2 = line2;
|
||||
end
|
||||
end
|
||||
|
||||
if( matches2 ~= nil )then
|
||||
for line3 in rex.split(matches2, "((\\W?\\d+))",0, 0)
|
||||
do
|
||||
if(line ~= nil) then
|
||||
changed = 1;
|
||||
sum = sum + tonumber(line3);
|
||||
end
|
||||
|
||||
if(matches3 ~= nil) then
|
||||
matches3 = matches3 .. line3;
|
||||
else
|
||||
matches3 = line3;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(changed == 1) then
|
||||
if(sum >= 20) then
|
||||
if(sum <= 127) then
|
||||
converted = converted .. string.char(sum);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(changed == 0) then
|
||||
local num = 0;
|
||||
if(string.len(chr) > 0) then
|
||||
num = tonumber(chr);
|
||||
end
|
||||
converted = converted .. string.char(num);
|
||||
end
|
||||
end
|
||||
|
||||
value = tmp_value .. "\n" .. converted;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function convertFromJSCharcode_hex(value)
|
||||
-- check for hexadecimal charcode pattern
|
||||
local matches_hex = "";
|
||||
local converted = "";
|
||||
local tmp_value = value;
|
||||
|
||||
for line in rex.gmatch(tmp_value, "(?ims:(?:(?:[\\\\]+\\w+\\s*){8,}))", 0, 0)
|
||||
do
|
||||
if(matches_hex ~= nil) then
|
||||
matches_hex = matches_hex .. "," .. line;
|
||||
else
|
||||
matches_hex = line;
|
||||
end
|
||||
end
|
||||
|
||||
if(matches_hex ~= nil) then
|
||||
|
||||
matches_hex = rex.gsub(matches_hex,"([ux])", "");
|
||||
|
||||
converted = "";
|
||||
|
||||
str = explode(",",matches_hex);
|
||||
|
||||
for i=1, table.getn(str) do
|
||||
|
||||
chr = str[i];
|
||||
|
||||
if(tonumber(chr) ~= 0) then
|
||||
converted = converted .. string.char(hex2dec(chr));
|
||||
end
|
||||
end
|
||||
|
||||
value = tmp_value .. "\n" .. converted;
|
||||
end
|
||||
|
||||
print(value);
|
||||
return value;
|
||||
end
|
||||
|
||||
function convertFromJSCharcode_oct(value)
|
||||
|
||||
local matches_oct = "";
|
||||
local converted_oct = "";
|
||||
local tmp_value = value;
|
||||
|
||||
-- check for octal charcode pattern
|
||||
|
||||
for line in rex.gmatch(tmp_value, "(?ims:(?:(?:[\\\\]+\\d+){8,}))", 0, 0)
|
||||
do
|
||||
if(matches_oct ~= nil) then
|
||||
matches_oct = matches_oct .. "," .. line;
|
||||
else
|
||||
matches_oct = line;
|
||||
end
|
||||
end
|
||||
|
||||
if(matches_oct ~= nil) then
|
||||
|
||||
matches_oct = rex.gsub(matches_oct,"(\\s)", "");
|
||||
|
||||
str = explode(",",matches_oct);
|
||||
|
||||
print(str);
|
||||
|
||||
for i=1, table.getn(str) do
|
||||
|
||||
chr = str[i];
|
||||
|
||||
if (tonumber(str[i]) ~= 0) then
|
||||
|
||||
n = oct2dec(chr);
|
||||
|
||||
n = dec2hex(n);
|
||||
|
||||
if(n ~= 0)then
|
||||
str2 = string.char(hex2dec(n));
|
||||
|
||||
if(converted_oct ~= nil) then
|
||||
converted_oct = converted_oct .. str2;
|
||||
else
|
||||
converted_oct = str2;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(converted_oct ~= nil) then
|
||||
value = tmp_value .. "\n" .. converted_oct;
|
||||
else
|
||||
value = tmp_value;
|
||||
end
|
||||
end
|
||||
|
||||
print(value);
|
||||
|
||||
return value;
|
||||
end
|
||||
|
||||
convertFromJSCharcode(value);
|
||||
m.log(4, "convertFromJSCharcode: " .. value .. "");
|
||||
convertFromJSCharcode_hex(value);
|
||||
m.log(4, "convertFromJSCharcode_hex: " .. value .. "");
|
||||
convertFromJSCharcode_oct(value);
|
||||
m.log(4, "convertFromJSCharcode_oct: " .. value .. "");
|
||||
|
||||
--[[ Eliminate JS regex modifiers ]]
|
||||
value = rex.gsub(value, "\/[gim]+", "\/", nil, 0, 0);
|
||||
m.log(4, "Eliminate JS regex modifiers: " .. value .. ".");
|
||||
|
||||
--[[ Converts from hex/dec entities ]]
|
||||
|
||||
-- deal with double encoded payload
|
||||
function htmlEntityDecode(value)
|
||||
value = rex.gsub(value, "&", "&", nil, 0, 0);
|
||||
local result;
|
||||
local tmp_value = value;
|
||||
|
||||
for line in rex.gmatch(tmp_value, "(?ms:&#x?([\\w]{2}\\d?);?)", 0, 0)
|
||||
do
|
||||
if(line ~= nil) then
|
||||
if(result ~= nil) then
|
||||
result = result .. line;
|
||||
else
|
||||
result = line;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if(result ~= nil) then
|
||||
result = sql_hexdecode(result);
|
||||
value = tmp_value .. "\n" .. result;
|
||||
result = rex.gsub(result, ";;", ";", nil, 0, 0);
|
||||
else
|
||||
value = tmp_value;
|
||||
end
|
||||
|
||||
|
||||
print(result);
|
||||
|
||||
return result;
|
||||
|
||||
end
|
||||
|
||||
htmlEntityDecode(value);
|
||||
m.log(4, "Converts from hex/dex entities: " .. value .. ".");
|
||||
|
||||
-- normalize obfuscated protocol handlers
|
||||
value = rex.gsub(value, "(?ms:(?:j\\s*a\\s*v\\s*a\\s*s\\s*c\\s*r\\s*i\\s*p\\s*t\\s*)|(d\\s*a\\s*t\\s*a\\s*))", "javascript", nil, 0, 0);
|
||||
|
||||
--[[ Normalize Quotes ]]
|
||||
-- normalize different quotes to "
|
||||
value = rex.gsub(value, "[\'\`\´\’\‘]", "\"", nil, 0, 0);
|
||||
m.log(4, "Normalize Quotes: " .. value .. ".");
|
||||
|
||||
-- make sure harmless quoted strings don't generate false alerts
|
||||
value = rex.gsub(value, "^\"([^\"=\\!><~]+)\"$", "%1", nil, 0, 0);
|
||||
m.log(4, "Harmless Quotes: " .. value .. ".");
|
||||
|
||||
|
||||
--[[ Converts SQLHEX to plain text ]]
|
||||
local tmp_value = value;
|
||||
while true do
|
||||
sql_hex_value = rex.match(tmp_value, "(?im:0x([a-fA-F\\d]{2,}[a-fA-F\\d]*)+)");
|
||||
if (sql_hex_value == nil) then break end
|
||||
m.log(4, "SQL Hex Data: " .. sql_hex_value .. ".");
|
||||
local sql_hex_decoded = sql_hexdecode(sql_hex_value);
|
||||
m.log(4, "SQL Hex Data Decoded: " .. sql_hex_decoded .. ".");
|
||||
tmp_value = rex.gsub(tmp_value, "(?im:0x([a-fA-F\\d]{2,}[a-fA-F\\d]*)+)", sql_hex_decoded, 1, 0, 0);
|
||||
m.log(4, "SQL Hex Data Normalized: " .. tmp_value .. ".");
|
||||
end
|
||||
value = rex.gsub(tmp_value, "(?m:0x\\d+)", "1", nil, 0, 0);
|
||||
|
||||
--[[ Converts basic SQL keywords and obfuscations ]]
|
||||
value = rex.gsub(value, "(?ims:(?:IS\\s+null)|(LIKE\\s+null)|(?:(?:^|\\W)IN[\+\\s]*\([\\s\\d\"]+[^\(\)]*\)))", "\"=0", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:\\W+\\s*like\\s*\\W+)", "1\" OR \"1\"", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:null[,\"\\s])", ",0", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:\\d+\\.)", " 1", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:,null)", ",0", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:between|mod)", "or", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:and\\s+\\d+\.?\\d*)", "", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:\\s+and\\s+)", " or ", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:[^\\w,\(]NULL|\\\\N|TRUE|FALSE|UTC_TIME|LOCALTIME(?:STAMP)?|CURRENT_\\w+|BINARY|(?:(?:ASCII|SOUNDEX|FIND_IN_SET|MD5|R?LIKE)[\+\\s]*\\([^\(\)]+\\))|(?:\-+\\d))", "0", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?ims:(?:NOT\\s+BETWEEN)|(?:IS\\s+NOT)|(?:NOT\\s+IN)|(?:XOR|\\WDIV\\W|\\WNOT\\W|<>|RLIKE(?:\\s+BINARY)?)|(?:REGEXP\\s+BINARY)|(?:SOUNDS\\s+LIKE))", "!", nil, 0, 0);
|
||||
value = rex.gsub(value, "\"\\s+\\d", "\"", nil, 0, 0);
|
||||
value = rex.gsub(value, "\\/(?i:\\d+|null)", "", nil, 0, 0);
|
||||
|
||||
m.log(4, "Convert SQL Keywords and Obfuscations: " .. value .. ".");
|
||||
|
||||
--[[ Detects nullbytes and controls chars via ord() ]]
|
||||
-- critical ctrl values
|
||||
value = rex.gsub(value, "(?i:cha?r\\((0|1|2|3|4|5|6|7|8|11|12|14|15|16|17|18|19|24|25|192|193|238|255)\\))", "%%00", nil, 0, 0);
|
||||
m.log(4, "Convert nullbytes and control chars via ord(): " .. value .. ".");
|
||||
|
||||
-- take care for malicious unicode characters
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%E(?:2|3)\%8(?:0|1)\%(?:A|8|9)\\w|\%EF\%BB\%BF|\%EF\%BF\%BD)|(?:&#(?:65|8)\\d{3};?))", "", nil, 0, 0));
|
||||
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%F0\%80\%BE))", ">", nil, 0, 0));
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%F0\%80\%BC))", "<", nil, 0, 0));
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%F0\%80\%A2))", "\"", nil, 0, 0));
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%F0\%80\%A7))", "\'", nil, 0, 0));
|
||||
value = urldecode(rex.gsub(urlencode(value), "(?i:(?:\%ff1c))", "<", nil, 0, 0));
|
||||
|
||||
value = rex.gsub(value, "(?i:(?:&[#x]*(200|820|200|820|zwn?j|lrm|rlm)\\w?;?))", "", nil, 0, 0);
|
||||
value = rex.gsub(value, "(?i:(?:&#(?:65|8)\\d{3};?)|(?:&#(?:56|7)3\\d{2};?)|(?:&#x(?:fe|20)\\w{2};?)|(?:&#x(?:d[c-f])\\w{2};?))", "", nil, 0, 0);
|
||||
value = rex.gsub(value, "(«|〈|<|‹|〈|⟨)", "<", nil, 0, 0);
|
||||
value = rex.gsub(value, "(»|〉|>|›|〉|⟩)", ">", nil, 0, 0);
|
||||
m.log(4, "Malicious unicode characters: " .. value .. "");
|
||||
|
||||
|
||||
--[[ This method matches and translates base64 strings and fragments
|
||||
used in data URIs ]]
|
||||
|
||||
tmp_value = value;
|
||||
while true do
|
||||
base64_value = rex.match(tmp_value, "([a-zA-Z0-9\+\/]{32,}={0,2})", 1, 0, 0);
|
||||
if (base64_value == nil) then break end
|
||||
m.log(4, "Base64 Data is: " .. base64_value .. ".");
|
||||
base64_value_decoded = base64decode(base64_value);
|
||||
m.log(4, "Base64 Data Decoded is: " .. base64_value_decoded .. ".");
|
||||
tmp_value = rex.gsub(tmp_value, "([a-zA-Z0-9\+\/]{32,}={0,2})", base64_value_decoded, 1, 0, 0);
|
||||
m.log(4, "Base64 Data Normalized: " .. tmp_value .. ".");
|
||||
end
|
||||
value = tmp_value;
|
||||
|
||||
|
||||
--[[ Detects nullbytes and controls chars via ord() ]]
|
||||
local mytable = {};
|
||||
mytable = str_split(value);
|
||||
j = 1
|
||||
while mytable[j] do
|
||||
if (string.byte(mytable[j]) >= 127) then
|
||||
mytable[j] = rex.gsub(mytable[j], ".*", " ", nil, 0, 0);
|
||||
end
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
value = table.concat(mytable);
|
||||
m.log(4, "Detect nullbytes and control chars via ord(): " .. value .. ".");
|
||||
|
||||
|
||||
--[[ Strip XML patterns ]]
|
||||
converted = strip_tags(value);
|
||||
if (converted ~= value) then
|
||||
value = (value .. "\n" .. converted);
|
||||
m.log(4, "Strip XML patterns: " .. value .. ".");
|
||||
end
|
||||
|
||||
--[[ This method converts JS unicode code points to regular characters ]]
|
||||
|
||||
function convertFromJSUnicode(args)
|
||||
local new_value = "";
|
||||
|
||||
for line in rex.gmatch(args, "(?ims:\\\\u[0-9a-f]{4})", 0, 0)
|
||||
do
|
||||
hex = print(string.sub(line,3,6))
|
||||
chr = string.char(hex2dec(string.sub(line,5,7)));
|
||||
if ( new_value == nil ) then
|
||||
new_value = chr;
|
||||
else
|
||||
new_value = new_value .. chr;
|
||||
end
|
||||
end
|
||||
|
||||
if ( string.len(new_value) > 0 ) then
|
||||
value = new_value .. "\n\\u0001";
|
||||
end
|
||||
end
|
||||
|
||||
convertFromJSUnicode(value);
|
||||
m.log(4, "Convert JS unicode code points to regular chars: " .. value .. "");
|
||||
|
||||
|
||||
--[[ Converts relevant UTF-7 tags to UTF-8 ]]
|
||||
value = rex.gsub(value,"\\+ACI\\-","\"");
|
||||
value = rex.gsub(value,"\\+ADw\\-","<");
|
||||
value = rex.gsub(value,"\\+AD4\\-",">");
|
||||
value = rex.gsub(value,"\\+AFs\\-","%[");
|
||||
value = rex.gsub(value,"\\+AF0\\-","]");
|
||||
value = rex.gsub(value,"\\+AHs\\-","{");
|
||||
value = rex.gsub(value,"\\+AH0\\-","}");
|
||||
value = rex.gsub(value,"\\+AFw\\-","\\");
|
||||
value = rex.gsub(value,"\\+ADs\\-",";");
|
||||
value = rex.gsub(value,"\\+ACM\\-","#");
|
||||
value = rex.gsub(value,"\\+ACY\\-","&");
|
||||
value = rex.gsub(value,"\\+ACU\\-","%%");
|
||||
value = rex.gsub(value,"\\+ACQ\\-","$");
|
||||
value = rex.gsub(value,"\\+AD0\\-","=");
|
||||
value = rex.gsub(value,"\\+AGA\\-","`");
|
||||
value = rex.gsub(value,"\\+ALQ\\-","\"");
|
||||
value = rex.gsub(value,"\\+IBg\\-","\"");
|
||||
value = rex.gsub(value,"\\+IBk\\-","\"");
|
||||
value = rex.gsub(value,"\\+AHw\\-","|");
|
||||
value = rex.gsub(value,"\\+ACo\\-","*");
|
||||
value = rex.gsub(value,"\\+AF4\\-","%^");
|
||||
value = rex.gsub(value,"\\+ACIAPg\\-","\">");
|
||||
value = rex.gsub(value,"\\+ACIAPgA8\\-","\">");
|
||||
m.log(4, "Convert relevant UTF-7 tags to UTF-8: " .. value .. "");
|
||||
|
||||
|
||||
--[[ Converts basic concatenations ]]
|
||||
function stripslashes(args)
|
||||
|
||||
local value = rex.gsub(args,"(\\\\(.?))","");
|
||||
|
||||
return value;
|
||||
end
|
||||
|
||||
function convertFromConcatenated(value)
|
||||
|
||||
--normalize remaining backslashes
|
||||
if (value ~= rex.gsub(value,"((\\w)\\\\)", "%1")) then
|
||||
value = value .. rex.gsub(value,"((\\w)\\\\)", "%1");
|
||||
end
|
||||
|
||||
local compare = stripslashes(value);
|
||||
|
||||
pattern = { "(?s:(?:<\/\\w+>\+<\\w+>))",
|
||||
"(?s:(?:\":\\d+[^\"\[]+\"))",
|
||||
"(?s:(?:\"?\"\+\\w+\+\"))",
|
||||
"(?s:(?:\"\\s*;[^\"]+\")|(?:\";[^\"]+:\\s*\"))",
|
||||
"(?s:(?:\"\\s*(?:\;|\\+).{8,18}:\\s*\"))",
|
||||
"(?s:(?:\";\\w+=)|(?:!\"\"&&\")|(?:~))",
|
||||
"(?s:(?:\"?\"\\+\"\"?\\+?\"?)|(?:;\\w+=\")|(?:\"[|&]{2,}))",
|
||||
"(?s:(?:\"\\s*\\W+\"))",
|
||||
"(?s:(?:\";\\w\\s*\\+=\\s*\\w?\\s*\"))",
|
||||
"(?s:(?:\"[|&;]+\\s*[^\|\&\\n]*[\|\&]+\\s*\"?))",
|
||||
"(?s:(?:\";\\s*\\w+\\W+\\w*\\s*[\|\&]*\"))",
|
||||
"(?s:(?:\"\\s*\"\\s*\.))",
|
||||
"((?:\\s*new\\s+\\w+\\s*[\\+\\\"\,]))",
|
||||
"((?:(?:^|\\s+)(?:do|else)\\s+))",
|
||||
"((?:(?:^|\\s+)(?:do|else)\\s+))",
|
||||
"((?:[{(]\\s*new\\s+\\w+\\s*[\)\}]))",
|
||||
"((?:(this|self)\.))",
|
||||
"((?:undefined))",
|
||||
"((?:in\\s+))" };
|
||||
|
||||
for i=1, table.getn(pattern) do
|
||||
-- strip out concatenations
|
||||
converted = rex.gsub(compare,pattern[i],"");
|
||||
end
|
||||
|
||||
-- strip object traversal
|
||||
converted = rex.gsub(converted,"(\\w(\.\\w\()))", "%1");
|
||||
|
||||
-- normalize obfuscated method calls
|
||||
converted = rex.gsub(converted,"(\\)\\s*\+)", ")");
|
||||
|
||||
--convert JS special numbers
|
||||
converted = rex.gsub(converted,"(?ims:(?:\\(*[.\\d]e[\+\-]*[^a-z\\W]+\\)*)|(?:NaN|Infinity)\\W)", "1");
|
||||
|
||||
if (converted ~= nil) then
|
||||
if (compare ~= converted) then
|
||||
value = value .. "\n" .. converted;
|
||||
end
|
||||
end
|
||||
|
||||
-- return value;
|
||||
end
|
||||
|
||||
convertFromConcatenated(value);
|
||||
m.log(4, "Convert basic concatenations: " .. value .. "");
|
||||
|
||||
|
||||
--[[ This method collects and decodes proprietary encoding types ]]
|
||||
|
||||
function convertFromProprietaryEncodings(args)
|
||||
|
||||
local value = args;
|
||||
|
||||
--Xajax error reportings
|
||||
value = rex.gsub(value,"(?im:<!\[CDATA\[(.*)\]\]>)","%1", nil, 0, 0);
|
||||
|
||||
--strip false alert triggering apostrophes
|
||||
value = rex.gsub(value,"(?m:(\\w)\"(s))", "%1%2");
|
||||
|
||||
--strip quotes within typical search patterns
|
||||
value = rex.gsub(value,"(^\"([^\"=\\!><~]+)\"/$)", "%1");
|
||||
|
||||
--OpenID login tokens
|
||||
value = rex.gsub(value,"({[\\w-]{8,9}\}(?:\{[\w=]{8}\}){2})", "");
|
||||
|
||||
--convert Content and \sdo\s to null
|
||||
value = rex.gsub(value,"(?s:Content|\\Wdo)", "");
|
||||
|
||||
--strip emoticons
|
||||
value = rex.gsub(value,
|
||||
"(?m:(?:\\s[:;]-[)\/PD]+)|(?:\\s;[)PD]+)|(?:\\s:[)PD]+)|-\.-|\^\^)",
|
||||
"");
|
||||
|
||||
--normalize separation char repetion
|
||||
value = rex.gsub(value,"(?m:([.+~=*_;\-])\1{2,})", "%1");
|
||||
|
||||
--normalize multiple single quotes
|
||||
value = rex.gsub(value,"(?m:/\"{2,})", "\"");
|
||||
|
||||
--normalize quoted numerical values and asterisks
|
||||
value = rex.gsub(value,"(?m:\"(\\d+)\")", "%1");
|
||||
|
||||
--normalize pipe separated request parameters
|
||||
value = rex.gsub(value,"(?m:\|(\\w+=\\w+))", "&%1");
|
||||
|
||||
--normalize ampersand listings
|
||||
value = rex.gsub(value,"((\\w\\s)&\\s(\\w))", "%1%2");
|
||||
|
||||
--normalize escaped RegExp modifiers
|
||||
value = rex.gsub(value,"(\/\\\\(\\w))", "/%1");
|
||||
|
||||
end
|
||||
|
||||
convertFromProprietaryEncodings(value);
|
||||
m.log(4, "convertFromProprietaryEncodings: " .. value .. "");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
normalized_name = rex.gsub(name, "^(.*)$", "tx.%1_normalized");
|
||||
m.setvar(normalized_name, value);
|
||||
|
||||
|
||||
--[[ This method is the centrifuge prototype ]]
|
||||
m.log(4, "Starting Centrifuge.. Arg Name = " ..name.. " and Arg Value = " ..value.. ".");
|
||||
|
||||
threshold = 3.49;
|
||||
|
||||
-- Examine each value
|
||||
if string.len(value) > 25 then
|
||||
local name = name;
|
||||
-- strip padding
|
||||
tmp_value = rex.gsub(value, "\\s{4}|==$", "", nil, 0, 0);
|
||||
m.log(4, "Strip Padding1 - name is: " .. name .. " and value is: " .. tmp_value ..".");
|
||||
tmp_value = rex.gsub(tmp_value, "\\s{4}|[\\p{L}\\d\+\-\=\,\.\%\(\)]{8,}", "aaa", nil, 0, 0);
|
||||
m.log(4, "Strip Padding2 - name is: " .. name .. " and value is: " .. tmp_value ..".");
|
||||
|
||||
-- Check for the attack char ratio
|
||||
tmp_value = rex.gsub(tmp_value, "([\*\.\!\?\+\-])\\1{1,}", "%1", nil, 0, 0);
|
||||
tmp_value = rex.gsub(tmp_value, "\"[\\p{L}\\d\\s]+\"", "", nil, 0, 0);
|
||||
|
||||
stripped_length = string.len(rex.gsub(tmp_value, "[\\d\\s\\p{L}\.\:\,\%\&\/\>\<\\-)\!\|]+", "", nil, 0, 0));
|
||||
m.log(4, "stripped_length is: " .. stripped_length .. ".");
|
||||
overall_value = rex.gsub(tmp_value, "([\\d\\s\\p{L}\:\,\.]{3,})+", "aaa", nil, 0, 0);
|
||||
m.log(4, "overall_value is: " .. overall_value .. ".");
|
||||
overall_length = string.len(rex.gsub(overall_value, "\\s{2,}", "", nil, 0, 0));
|
||||
m.log(4, "overall_length is: " .. overall_length .. ".");
|
||||
|
||||
if ((stripped_length ~= 0) and (overall_length/stripped_length <= threshold)) then
|
||||
ratio_value = (overall_length/stripped_length);
|
||||
ratio_name = rex.gsub(name, "^(.*)$", "tx.%1_centrifuge_ratio");
|
||||
m.setvar(ratio_name, ratio_value);
|
||||
m.log(4, "Threshold is: " .. threshold .. " and Ratio Value is: " .. ratio_value .. ".");
|
||||
end
|
||||
end
|
||||
|
||||
-- Examine each value
|
||||
if string.len(value) > 40 then
|
||||
|
||||
converted = value;
|
||||
|
||||
mytable = str_split_unique(converted)
|
||||
|
||||
j = 1
|
||||
while mytable[j] do
|
||||
print(mytable[j])
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
converted = table.concat(mytable);
|
||||
m.log(4, "Unique/Sorted: " .. converted .. ".");
|
||||
|
||||
-- Replace all non-special chars
|
||||
converted = rex.gsub(converted, "[\\w\\s\\p{L},\.:!]", "");
|
||||
m.log(4, "Replace non-special chars: " .. converted .. ".");
|
||||
|
||||
|
||||
-- Normalize certain tokens
|
||||
converted = rex.gsub(converted, "(\\~|\\^|\\||\\*|\\%|\\&|\\/)", "+");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
converted = rex.gsub(converted, "(\\+|\\-)\\s*\\d+", "+");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
converted = rex.gsub(converted, "(\\(|\\)|\\[|\\]|\\{|\\})", "(");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
converted = rex.gsub(converted, "(\\!|\\?|\\:|\=)", ":");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
converted = rex.gsub(converted, "[^:(+]", "");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
converted = string.gsub(converted, "\\", "");
|
||||
m.log(4, "Normalize certain tokens: " .. converted .. ".");
|
||||
|
||||
mytable = str_split(converted)
|
||||
table.sort(mytable);
|
||||
converted = table.concat(mytable);
|
||||
m.log(4, "Sorted: " .. converted .. ".");
|
||||
stripped_name = rex.gsub(name, "^(.*)$", "tx.%1_centrifuge_converted");
|
||||
m.setvar(stripped_name, converted);
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if value ~= "." then
|
||||
|
||||
return ("Normalized Payload: " .. name .. " = " .. value .. "");
|
||||
else
|
||||
-- Nothing wrong found.
|
||||
return nil;
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,251 @@
|
||||
function main()
|
||||
|
||||
--[[ Enforce Request Method ]]
|
||||
EnforceRequestMethod()
|
||||
|
||||
--[[ Enforce Number of Parameters/ARGS ]]
|
||||
EnforceNumOfArgs()
|
||||
|
||||
--[[ Enforce Parameter Names ]]
|
||||
EnforceArgsNames()
|
||||
|
||||
--[[ Enforce Parameter Lengths ]]
|
||||
EnforceArgsLength()
|
||||
|
||||
--[[ Enforce Parameter Character Class ]]
|
||||
EnforceArgCharClass()
|
||||
|
||||
m.log(4, "Ending Profile Enforcer Script")
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[ Begin Enforcement Functions ]]
|
||||
|
||||
function EnforceArgCharClass()
|
||||
local Args = {}
|
||||
Args = m.getvars("ARGS", {"none"})
|
||||
local EnforceArgCharClassEmail = m.getvar("RESOURCE.enforce_charclass_email")
|
||||
local EnforceArgCharClassDigits = m.getvar("RESOURCE.enforce_charclass_digits")
|
||||
local EnforceArgCharClassUrl = m.getvar("RESOURCE.enforce_charclass_url")
|
||||
local EnforceArgCharClassPath = m.getvar("RESOURCE.enforce_charclass_path")
|
||||
local EnforceArgCharClassFlag = m.getvar("RESOURCE.enforce_charclass_flag")
|
||||
local EnforceArgCharClassAlpha = m.getvar("RESOURCE.enforce_charclass_alphas")
|
||||
local EnforceArgCharClassAlphaNumeric = m.getvar("RESOURCE.enforce_charclass_alphanumeric")
|
||||
local EnforceArgCharClassSafeText = m.getvar("RESOURCE.enforce_charclass_safetext")
|
||||
|
||||
for k,v in pairs(Args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "CharClass Check - Arg Name: " ..name.. " and Value: " ..value.. ".");
|
||||
|
||||
--[[ Check for Digits Character Class ]]
|
||||
if (EnforceArgCharClassDigits) then
|
||||
local CheckArgCharClassDigits = string.find(EnforceArgCharClassDigits, name)
|
||||
if (CheckArgCharClassDigits) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Digits Enforcement list.")
|
||||
if string.match(value, "^%d+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches digit class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match digit class.")
|
||||
m.setvar("TX." ..name.. "_digits_violation", value)
|
||||
m.setvar("TX.digits_violation_name", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Check for Email Character Class ]]
|
||||
if (EnforceArgCharClassEmail) then
|
||||
local CheckArgCharClassEmail = string.find(EnforceArgCharClassEmail, name)
|
||||
if (CheckArgCharClassEmail) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Email Enforcement list.")
|
||||
if string.match(value, "^[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches email class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match email class.")
|
||||
m.setvar("TX." ..name.. "_email_violation", value)
|
||||
m.setvar("TX.email_violation_name", name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[ Check for URL Class ]]
|
||||
if (EnforceArgCharClassUrl) then
|
||||
local CheckArgCharClassUrl = string.find(EnforceArgCharClassUrl, name)
|
||||
if (CheckArgCharClassUrl) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Url Enforcement list.")
|
||||
if string.match(value, "[A-Za-z]+://[A-Za-z0-9-_]+%.[A-Za-z0-9-_.]+/?") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches url class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match url class.")
|
||||
m.setvar("TX." ..name.. "_url_violation", value)
|
||||
m.setvar("TX.url_violation_name", name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[ Check for Path Class ]]
|
||||
if (EnforceArgCharClassPath) then
|
||||
local CheckArgCharClassPath = string.find(EnforceArgCharClassPath, name)
|
||||
if (CheckArgCharClassPath) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Path Enforcement list.")
|
||||
if string.match(value, "[-a-zA-Z0-9/._]*/[-a-zA-Z0-9/._]*") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches path class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match path class.")
|
||||
m.setvar("TX." ..name.. "_path_violation", value)
|
||||
m.setvar("TX.path_violation_name", name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[ Check for Flag Parameter Class ]]
|
||||
if (EnforceArgCharClassFlag) then
|
||||
local CheckArgCharClassFlag = string.find(EnforceArgCharClassFlag, name)
|
||||
if (CheckArgCharClassFlag) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Flag Enforcement list.")
|
||||
if string.match(value, "^$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches flag class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match flag class.")
|
||||
m.setvar("TX." ..name.. "_flag_violation", value)
|
||||
m.setvar("TX.flag_violation_name", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Check for Alpha/Letters Character Class ]]
|
||||
if (EnforceArgCharClassAlpha) then
|
||||
local CheckArgCharClassAlpha = string.find(EnforceArgCharClassAlpha, name)
|
||||
if (CheckArgCharClassAlpha) then
|
||||
m.log(4, "Arg Name: " .. name .. " in Alpha Enforcement list.")
|
||||
if string.match(value, "^%a+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches alpha class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match alpha class.")
|
||||
m.setvar("TX." ..name.. "_alpha_violation", value)
|
||||
m.setvar("TX.alpha_violation_name", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Check for AlphaNumeric Character Class ]]
|
||||
if (EnforceArgCharClassAlphaNumeric) then
|
||||
local CheckArgCharClassAlphaNumeric = string.find(EnforceArgCharClassAlphaNumeric, name)
|
||||
if (CheckArgCharClassAlphaNumeric) then
|
||||
m.log(4, "Arg Name: " .. name .. " in AlphaNumeric Enforcement list.")
|
||||
if string.match(value, "^%w+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches alphanumeric class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match alphanumeric class.")
|
||||
m.setvar("TX." ..name.. "_alphanumeric_violation", value)
|
||||
m.setvar("TX.alphanumeric_violation_name", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Check for SafeText Character Class ]]
|
||||
if (EnforceArgCharClassSafeText) then
|
||||
local CheckArgCharClassSafeText = string.find(EnforceArgCharClassSafeText, name)
|
||||
if (CheckArgCharClassSafeText) then
|
||||
m.log(4, "Arg Name: " .. name .. " in SafeText Enforcement list.")
|
||||
if string.match(value, "^[a-zA-Z0-9%s_%.%-]+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches safetext class.")
|
||||
else
|
||||
m.log(4, "Parameter " ..name.. " payload does not match safetext class.")
|
||||
m.setvar("TX." ..name.. "_safetext_violation", value)
|
||||
m.setvar("TX.safetext_violation_name", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function EnforceArgsLength()
|
||||
local ArgsLength = {}
|
||||
ArgsLength = m.getvars("ARGS", {"none", "length"})
|
||||
|
||||
for k,v in pairs(ArgsLength) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
value = tonumber(value);
|
||||
m.log(4, "Arg Name: " ..name.. " and Length: " ..value.. ".");
|
||||
|
||||
local MinArgLength = tonumber(m.getvar("RESOURCE." .. name .. "_length_min", {"none"}))
|
||||
local MaxArgLength = tonumber(m.getvar("RESOURCE." .. name .. "_length_max", {"none"}))
|
||||
|
||||
if ((value > MinArgLength) and (value < MaxArgLength)) then
|
||||
m.log(4, "Arg Name: " .. name .. " with Length: :" ..value.. " is within normal range.")
|
||||
elseif value < MinArgLength then
|
||||
m.log(4, "Arg Name: " .. name .. " Length " ..value.. " is below the normal range.")
|
||||
m.setvar("TX." .. name .. "_min_length_violation", value)
|
||||
m.setvar("TX.MinArgLength", MinArgLength)
|
||||
m.setvar("TX.MinArgLengthName", name)
|
||||
elseif value > MaxArgLength then
|
||||
m.log(4, "Arg Name: " .. name .. " Length " ..value.. " is above the normal range.")
|
||||
m.setvar("TX." .. name .. "_max_length_violation", value)
|
||||
m.setvar("TX.MaxArgLength", MaxArgLength)
|
||||
m.setvar("TX.MaxArgLengthName", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function EnforceArgsNames()
|
||||
local ArgsNames = {}
|
||||
ArgsNames = m.getvars("ARGS_NAMES", {"none"})
|
||||
local EnforceArgsNames = m.getvar("RESOURCE.enforce_args_names")
|
||||
|
||||
for k,v in pairs(ArgsNames) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "ArgsName: " ..value.. ".");
|
||||
|
||||
local CheckArgsNames = string.find(EnforceArgsNames, value)
|
||||
if (CheckArgsNames) then
|
||||
m.log(4, "Arg Name: " .. value .. " is valid.")
|
||||
else
|
||||
m.log(4, "Args Name: " .. value .. " is not valid.")
|
||||
m.setvar("TX.args_names_violation", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function EnforceRequestMethod()
|
||||
local RequestMethod = m.getvar("REQUEST_METHOD", {"none"})
|
||||
|
||||
local EnforceRequestMethods = m.getvar("RESOURCE.enforce_request_methods")
|
||||
local EnforceMethods = string.find(EnforceRequestMethods, RequestMethod)
|
||||
if (EnforceMethods) then
|
||||
m.log(4, "Request Method " .. RequestMethod .. " already in Enforcement List.")
|
||||
else
|
||||
m.log(4, "Request Method: " .. RequestMethod .. " profile violation.")
|
||||
m.setvar("TX.request_method_violation", "1")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function EnforceNumOfArgs()
|
||||
local ARGS = {}
|
||||
local ARGS = m.getvars("ARGS", {"none"})
|
||||
local NumOfArgs = tonumber(#ARGS)
|
||||
local MinNumOfArgs = tonumber(m.getvar("RESOURCE.MinNumOfArgs", {"none"}))
|
||||
local MaxNumOfArgs = tonumber(m.getvar("RESOURCE.MaxNumOfArgs", {"none"}))
|
||||
local EnforceNumOfArgs = m.getvar("RESOURCE.enforce_num_of_args")
|
||||
|
||||
if ((NumOfArgs > MinNumOfArgs) and (NumOfArgs < MaxNumOfArgs)) then
|
||||
m.log(4, "Number of ARGS is within normal range.")
|
||||
elseif NumOfArgs < MinNumOfArgs then
|
||||
m.log(4, "Number of ARGS is less than MinNumOfArgs: " .. MinNumOfArgs .. ".")
|
||||
m.setvar("TX.MIN_NUM_ARGS_VIOLATION", "1")
|
||||
m.setvar("TX.NUM_OF_ARGS", NumOfArgs)
|
||||
elseif NumOfArgs > MaxNumOfArgs then
|
||||
m.log(4, "Number of ARGS is more than MxxiaxinNumOfArgs: " .. MaxNumOfArgs .. ".")
|
||||
m.setvar("TX.MAX_NUM_ARGS_VIOLATION", "1")
|
||||
m.setvar("TX.NUM_OF_ARGS", NumOfArgs)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,789 @@
|
||||
function main()
|
||||
|
||||
--[[ Global Vars ]]
|
||||
--[[ Import Profile Learning Thresholds
|
||||
|
||||
[resource.min_traffic_threshold]
|
||||
Set the resource.min_traffic_threshold as the minimum number of "clean" transactions
|
||||
to profile/inspect before enforcement of the profile begins.
|
||||
|
||||
[resource.min_pattern_threshold]
|
||||
resource.min_pattern_threshold is the minimum number of times that an individual match should occur
|
||||
in order to include the it into the learned profile
|
||||
|
||||
]]
|
||||
|
||||
MinPatternThreshold = tonumber(m.getvar("RESOURCE.min_pattern_threshold"))
|
||||
MinTrafficThreshold = tonumber(m.getvar("RESOURCE.min_traffic_threshold"))
|
||||
TrafficCounter = m.getvar("RESOURCE.traffic_counter")
|
||||
if TrafficCounter == nil then
|
||||
TrafficCounter = "1"
|
||||
m.setvar("RESOURCE.traffic_counter", TrafficCounter)
|
||||
m.log(4, "Traffic Counter: " ..TrafficCounter.. ".")
|
||||
else
|
||||
TrafficCounter = tonumber(TrafficCounter + 1)
|
||||
m.setvar("RESOURCE.traffic_counter", TrafficCounter)
|
||||
m.log(4, "Traffic Counter: " ..TrafficCounter.. ".")
|
||||
end
|
||||
|
||||
--[[ Profile Request Method ]]
|
||||
ProfileRequestMethod()
|
||||
|
||||
--[[ Profile Number of Parameters/ARGS ]]
|
||||
ProfileNumOfArgs()
|
||||
|
||||
--[[ Profile Parameter Names ]]
|
||||
ProfileArgsNames()
|
||||
|
||||
--[[ Profile Parameter Lengths ]]
|
||||
ProfileArgsLength()
|
||||
|
||||
--[[ Profile Parameter Character Class ]]
|
||||
ProfileArgCharClass()
|
||||
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("RESOURCE.enforce_re_profile", "1")
|
||||
end
|
||||
|
||||
m.log(4, "Ending Profile Analyzer Script")
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[ Begin Profiler Functions ]]
|
||||
|
||||
function ProfileArgCharClass()
|
||||
local Args = {}
|
||||
Args = m.getvars("ARGS", {"none"})
|
||||
|
||||
for k,v in pairs(Args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "CharClass Check - Arg Name: " ..name.. " and Value: " ..value.. ".");
|
||||
|
||||
--[[ Check for Digits Character Class ]]
|
||||
if string.match(value, "^%d+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches digit class.")
|
||||
local EnforceArgCharClassDigits = m.getvar("RESOURCE.enforce_charclass_digits")
|
||||
if not (EnforceArgCharClassDigits) then
|
||||
local ArgDigitCounter = m.getvar("RESOURCE." ..name.. "_digit_counter")
|
||||
if not (ArgDigitCounter) then
|
||||
ArgDigitCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Digit Counter: " .. ArgDigitCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_digit_counter", ArgDigitCounter)
|
||||
else
|
||||
ArgDigitCounter = ArgDigitCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Digit Counter: " .. ArgDigitCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_digit_counter", ArgDigitCounter)
|
||||
end
|
||||
|
||||
if (ArgDigitCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassDigits) then
|
||||
EnforceArgCharClassDigits = name
|
||||
else
|
||||
EnforceArgCharClassDigits = EnforceArgCharClassDigits .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Digits Enforcement list: " .. EnforceArgCharClassDigits)
|
||||
m.setvar("RESOURCE.enforce_charclass_digits", EnforceArgCharClassDigits)
|
||||
m.setvar("!RESOURCE." .. name .. "_digit_counter", "0")
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassDigits = string.find(EnforceArgCharClassDigits, name)
|
||||
if (CheckArgCharClassDigits) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Digits Enforcement list.")
|
||||
else
|
||||
local ArgDigitCounter = m.getvar("RESOURCE." ..name.. "_digit_counter")
|
||||
if not (ArgDigitCounter) then
|
||||
ArgDigitCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Digit Counter: " .. ArgDigitCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_digit_counter", ArgDigitCounter)
|
||||
else
|
||||
ArgDigitCounter = ArgDigitCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Digit Counter: " .. ArgDigitCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_digit_counter", ArgDigitCounter)
|
||||
end
|
||||
|
||||
if (ArgDigitCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassDigits) then
|
||||
EnforceArgCharClassDigits = name
|
||||
else
|
||||
EnforceArgCharClassDigits = EnforceArgCharClassDigits .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Digits Enforcement list: " .. EnforceArgCharClassDigits)
|
||||
m.setvar("RESOURCE.enforce_charclass_digits", EnforceArgCharClassDigits)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_digit_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Check for Email Class ]]
|
||||
elseif string.match(value, "^[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches email class.")
|
||||
local EnforceArgCharClassEmail = m.getvar("RESOURCE.enforce_charclass_email")
|
||||
if not (EnforceArgCharClassEmail) then
|
||||
local ArgEmailCounter = m.getvar("RESOURCE." ..name.. "_email_counter")
|
||||
if not (ArgEmailCounter) then
|
||||
ArgEmailCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Email Counter: " .. ArgEmailCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_email_counter", ArgEmailCounter)
|
||||
else
|
||||
ArgEmailCounter = ArgEmailCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Email Counter: " .. ArgEmailCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_email_counter", ArgEmailCounter)
|
||||
end
|
||||
|
||||
if (ArgEmailCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassEmail) then
|
||||
EnforceArgCharClassEmail = name
|
||||
else
|
||||
EnforceArgCharClassEmail = EnforceArgCharClassEmail .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Email Enforcement list: " .. EnforceArgCharClassEmail)
|
||||
m.setvar("RESOURCE.enforce_charclass_email", EnforceArgCharClassEmail)
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassEmail = string.find(EnforceArgCharClassEmail, name)
|
||||
if (CheckArgCharClassEmail) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Email Enforcement list.")
|
||||
else
|
||||
local ArgEmailCounter = m.getvar("RESOURCE." ..name.. "_email_counter")
|
||||
if not (ArgEmailCounter) then
|
||||
ArgEmailCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Email Counter: " .. ArgEmailCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_email_counter", ArgEmailCounter)
|
||||
else
|
||||
ArgEmailCounter = ArgEmailCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Email Counter: " .. ArgEmailCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_email_counter", ArgEmailCounter)
|
||||
end
|
||||
|
||||
if (ArgEmailCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassEmail) then
|
||||
EnforceArgCharClassEmail = name
|
||||
else
|
||||
EnforceArgCharClassEmail = EnforceArgCharClassEmail .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Email Enforcement list: " .. EnforceArgCharClassEmail)
|
||||
m.setvar("RESOURCE.enforce_charclass_email", EnforceArgCharClassEmail)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_email_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Check for URL Class ]]
|
||||
elseif string.match(value, "[A-Za-z]+://[A-Za-z0-9-_]+%.[A-Za-z0-9-_.]+/?") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches url class.")
|
||||
local EnforceArgCharClassUrl = m.getvar("RESOURCE.enforce_charclass_url")
|
||||
if not (EnforceArgCharClassUrl) then
|
||||
local ArgUrlCounter = m.getvar("RESOURCE." ..name.. "_url_counter")
|
||||
if not (ArgUrlCounter) then
|
||||
ArgUrlCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Url Counter: " .. ArgUrlCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_url_counter", ArgUrlCounter)
|
||||
else
|
||||
ArgUrlCounter = ArgUrlCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Url Counter: " .. ArgUrlCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_url_counter", ArgUrlCounter)
|
||||
end
|
||||
|
||||
if (ArgUrlCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassUrl) then
|
||||
EnforceArgCharClassUrl = name
|
||||
else
|
||||
EnforceArgCharClassUrl = EnforceArgCharClassUrl .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Url Enforcement list: " .. EnforceArgCharClassUrl)
|
||||
m.setvar("RESOURCE.enforce_charclass_url", EnforceArgCharClassUrl)
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassUrl = string.find(EnforceArgCharClassUrl, name)
|
||||
if (CheckArgCharClassUrl) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Url Enforcement list.")
|
||||
else
|
||||
local ArgUrlCounter = m.getvar("RESOURCE." ..name.. "_url_counter")
|
||||
if not (ArgUrlCounter) then
|
||||
ArgUrlCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Url Counter: " .. ArgUrlCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_url_counter", ArgUrlCounter)
|
||||
else
|
||||
ArgUrlCounter = ArgUrlCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Url Counter: " .. ArgUrlCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_url_counter", ArgUrlCounter)
|
||||
end
|
||||
|
||||
if (ArgUrlCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassUrl) then
|
||||
EnforceArgCharClassUrl = name
|
||||
else
|
||||
EnforceArgCharClassUrl = EnforceArgCharClassUrl .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Url Enforcement list: " .. EnforceArgCharClassUrl)
|
||||
m.setvar("RESOURCE.enforce_charclass_url", EnforceArgCharClassUrl)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_url_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Check for Path Class ]]
|
||||
elseif string.match(value, "[-a-zA-Z0-9/._]*/[-a-zA-Z0-9/._]*") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches path class.")
|
||||
local EnforceArgCharClassPath = m.getvar("RESOURCE.enforce_charclass_path")
|
||||
if not (EnforceArgCharClassPath) then
|
||||
local ArgPathCounter = m.getvar("RESOURCE." ..name.. "_path_counter")
|
||||
if not (ArgPathCounter) then
|
||||
ArgPathCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Path Counter: " .. ArgPathCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_path_counter", ArgPathCounter)
|
||||
else
|
||||
ArgPathCounter = ArgPathCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Path Counter: " .. ArgPathCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_path_counter", ArgPathCounter)
|
||||
end
|
||||
|
||||
if (ArgPathCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassPath) then
|
||||
EnforceArgCharClassPath = name
|
||||
else
|
||||
EnforceArgCharClassPath = EnforceArgCharClassPath .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Path Enforcement list: " .. EnforceArgCharClassPath)
|
||||
m.setvar("RESOURCE.enforce_charclass_path", EnforceArgCharClassPath)
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassPath = string.find(EnforceArgCharClassPath, name)
|
||||
if (CheckArgCharClassPath) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Path Enforcement list.")
|
||||
else
|
||||
local ArgPathCounter = m.getvar("RESOURCE." ..name.. "_path_counter")
|
||||
if not (ArgPathCounter) then
|
||||
ArgPathCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Path Counter: " .. ArgPathCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_path_counter", ArgPathCounter)
|
||||
else
|
||||
ArgPathCounter = ArgPathCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Path Counter: " .. ArgPathCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_path_counter", ArgPathCounter)
|
||||
end
|
||||
|
||||
if (ArgPathCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassPath) then
|
||||
EnforceArgCharClassPath = name
|
||||
else
|
||||
EnforceArgCharClassPath = EnforceArgCharClassPath .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Path Enforcement list: " .. EnforceArgCharClassPath)
|
||||
m.setvar("RESOURCE.enforce_charclass_path", EnforceArgCharClassPath)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_path_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Check for Flag Parameter Class ]]
|
||||
elseif string.match(value, "^$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches flag parameter class.")
|
||||
local EnforceArgCharClassFlag = m.getvar("RESOURCE.enforce_charclass_flag")
|
||||
if not (EnforceArgCharClassFlag) then
|
||||
local ArgFlagCounter = m.getvar("RESOURCE." ..name.. "_flag_counter")
|
||||
if not (ArgFlagCounter) then
|
||||
ArgFlagCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Flag Counter: " .. ArgFlagCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_flag_counter", ArgFlagCounter)
|
||||
else
|
||||
ArgFlagCounter = ArgFlagCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Flag Counter: " .. ArgFlagCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_flag_counter", ArgFlagCounter)
|
||||
end
|
||||
|
||||
if (ArgFlagCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassFlag) then
|
||||
EnforceArgCharClassFlag = name
|
||||
else
|
||||
EnforceArgCharClassFlag = EnforceArgCharClassFlag .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Flag Enforcement list: " .. EnforceArgCharClassFlag)
|
||||
m.setvar("RESOURCE.enforce_charclass_flag", EnforceArgCharClassFlag)
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassFlag = string.find(EnforceArgCharClassFlag, name)
|
||||
if (CheckArgCharClassFlag) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Flag Enforcement list.")
|
||||
else
|
||||
local ArgFlagCounter = m.getvar("RESOURCE." ..name.. "_flag_counter")
|
||||
if not (ArgFlagCounter) then
|
||||
ArgFlagCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Flag Counter: " .. ArgFlagCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_flag_counter", ArgFlagCounter)
|
||||
else
|
||||
ArgFlagCounter = ArgFlagCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Flag Counter: " .. ArgFlagCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_flag_counter", ArgFlagCounter)
|
||||
end
|
||||
|
||||
if (ArgFlagCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassFlag) then
|
||||
EnforceArgCharClassFlag = name
|
||||
else
|
||||
EnforceArgCharClassFlag = EnforceArgCharClassFlag .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Flag Enforcement list: " .. EnforceArgCharClassFlag)
|
||||
m.setvar("RESOURCE.enforce_charclass_flag", EnforceArgCharClassFlag)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_flag_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--[[ Check for Alpha/Letters Character Class ]]
|
||||
elseif string.match(value, "^%a+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches alpha class.")
|
||||
local EnforceArgCharClassAlpha = m.getvar("RESOURCE.enforce_charclass_alphas")
|
||||
if not (EnforceArgCharClassAlpha) then
|
||||
local ArgAlphaCounter = m.getvar("RESOURCE." ..name.. "_alpha_counter")
|
||||
if not (ArgAlphaCounter) then
|
||||
ArgAlphaCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Alpha Counter: " .. ArgAlphaCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alpha_counter", ArgAlphaCounter)
|
||||
else
|
||||
ArgAlphaCounter = ArgAlphaCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Alpha Counter: " .. ArgAlphaCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alpha_counter", ArgAlphaCounter)
|
||||
end
|
||||
|
||||
if (ArgAlphaCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassAlpha) then
|
||||
EnforceArgCharClassAlpha = name
|
||||
else
|
||||
EnforceArgCharClassAlpha = EnforceArgCharClassAlpha .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Alpha Enforcement list: " .. EnforceArgCharClassAlpha)
|
||||
m.setvar("RESOURCE.enforce_charclass_alphas", EnforceArgCharClassAlpha)
|
||||
m.setvar("!RESOURCE." .. name .. "_alpha_counter", "0")
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassAlpha = string.find(EnforceArgCharClassAlpha, name)
|
||||
if (CheckArgCharClassAlpha) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in Alpha Enforcement list.")
|
||||
else
|
||||
local ArgAlphaCounter = m.getvar("RESOURCE." ..name.. "_alpha_counter")
|
||||
if not (ArgAlphaCounter) then
|
||||
ArgAlphaCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Alpha Counter: " .. ArgAlphaCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alpha_counter", ArgAlphaCounter)
|
||||
else
|
||||
ArgAlphaCounter = ArgAlphaCounter + 1
|
||||
m.log(4, "Updating " .. name .. " Alpha Counter: " .. ArgAlphaCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alpha_counter", ArgAlphaCounter)
|
||||
end
|
||||
|
||||
if (ArgAlphaCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassAlpha) then
|
||||
EnforceArgCharClassAlpha = name
|
||||
else
|
||||
EnforceArgCharClassAlpha = EnforceArgCharClassAlpha .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the Alpha Enforcement list: " .. EnforceArgCharClassAlpha)
|
||||
m.setvar("RESOURCE.enforce_charclass_alphas", EnforceArgCharClassAlpha)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_alpha_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Check for AlphaNumeric Character Class ]]
|
||||
elseif string.match(value, "^%w+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches alphanumeric class.")
|
||||
local EnforceArgCharClassAlphaNumeric = m.getvar("RESOURCE.enforce_charclass_alphanumeric")
|
||||
if not (EnforceArgCharClassAlphaNumeric) then
|
||||
local ArgAlphaNumericCounter = m.getvar("RESOURCE." ..name.. "_alphanumeric_counter")
|
||||
if not (ArgAlphaNumericCounter) then
|
||||
ArgAlphaNumericCounter = 1
|
||||
m.log(4, "Creating " .. name .. " AlphaNumeric Counter: " .. ArgAlphaNumericCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alphanumeric_counter", ArgAlphaNumericCounter)
|
||||
else
|
||||
ArgAlphaNumericCounter = ArgAlphaNumericCounter + 1
|
||||
m.log(4, "Updating " .. name .. " AlphaNumeric Counter: " .. ArgAlphaNumericCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alphanumeric_counter", ArgAlphaNumericCounter)
|
||||
end
|
||||
|
||||
if (ArgAlphaNumericCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassAlphaNumeric) then
|
||||
EnforceArgCharClassAlphaNumeric = name
|
||||
else
|
||||
EnforceArgCharClassAlphaNumeric = EnforceArgCharClassAlphaNumeric .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the AlphaNumeric Enforcement list: " .. EnforceArgCharClassAlphaNumeric)
|
||||
m.setvar("RESOURCE.enforce_charclass_alphanumeric", EnforceArgCharClassAlphaNumeric)
|
||||
m.setvar("!RESOURCE." .. name .. "_alphanumeric_counter", "0")
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassAlphaNumeric = string.find(EnforceArgCharClassAlphaNumeric, name)
|
||||
if (CheckArgCharClassAlphaNumeric) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in AlphaNumeric Enforcement list.")
|
||||
else
|
||||
local ArgAlphaNumericCounter = m.getvar("RESOURCE." ..name.. "_alphanumeric_counter")
|
||||
if not (ArgAlphaNumericCounter) then
|
||||
ArgAlphaNumericCounter = 1
|
||||
m.log(4, "Creating " .. name .. " AlphaNumeric Counter: " .. ArgAlphaNumericCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alphanumeric_counter", ArgAlphaNumericCounter)
|
||||
else
|
||||
ArgAlphaNumericCounter = ArgAlphaNumericCounter + 1
|
||||
m.log(4, "Updating " .. name .. " AlphaNumeric Counter: " .. ArgAlphaNumericCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_alphanumeric_counter", ArgAlphaNumericCounter)
|
||||
end
|
||||
|
||||
if (ArgAlphaNumericCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassAlphaNumeric) then
|
||||
EnforceArgCharClassAlphaNumeric = name
|
||||
else
|
||||
EnforceArgCharClassAlphaNumeric = EnforceArgCharClassAlphaNumeric .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the AlphaNumeric Enforcement list: " .. EnforceArgCharClassAlphaNumeric)
|
||||
m.setvar("RESOURCE.enforce_charclass_alphanumeric", EnforceArgCharClassAlphaNumeric)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_alphanumeric_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
--[[ Check for SafeText Character Class ]]
|
||||
elseif string.match(value, "^[a-zA-Z0-9%s_%.%-]+$") then
|
||||
m.log(4, "Parameter " ..name.. " payload matches safetext class.")
|
||||
local EnforceArgCharClassSafeText = m.getvar("RESOURCE.enforce_charclass_safetext")
|
||||
if not (EnforceArgCharClassSafeText) then
|
||||
local ArgSafeTextCounter = m.getvar("RESOURCE." ..name.. "_safetext_counter")
|
||||
if not (ArgSafeTextCounter) then
|
||||
ArgSafeTextCounter = 1
|
||||
m.log(4, "Creating " .. name .. " SafeText Counter: " .. ArgSafeTextCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_safetext_counter", ArgSafeTextCounter)
|
||||
else
|
||||
ArgSafeTextCounter = ArgSafeTextCounter + 1
|
||||
m.log(4, "Updating " .. name .. " SafeText Counter: " .. ArgSafeTextCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_safetext_counter", ArgSafeTextCounter)
|
||||
end
|
||||
|
||||
if (ArgSafeTextCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassSafeText) then
|
||||
EnforceArgCharClassSafeText = name
|
||||
else
|
||||
EnforceArgCharClassSafeText = EnforceArgCharClassSafeText .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the SafeText Enforcement list: " .. EnforceArgCharClassSafeText)
|
||||
m.setvar("RESOURCE.enforce_charclass_safetext", EnforceArgCharClassSafeText)
|
||||
end
|
||||
else
|
||||
local CheckArgCharClassSafeText = string.find(EnforceArgCharClassSafeText, name)
|
||||
if (CheckArgCharClassSafeText) then
|
||||
m.log(4, "Arg Name: " .. name .. " already in SafeText Enforcement list.")
|
||||
else
|
||||
local ArgSafeTextCounter = m.getvar("RESOURCE." ..name.. "_safetext_counter")
|
||||
if not (ArgSafeTextCounter) then
|
||||
ArgSafeTextCounter = 1
|
||||
m.log(4, "Creating " .. name .. " SafeText Counter: " .. ArgSafeTextCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_safetext_counter", ArgSafeTextCounter)
|
||||
else
|
||||
ArgSafeTextCounter = ArgSafeTextCounter + 1
|
||||
m.log(4, "Updating " .. name .. " SafeText Counter: " .. ArgSafeTextCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_safetext_counter", ArgSafeTextCounter)
|
||||
end
|
||||
|
||||
if (ArgSafeTextCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgCharClassSafeText) then
|
||||
EnforceArgCharClassSafeText = name
|
||||
else
|
||||
EnforceArgCharClassSafeText = EnforceArgCharClassSafeText .. ", " .. name
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " Reached Pattern Threshold. Adding it to the SafeText Enforcement list: " .. EnforceArgCharClassSafeText)
|
||||
m.setvar("RESOURCE.enforce_charclass_safetext", EnforceArgCharClassSafeText)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE." .. name .. "_safetext_counter", "0")
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ProfileArgsLength()
|
||||
local ArgsLength = {}
|
||||
ArgsLength = m.getvars("ARGS", {"none", "length"})
|
||||
|
||||
for k,v in pairs(ArgsLength) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "Arg Name: " ..name.. " and Length: " ..value.. ".");
|
||||
|
||||
local EnforceArgLength = m.getvar("RESOURCE.enforce_" ..name .. "_length")
|
||||
if EnforceArgsLength ~= nil then
|
||||
local CheckArgsLength = string.find(EnforceArgLength, value)
|
||||
if (CheckArgsLength) then
|
||||
m.log(4, "Arg Name: " .. name .. " with Length: :" ..value.. " already in Enforcement list.")
|
||||
else
|
||||
local ArgLengthCounter = m.getvar("RESOURCE." .. name .. "_length_" ..value.. "_counter")
|
||||
if not (ArgLengthCounter) then
|
||||
ArgLengthCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Length " ..value.. " Counter: " .. ArgLengthCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_length_" ..value.. "_counter", ArgLengthCounter)
|
||||
else
|
||||
ArgLengthCounter = ArgLengthCounter + 1
|
||||
m.log(4, "Increasing " .. name .. " Length " .. value .. " Counter: " .. ArgLengthCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_length_" ..value.. "_counter", ArgLengthCounter)
|
||||
end
|
||||
|
||||
|
||||
if (ArgLengthCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgLength) then
|
||||
EnforceArgLength = value
|
||||
else
|
||||
EnforceArgLength = EnforceArgLength .. ", " .. value
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " with Length: " .. value .. " Reached Pattern Threshold. Adding it to the Enforcement list: " .. EnforceArgLength)
|
||||
m.setvar("RESOURCE.enforce_" ..name .. "_length", EnforceArgLength)
|
||||
end
|
||||
end
|
||||
else
|
||||
local ArgLengthCounter = m.getvar("RESOURCE." .. name .. "_length_" ..value.. "_counter")
|
||||
if not (ArgLengthCounter) then
|
||||
ArgLengthCounter = 1
|
||||
m.log(4, "Creating " .. name .. " Length " ..value.. " Counter: " .. ArgLengthCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_length_" ..value.. "_counter", ArgLengthCounter)
|
||||
else
|
||||
ArgLengthCounter = ArgLengthCounter + 1
|
||||
m.log(4, "Increasing " .. name .. " Length " .. value .. " Counter: " .. ArgLengthCounter)
|
||||
m.setvar("RESOURCE." .. name .. "_length_" ..value.. "_counter", ArgLengthCounter)
|
||||
end
|
||||
|
||||
if (ArgLengthCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgLength) then
|
||||
EnforceArgLength = value
|
||||
else
|
||||
EnforceArgLength = EnforceArgLength .. ", " .. value
|
||||
end
|
||||
|
||||
m.log(4, "Arg Name: " .. name .. " with Length: " .. value .. " Reached Pattern Threshold. Adding it to the Enforcement list: " .. EnforceArgLength)
|
||||
m.setvar("RESOURCE.enforce_" ..name.. "_length", EnforceArgLength)
|
||||
end
|
||||
end
|
||||
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
i=1
|
||||
length_of_arg={}
|
||||
for num in string.gmatch(EnforceArgLength, "%d+") do
|
||||
length_of_arg[i]=num;i=i+1;
|
||||
end
|
||||
local MinArgLength = math.min(unpack(length_of_arg))
|
||||
m.setvar("RESOURCE." .. name .. "_length_min", MinArgLength)
|
||||
local MaxArgLength = math.max(unpack(length_of_arg))
|
||||
m.setvar("RESOURCE." .. name .. "_length_max", MaxArgLength)
|
||||
m.log(4, "Min Length of " .. name .. ": " ..MinArgLength.. " and Max Length: " ..MaxArgLength.. ".")
|
||||
m.setvar("!RESOURCE." .. name .. "_length_" ..value.. "_counter", "0")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ProfileArgsNames()
|
||||
local ArgsNames = {}
|
||||
ArgsNames = m.getvars("ARGS_NAMES", {"none"})
|
||||
local EnforceArgsNames = m.getvar("RESOURCE.enforce_args_names")
|
||||
|
||||
for k,v in pairs(ArgsNames) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "ArgsName: " ..value.. ".");
|
||||
|
||||
if EnforceArgsNames ~= nil then
|
||||
local CheckArgsNames = string.find(EnforceArgsNames, value)
|
||||
if (CheckArgsNames) then
|
||||
m.log(4, "Arg Name: " .. value .. " already in Enforcement list.")
|
||||
else
|
||||
|
||||
local ArgsNamesCounter = m.getvar("RESOURCE.args_names_counter_" .. value)
|
||||
if not (ArgsNamesCounter) then
|
||||
ArgsNamesCounter = 1
|
||||
m.log(4, "Creating " .. value .. " Pattern Score: " .. ArgsNamesCounter)
|
||||
m.setvar("RESOURCE.args_names_counter_" .. value, ArgsNamesCounter)
|
||||
else
|
||||
ArgsNamesCounter = ArgsNamesCounter + 1
|
||||
m.log(4, "Increasing " .. value .. " Pattern Score to: " .. ArgsNamesCounter)
|
||||
m.setvar("RESOURCE.args_names_counter_" .. value, ArgsNamesCounter)
|
||||
end
|
||||
|
||||
|
||||
if (ArgsNamesCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgsNames) then
|
||||
EnforceArgsNames = value
|
||||
else
|
||||
EnforceArgsNames = EnforceArgsNames .. ", " .. value
|
||||
end
|
||||
|
||||
m.log(4, "Args Names: " .. value .. " Reached Pattern Threshold. Adding it to the Enforcement list: " .. EnforceArgsNames)
|
||||
m.setvar("RESOURCE.enforce_args_names", EnforceArgsNames)
|
||||
m.setvar("!RESOURCE.args_names_counter_" .. value, "0")
|
||||
end
|
||||
end
|
||||
else
|
||||
local ArgsNamesCounter = m.getvar("RESOURCE.args_names_counter_" .. value)
|
||||
if not (ArgsNamesCounter) then
|
||||
ArgsNamesCounter = 1
|
||||
m.log(4, "Creating " .. value .. " Pattern Score: " .. ArgsNamesCounter)
|
||||
m.setvar("RESOURCE.args_names_counter_" .. value, ArgsNamesCounter)
|
||||
else
|
||||
ArgsNamesCounter = ArgsNamesCounter + 1
|
||||
m.log(4, "Increasing " .. value .. " Pattern Score to: " .. ArgsNamesCounter)
|
||||
m.setvar("RESOURCE.args_names_counter_" .. value, ArgsNamesCounter)
|
||||
end
|
||||
|
||||
|
||||
if (ArgsNamesCounter == MinPatternThreshold) then
|
||||
if not (EnforceArgsNames) then
|
||||
EnforceArgsNames = value
|
||||
else
|
||||
EnforceArgsNames = EnforceArgsNames .. ", " .. value
|
||||
end
|
||||
|
||||
m.log(4, "Args Names: " .. value .. " Reached Pattern Threshold. Adding it to the Enforcement list: " .. EnforceArgsNames)
|
||||
m.setvar("RESOURCE.enforce_args_names", EnforceArgsNames)
|
||||
m.setvar("!RESOURCE.args_names_counter_" .. value, "0")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProfileRequestMethod()
|
||||
local RequestMethod = m.getvar("REQUEST_METHOD", {"none"})
|
||||
|
||||
local EnforceRequestMethods = m.getvar("RESOURCE.enforce_request_methods")
|
||||
if EnforceRequestMethods ~= nil then
|
||||
local CheckEnforceMethods = string.find(EnforceRequestMethods, RequestMethod)
|
||||
if (CheckEnforceMethods) then
|
||||
m.log(4, "Request Method " .. RequestMethod .. " already in Enforcement List.")
|
||||
end
|
||||
end
|
||||
|
||||
local RequestMethodCounter = m.getvar("RESOURCE.request_method_counter_" .. RequestMethod)
|
||||
if not (RequestMethodCounter) then
|
||||
RequestMethodCounter = 1
|
||||
m.log(4, "Creating " .. RequestMethod .. " Pattern Score: " .. RequestMethodCounter)
|
||||
m.setvar("RESOURCE.request_method_counter_" .. RequestMethod, RequestMethodCounter)
|
||||
else
|
||||
RequestMethodCounter = RequestMethodCounter + 1
|
||||
m.log(4, "Increasing " .. RequestMethod .. " Pattern Score to: " .. RequestMethodCounter)
|
||||
m.setvar("RESOURCE.request_method_counter_" .. RequestMethod, RequestMethodCounter)
|
||||
end
|
||||
|
||||
if (RequestMethodCounter == MinPatternThreshold) then
|
||||
if not (EnforceRequestMethods) then
|
||||
EnforceRequestMethods = RequestMethod
|
||||
else
|
||||
EnforceRequestMethods = EnforceRequestMethods .. ", " .. RequestMethod
|
||||
end
|
||||
|
||||
m.log(4, "Request Method Reached Pattern Threshold. Adding it to the EnforceRequestMethods list: " .. EnforceRequestMethods)
|
||||
m.setvar("RESOURCE.enforce_request_methods", EnforceRequestMethods)
|
||||
end
|
||||
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
m.setvar("!RESOURCE.request_method_counter_" .. RequestMethod, "0")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ProfileNumOfArgs()
|
||||
local ARGS = {}
|
||||
local ARGS = m.getvars("ARGS", {"none"})
|
||||
local NumOfArgs = tonumber(#ARGS)
|
||||
|
||||
local EnforceNumOfArgs = m.getvar("RESOURCE.enforce_num_of_args")
|
||||
if EnforceNumOfArgs ~= nil then
|
||||
local CheckNumOfArgs = string.find(EnforceNumOfArgs, NumOfArgs)
|
||||
if (CheckNumOfArgs) then
|
||||
m.log(4, "ARGS #: " .. NumOfArgs .. " already in Enforcement List.")
|
||||
end
|
||||
end
|
||||
|
||||
local NumOfArgsCounter = m.getvar("RESOURCE.NumOfArgs_counter_" .. NumOfArgs)
|
||||
if not (NumOfArgsCounter) then
|
||||
NumOfArgsCounter = 1
|
||||
m.log(4, "Current # of ARGS: " ..NumOfArgs.. " has not been previously seen.")
|
||||
m.log(4, "Creating " .. NumOfArgs .. " Pattern Score to: " .. NumOfArgsCounter)
|
||||
m.setvar("RESOURCE.NumOfArgs_counter_" .. NumOfArgs, NumOfArgsCounter)
|
||||
else
|
||||
NumOfArgsCounter = NumOfArgsCounter + 1
|
||||
m.log(4, "Current # of ARGS: " ..NumOfArgs.. " has been previously seen.")
|
||||
m.log(4, "Increasing " .. NumOfArgs .. " Pattern Score to: " .. NumOfArgsCounter)
|
||||
m.setvar("RESOURCE.NumOfArgs_counter_" .. NumOfArgs, NumOfArgsCounter)
|
||||
end
|
||||
|
||||
|
||||
if (NumOfArgsCounter == MinPatternThreshold) then
|
||||
if not (EnforceNumOfArgs) then
|
||||
EnforceNumOfArgs = NumOfArgs
|
||||
else
|
||||
EnforceNumOfArgs = EnforceNumOfArgs.. ", " ..NumOfArgs
|
||||
end
|
||||
m.log(4, "NumOfArgs Reached Pattern Threshold. Adding it to the EnforceRequestMethods list: " .. EnforceNumOfArgs)
|
||||
m.setvar("RESOURCE.enforce_num_of_args", EnforceNumOfArgs)
|
||||
end
|
||||
|
||||
if (TrafficCounter == MinTrafficThreshold) then
|
||||
i=1
|
||||
num_of_args={}
|
||||
for num in string.gmatch(EnforceNumOfArgs, "%d+") do
|
||||
num_of_args[i]=num;i=i+1;
|
||||
end
|
||||
local MinNumOfArgs = math.min(unpack(num_of_args))
|
||||
m.setvar("RESOURCE.MinNumOfArgs", MinNumOfArgs)
|
||||
local MaxNumOfArgs = math.max(unpack(num_of_args))
|
||||
m.setvar("RESOURCE.MaxNumOfArgs", MaxNumOfArgs)
|
||||
m.log(4, "Min # of ARGS: " ..MinNumOfArgs.. " and Max # of ARGS: " ..MaxNumOfArgs.. ".")
|
||||
m.setvar("!RESOURCE.NumOfArgs_counter_" .. NumOfArgs, "0")
|
||||
end
|
||||
end
|
||||
|
||||
205
iis/ModSecurityIIS/owasp_crs/lua/arachni_integration.lua
Normal file
205
iis/ModSecurityIIS/owasp_crs/lua/arachni_integration.lua
Normal file
@@ -0,0 +1,205 @@
|
||||
--
|
||||
-- Include Arachni RPC client code
|
||||
--
|
||||
require "client"
|
||||
|
||||
--
|
||||
-- Call main ModSecurity Lua function
|
||||
--
|
||||
function main()
|
||||
|
||||
--
|
||||
-- Set the remote Arachni RPC host
|
||||
--
|
||||
arachni_host = '192.168.168.128'
|
||||
|
||||
--
|
||||
-- Extract Request Data
|
||||
--
|
||||
host = m.getvar("REQUEST_HEADERS.host")
|
||||
m.log(4, "Arachni: Host: " .. host)
|
||||
request_filename = m.getvar("REQUEST_FILENAME")
|
||||
m.log(4, "Arachni: Filename: " .. request_filename)
|
||||
url_to_scan = "http://" .. host .. request_filename
|
||||
m.log(4, "Arachni: URL to scan is: " .. url_to_scan)
|
||||
request_method = m.getvar("REQUEST_METHOD")
|
||||
m.log(4, "Arachni: Request Method is: " .. request_method)
|
||||
|
||||
--
|
||||
-- Convert ModSecurity ARGS data into a local table called args
|
||||
--
|
||||
ARGS = {}
|
||||
ARGS = m.getvars("ARGS")
|
||||
args = {}
|
||||
|
||||
for k,v in pairs(ARGS) do
|
||||
name = v["name"];
|
||||
name = string.gsub(name, "ARGS:(.*)", "%1")
|
||||
value = v["value"];
|
||||
m.log(4, "Arachni: Arg Name: " ..name.. " and Value: " ..value.. ".");
|
||||
|
||||
args[name] = value
|
||||
end
|
||||
|
||||
local yaml_args = yaml.dump ( args )
|
||||
m.log(4, "Arachni: Updated ARGS table is: " .. yaml_args)
|
||||
|
||||
|
||||
--
|
||||
-- Convert ModSecrity COOKIE data into a local table called cookies_table
|
||||
--
|
||||
COOKIES = {}
|
||||
COOKIES = m.getvars("REQUEST_COOKIES")
|
||||
cookies_table = {}
|
||||
|
||||
for k,v in pairs(COOKIES) do
|
||||
name = v["name"];
|
||||
name = string.gsub(name, "REQUEST_COOKIES:(.*)", "%1")
|
||||
value = v["value"];
|
||||
m.log(4, "Arachni: Cookie Name: " ..name.. " and Value: " ..value.. ".");
|
||||
|
||||
cookies_table[name] = value
|
||||
end
|
||||
|
||||
local yaml_cookies = yaml.dump ( cookies_table )
|
||||
m.log(4, "Arachni: Updated Cookies table is: " .. yaml_cookies)
|
||||
|
||||
--
|
||||
-- Initiate Arachni RPC Dispatchers
|
||||
--
|
||||
dispatcher = ArachniRPCClient:new( { host = arachni_host, port = 7331 } )
|
||||
instance_info = dispatcher:call( 'dispatcher.dispatch' )
|
||||
|
||||
--
|
||||
-- Check to see if we have previously initiated a scan for the resource
|
||||
--
|
||||
-- If we have not, then we will contact the Dispatcher and start a scan
|
||||
--
|
||||
local arachni_scan_initiated = m.getvar("RESOURCE.arachni_scan_initiated")
|
||||
if arachni_scan_initiated == nil then
|
||||
|
||||
--
|
||||
-- Set the host to match the remote Dispatcher
|
||||
--
|
||||
instance = ArachniRPCClient:new({
|
||||
host = arachni_host,
|
||||
port = instance_info.port,
|
||||
token = instance_info.token
|
||||
})
|
||||
|
||||
|
||||
opts = {
|
||||
url = url_to_scan,
|
||||
audit_links = true,
|
||||
audit_forms = true,
|
||||
audit_cookies = true,
|
||||
-- only audit the stuff passed to vector feed
|
||||
link_count_limit = 0,
|
||||
cookies = cookies_table
|
||||
}
|
||||
|
||||
instance:call( 'modules.load', { 'xss', 'sqli', 'path_traversal' } )
|
||||
|
||||
vectors = {}
|
||||
|
||||
-- add a form var (for POST params)
|
||||
table.insert( vectors, {
|
||||
type = 'form',
|
||||
method = request_method,
|
||||
action = url_to_scan,
|
||||
inputs = args
|
||||
})
|
||||
|
||||
local yaml_vectors = yaml.dump( vectors )
|
||||
m.log(4, "Arachni: Yaml output of vectors is: " .. yaml_vectors)
|
||||
|
||||
plugins = {
|
||||
vector_feed = {
|
||||
vectors = vectors
|
||||
}
|
||||
}
|
||||
instance:call( 'plugins.load', plugins )
|
||||
instance:call( 'opts.set', opts )
|
||||
instance:call( 'framework.run' )
|
||||
|
||||
--
|
||||
-- Save the Dispatcher port/token data to pull the report later
|
||||
--
|
||||
m.setvar("RESOURCE.arachni_scan_initiated", "1")
|
||||
m.setvar("RESOURCE.arachni_instance_info_port", instance_info.port)
|
||||
m.setvar("RESOURCE.arachni_instance_info_token", instance_info.token)
|
||||
return ("Arachni: Scan Initiated. Exiting")
|
||||
|
||||
else
|
||||
|
||||
--
|
||||
-- If we have previously initiated a scan, we will now check for a report
|
||||
--
|
||||
m.log(4, "Arachni: Previous scan was initiated, checking scan status.")
|
||||
local instance_info_port = m.getvar("RESOURCE.arachni_instance_info_port")
|
||||
local instance_info_token = m.getvar("RESOURCE.arachni_instance_info_token")
|
||||
m.log(4, "Arachni: Port info: " .. instance_info_port .. " and Token info: " .. instance_info_token)
|
||||
|
||||
instance = ArachniRPCClient:new({
|
||||
host = arachni_host,
|
||||
port = instance_info_port,
|
||||
token = instance_info_token
|
||||
})
|
||||
|
||||
if instance:call( 'framework.busy?' ) then
|
||||
m.log(4, "Arachni: Scan still in progress, framework is busy. Exiting.")
|
||||
return ("Arachni scan still in progress, framework is busy. Exiting.")
|
||||
else
|
||||
m.log(4, "Arachni: Scan completed - calling for report.")
|
||||
local results = instance:call( 'framework.issues_as_hash' )
|
||||
yaml_results = yaml.dump( results )
|
||||
m.log(4, "Arachni: Yaml Results: " .. yaml_results)
|
||||
|
||||
for k,v in pairs(results) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
|
||||
if ( v["mod_name"] == "XSS" ) then
|
||||
local XssVulnParams = m.getvar("RESOURCE.xss_vulnerable_params")
|
||||
if not (XssVulnParams) then
|
||||
m.log(4, "Arachni: Vulnerability Identified for Parameter: \"" .. v["var"] .. "\", Vulnerability Type: \"" .. v["mod_name"] .. "\"")
|
||||
m.setvar("RESOURCE.xss_vulnerable_params", v["var"])
|
||||
else
|
||||
local CheckArgInXssVulnParams = string.find(XssVulnParams, v["var"])
|
||||
if (CheckArgInXssVulnParams) then
|
||||
m.log(4, "Arachni: Arg Name: " .. v["var"] .. " already in XSS Vuln list.")
|
||||
else
|
||||
m.log(4, "Arachni: Vulnerability Identified for Parameter: \"" .. v["var"] .. "\", Vulnerability Type: \"" .. v["mod_name"] .. "\"")
|
||||
XssVulnParams = XssVulnParams .. ", " .. v["var"]
|
||||
m.setvar("RESOURCE.xss_vulnerable_params", XssVulnParams)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( v["mod_name"] == "SQLInjection" ) then
|
||||
local SQLiVulnParams = m.getvar("RESOURCE.sqli_vulnerable_params")
|
||||
if not (SQLiVulnParams) then
|
||||
m.log(4, "Arachni: Vulnerability Identified for Parameter: \"" .. v["var"] .. "\", Vulnerability Type: \"" .. v["mod_name"] .. "\"")
|
||||
m.setvar("RESOURCE.sqli_vulnerable_params", v["var"])
|
||||
else
|
||||
local CheckArgInSQLiVulnParams = string.find(SQLiVulnParams, v["var"])
|
||||
if (CheckArgInSQLiVulnParams) then
|
||||
m.log(4, "Arachni: Arg Name: " .. v["var"] .. " already in SQLi Vuln list.")
|
||||
else
|
||||
m.log(4, "Arachni: Vulnerability Identified for Parameter: \"" .. v["var"] .. "\", Vulnerability Type: \"" .. v["mod_name"] .. "\"")
|
||||
SQLiVulnParams = SQLiVulnParams .. ", " .. v["var"]
|
||||
m.setvar("RESOURCE.sqli_vulnerable_params", SQLiVulnParams)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
instance:call( 'service.shutdown' )
|
||||
m.setvar("RESOURCE.arachni_scan_completed", "1")
|
||||
return ("Arachni: Done")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
91
iis/ModSecurityIIS/owasp_crs/lua/bayes_check_spam.lua
Normal file
91
iis/ModSecurityIIS/owasp_crs/lua/bayes_check_spam.lua
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env lua
|
||||
require("io");
|
||||
|
||||
function table.val_to_str ( v )
|
||||
if "string" == type( v ) then
|
||||
v = string.gsub( v, "\n", "\\n" )
|
||||
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
|
||||
return "'" .. v .. "'"
|
||||
end
|
||||
return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
|
||||
else
|
||||
return "table" == type( v ) and table.tostring( v ) or
|
||||
tostring( v )
|
||||
end
|
||||
end
|
||||
|
||||
function table.key_to_str ( k )
|
||||
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
|
||||
return k
|
||||
else
|
||||
return "[" .. table.val_to_str( k ) .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
function table.tostring( tbl )
|
||||
local result, done = {}, {}
|
||||
for k, v in ipairs( tbl ) do
|
||||
table.insert( result, table.val_to_str( v ) )
|
||||
done[ k ] = true
|
||||
end
|
||||
for k, v in pairs( tbl ) do
|
||||
if not done[ k ] then
|
||||
table.insert( result,
|
||||
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
|
||||
end
|
||||
end
|
||||
return "{" .. table.concat( result, "," ) .. "}"
|
||||
end
|
||||
|
||||
|
||||
function main()
|
||||
local mf = require "moonfilter"
|
||||
-- define the classes to use
|
||||
mf.classes("/var/log/httpd/spam", "/var/log/httpd/ham")
|
||||
|
||||
-- create ham+spam DB on disk -- this is only necessary the first time
|
||||
-- use command line moonfilter.lua to initially create the DBs outside
|
||||
-- of ModSecurity
|
||||
--mf.create()
|
||||
|
||||
local anomaly_score = m.getvar("TX.ANOMALY_SCORE", "none");
|
||||
anomaly_score = tonumber(anomaly_score);
|
||||
|
||||
if not (anomaly_score) then
|
||||
local score = ""
|
||||
|
||||
local args = {};
|
||||
args = m.getvars("ARGS", {"none"});
|
||||
if (#args == "0") then
|
||||
m.log(4, "# of ARGS: " ..#args.. ".");
|
||||
return nil;
|
||||
end
|
||||
-- Place ARGS data into key/value pairs for inspection
|
||||
for k,v in pairs(args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "Arg Name: " ..name.. " and Arg Value: " ..value.. ".");
|
||||
mf.text = value;
|
||||
local class_result = mf.classify()
|
||||
|
||||
class_result = table.tostring(class_result)
|
||||
m.log(4, "Classify Results: " .. class_result .. ".")
|
||||
class = string.gsub(class_result, ".*class=\"(.*)\".*", "%1")
|
||||
if (class == "/var/log/httpd/spam") then
|
||||
score = string.gsub(class_result, ".*prob=(%d\.%d%d%d%d%d%d%d%d%d%d%d%d%d%d)\,.*", "%1")
|
||||
score = tonumber(score)
|
||||
if (score) then
|
||||
if (score > 0.90) then
|
||||
m.log(4, "Classify Results: " .. class .. ".")
|
||||
m.setvar("tx.bayes_score", class_result);
|
||||
m.setvar("tx.bayes_var_name", name);
|
||||
m.setvar("tx.bayes_var", value);
|
||||
return("Bayesian Analaysis Alert for " .. name .. " with payload: \"" .. value .. "\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
|
||||
34
iis/ModSecurityIIS/owasp_crs/lua/bayes_train_ham.lua
Normal file
34
iis/ModSecurityIIS/owasp_crs/lua/bayes_train_ham.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/lua
|
||||
require("io");
|
||||
|
||||
function main()
|
||||
local mf = require "moonfilter"
|
||||
-- define the classes to use
|
||||
mf.classes("/var/log/httpd/spam", "/var/log/httpd/ham")
|
||||
-- create ham+spam DB on disk -- this is only necessary the first time
|
||||
-- mf.create()
|
||||
|
||||
local score = ""
|
||||
local value = ""
|
||||
|
||||
local args = {};
|
||||
args = m.getvars("ARGS", {"none"});
|
||||
if (#args == 0) then
|
||||
m.log(4, "# of ARGS: " ..#args.. ".");
|
||||
return nil;
|
||||
end
|
||||
-- Place ARGS data into key/value pairs for inspection
|
||||
for k,v in pairs(args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "Arg Name: " ..name.. " and Arg Value: " ..value.. ".");
|
||||
mf.text = value;
|
||||
local train_result = mf.train("/var/log/httpd/ham")
|
||||
|
||||
end
|
||||
-- return nil;
|
||||
m.log(4, "Low Bayesian Score: " .. score .. ". Training payloads as non-malicious.")
|
||||
m.setvar("tx.bayes_msg", "Training payload as ham: " .. value .. ".");
|
||||
return ("Training payloads as non-malicious: " .. value .. ".");
|
||||
|
||||
end
|
||||
67
iis/ModSecurityIIS/owasp_crs/lua/bayes_train_spam.lua
Normal file
67
iis/ModSecurityIIS/owasp_crs/lua/bayes_train_spam.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/lua
|
||||
require("io");
|
||||
|
||||
function table.val_to_str ( v )
|
||||
if "string" == type( v ) then
|
||||
v = string.gsub( v, "\n", "\\n" )
|
||||
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
|
||||
return "'" .. v .. "'"
|
||||
end
|
||||
return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
|
||||
else
|
||||
return "table" == type( v ) and table.tostring( v ) or
|
||||
tostring( v )
|
||||
end
|
||||
end
|
||||
|
||||
function table.key_to_str ( k )
|
||||
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
|
||||
return k
|
||||
else
|
||||
return "[" .. table.val_to_str( k ) .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
function table.tostring( tbl )
|
||||
local result, done = {}, {}
|
||||
for k, v in ipairs( tbl ) do
|
||||
table.insert( result, table.val_to_str( v ) )
|
||||
done[ k ] = true
|
||||
end
|
||||
for k, v in pairs( tbl ) do
|
||||
if not done[ k ] then
|
||||
table.insert( result,
|
||||
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
|
||||
end
|
||||
end
|
||||
return "{" .. table.concat( result, "," ) .. "}"
|
||||
end
|
||||
|
||||
function main()
|
||||
local mf = require "moonfilter"
|
||||
-- define the classes to use
|
||||
mf.classes("/var/log/httpd/spam", "/var/log/httpd/ham")
|
||||
-- create ham+spam DB on disk -- this is only necessary the first time
|
||||
-- mf.create()
|
||||
|
||||
local args = {};
|
||||
args = m.getvars("MATCHED_VARS", {"none"});
|
||||
if (#args == "0") then
|
||||
m.log(4, "# of ARGS: " ..#args.. ".");
|
||||
return nil;
|
||||
end
|
||||
-- Place ARGS data into key/value pairs for inspection
|
||||
for k,v in pairs(args) do
|
||||
name = v["name"];
|
||||
value = v["value"];
|
||||
m.log(4, "Arg Name: " ..name.. " and Arg Value: " ..value.. ".");
|
||||
mf.text = value;
|
||||
local train_result = mf.train("/var/log/httpd/spam")
|
||||
train_result = table.tostring(train_result)
|
||||
m.log(4, "Train Results: " .. train_result .. ".")
|
||||
|
||||
m.setvar("tx.bayes_msg", "Completed Bayesian SPAM Training on Payload: " .. mf.text .. ".");
|
||||
return("Completed Bayesian SPAM Training on Payload: " .. mf.text .. ".");
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
37
iis/ModSecurityIIS/owasp_crs/lua/gather_ip_data.lua
Normal file
37
iis/ModSecurityIIS/owasp_crs/lua/gather_ip_data.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/opt/local/bin/lua
|
||||
require("io");
|
||||
|
||||
function main()
|
||||
local anomaly_score = m.getvar("TX.ANOMALY_SCORE", "none");
|
||||
m.log(4, "Anomaly Score is: " .. anomaly_score .. ".");
|
||||
local remote_addr = m.getvar("ARGS.REMOTE_ADDR", "none");
|
||||
m.log(4, "Remote IP is: " .. remote_addr .. ".");
|
||||
local ip_hostname = m.getvar("IP.HOSTNAME", "none");
|
||||
|
||||
if ((anomaly_score ~= nil) and (ip_hostname == nil)) then
|
||||
local hostname = "NONE";
|
||||
local abuse_contact = "NONE";
|
||||
n = os.tmpname ()
|
||||
os.execute ("nslookup '" .. remote_addr .. "' > " .. n)
|
||||
os.execute ("whois '" .. remote_addr .. "' >> " .. n)
|
||||
for line in io.lines (n) do
|
||||
if string.match(line, "name = ") then
|
||||
hostname = line
|
||||
end
|
||||
|
||||
if string.match(line, "abuse") then
|
||||
abuse_contact = line
|
||||
end
|
||||
end
|
||||
m.log(4, "Hostname is: " .. hostname .. ".");
|
||||
m.setvar("tx.hostname", hostname);
|
||||
|
||||
m.log(4, "Abuse Contact is: " .. abuse_contact .. ".");
|
||||
m.setvar("tx.abuse_contact", abuse_contact);
|
||||
|
||||
os.remove (n)
|
||||
return("Nslookup: " .. hostname .. " and WHOIS Abuse Info: " .. abuse_contact .. "");
|
||||
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
25
iis/ModSecurityIIS/owasp_crs/lua/osvdb.lua
Normal file
25
iis/ModSecurityIIS/owasp_crs/lua/osvdb.lua
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/opt/local/bin/lua
|
||||
|
||||
local request_filename = m.getvar("REQUEST_FILENAME", "none")
|
||||
local args = {};
|
||||
args = m.getvars("ARGS_NAMES", "none")
|
||||
|
||||
function main ()
|
||||
for line in io.lines("/usr/local/apache/conf/modsec_current/base_rules/vulnerabilities.txt") do
|
||||
if line:find(request_filename) then
|
||||
if string.find(line, "^%d+\,") then
|
||||
for k,v in pairs(args) do
|
||||
local arg_name = v["value"] .. "=";
|
||||
if string.find(line, arg_name) then
|
||||
m.setvar("resource.osvdb_check", "1")
|
||||
m.setvar("resource.osvdb_vulnerable", "1")
|
||||
m.setvar("tx.osvdb_msg", line)
|
||||
return(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
m.setvar("resource.osvdb_check", "1")
|
||||
return nil
|
||||
end
|
||||
38
iis/ModSecurityIIS/owasp_crs/lua/profile_page_scripts.lua
Normal file
38
iis/ModSecurityIIS/owasp_crs/lua/profile_page_scripts.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/opt/local/bin/lua
|
||||
|
||||
function main()
|
||||
|
||||
local response_body = m.getvar("RESPONSE_BODY", "none");
|
||||
|
||||
if response_body ~= "" then
|
||||
|
||||
local _, nscripts = string.gsub(response_body, "<script", "");
|
||||
local _, niframes = string.gsub(response_body, "<iframe", "");
|
||||
local _, nlinks = string.gsub(response_body, "a href", "");
|
||||
local _, nimages = string.gsub(response_body, "<img", "");
|
||||
|
||||
if nscripts == nil then
|
||||
nscripts = 0
|
||||
end
|
||||
if niframes == nil then
|
||||
niframes = 0
|
||||
end
|
||||
if nlinks == nil then
|
||||
nlinks = 0
|
||||
end
|
||||
if nimages == nil then
|
||||
nimages = 0
|
||||
end
|
||||
m.log(3, "niframes[" .. niframes .. "]");
|
||||
m.setvar("tx.niframes", niframes);
|
||||
m.log(3, "nscripts[" .. nscripts .. "]");
|
||||
m.setvar("tx.nscripts", nscripts);
|
||||
m.log(3, "nlinks[" .. nlinks .. "]");
|
||||
m.setvar("tx.nlinks", nlinks);
|
||||
m.log(3, "nimages[" .. nimages .. "]");
|
||||
m.setvar("tx.nimages", nimages);
|
||||
return nil;
|
||||
end
|
||||
|
||||
return nil;
|
||||
end
|
||||
Reference in New Issue
Block a user