add v0.2.1
parent
3af50b45e3
commit
4b99b0de33
65
README.md
65
README.md
|
@ -7,7 +7,7 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
|
||||||
现在开源出来.其中包含我们的过滤规则。如果大家有什么建议和想fa,欢迎和我一起完善。
|
现在开源出来.其中包含我们的过滤规则。如果大家有什么建议和想fa,欢迎和我一起完善。
|
||||||
|
|
||||||
###用途:
|
###用途:
|
||||||
|
|
||||||
防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击
|
防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击
|
||||||
防止svn/备份之类文件泄漏
|
防止svn/备份之类文件泄漏
|
||||||
防止ApacheBench之类压力测试工具的攻击
|
防止ApacheBench之类压力测试工具的攻击
|
||||||
|
@ -18,29 +18,60 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
|
||||||
|
|
||||||
###效果图如下:
|
###效果图如下:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
###推荐安装:
|
###推荐安装:
|
||||||
|
|
||||||
请自行给nginx安装ngx_lua模块,需要lujit做lua支持
|
请自行给nginx安装ngx_lua模块,推荐使用lujit做lua支持
|
||||||
|
|
||||||
请提前新建/data/logs/hack/目录攻击日志,并赋予nginx用户对该目录的写入权限。
|
|
||||||
|
|
||||||
|
|
||||||
###配置部分:
|
###使用说明:
|
||||||
|
|
||||||
编辑init.lua配置部分
|
nginx安装路径假设为:/usr/local/nginx/conf/
|
||||||
logpath='/data/logs/hack/'
|
|
||||||
rulepath='/usr/local/nginx/conf/wafconf/'
|
|
||||||
syslogserver='127.0.0.1'
|
|
||||||
如果需要开启syslog传输,请取消掉log函数部分的注释
|
|
||||||
filext是限制上传的文件后缀名
|
|
||||||
|
|
||||||
在nginx.conf的http段添加
|
把ngx_lua_waf下载到conf目录下,解压命名为waf
|
||||||
init_by_lua_file /usr/local/nginx/conf/init.lua;
|
|
||||||
access_by_lua_file /usr/local/nginx/conf/waf.lua;
|
在nginx.conf的http段添加
|
||||||
|
|
||||||
注意:第一次安装配置好需要重启nginx
|
lua_package_path "/usr/local/nginx/conf/waf/?.lua";
|
||||||
|
lua_shared_dict limit 10m;
|
||||||
|
init_by_lua_file /usr/local/nginx/conf/waf/init.lua;
|
||||||
|
access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;
|
||||||
|
|
||||||
|
配置config.lua里的waf规则目录(一般在waf/conf/目录下)
|
||||||
|
|
||||||
|
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
|
||||||
|
|
||||||
|
绝对路径如有变动,需对应修改
|
||||||
|
|
||||||
|
###配置文件详细说明:
|
||||||
|
|
||||||
|
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
|
||||||
|
--规则存放目录
|
||||||
|
attacklog = "off"
|
||||||
|
--是否开启攻击信息记录,需要配置logdir
|
||||||
|
logdir = "/usr/local/nginx/logs/hack/"
|
||||||
|
--log存储目录,该目录需要nginx用户的可写权限
|
||||||
|
UrlDeny="on"
|
||||||
|
--是否拦截url访问
|
||||||
|
Redirect="on"
|
||||||
|
--是否拦截后重定向
|
||||||
|
CookieMatch = "on"
|
||||||
|
--是否拦截cookie攻击
|
||||||
|
postMatch = "on"
|
||||||
|
--是否拦截post攻击
|
||||||
|
whiteModule = "on"
|
||||||
|
--是否开启白名单
|
||||||
|
ipWhitelist={"127.0.0.1"}
|
||||||
|
--ip白名单,多个ip用逗号分隔
|
||||||
|
CCDeny="on"
|
||||||
|
--是否开启拦截cc攻击(需要nginx.conf的http段增加lua_shared_dict limit 10m;)
|
||||||
|
CCrate = "100/60"
|
||||||
|
--设置cc攻击频率,单位为秒.
|
||||||
|
--默认1分钟同一个IP只能请求同一个文件(request_filename)100次
|
||||||
|
html=[[Please go away~~]]
|
||||||
|
--警告内容,可在中括号内自定义
|
||||||
|
备注:不要乱动双引号,区分大小写
|
||||||
|
|
||||||
###规则更新:
|
###规则更新:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
|
||||||
|
attacklog = "off"
|
||||||
|
logdir = "/usr/local/nginx/logs/hack/"
|
||||||
|
UrlDeny="on"
|
||||||
|
Redirect="on"
|
||||||
|
CookieMatch="on"
|
||||||
|
postMatch="on"
|
||||||
|
whiteModule="on"
|
||||||
|
ipWhitelist={"127.0.0.1"}
|
||||||
|
CCDeny="off"
|
||||||
|
CCrate="100/60"
|
||||||
|
html=[[Please go away~~ ]]
|
260
init.lua
260
init.lua
|
@ -1,67 +1,52 @@
|
||||||
--配置部分
|
require 'config'
|
||||||
logpath='/data/logs/hack/'
|
local match = string.match
|
||||||
rulepath='/usr/local/nginx/conf/wafconf/'
|
local ngxmatch=ngx.re.match
|
||||||
syslogserver='127.0.0.1'
|
local unescape=ngx.unescape_uri
|
||||||
filext=''
|
local get_headers = ngx.req.get_headers
|
||||||
--如果需要开启syslog传输,请取消掉log函数部分的注释
|
local optionIsOn = function (options) return options == "on" and true or false end
|
||||||
--syslog函数和本地日志记录函数
|
logpath = logdir
|
||||||
local bit = require "bit"
|
rulepath = RulePath
|
||||||
local ffi = require "ffi"
|
UrlDeny = optionIsOn(UrlDeny)
|
||||||
local C = ffi.C
|
PostCheck = optionIsOn(postMatch)
|
||||||
local bor = bit.bor
|
CookieCheck = optionIsOn(cookieMatch)
|
||||||
ffi.cdef[[
|
WhiteCheck = optionIsOn(whiteModule)
|
||||||
int write(int fd, const char *buf, int nbyte);
|
PathInfoFix = optionIsOn(PathInfoFix)
|
||||||
int open(const char *path, int access, int mode);
|
attacklog = optionIsOn(attacklog)
|
||||||
int close(int fd);
|
CCDeny = optionIsOn(CCDeny)
|
||||||
]]
|
CCrate = CCrate
|
||||||
|
Redirect=optionIsOn(Redirect)
|
||||||
local O_RDWR = 0X0002;
|
ipWhitelist=ipWhitelist
|
||||||
local O_CREAT = 0x0040;
|
function getClientIp()
|
||||||
local O_APPEND = 0x0400;
|
IP = ngx.req.get_headers()["X-Real-IP"]
|
||||||
local S_IRUSR = 0x0100;
|
if IP == nil then
|
||||||
local S_IWUSR = 0x0080;
|
IP = ngx.var.remote_addr
|
||||||
function write(logfile,msg)
|
|
||||||
local logger_fd = C.open(logfile, bor(O_RDWR, O_CREAT, O_APPEND), bor(S_IRUSR,S_IWUSR));
|
|
||||||
local c = msg;
|
|
||||||
C.write(logger_fd, c, #c);
|
|
||||||
C.close(logger_fd)
|
|
||||||
end
|
|
||||||
function syslog(msg)
|
|
||||||
ngx.header.content_type = "text/html"
|
|
||||||
local sock = ngx.socket.udp()
|
|
||||||
local ok, err = sock:setpeername(syslogserver, 514)
|
|
||||||
--上面的ip和端口就是syslog server的ip和端口地址,可自行修改
|
|
||||||
if not ok then
|
|
||||||
ngx.say("failed to connect to syslog server: ", err)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
ok, err = sock:send('<30>'..msg)
|
|
||||||
sock:close()
|
|
||||||
end
|
|
||||||
function log(method,url,data)
|
|
||||||
if data then
|
|
||||||
if ngx.var.http_user_agent then
|
|
||||||
-- syslog(ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \""..data.."\" \""..ngx.status.."\" \""..ngx.var.http_user_agent.."\"\n")
|
|
||||||
write(logpath..'/'..ngx.var.server_name.."_sec.log",ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \""..data.."\" \""..ngx.status.."\" \""..ngx.var.http_user_agent.."\"\n")
|
|
||||||
else
|
|
||||||
-- syslog(ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \""..data.."\" \"-\"\n")
|
|
||||||
write(logpath..'/'..ngx.var.server_name.."_sec.log",ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \""..data.."\" \"-\"\n")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if ngx.var.http_user_agent then
|
|
||||||
-- syslog(ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \"-\" \""..ngx.var.http_user_agent.."\"\n")
|
|
||||||
write(logpath..'/'..ngx.var.server_name.."_sec.log",ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \"-\" \""..ngx.var.http_user_agent.."\"\n")
|
|
||||||
else
|
|
||||||
-- syslog(ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \"-\" \"".."-\"\n")
|
|
||||||
write(logpath..'/'..ngx.var.server_name.."_sec.log",ngx.var.remote_addr.." ".." ["..ngx.localtime().."] \""..method.." "..url.."\" \"-\" \"".."-\"\n")
|
|
||||||
end
|
end
|
||||||
end
|
if IP == nil then
|
||||||
|
IP = "unknown"
|
||||||
|
end
|
||||||
|
return IP
|
||||||
end
|
end
|
||||||
--------------------------------------响应函数--------------------------------------------------------------------------------
|
function write(logfile,msg)
|
||||||
function check()
|
local fd = io.open(logfile,"ab")
|
||||||
ngx.header.content_type = "text/html"
|
if fd == nil then return end
|
||||||
ngx.print("just a joke hehe~ !!")
|
fd:write(msg)
|
||||||
ngx.exit(200)
|
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
|
end
|
||||||
------------------------------------规则读取函数-------------------------------------------------------------------
|
------------------------------------规则读取函数-------------------------------------------------------------------
|
||||||
function read_rule(var)
|
function read_rule(var)
|
||||||
|
@ -71,10 +56,149 @@ function read_rule(var)
|
||||||
table.insert(t,line)
|
table.insert(t,line)
|
||||||
end
|
end
|
||||||
file:close()
|
file:close()
|
||||||
return(table.concat(t,"|"))
|
return(t)
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
function say_html()
|
||||||
|
if Redirect then
|
||||||
|
ngx.header.content_type = "text/html"
|
||||||
|
ngx.say(html)
|
||||||
|
ngx.exit(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function whiteurl()
|
||||||
|
if WhiteCheck then
|
||||||
|
for _,rule in pairs(wturlrules) do
|
||||||
|
if ngxmatch(ngx.var.request_uri,rule,"isjo") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
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
|
||||||
|
data=table.concat(val, " ")
|
||||||
|
else
|
||||||
|
data=val
|
||||||
|
end
|
||||||
|
if data and type(data) ~= "boolean" 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 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
|
||||||
|
for _,rule in pairs(uarules) do
|
||||||
|
if ngxmatch(ua,rule,"isjo") then
|
||||||
|
log('UA',ngx.var.request_uri,"-",rule)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
function body(data)
|
||||||
|
for _,rule in pairs(postrules) do
|
||||||
|
if 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 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
|
||||||
|
CCcount=tonumber(string.match(CCrate,'(.*)/'))
|
||||||
|
CCseconds=tonumber(string.match(CCrate,'/(.*)'))
|
||||||
|
local token=getClientIp()..ngx.var.request_filename
|
||||||
|
local limit = ngx.shared.limit
|
||||||
|
local req,_=limit:get(token)
|
||||||
|
if req then
|
||||||
|
if req > CCcount then
|
||||||
|
ngx.exit(503)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
limit:incr(token,1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
limit:set(token,1,CCseconds)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_boundary()
|
||||||
|
local header = get_headers()["content-type"]
|
||||||
|
if not header then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(header) == "table" then
|
||||||
|
header = header[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
local m = match(header, ";%s*boundary=\"([^\"]+)\"")
|
||||||
|
if m then
|
||||||
|
return m
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
end
|
||||||
regex=read_rule('global')
|
|
||||||
get=read_rule('get')
|
|
||||||
post=read_rule('post')
|
|
||||||
agent=read_rule('user-agent')
|
|
||||||
whitelist=read_rule('whitelist')
|
|
||||||
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
-- Copyright (C) Yichun Zhang (agentzh)
|
||||||
|
|
||||||
|
|
||||||
|
local sub = string.sub
|
||||||
|
local req_socket = ngx.req.socket
|
||||||
|
local null = ngx.null
|
||||||
|
local match = string.match
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local error = error
|
||||||
|
local get_headers = ngx.req.get_headers
|
||||||
|
local type = type
|
||||||
|
local print = print
|
||||||
|
|
||||||
|
|
||||||
|
local _M = { _VERSION = '0.08' }
|
||||||
|
|
||||||
|
|
||||||
|
local MAX_LINE_SIZE = 512
|
||||||
|
|
||||||
|
local STATE_BEGIN = 1
|
||||||
|
local STATE_READING_HEADER = 2
|
||||||
|
local STATE_READING_BODY = 3
|
||||||
|
local STATE_EOF = 4
|
||||||
|
|
||||||
|
|
||||||
|
local mt = { __index = _M }
|
||||||
|
|
||||||
|
local state_handlers
|
||||||
|
|
||||||
|
|
||||||
|
local function get_boundary()
|
||||||
|
local header = get_headers()["content-type"]
|
||||||
|
if not header then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(header) == "table" then
|
||||||
|
header = header[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
local m = match(header, ";%s*boundary=\"([^\"]+)\"")
|
||||||
|
if m then
|
||||||
|
return m
|
||||||
|
end
|
||||||
|
|
||||||
|
return match(header, ";%s*boundary=([^\",;]+)")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function _M.new(self, chunk_size)
|
||||||
|
local boundary = get_boundary()
|
||||||
|
|
||||||
|
print("boundary: ", boundary)
|
||||||
|
|
||||||
|
if not boundary then
|
||||||
|
return nil, "no boundary defined in Content-Type"
|
||||||
|
end
|
||||||
|
|
||||||
|
print('boundary: "', boundary, '"')
|
||||||
|
|
||||||
|
local sock, err = req_socket()
|
||||||
|
if not sock then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local read2boundary, err = sock:receiveuntil("--" .. boundary)
|
||||||
|
if not read2boundary then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local read_line, err = sock:receiveuntil("\r\n")
|
||||||
|
if not read_line then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable({
|
||||||
|
sock = sock,
|
||||||
|
size = chunk_size or 4096,
|
||||||
|
read2boundary = read2boundary,
|
||||||
|
read_line = read_line,
|
||||||
|
boundary = boundary,
|
||||||
|
state = STATE_BEGIN
|
||||||
|
}, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function _M.set_timeout(self, timeout)
|
||||||
|
local sock = self.sock
|
||||||
|
if not sock then
|
||||||
|
return nil, "not initialized"
|
||||||
|
end
|
||||||
|
|
||||||
|
return sock:settimeout(timeout)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function discard_line(self)
|
||||||
|
local read_line = self.read_line
|
||||||
|
|
||||||
|
local line, err = self.read_line(MAX_LINE_SIZE)
|
||||||
|
if not line then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local dummy, err = self.read_line(1)
|
||||||
|
if dummy then
|
||||||
|
return nil, "line too long: " .. line .. dummy .. "..."
|
||||||
|
end
|
||||||
|
|
||||||
|
if err then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function discard_rest(self)
|
||||||
|
local sock = self.sock
|
||||||
|
local size = self.size
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local dummy, err = sock:receive(size)
|
||||||
|
if err and err ~= 'closed' then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
if not dummy then
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function read_body_part(self)
|
||||||
|
local read2boundary = self.read2boundary
|
||||||
|
|
||||||
|
local chunk, err = read2boundary(self.size)
|
||||||
|
if err then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
if not chunk then
|
||||||
|
local sock = self.sock
|
||||||
|
|
||||||
|
local data = sock:receive(2)
|
||||||
|
if data == "--" then
|
||||||
|
local ok, err = discard_rest(self)
|
||||||
|
if not ok then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
self.state = STATE_EOF
|
||||||
|
return "part_end"
|
||||||
|
end
|
||||||
|
|
||||||
|
if data ~= "\r\n" then
|
||||||
|
local ok, err = discard_line(self)
|
||||||
|
if not ok then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.state = STATE_READING_HEADER
|
||||||
|
return "part_end"
|
||||||
|
end
|
||||||
|
|
||||||
|
return "body", chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function read_header(self)
|
||||||
|
local read_line = self.read_line
|
||||||
|
|
||||||
|
local line, err = read_line(MAX_LINE_SIZE)
|
||||||
|
if err then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local dummy, err = read_line(1)
|
||||||
|
if dummy then
|
||||||
|
return nil, nil, "line too long: " .. line .. dummy .. "..."
|
||||||
|
end
|
||||||
|
|
||||||
|
if err then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
-- print("read line: ", line)
|
||||||
|
|
||||||
|
if line == "" then
|
||||||
|
-- after the last header
|
||||||
|
self.state = STATE_READING_BODY
|
||||||
|
return read_body_part(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
local key, value = match(line, "([^: \t]+)%s*:%s*(.+)")
|
||||||
|
if not key then
|
||||||
|
return 'header', line
|
||||||
|
end
|
||||||
|
|
||||||
|
return 'header', {key, value, line}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function eof()
|
||||||
|
return "eof", nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function _M.read(self)
|
||||||
|
local size = self.size
|
||||||
|
|
||||||
|
local handler = state_handlers[self.state]
|
||||||
|
if handler then
|
||||||
|
return handler(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil, "bad state: " .. self.state
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function read_preamble(self)
|
||||||
|
local sock = self.sock
|
||||||
|
if not sock then
|
||||||
|
return nil, nil, "not initialized"
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = self.size
|
||||||
|
local read2boundary = self.read2boundary
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local preamble, err = read2boundary(size)
|
||||||
|
if not preamble then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
-- discard the preamble data chunk
|
||||||
|
-- print("read preamble: ", preamble)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = discard_line(self)
|
||||||
|
if not ok then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local read2boundary, err = sock:receiveuntil("\r\n--" .. self.boundary)
|
||||||
|
if not read2boundary then
|
||||||
|
return nil, nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
self.read2boundary = read2boundary
|
||||||
|
|
||||||
|
self.state = STATE_READING_HEADER
|
||||||
|
return read_header(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
state_handlers = {
|
||||||
|
read_preamble,
|
||||||
|
read_header,
|
||||||
|
read_body_part,
|
||||||
|
eof
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return _M
|
80
waf.lua
80
waf.lua
|
@ -1,24 +1,60 @@
|
||||||
ngx.req.read_body()
|
local upload = require "upload"
|
||||||
if ngx.re.match(ngx.var.request_uri,whitelist,"isjo") then
|
local content_length=tonumber(ngx.req.get_headers()['content-length'])
|
||||||
return
|
local method=ngx.req.get_method()
|
||||||
else
|
if whiteip() then
|
||||||
if ngx.re.match(ngx.unescape_uri(ngx.var.request_uri),regex.."|"..get,"isjo") then
|
elseif denycc() then
|
||||||
log('GET',ngx.unescape_uri(ngx.var.request_uri))
|
elseif ngx.var.http_Acunetix_Aspect then
|
||||||
check()
|
ngx.exit(444)
|
||||||
elseif ngx.var.http_user_agent and ngx.re.match(ngx.var.http_user_agent,regex.."|"..agent,"isjo") then
|
elseif ngx.var.http_X_Scan_Memo then
|
||||||
log('USER-AGENT',ngx.unescape_uri(ngx.var.request_uri))
|
ngx.exit(444)
|
||||||
check()
|
elseif whiteurl() then
|
||||||
elseif ngx.req.get_body_data() and ngx.re.match(ngx.unescape_uri(ngx.req.get_body_data()),regex.."|"..post,"isjo") then
|
elseif ua() then
|
||||||
log('POST',ngx.unescape_uri(ngx.var.request_uri),ngx.unescape_uri(ngx.req.get_body_data()))
|
elseif url() then
|
||||||
check()
|
elseif args() then
|
||||||
elseif ngx.req.get_headers()["Cookie"] and ngx.re.match(ngx.unescape_uri(ngx.req.get_headers()["Cookie"]),regex,"isjo")then
|
elseif cookie() then
|
||||||
log('COOKIE',ngx.unescape_uri(ngx.var.request_uri),ngx.unescape_uri(ngx.req.get_headers()["Cookie"]))
|
elseif PostCheck then
|
||||||
check()
|
if method=="POST" then
|
||||||
elseif ngx.req.get_headers()['Acunetix-Aspect'] then
|
local boundary = get_boundary()
|
||||||
ngx.exit(400)
|
if boundary then
|
||||||
elseif ngx.req.get_headers()['X-Scan-Memo'] then
|
local form = upload:new(500)
|
||||||
ngx.exit(400)
|
if not form then
|
||||||
else
|
return
|
||||||
return
|
end
|
||||||
|
form:set_timeout(1000) -- 1 sec
|
||||||
|
while true do
|
||||||
|
local typ, res, err = form:read()
|
||||||
|
if not typ then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if typ=="body" then
|
||||||
|
body(res)
|
||||||
|
end
|
||||||
|
|
||||||
|
if typ == "eof" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- local typ, res, err = form:read()
|
||||||
|
-- body(res)
|
||||||
|
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
|
||||||
|
data=table.concat(val, ", ")
|
||||||
|
else
|
||||||
|
data=val
|
||||||
|
end
|
||||||
|
if data and type(data) ~= "boolean" and body(data) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
\.\./
|
||||||
|
\:\$
|
||||||
|
\$\{
|
||||||
|
select.+(from|limit)
|
||||||
|
(?:(union(.*?)select))
|
||||||
|
having|rongjitest
|
||||||
|
sleep\((\s*)(\d*)(\s*)\)
|
||||||
|
benchmark\((.*)\,(.*)\)
|
||||||
|
base64_decode\(
|
||||||
|
(?:from\W+information_schema\W)
|
||||||
|
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||||
|
(?:etc\/\W*passwd)
|
||||||
|
into(\s+)+(?:dump|out)file\s*
|
||||||
|
group\s+by.+\(
|
||||||
|
xwork.MethodAccessor
|
||||||
|
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||||
|
xwork\.MethodAccessor
|
||||||
|
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||||
|
java\.lang
|
||||||
|
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
|
@ -0,0 +1,20 @@
|
||||||
|
\.\./
|
||||||
|
\:\$
|
||||||
|
\$\{
|
||||||
|
select.+(from|limit)
|
||||||
|
(?:(union(.*?)select))
|
||||||
|
having|rongjitest
|
||||||
|
sleep\((\s*)(\d*)(\s*)\)
|
||||||
|
benchmark\((.*)\,(.*)\)
|
||||||
|
base64_decode\(
|
||||||
|
(?:from\W+information_schema\W)
|
||||||
|
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||||
|
(?:etc\/\W*passwd)
|
||||||
|
into(\s+)+(?:dump|out)file\s*
|
||||||
|
group\s+by.+\(
|
||||||
|
xwork.MethodAccessor
|
||||||
|
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||||
|
xwork\.MethodAccessor
|
||||||
|
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||||
|
java\.lang
|
||||||
|
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
|
@ -37,6 +37,16 @@ phpinfo\(
|
||||||
(?:\b(?:\.(?:ht(?:access|passwd|group)|www_?acl)|global\.asa|httpd\.conf|boot\.ini)\b|\/etc\/)
|
(?:\b(?:\.(?:ht(?:access|passwd|group)|www_?acl)|global\.asa|httpd\.conf|boot\.ini)\b|\/etc\/)
|
||||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data|expect)\:\/
|
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data|expect)\:\/
|
||||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||||
java\.lang\.Process
|
\/proc\/(\d+|self)\/environ
|
||||||
java\.io\.File
|
\<(iframe|script|body|img)
|
||||||
|
javascript\:
|
||||||
|
onmouseover\=
|
||||||
|
ewebe
|
||||||
|
jmx-console
|
||||||
|
javascript\:
|
||||||
|
phpmyadmin
|
||||||
\$\{
|
\$\{
|
||||||
|
java\.lang
|
||||||
|
\)\.exec\(
|
||||||
|
\(\'
|
||||||
|
\"\=
|
||||||
|
|
21
wafconf/post
21
wafconf/post
|
@ -1 +1,20 @@
|
||||||
\)\.exec\(
|
\.\./
|
||||||
|
\:\$
|
||||||
|
\$\{
|
||||||
|
select.+(from|limit)
|
||||||
|
(?:(union(.*?)select))
|
||||||
|
having|rongjitest
|
||||||
|
sleep\((\s*)(\d*)(\s*)\)
|
||||||
|
benchmark\((.*)\,(.*)\)
|
||||||
|
base64_decode\(
|
||||||
|
(?:from\W+information_schema\W)
|
||||||
|
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||||
|
(?:etc\/\W*passwd)
|
||||||
|
into(\s+)+(?:dump|out)file\s*
|
||||||
|
group\s+by.+\(
|
||||||
|
xwork.MethodAccessor
|
||||||
|
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||||
|
xwork\.MethodAccessor
|
||||||
|
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||||
|
java\.lang
|
||||||
|
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
\.(svn|htaccess|bash_history)
|
||||||
|
\.(bak|inc|old|mdb|sql|backup|java|class)$
|
||||||
|
(vhost|bbs|host|wwwroot|www|site|root|hytop|flashfxp).*.rar
|
||||||
|
(phpmyadmin|jmx-console|jmxinvokerservlet)
|
||||||
|
java\.lang
|
||||||
|
/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp)
|
|
@ -1 +1 @@
|
||||||
.*(LWP::Simple|winhttp|clshttp|HTTrack|harvest|nsauditor|dirbuster|pangolin|nmap|sqlninja|grendel-scan|hydra|perl|HTMLParser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|PycURL|sae|zmeu|BabyKrokodil|python|netsparker|httperf|ApacheBench|webbench).*
|
(HTTrack|harvest|audit|dirbuster|pangolin|nmap|sqln|-scan|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|PycURL|zmeu|BabyKrokodil|netsparker|httperf|bench)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/123/
|
Loading…
Reference in New Issue