From 34f8ef702df0ff401b9dfbb88d74b5536bca015a Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Fri, 26 Apr 2019 15:58:58 +0800 Subject: [PATCH] update --- plugins/op_waf/index.py | 4 + plugins/op_waf/waf/lua/common.lua | 30 ++++ plugins/op_waf/waf/lua/init.lua | 283 ++++-------------------------- plugins/op_waf/waf/lua/waf.lua | 89 +--------- 4 files changed, 72 insertions(+), 334 deletions(-) create mode 100644 plugins/op_waf/waf/lua/common.lua diff --git a/plugins/op_waf/index.py b/plugins/op_waf/index.py index 5d6a20d19..f3fa34ac8 100755 --- a/plugins/op_waf/index.py +++ b/plugins/op_waf/index.py @@ -135,10 +135,14 @@ def stop(): def restart(): + stop() + start() return 'ok' def reload(): + stop() + start() return 'ok' def getJsonPath(name): diff --git a/plugins/op_waf/waf/lua/common.lua b/plugins/op_waf/waf/lua/common.lua new file mode 100644 index 000000000..a170bc0af --- /dev/null +++ b/plugins/op_waf/waf/lua/common.lua @@ -0,0 +1,30 @@ + + +function return_message(status,msg) + ngx.header.content_type = "application/json;" + ngx.status = status + ngx.say(json.encode(msg)) + ngx.exit(status) +end + + +function return_html(status,html) + ngx.header.content_type = "text/html" + ngx.status = status + ngx.say(html) + ngx.exit(status) +end + +function read_file_body(filename) + fp = io.open(filename,'r') + if fp == nil then + return nil + end + fbody = fp:read("*a") + fp:close() + if fbody == '' then + return nil + end + return fbody +end + diff --git a/plugins/op_waf/waf/lua/init.lua b/plugins/op_waf/waf/lua/init.lua index 8d731391d..970f75bc6 100644 --- a/plugins/op_waf/waf/lua/init.lua +++ b/plugins/op_waf/waf/lua/init.lua @@ -1,261 +1,52 @@ -RulePath = "{$WAF_PATH}/wafconf" -attacklog = "on" -logdir = "{$ROOT_PATH}/wwwlogs/waf/" -UrlDeny="on" -Redirect="on" -CookieMatch="off" -postMatch="off" -whiteModule="on" -black_fileExt={"php","jsp"} -ipWhitelist={"127.0.0.2"} -ipBlocklist={"1.0.0.1"} -CCDeny="off" -CCrate="300/60" +local cpath = "{$WAF_PATH}/" +local logdir = "{$ROOT_PATH}/wwwlogs/waf/" +local json = require "cjson" - - -require 'config' -local match = string.match -local ngxmatch=ngx.re.find -local unescape=ngx.unescape_uri -local get_headers = ngx.req.get_headers -local optionIsOn = function (options) return options == "on" and true or false end -logpath = logdir -rulepath = RulePath -UrlDeny = optionIsOn(UrlDeny) -PostCheck = optionIsOn(postMatch) -CookieCheck = optionIsOn(cookieMatch) -WhiteCheck = optionIsOn(whiteModule) -PathInfoFix = optionIsOn(PathInfoFix) -attacklog = optionIsOn(attacklog) -CCDeny = optionIsOn(CCDeny) -Redirect=optionIsOn(Redirect) -function getClientIp() - IP = ngx.var.remote_addr - if IP == nil then - IP = "unknown" - end - return IP -end -function write(logfile,msg) - local fd = io.open(logfile,"ab") - if fd == nil then return end - fd:write(msg) - fd:flush() - fd:close() -end -function log(method,url,data,ruletag) - if attacklog then - local realIp = getClientIp() - local ua = ngx.var.http_user_agent - local servername=ngx.var.server_name - local time=ngx.localtime() - if ua then - line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n" - else - line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n" - end - local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log" - write(filename,line) - end -end -------------------------------------规则读取函数------------------------------------------------------------------- -function read_rule(var) - file = io.open(rulepath..'/'..var,"r") - if file==nil then - return - end - t = {} - for line in file:lines() do - table.insert(t,line) - end - file:close() - return(t) +function return_message(status,msg) + ngx.header.content_type = "application/json;" + ngx.status = status + ngx.say(json.encode(msg)) + ngx.exit(status) end -urlrules=read_rule('url') -argsrules=read_rule('args') -uarules=read_rule('user-agent') -wturlrules=read_rule('whiteurl') -postrules=read_rule('post') -ckrules=read_rule('cookie') -html=read_rule('returnhtml') -function say_html() - if Redirect then - ngx.header.content_type = "text/html" - ngx.status = ngx.HTTP_FORBIDDEN - ngx.say(html) - ngx.exit(ngx.status) - end +function return_html(status,html) + ngx.header.content_type = "text/html" + ngx.status = status + ngx.say(html) + ngx.exit(status) end -function whiteurl() - if WhiteCheck then - if wturlrules ~=nil then - for _,rule in pairs(wturlrules) do - if ngxmatch(ngx.var.uri,rule,"isjo") then - return true - end - end - end - end - return false -end -function fileExtCheck(ext) - local items = Set(black_fileExt) - ext=string.lower(ext) - if ext then - for rule in pairs(items) do - if ngx.re.match(ext,rule,"isjo") then - log('POST',ngx.var.request_uri,"-","file attack with ext "..ext) - say_html() - end - end - end - return false -end -function Set (list) - local set = {} - for _, l in ipairs(list) do set[l] = true end - return set -end -function args() - for _,rule in pairs(argsrules) do - local args = ngx.req.get_uri_args() - for key, val in pairs(args) do - if type(val)=='table' then - local t={} - for k,v in pairs(val) do - if v == true then - v="" - end - table.insert(t,v) - end - data=table.concat(t, " ") - else - data=val - end - if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"isjo") then - log('GET',ngx.var.request_uri,"-",rule) - say_html() - return true - end - end - end - return false -end - - -function url() - if UrlDeny then - for _,rule in pairs(urlrules) do - if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"isjo") then - log('GET',ngx.var.request_uri,"-",rule) - say_html() - return true - end - end - end - return false -end - -function ua() - local ua = ngx.var.http_user_agent - if ua ~= nil then - for _,rule in pairs(uarules) do - if rule ~="" and ngxmatch(ua,rule,"isjo") then - log('UA',ngx.var.request_uri,"-",rule) - say_html() - return true - end - end - end - return false -end -function body(data) - for _,rule in pairs(postrules) do - if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"isjo") then - log('POST',ngx.var.request_uri,data,rule) - say_html() - return true - end - end - return false -end -function cookie() - local ck = ngx.var.http_cookie - if CookieCheck and ck then - for _,rule in pairs(ckrules) do - if rule ~="" and ngxmatch(ck,rule,"isjo") then - log('Cookie',ngx.var.request_uri,"-",rule) - say_html() - return true - end - end - end - return false -end - -function denycc() - if CCDeny then - local uri=ngx.var.uri - CCcount=tonumber(string.match(CCrate,'(.*)/')) - CCseconds=tonumber(string.match(CCrate,'/(.*)')) - local token = getClientIp()..uri - local limit = ngx.shared.limit - local req,_=limit:get(token) - if req then - if req > CCcount then - ngx.exit(444) - return true - else - limit:incr(token,1) - end - else - limit:set(token,1,CCseconds) - end +function read_file_body(filename) + fp = io.open(filename,'r') + if fp == nil then + return nil end - return false -end - -function get_boundary() - local header = get_headers()["content-type"] - if not header then + fbody = fp:read("*a") + fp:close() + if fbody == '' then return nil end + return fbody +end - if type(header) == "table" then - header = header[1] - end - local m = match(header, ";%s*boundary=\"([^\"]+)\"") - if m then - return m - end +-- local config = read_file_body(cpath .. 'config.json') +local config = json.decode(read_file_body(cpath .. 'config.json')) +-- local site_config = json.decode(read_file_body(cpath .. 'site.json')) - return match(header, ";%s*boundary=([^\",;]+)") -end -function whiteip() - if next(ipWhitelist) ~= nil then - for _,ip in pairs(ipWhitelist) do - if getClientIp()==ip then - return true - end - end - end - return false -end +-- function args() +-- if not config['get']['open'] or not is_site_config('get') then return false end +-- if is_ngx_match(args_rules,uri_request_args,'args') then +-- write_log('args','regular') +-- return_html(config['get']['status'],get_html) +-- return true +-- end +-- return false +-- end -function blockip() - if next(ipBlocklist) ~= nil then - for _,ip in pairs(ipBlocklist) do - if getClientIp()==ip then - ngx.exit(444) - return true - end - end - end - return false +function waf() + -- return_html(200,cpath .. 'config.json') + return_message(200, config) end diff --git a/plugins/op_waf/waf/lua/waf.lua b/plugins/op_waf/waf/lua/waf.lua index 8ce05f46f..d86c145a1 100644 --- a/plugins/op_waf/waf/lua/waf.lua +++ b/plugins/op_waf/waf/lua/waf.lua @@ -1,88 +1 @@ -local content_length=tonumber(ngx.req.get_headers()['content-length']) -local method=ngx.req.get_method() -local ngxmatch=ngx.re.match -if whiteip() then -elseif blockip() then -elseif denycc() then -elseif ngx.var.http_Acunetix_Aspect then - ngx.exit(444) -elseif ngx.var.http_X_Scan_Memo then - ngx.exit(444) -elseif whiteurl() then -elseif ua() then -elseif url() then -elseif args() then -elseif cookie() then -elseif PostCheck then - if method=="POST" then - local boundary = get_boundary() - if boundary then - local len = string.len - local sock, err = ngx.req.socket() - if not sock then - return - end - ngx.req.init_body(128 * 1024) - sock:settimeout(0) - local content_length = nil - content_length=tonumber(ngx.req.get_headers()['content-length']) - local chunk_size = 4096 - if content_length < chunk_size then - chunk_size = content_length - end - local size = 0 - while size < content_length do - local data, err, partial = sock:receive(chunk_size) - data = data or partial - if not data then - return - end - ngx.req.append_body(data) - if body(data) then - return true - end - size = size + len(data) - local m = ngxmatch(data,[[Content-Disposition: form-data;(.+)filename="(.+)\\.(.*)"]],'ijo') - if m then - fileExtCheck(m[3]) - filetranslate = true - else - if ngxmatch(data,"Content-Disposition:",'isjo') then - filetranslate = false - end - if filetranslate==false then - if body(data) then - return true - end - end - end - local less = content_length - size - if less < chunk_size then - chunk_size = less - end - end - ngx.req.finish_body() - else - ngx.req.read_body() - local args = ngx.req.get_post_args() - if not args then - return - end - for key, val in pairs(args) do - if type(val) == "table" then - if type(val[1]) == "boolean" then - return - end - data=table.concat(val, ", ") - else - data=val - end - if data and type(data) ~= "boolean" and body(data) then - body(key) - end - end - end - end -else - return -end +waf() \ No newline at end of file