Compare commits
4 Commits
master
...
distribute
Author | SHA1 | Date |
---|---|---|
![]() |
16f85b4733 | |
![]() |
7e2638ed07 | |
![]() |
1283448f44 | |
![]() |
8b74143a0d |
123
README.md
123
README.md
|
@ -4,10 +4,10 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
|
|||
|
||||
代码很简单,开发初衷主要是使用简单,高性能和轻量级。
|
||||
|
||||
现在开源出来,遵从MIT许可协议。其中包含我们的过滤规则。如果大家有什么建议和想fa,欢迎和我一起完善。
|
||||
现在开源出来.其中包含我们的过滤规则。如果大家有什么建议和想fa,欢迎和我一起完善。
|
||||
|
||||
###用途:
|
||||
|
||||
|
||||
防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击
|
||||
防止svn/备份之类文件泄漏
|
||||
防止ApacheBench之类压力测试工具的攻击
|
||||
|
@ -16,83 +16,31 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
|
|||
屏蔽图片附件类目录php执行权限
|
||||
防止webshell上传
|
||||
|
||||
###推荐安装:
|
||||
|
||||
推荐使用lujit2.1做lua支持
|
||||
|
||||
ngx_lua如果是0.9.2以上版本,建议正则过滤函数改为ngx.re.find,匹配效率会提高三倍左右。
|
||||
|
||||
|
||||
###使用说明:
|
||||
|
||||
nginx安装路径假设为:/usr/local/nginx/conf/
|
||||
|
||||
把ngx_lua_waf下载到conf目录下,解压命名为waf
|
||||
|
||||
在nginx.conf的http段添加
|
||||
|
||||
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/"
|
||||
|
||||
绝对路径如有变动,需对应修改
|
||||
|
||||
然后重启nginx即可
|
||||
|
||||
|
||||
###配置文件详细说明:
|
||||
|
||||
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"
|
||||
--是否开启URL白名单
|
||||
black_fileExt={"php","jsp"}
|
||||
--填写不允许上传文件后缀类型
|
||||
ipWhitelist={"127.0.0.1"}
|
||||
--ip白名单,多个ip用逗号分隔
|
||||
ipBlocklist={"1.0.0.1"}
|
||||
--ip黑名单,多个ip用逗号分隔
|
||||
CCDeny="on"
|
||||
--是否开启拦截cc攻击(需要nginx.conf的http段增加lua_shared_dict limit 10m;)
|
||||
CCrate = "100/60"
|
||||
--设置cc攻击频率,单位为秒.
|
||||
--默认1分钟同一个IP只能请求同一个地址100次
|
||||
html=[[Please go away~~]]
|
||||
--警告内容,可在中括号内自定义
|
||||
备注:不要乱动双引号,区分大小写
|
||||
|
||||
###检查规则是否生效
|
||||
|
||||
部署完毕可以尝试如下命令:
|
||||
|
||||
curl http://xxxx/test.php?id=../etc/passwd
|
||||
返回"Please go away~~"字样,说明规则生效。
|
||||
|
||||
注意:默认,本机在白名单不过滤,可自行调整config.lua配置
|
||||
|
||||
|
||||
###效果图如下:
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
###推荐安装:
|
||||
|
||||
请自行给nginx安装ngx_lua模块,需要lujit做lua支持
|
||||
|
||||
请提前新建/data/logs/hack/目录攻击日志,并赋予nginx用户对该目录的写入权限。
|
||||
|
||||
|
||||
###配置部分:
|
||||
|
||||
编辑init.lua配置部分
|
||||
logpath='/data/logs/hack/'
|
||||
rulepath='/usr/local/nginx/conf/wafconf/'
|
||||
syslogserver='127.0.0.1'
|
||||
如果需要开启syslog传输,请取消掉log函数部分的注释
|
||||
filext是限制上传的文件后缀名
|
||||
|
||||
在nginx.conf的http段添加
|
||||
init_by_lua_file /usr/local/nginx/conf/init.lua;
|
||||
access_by_lua_file /usr/local/nginx/conf/waf.lua;
|
||||
|
||||
注意:第一次安装配置好需要重启nginx
|
||||
|
||||
###规则更新:
|
||||
|
||||
|
@ -106,8 +54,8 @@ nginx安装路径假设为:/usr/local/nginx/conf/
|
|||
|
||||
过滤规则在wafconf下,可根据需求自行调整,每条规则需换行,或者用|分割
|
||||
|
||||
args里面的规则get参数进行过滤的
|
||||
url是只在get请求url过滤的规则
|
||||
global是全局过滤文件,里面的规则对post和get都过滤
|
||||
get是只在get请求过滤的规则
|
||||
post是只在post请求过滤的规则
|
||||
whitelist是白名单,里面的url匹配到不做过滤
|
||||
user-agent是对user-agent的过滤规则
|
||||
|
@ -118,21 +66,10 @@ nginx安装路径假设为:/usr/local/nginx/conf/
|
|||
日志文件名称格式如下:虚拟主机名_sec.log
|
||||
|
||||
|
||||
## Copyright
|
||||
###关于
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Weibo</td><td>神奇的魔法师</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Forum</td><td>http://bbs.linuxtone.org/</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Copyright</td><td>Copyright (c) 2013- loveshell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>License</td><td>MIT License</td>
|
||||
</tr>
|
||||
</table>
|
||||
欢迎大家到http://bbs.linuxtone.org 多多交流
|
||||
|
||||
weibo: [@ppla](http://weibo.com/opscode)
|
||||
|
||||
感谢ngx_lua模块的开发者[@agentzh](https://github.com/agentzh/),春哥是我所接触过开源精神最好的人
|
||||
|
|
45
config.lua
45
config.lua
|
@ -1,45 +0,0 @@
|
|||
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
|
||||
attacklog = "on"
|
||||
logdir = "/usr/local/nginx/logs/hack/"
|
||||
UrlDeny="on"
|
||||
Redirect="on"
|
||||
CookieMatch="on"
|
||||
postMatch="on"
|
||||
whiteModule="on"
|
||||
black_fileExt={"php","jsp"}
|
||||
ipWhitelist={"127.0.0.1"}
|
||||
ipBlocklist={"1.0.0.1"}
|
||||
CCDeny="off"
|
||||
CCrate="100/60"
|
||||
html=[[
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>网站防火墙</title>
|
||||
<style>
|
||||
p {
|
||||
line-height:20px;
|
||||
}
|
||||
ul{ list-style-type:none;}
|
||||
li{ list-style-type:none;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style=" padding:0; margin:0; font:14px/1.5 Microsoft Yahei, 宋体,sans-serif; color:#555;">
|
||||
|
||||
<div style="margin: 0 auto; width:1000px; padding-top:70px; overflow:hidden;">
|
||||
|
||||
|
||||
<div style="width:600px; float:left;">
|
||||
<div style=" height:40px; line-height:40px; color:#fff; font-size:16px; overflow:hidden; background:#6bb3f6; padding-left:20px;">网站防火墙 </div>
|
||||
<div style="border:1px dashed #cdcece; border-top:none; font-size:14px; background:#fff; color:#555; line-height:24px; height:220px; padding:20px 20px 0 20px; overflow-y:auto;background:#f3f7f9;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#fc4f03;">您的请求带有不合法参数,已被网站管理员设置拦截!</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">可能原因:您提交的内容包含危险的攻击请求</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;">如何解决:</p>
|
||||
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1)检查提交内容;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2)如网站托管,请联系空间提供商;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3)普通网站访客,请联系网站管理员;</li></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
]]
|
322
init.lua
322
init.lua
|
@ -1,128 +1,120 @@
|
|||
require 'config'
|
||||
local match = string.match
|
||||
local ngxmatch=ngx.re.match
|
||||
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
|
||||
--配置部分
|
||||
logpath='/data/logs/hack/'
|
||||
rulepath='/usr/local/openresty/nginx/conf/ngx_lua_waf/wafconf/'
|
||||
syslogserver='127.0.0.1'
|
||||
filext=''
|
||||
--如果需要开启syslog传输,请取消掉log函数部分的注释
|
||||
--syslog函数和本地日志记录函数
|
||||
local bit = require "bit"
|
||||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local bor = bit.bor
|
||||
ffi.cdef[[
|
||||
int write(int fd, const char *buf, int nbyte);
|
||||
int open(const char *path, int access, int mode);
|
||||
int close(int fd);
|
||||
]]
|
||||
|
||||
local O_RDWR = 0X0002;
|
||||
local O_CREAT = 0x0040;
|
||||
local O_APPEND = 0x0400;
|
||||
local S_IRUSR = 0x0100;
|
||||
local S_IWUSR = 0x0080;
|
||||
function write(logfile,msg)
|
||||
local fd = io.open(logfile,"ab")
|
||||
if fd == nil then return end
|
||||
fd:write(msg)
|
||||
fd:flush()
|
||||
fd:close()
|
||||
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 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)
|
||||
function syslog(msg)
|
||||
ngx.header.content_type = "text/html"
|
||||
kern = 0
|
||||
user = 1
|
||||
mail = 2
|
||||
daemon = 3
|
||||
auth = 4
|
||||
syslog = 5
|
||||
lpr = 6
|
||||
news = 7
|
||||
uucp = 8
|
||||
cron = 9
|
||||
authpriv = 10
|
||||
ftp = 11
|
||||
local0 = 16
|
||||
local1 = 17
|
||||
local2 = 18
|
||||
local3 = 19
|
||||
local4 = 20
|
||||
local5 = 21
|
||||
local6 = 22
|
||||
local7 = 23
|
||||
|
||||
emerg = 0
|
||||
alert = 1
|
||||
crit = 2
|
||||
err = 3
|
||||
warning = 4
|
||||
notice = 5
|
||||
info = 6
|
||||
debug = 7
|
||||
|
||||
|
||||
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
|
||||
level=info
|
||||
facility=daemon
|
||||
sign=level+facility*8
|
||||
ok, err = sock:send('<'..sign..'>'..msg)
|
||||
sock:close()
|
||||
end
|
||||
function log()
|
||||
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().."] \""..ngx.req.get_method().." "..ngx.var.request_uri.."\" \"-\" \""..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().."] \""..ngx.req.get_method().." "..ngx.var.request_uri.."\" \"-\" \"".."-\"\n")
|
||||
end
|
||||
end
|
||||
------------------------------------规则读取函数-------------------------------------------------------------------
|
||||
function read_rule(var)
|
||||
file = io.open(rulepath..'/'..var,"r")
|
||||
if file==nil then
|
||||
return
|
||||
end
|
||||
function getrule(method,dict)
|
||||
local waf = dict;
|
||||
file = io.open(rulepath..'/'..method,"r")
|
||||
t = {}
|
||||
for line in file:lines() do
|
||||
table.insert(t,line)
|
||||
waf.set(waf,line,true)
|
||||
end
|
||||
file:close()
|
||||
return(t)
|
||||
end
|
||||
local update = ngx.shared.update;
|
||||
local updated_at = update:get("updated_at");
|
||||
if updated_at == nil or updated_at < ( ngx.now() - 10 ) then
|
||||
getrule('urlpath',ngx.shared.urlpath)
|
||||
getrule('post',ngx.shared.post)
|
||||
getrule('user-agent',ngx.shared.ua)
|
||||
getrule('args',ngx.shared.args)
|
||||
|
||||
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.status = ngx.HTTP_FORBIDDEN
|
||||
ngx.say(html)
|
||||
ngx.exit(ngx.status)
|
||||
end
|
||||
else
|
||||
update:set("updated_at", ngx.now());
|
||||
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
|
||||
function say_html(ruleid)
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.say('Please go away~~~')
|
||||
log()
|
||||
ngx.exit(200)
|
||||
end
|
||||
function args()
|
||||
for _,rule in pairs(argsrules) do
|
||||
for k,v in pairs(ngx.shared.args:get_keys()) 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()
|
||||
if ngx.re.match(val,v,"isjo") then
|
||||
say_html(k)
|
||||
log('GET')
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -130,116 +122,34 @@ function args()
|
|||
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
|
||||
for k,v in pairs(ngx.shared.urlpath:get_keys()) do
|
||||
if ngx.re.match(ngx.var.request_uri,v,"isjo") then
|
||||
say_html(k)
|
||||
log('GET')
|
||||
return true
|
||||
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
|
||||
for k,v in pairs(ngx.shared.ua:get_keys()) do
|
||||
if ngx.re.match(ngx.var.http_user_agent,v,"isjo") then
|
||||
say_html(k)
|
||||
log('User-agent')
|
||||
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()
|
||||
|
||||
function body()
|
||||
for k,v in pairs(ngx.shared.post:get_keys()) do
|
||||
if ngx.req.get_body_data() and ngx.re.match(ngx.req.get_body_data(),v,"isjo") then
|
||||
say_html(k)
|
||||
log('POST')
|
||||
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(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
|
||||
|
||||
function blockip()
|
||||
if next(ipBlocklist) ~= nil then
|
||||
for _,ip in pairs(ipBlocklist) do
|
||||
if getClientIp()==ip then
|
||||
ngx.exit(403)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
|
10
install.sh
10
install.sh
|
@ -1,6 +1,6 @@
|
|||
mkdir -p /data/src
|
||||
cd /data/src
|
||||
if [ ! -x "LuaJIT-2.0.0.tar.gz" ]; then
|
||||
if [ ! -x "LuaJIT-2.0.0.tar.gz"]; then
|
||||
wget http://luajit.org/download/LuaJIT-2.0.0.tar.gz
|
||||
fi
|
||||
tar zxvf LuaJIT-2.0.0.tar.gz
|
||||
|
@ -9,16 +9,16 @@ make
|
|||
make install PREFIX=/usr/local/lj2
|
||||
ln -s /usr/local/lj2/lib/libluajit-5.1.so.2 /lib64/
|
||||
cd /data/src
|
||||
if [ ! -x "v0.2.17rc2.zip" ]; then
|
||||
if [ ! -x "v0.2.17rc2.zip"]; then
|
||||
wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.17rc2.zip
|
||||
fi
|
||||
unzip v0.2.17rc2
|
||||
if [ ! -x "v0.7.4.zip" ]; then
|
||||
if [ ! -x "v0.7.4.zip"]; then
|
||||
wget https://github.com/chaoslawful/lua-nginx-module/archive/v0.7.4.zip
|
||||
fi
|
||||
unzip v0.7.4
|
||||
cd /data/src
|
||||
if [ ! -x "pcre-8.10.tar.gz" ]; then
|
||||
if [ ! -x "pcre-8.10.tar.gz"]; then
|
||||
wget http://blog.s135.com/soft/linux/nginx_php/pcre/pcre-8.10.tar.gz
|
||||
fi
|
||||
tar zxvf pcre-8.10.tar.gz
|
||||
|
@ -26,7 +26,7 @@ cd pcre-8.10/
|
|||
./configure
|
||||
make && make install
|
||||
cd ..
|
||||
if [ ! -x "nginx-1.2.4.tar.gz" ]; then
|
||||
if [ ! -x "nginx-1.2.4.tar.gz"]; then
|
||||
wget 'http://nginx.org/download/nginx-1.2.4.tar.gz'
|
||||
fi
|
||||
tar -xzvf nginx-1.2.4.tar.gz
|
||||
|
|
97
waf.lua
97
waf.lua
|
@ -1,88 +1,21 @@
|
|||
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
|
||||
ngx.req.read_body()
|
||||
if ngx.req.get_headers()['Acunetix-Aspect'] then
|
||||
ngx.exit(400)
|
||||
elseif ngx.req.get_headers()['X-Scan-Memo'] then
|
||||
ngx.exit(400)
|
||||
end
|
||||
if 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
|
||||
elseif ngx.req.get_body_data() and ngx.re.match(ngx.req.get_body_data(),[[Content-Disposition: form-data;(.*)filename=]],"isjo") ==nil then
|
||||
ngx.req.read_body()
|
||||
body()
|
||||
ngx.req.discard_body()
|
||||
elseif string.len(filext) >0 then
|
||||
if ngx.req.get_body_data() and ngx.re.match(ngx.req.get_body_data(),"Content-Disposition: form-data;(.*)filename=\"(.*)."..filext.."\"","isjo") then
|
||||
ngx.exit('Not Allow Uploaded!!')
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
||||
log('User-agent')
|
||||
|
|
59
wafconf/args
59
wafconf/args
|
@ -1,22 +1,39 @@
|
|||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
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
|
||||
order(.*)by(.*)\d
|
||||
(?:alter\s*\w+.*character\s+set\s+\w+)|(";\s*waitfor\s+time\s+")
|
||||
(?:%c0%ae\/)
|
||||
\<\!ENTITY(.*)SYSTEM(.*)\>
|
||||
(?:\Wselect.+\W*from)|((?:select|create|rename|truncate|alter|delete|update|insert|desc)\s*\(\s*space\s*\()
|
||||
(?:(?:select|create|rename|truncate|alter|delete|update|insert|desc)\s+(?:(?:group_)concat|char|load_file)\s?\(?)|(?:end\s*\);)|("\s+regexp\W)|(?:[\s(]load_file\s*\()
|
||||
(?i:(\%SYSTEMROOT\%))
|
||||
(?:merge.*using\s*\()|(execute\s*immediate\s*")|(?:\W+\d*\s*having\s*[^\s\-])|(?:match\s*[\w(),+-]+\s*against\s*\()
|
||||
(?:\<!-|-->)|(?:<!\[\W)|(?:\]!>)
|
||||
(?:procedure\s+analyse\s*\()|(?:create\s+(procedure|function)\s*\w+\s*\(\s*\)\s*-)|(?:declare[^\w]+[@#]\s*\w+)|(exec\s*\(\s*@)
|
||||
(?:[\s()]case\s*\()|(?:\)\s*like\s*\()|(?:having\s*[^\s]+\s*[^\w\s])|(?:if\s?\([\d\w]\s*[=<>~])
|
||||
(?:(select|;)\s+(?:benchmark|if|sleep)\s*?\(\s*\(?\s*\w+)
|
||||
(?:select\s*pg_sleep)|(?:waitfor\s*delay\s?"+\s?\d)|(?:;\s*shutdown\s*(?:;|--|#|\/\*|{))
|
||||
(?:\sexec\s+xp_cmdshell)|(?:from\W+information_schema\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\s*\([^\)]*)|(?:exec\s+master\.)|(?:union select @)|(?:union[\w(\s]*select)|(?:select.*\w?user\()|(?:into[\s+]+(?:dump|out)file\s*)
|
||||
(?:(sleep\((\s*)(\d*)(\s*)\)|benchmark\((.*)\,(.*)\)))
|
||||
(?:@.+=\s*\(\s*select)|(?:\d\s+group\s+by.+\()|(?:(?:;|#|--)\s*(?:drop|alter))|(?:(?:;|#|--)\s*(?:update|insert)\s*\w{2,})
|
||||
(?:\\u00[a-f0-9]{2})|(?:\\x0*[a-f0-9]{2})|(?:\\\d{2,3})
|
||||
(?:\w\.exe\??\s)|(?:\d\.\dx\|)|(?:%(?:c0\.|af\.|5c\.))|(?:\/(?:%2e){2})
|
||||
(?:%u(?:ff|00|e\d)\w\w)
|
||||
(?:(union(.*)select(.*)))
|
||||
(?:\wscript:|@import[^\w]|;base64|base64,)|(?:\w\s*\([\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+\))
|
||||
\.\.\/
|
||||
substr\(
|
||||
[\s\"'`;\/0-9\=]+on\w+\s*=
|
||||
background\b\W*?:\W*?url|background-image\b\W*?:|behavior\b\W*?:\W*?url|-moz-binding\b|@import\b|expression\b\W*?\(
|
||||
(fromcharcode|alert|eval)\s*\(
|
||||
((?:=|U\s*R\s*L\s*\()\s*[^>]*\s*S\s*C\s*R\s*I\s*P\s*T\s*:|:|[\s\S]allowscriptaccess[\s\S]|[\s\S]data:text\/html[\s\S]|[\s\S]xlink:href[\s\S]|<style[^>]*>[\s\S]*?|[\s\S]@import[\s\S]|<applet[^>]*>[\s\S]*?|<meta[^>]*>[\s\S]*?|<object[^>]*>[\s\S]*?)
|
||||
\<(iframe|script|body|img|layer)
|
||||
(?i:(?:\A|[^\d])0x[a-f\d]{3,}[a-f\d]*)+
|
||||
(?i:(\!\=|\&\&|\|\||>>|<<|>=|<=|<>|<=>|xor|rlike|regexp|isnull)|(?:not\s+between\s+0\s+and)|(?:is\s+null)|(like\s+null)|(?:(?:^|\W)in[+\s]*\([\s\d\"]+[^()]*\))|(?:xor|<>|rlike(?:\s+binary)?)|(?:regexp\s+binary))
|
||||
(?i:(?:m(?:s(?:ysaccessobjects|ysaces|ysobjects|ysqueries|ysrelationships|ysaccessstorage|ysaccessxml|ysmodules|ysmodules2|db)|aster\.\.sysdatabases|ysql\.db)|s(?:ys(?:\.database_name|aux)|chema(?:\W*\(|_name)|qlite(_temp)?_master)|d(?:atabas|b_nam)e\W*\(|information_schema|pg_(catalog|toast)|northwind|tempdb))
|
||||
(%0d|%0a)
|
||||
phpinfo\(
|
||||
(?:\((?:\W*?(?:objectc(?:ategory|lass)|homedirectory|[gu]idnumber|cn)\b\W*?=|[^\w\x80-\xFF]*?[\!\&\|][^\w\x80-\xFF]*?\()|\)[^\w\x80-\xFF]*?\([^\w\x80-\xFF]*?[\!\&\|])
|
||||
\<\!\-\-\W*?#\W*?(?:e(?:cho|xec)|printenv|include|cmd)
|
||||
(?i:(\binclude\s*\([^)]*|mosConfig_absolute_path|_CONF\[path\]|_SERVER\[DOCUMENT_ROOT\]|GALLERY_BASEDIR|path\[docroot\]|appserv_root|config\[root_dir\])=(ht|f)tps?:\/\/)
|
||||
(?:\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)\:\/
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
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)\[
|
20
wafconf/post
20
wafconf/post
|
@ -1,19 +1 @@
|
|||
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)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
||||
\)\.exec\(
|
|
@ -1,6 +0,0 @@
|
|||
\.(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)
|
|
@ -0,0 +1,33 @@
|
|||
injected_by_wvs
|
||||
\.(bak|inc|old|mdb|sql|backup|java|class)$
|
||||
some-inexistent-website
|
||||
boot\.ini
|
||||
never_could_exist_file_nosec
|
||||
SomeCustomInjectedHeader
|
||||
((.*)/(attachments|js|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp))
|
||||
\/proc\/(\d+|self)\/environ
|
||||
.htaccess
|
||||
\<(iframe|script|body|img)
|
||||
\/\!\*
|
||||
\/\*.*?\*\/
|
||||
javascript\:
|
||||
onmouseover\=
|
||||
\.svn
|
||||
ewebeditor
|
||||
\.nsf
|
||||
\.mdb
|
||||
jmx-console
|
||||
javascript\:
|
||||
nosec\.txt
|
||||
thisdoesnotexist
|
||||
phpmyadmin
|
||||
jsky_test\.txt
|
||||
\$\{
|
||||
lang\.Runtime
|
||||
getInputStream
|
||||
getRuntime
|
||||
\)\.exec\(
|
||||
\(\'
|
||||
\"\=
|
||||
jmxinvokerservlet
|
||||
(vhost|bbs|host|wwwroot|www|site|root|hytop|flashfxp).*.rar
|
|
@ -1 +1 @@
|
|||
(HTTrack|harvest|audit|dirbuster|pangolin|nmap|sqln|-scan|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|PycURL|zmeu|BabyKrokodil|netsparker|httperf|bench| SF/)
|
||||
.*(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).*
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
^/zcms/|^/discuz/
|
|
@ -1 +0,0 @@
|
|||
^/123/$
|
Loading…
Reference in New Issue