\
@@ -1394,7 +1394,7 @@ function siteWafConfig(siteName, type) {
type: 1,
title: "网站配置【" + siteName + "】",
area: ['700px', '500px'],
- closeBtn: 2,
+ closeBtn: 1,
shadeClose: false,
content: '
'
});
diff --git a/plugins/op_waf/t/index.py b/plugins/op_waf/t/index.py
index 65db38e92..59654236b 100644
--- a/plugins/op_waf/t/index.py
+++ b/plugins/op_waf/t/index.py
@@ -22,7 +22,7 @@ from random import Random
TEST_URL = "http://t1.cn/"
-def httpGet(url, timeout):
+def httpGet(url, timeout=10):
import urllib.request
try:
@@ -34,6 +34,19 @@ def httpGet(url, timeout):
return str(e)
+def httpGet__UA(url, ua, timeout=10):
+ import urllib.request
+ headers = {'user-agent': ua}
+ try:
+ req = urllib.request.Request(url, headers=headers)
+ response = urllib.request.urlopen(req)
+ result = response.read().decode('utf-8')
+ return result
+
+ except Exception as e:
+ return str(e)
+
+
def httpPost(url, data, timeout=10):
"""
发送POST请求
@@ -74,15 +87,57 @@ def httpPost(url, data, timeout=10):
def test_Dir():
+ '''
+ 目录保存
+ '''
url = TEST_URL + '?t=../etc/passwd'
print("args test start")
- httpGet(url, 10)
+ url_val = httpGet(url, 10)
+ # print(url_val)
print("args test end")
+def test_UA():
+ '''
+ user-agent 过滤
+ '''
+ url = TEST_URL
+ print("user-agent test start")
+ url_val = httpGet__UA(url, 'ApacheBench')
+ print(url_val)
+ print("user-agent test end")
+
+
+def test_POST():
+ '''
+ user-agent 过滤
+ '''
+ url = TEST_URL
+ print("POST test start")
+ url_val = httpPost(url, {'data': "substr($mmsss,0,1)"})
+ # url_val = httpPost(url, {'data': "123123"})
+ print(url_val)
+ print("POST test end")
+
+
+def test_scan():
+ '''
+ 目录保存
+ '''
+ url = TEST_URL + '/acunetix_wvs_security_test?t=1'
+ print("scan test start")
+ url_val = httpGet(url, 10)
+ print(url_val)
+ print("scan test end")
+
+
def test_start():
test_Dir()
+ test_UA()
+ test_POST()
+ test_scan()
if __name__ == "__main__":
+ os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.1 && sh install.sh install 0.1')
test_start()
diff --git a/plugins/op_waf/waf/lua/common.lua b/plugins/op_waf/waf/lua/common.lua
index f04c1686b..22c6838ef 100644
--- a/plugins/op_waf/waf/lua/common.lua
+++ b/plugins/op_waf/waf/lua/common.lua
@@ -1,26 +1,87 @@
local setmetatable = setmetatable
-local _M = { _VERSION = '0.01' }
+local _M = { _VERSION = '0.02' }
local mt = { __index = _M }
+
local json = require "cjson"
local ngx_match = ngx.re.find
+local debug_mode = false
+
+local waf_root = "{$WAF_ROOT}"
+local cpath = waf_root.."/waf/"
+local logdir = waf_root.."/logs/"
+local rpath = cpath.."/rule/"
+
+function _M.new(self)
-function _M.new(self, cpath, rpath, logdir)
- -- ngx.log(ngx.ERR,"read:"..cpath..",rpath:"..rpath)
- local opt = {
- cpath = cpath,
- rpath = rpath,
- logdir = logdir,
- config = '',
- site_config = '',
- params = nil
+
+ local self = {
+ waf_root = waf_root,
+ cpath = cpath,
+ rpath = rpath,
+ logdir = logdir,
+ config = '',
+ site_config = '',
+ params = nil
}
- local p = setmetatable(opt, mt)
- return p
+ return setmetatable(self, mt)
end
+function _M.setDebug(self, mode)
+ debug_mode = mode
+end
+
+
+-- 调试方式
+function _M.D(self, msg)
+
+ if not debug_mode then return true end
+
+ local _msg = ''
+ if type(msg) == 'table' then
+ for key, val in pairs(msg) do
+ _msg = tostring( key)..':'.."\n"
+ end
+ elseif type(msg) == 'string' then
+ _msg = msg
+ elseif type(msg) == 'nil' then
+ _msg = 'nil'
+ else
+ _msg = msg
+ end
+
+
+ local fp = io.open(waf_root.."/debug.log", "ab")
+ if fp == nil then
+ return nil
+ end
+
+ local localtime = os.date("%Y-%m-%d %H:%M:%S")
+ if server_name then
+ fp:write(tostring(_msg) .. "\n")
+ else
+ fp:write(localtime..":"..tostring(_msg) .. "\n")
+ end
+
+ fp:flush()
+ fp:close()
+ return true
+end
+
+
+local function write_file_clear(filename, body)
+ fp = io.open(filename,'w')
+ if fp == nil then
+ return nil
+ end
+ fp:write(body)
+ fp:flush()
+ fp:close()
+ return true
+end
+
function _M.setConfData( self, config, site_config )
self.config = config
self.site_config = site_config
@@ -94,6 +155,10 @@ function _M.compare_ip(self,ips)
end
+function _M.to_json(self, msg)
+ return json.encode(msg)
+end
+
function _M.return_message(self, status, msg)
ngx.header.content_type = "application/json;"
ngx.status = status
@@ -136,15 +201,9 @@ function _M.write_file(self, filename, body)
return true
end
+
function _M.write_file_clear(self, filename, body)
- fp = io.open(filename,'w')
- if fp == nil then
- return nil
- end
- fp:write(body)
- fp:flush()
- fp:close()
- return true
+ return write_file_clear(filename, body)
end
@@ -234,11 +293,21 @@ function _M.read_file(self, name)
end
function _M.read_file_table( self, name )
- return self:select_rule(self:read_file('args'))
+ return self:select_rule(self:read_file(name))
end
+local function timer_at_inc_log(premature)
+ local total_path = cpath .. 'total.json'
+ local tbody = ngx.shared.limit:get(total_path)
+ if not tbody then
+ return false
+ end
+ return write_file_clear(total_path,tbody)
+end
+
function _M.inc_log(self, name, rule)
+
local server_name = self.params['server_name']
local total_path = self.cpath .. 'total.json'
local tbody = ngx.shared.limit:get(total_path)
@@ -246,7 +315,10 @@ function _M.inc_log(self, name, rule)
tbody = self:read_file_body(total_path)
if not tbody then return false end
end
+
local total = json.decode(tbody)
+
+ -- 开始计算
if not total['sites'] then total['sites'] = {} end
if not total['sites'][server_name] then total['sites'][server_name] = {} end
if not total['sites'][server_name][name] then total['sites'][server_name][name] = 0 end
@@ -256,13 +328,15 @@ function _M.inc_log(self, name, rule)
total['total'] = total['total'] + 1
total['sites'][server_name][name] = total['sites'][server_name][name] + 1
total['rules'][name] = total['rules'][name] + 1
+
local total_log = json.encode(total)
if not total_log then return false end
+
ngx.shared.limit:set(total_path,total_log)
- if not ngx.shared.limit:get('mw_waf_timeout') then
- self:write_file_clear(total_path,total_log)
- ngx.shared.limit:set('mw_waf_timeout',1,5)
- end
+
+ -- 异步执行
+ ngx.timer.at(1, timer_at_inc_log)
+
end
@@ -294,6 +368,54 @@ end
-- end
+function _M.is_ngx_match_orgin(self,rule,match, sign)
+ if ngx_match(ngx.unescape_uri(match), rule,"isjo") then
+ error_rule = rule .. ' >> ' .. sign .. ':' .. match
+ return true
+ end
+ return false
+end
+
+
+function _M.ngx_match_string(self, rules, content,sign)
+ local t = self:is_ngx_match_orgin(rules, content, sign)
+ if t then
+ return true
+ end
+
+ return false
+end
+
+function _M.is_ngx_match_ua(self, rules, content)
+ -- ngx.header.content_type = "text/html"
+ for i,rule in ipairs(rules)
+ do
+ -- 开启的规则,才匹配。
+ if rule[1] == 1 then
+ local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
+ if t then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function _M.is_ngx_match_post(self, rules, content)
+ for i,rule in ipairs(rules)
+ do
+ -- 开启的规则,才匹配。
+ if rule[1] == 1 then
+ local t = self:is_ngx_match_orgin(rule[2],content, rule[3])
+ if t then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+
function _M.is_ngx_match(self, rules, sbody, rule_name)
if rules == nil or sbody == nil then return false end
if type(sbody) == "string" then
@@ -341,6 +463,7 @@ end
function _M.write_log(self, name, rule)
+
local ip = self.params['ip']
local retry = self.config['retry']['retry']
local retry_time = self.config['retry']['retry_time']
diff --git a/plugins/op_waf/waf/lua/init.lua b/plugins/op_waf/waf/lua/init.lua
index 6539aec1f..983a90cef 100644
--- a/plugins/op_waf/waf/lua/init.lua
+++ b/plugins/op_waf/waf/lua/init.lua
@@ -1,47 +1,27 @@
-
-local cpath = "{$WAF_PATH}/"
-local rpath = "{$WAF_PATH}/rule/"
-local logdir = "{$WAF_ROOT}/logs/"
local json = require "cjson"
local ngx_match = ngx.re.find
-local _C = require "common"
-local C = _C:new(cpath, rpath, logdir)
+local __C = require "common"
+local C = __C:new()
+
+local waf_root = "{$WAF_ROOT}"
-config = C:read_file_body_decode(cpath .. 'config.json')
-local site_config = C:read_file_body_decode(cpath .. 'site.json')
+config = C:read_file_body_decode(waf_root.."/waf/"..'config.json')
+local site_config = C:read_file_body_decode(waf_root.."/waf/"..'site.json')
C:setConfData(config, site_config)
--- D func
-local function D(msg)
- local _msg = ''
- if type(msg) == 'table' then
- for key, val in pairs(msg) do
- _msg = key..':'..val.."\n"
- end
- elseif type(msg) == 'string' then
- _msg = msg
- elseif type(msg) == 'nil' then
- _msg = 'nil'
- else
- _msg = msg
- end
- if not debug_mode then return true end
- local fp = io.open(cpath..'debug.log', 'ab')
- if fp == nil then
- return nil
- end
- local localtime = os.date("%Y-%m-%d %H:%M:%S")
- if server_name then
- fp:write(tostring(_msg) .. "\n")
- else
- fp:write(localtime..":"..tostring(_msg) .. "\n")
- end
- fp:flush()
- fp:close()
- return true
-end
+
+local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
+local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
+local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
+local args_rules = C:read_file_table('args')
+local ip_white_rules = C:read_file('ip_white')
+local ip_black_rules = C:read_file('ip_black')
+local scan_black_rules = C:read_file('scan_black')
+local user_agent_rules = C:read_file('user_agent')
+local post_rules = C:read_file('post')
+
function initParams()
local data = {}
@@ -53,13 +33,14 @@ function initParams()
data['uri_request_args'] = ngx.req.get_uri_args()
data['method'] = ngx.req.get_method()
data['request_uri'] = ngx.var.request_uri
+ data['cookie'] = ngx.var.http_cookie
return data
end
local params = initParams()
C:setParams(params)
-
+C:setDebug(true)
function get_return_state(rstate,rmsg)
result = {}
@@ -102,7 +83,7 @@ function save_ip_on(data)
end
end
-function remove_btwaf_drop_ip()
+function remove_waf_drop_ip()
if not uri_request_args['ip'] or not C:is_ipaddr(uri_request_args['ip']) then return get_return_state(true,'格式错误') end
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
@@ -125,7 +106,7 @@ function remove_btwaf_drop_ip()
return get_return_state(true,uri_request_args['ip'] .. '已解封')
end
-function clean_btwaf_drop_ip()
+function clean_waf_drop_ip()
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data2=json.decode(ret2)
@@ -155,14 +136,6 @@ function min_route()
end
end
-local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
-local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
-local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
-local args_rules = C:read_file_table('args')
-local ip_white_rules = C:read_file('ip_white')
-local ip_black_rules = C:read_file('ip_black')
-local scan_black_rules = C:read_file('scan_black')
-
function waf_args()
if not config['get']['open'] or not C:is_site_config('get') then return false end
if C:is_ngx_match(args_rules, params['uri_request_args'],'args') then
@@ -208,9 +181,9 @@ end
function waf_user_agent()
- D("12312")
- if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
- if C:is_ngx_match(user_agent_rules,params['request_header']['user-agent'],'user_agent') then
+ -- user_agent 过滤
+ if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
+ if C:is_ngx_match_ua(user_agent_rules,params['request_header']['user-agent']) then
C:write_log('user_agent','regular')
C:return_html(config['user-agent']['status'],user_agent_html)
return true
@@ -288,20 +261,25 @@ end
function waf_scan_black()
+ -- 扫描软件禁止
if not config['scan']['open'] or not C:is_site_config('scan') then return false end
- if C:is_ngx_match(scan_black_rules['cookie'],params["request_header"]["cookie"],false) then
- C:write_log('scan','regular')
- ngx.exit(config['scan']['status'])
- return true
+ if not params["cookie"] then
+ if C:ngx_match_string(scan_black_rules['cookie'], tostring(params["cookie"]),'scan') then
+ C:write_log('scan','regular')
+ ngx.exit(config['scan']['status'])
+ return true
+ end
end
- if C:is_ngx_match(scan_black_rules['args'],params["request_uri"],false) then
+
+ if C:ngx_match_string(scan_black_rules['args'], params["request_uri"], 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
end
+
for key,value in pairs(params["request_header"])
do
- if C:is_ngx_match(scan_black_rules['header'], key, false) then
+ if C:ngx_match_string(scan_black_rules['header'], key, 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
@@ -334,7 +312,19 @@ function waf_post()
return false
end
- if C:is_ngx_match(post_rules,request_args,'post') then
+ for key, val in pairs(request_args) do
+ if type(val) == "table" then
+ if type(val[1]) == "boolean" then
+ return false
+ end
+ data = table.concat(val, ", ")
+ else
+ data = val
+ end
+
+ end
+
+ if C:is_ngx_match_post(post_rules,data) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
@@ -367,10 +357,11 @@ function post_data_chekc()
end
if not list_list then return false end
- aaa=nil
+
+ aaa = nil
for k,v in pairs(request_args)
do
- aaa=v
+ aaa = v
end
if not aaa then return false end
@@ -382,7 +373,7 @@ function post_data_chekc()
if not data_len then return false end
if arrlen(data_len) ==0 then return false end
- if C:is_ngx_match(post_rules,data_len,'post') then
+ if C:is_ngx_match_post(post_rules , data_len) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
@@ -601,6 +592,8 @@ function waf()
end
waf_args()
+
+ -- 扫描软件禁止
waf_scan_black()
waf_post()
diff --git a/plugins/op_waf/waf/rule/user_agent.json b/plugins/op_waf/waf/rule/user_agent.json
index 57d5d72e9..0f5c5318c 100755
--- a/plugins/op_waf/waf/rule/user_agent.json
+++ b/plugins/op_waf/waf/rule/user_agent.json
@@ -1 +1 @@
-[[1,"(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)","关键词过滤1",0],[2,"(ApacheBench)","AB测试",0]]
\ No newline at end of file
+[[1,"(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)","关键词过滤1",0],[1,"(ApacheBench)","AB测试",0]]
\ No newline at end of file