Compare commits

...

87 Commits

Author SHA1 Message Date
loveshell 314a2f62ec filter some post data
thanks for bajief
2016-04-06 12:17:47 +08:00
loveshell 6606edda34 fix concat table bool and string 2016-01-30 10:20:28 +08:00
loveshell 3492d0601c fix ip 2016-01-10 22:45:34 +08:00
loveshell fa5bf74cbe fix table concat bug 2015-10-28 13:51:45 +08:00
loveshell f609d3296d Update README.md 2015-10-21 12:38:43 +08:00
loveshell 2b1079ee50 fix readme 2015-10-21 12:37:02 +08:00
loveshell 6a38f4fe2d fix symbols 2015-08-24 15:22:41 +08:00
loveshell c0b121a64c fix data is ni 2015-06-23 22:52:33 +08:00
loveshell 14a78d0155 add local var 2015-05-19 20:21:52 +08:00
loveshell 2897e494ea low ngxlua support ngxmatch 2015-05-14 12:09:54 +08:00
loveshell 834c937a83 统一下低版本支持的ngx.re.match 2015-05-14 12:07:14 +08:00
loveshell 20173bd93d find to match 2015-05-14 11:52:56 +08:00
loveshell caff7def0b delete ... 2015-04-28 18:26:26 +08:00
loveshell 1b21447698 w2b 2015-04-19 12:25:52 +08:00
loveshell ee2e656e5a fix match 2015-04-19 12:25:06 +08:00
loveshell ee40966545 修改文件上传的白名单为黑名单 2015-04-19 12:13:08 +08:00
loveshell ca4383accc update black filext 2015-04-19 12:12:33 +08:00
loveshell f03a947767 增加填写可上传文件后缀类型 2015-04-17 22:24:06 +08:00
loveshell 4723116d66 fix regexp 2015-04-17 22:14:03 +08:00
loveshell cd28b33838 添加几个常见文件类型 2015-04-17 22:07:40 +08:00
loveshell 632f120540 临时转义下小写 2015-04-17 22:05:12 +08:00
loveshell a636af1bdd 删除html没用部分 2015-04-08 01:04:17 +08:00
loveshell a2b9a7af93 字符编码修改 2015-04-08 00:59:16 +08:00
loveshell cac5b10168 增加waf拦截的友好提示 2015-04-08 00:42:32 +08:00
loveshell 5440ec88fa 修改拦截响应为403 2015-04-08 00:29:47 +08:00
loveshell aba8bdbc8c 增加文件扩展名的函数处理 2015-04-08 00:20:48 +08:00
loveshell a019ff00b5 增加上传文件白名单 2015-04-08 00:18:57 +08:00
loveshell eaa4055a98 增加post对上传文件的检测流程 2015-04-08 00:18:21 +08:00
loveshell ae8aa78f9f 白名单只对uri做判断 2015-04-07 23:49:55 +08:00
loveshell 564979d0c1 确实存在一处笔误 2015-04-07 23:39:41 +08:00
loveshell 9a2efe4b5c fix regexp opt
测试代码
2015-04-07 23:29:19 +08:00
loveshell 1366d4fc00 白名单url例子写标准点。。。 2015-04-07 23:10:53 +08:00
loveshell 569e08a759 fix post val false 2014-11-18 20:36:16 +08:00
loveshell 3b125676b1 fix args false 2014-09-24 16:19:15 +08:00
loveshell 686219a71c fix post data mpty 2014-09-11 11:39:45 +08:00
loveshell 513c19dea5 Merge pull request #23 from harston/patch-1
Update user-agent
2014-07-14 14:45:58 +08:00
loveshell 33940892a5 fix PCRE_MULTILINE 2014-05-29 11:52:00 +08:00
harston 0d69c30843 Update user-agent
Skipfish default user-agent
2014-05-24 12:02:28 +02:00
loveshell 2b32a34dfc Update waf.lua 2014-04-10 21:45:39 +08:00
loveshell aa5a2fbdbd fix while boundary 2014-04-09 10:46:41 +08:00
loveshell 0c4363524d Update README.md 2013-12-12 17:44:31 +08:00
loveshell b89043f528 Update README.md 2013-12-12 17:43:59 +08:00
loveshell d1bad7299c Update README.md 2013-12-12 17:40:43 +08:00
loveshell ed6b345db3 Update waf.lua 2013-12-12 17:40:23 +08:00
loveshell 047e0278f9 Delete upload.lua 2013-12-12 17:38:26 +08:00
loveshell 2eb22c20a3 delete some rules 2013-12-12 16:14:21 +08:00
loveshell eb09951510 fix get error rules 2013-12-12 16:11:24 +08:00
loveshell 7945598b84 fix post error rules 2013-12-12 16:10:46 +08:00
loveshell 8063e990ae fix deny cc uri 2013-12-10 14:35:12 +08:00
loveshell 340283ac65 fix blockip 2013-12-10 14:05:11 +08:00
loveshell 148271bc0a Update README.md 2013-12-02 09:44:17 +08:00
loveshell 6ecb0d181e fix readme 2013-11-30 10:05:58 +08:00
loveshell f4f36ff0e1 add some instructions 2013-11-30 10:04:24 +08:00
loveshell ae541cfaad Update post 2013-11-30 00:46:58 +08:00
loveshell f18759b045 Update args 2013-11-30 00:46:44 +08:00
loveshell d91e7654b2 Update post 2013-11-30 00:42:10 +08:00
loveshell 1e2491d220 Update args 2013-11-30 00:41:21 +08:00
loveshell f9fa83c49d fix token 2013-11-29 13:06:57 +08:00
loveshell 339d5ebfec Update init.lua 2013-11-19 10:19:28 +08:00
loveshell 842dec7297 Update README.md 2013-11-12 17:02:48 +08:00
loveshell 1be6e81799 Update README.md 2013-11-12 17:02:19 +08:00
loveshell 3a61de52ff Update init.lua 2013-11-12 08:06:03 +08:00
loveshell 27ab0cf42d Update README.md 2013-11-12 08:04:53 +08:00
loveshell 75837ac2d3 Update README.md 2013-11-12 08:04:29 +08:00
loveshell 51c3af7690 Update README.md 2013-11-12 08:03:48 +08:00
loveshell ccc2851160 fix eval ua deny 2013-11-12 01:06:35 +08:00
loveshell 7237a7e7e0 Update README.md 2013-11-11 15:27:26 +08:00
loveshell 749efd6a1a Create post 2013-11-08 23:55:40 +08:00
loveshell 201b62beac Update args 2013-11-08 23:55:15 +08:00
loveshell e1ffb54cc3 Update init.lua 2013-11-08 18:17:05 +08:00
loveshell 87646bb1ef Update init.lua 2013-11-08 10:37:28 +08:00
loveshell 9c98cefeea Update README.md 2013-11-08 10:18:59 +08:00
loveshell ab440f708b Update config.lua 2013-11-08 10:18:26 +08:00
loveshell c63ec5e395 Update init.lua 2013-11-08 10:17:46 +08:00
loveshell aaf0dfc2a9 Update init.lua 2013-11-08 10:16:37 +08:00
loveshell 7ab2b22eda Update README.md 2013-11-08 09:48:36 +08:00
kindle df1710e9ce delete some file 2013-11-07 13:24:04 +08:00
kindle df45c9884a fix empty rules error 2013-11-07 12:44:31 +08:00
kindle 4b99b0de33 add v0.2.1 2013-11-05 21:35:07 +08:00
loveshell 3af50b45e3 Update init.lua 2013-08-07 16:13:46 +08:00
loveshell 9e203bacf8 Update init.lua 2013-08-06 16:59:41 +08:00
loveshell 29267170a4 Update init.lua 2013-08-03 00:22:37 +08:00
loveshell 9926cb5991 Update init.lua 2013-08-03 00:17:55 +08:00
loveshell 7ebb37d4f8 Update waf.lua 2013-08-02 22:21:27 +08:00
loveshell a5746830e3 Update waf.lua 2013-08-01 20:14:18 +08:00
loveshell f315b4870a some add 2013-07-23 22:48:09 +08:00
loveshell bd0d9a1a19 Update install.sh 2013-04-24 16:24:09 +08:00
14 changed files with 526 additions and 238 deletions

115
README.md
View File

@ -4,10 +4,10 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
代码很简单,开发初衷主要是使用简单,高性能和轻量级。
现在开源出来.其中包含我们的过滤规则。如果大家有什么建议和想fa欢迎和我一起完善。
现在开源出来遵从MIT许可协议。其中包含我们的过滤规则。如果大家有什么建议和想fa欢迎和我一起完善。
###用途:
防止sql注入本地包含部分溢出fuzzing测试xss,SSRF等web攻击
防止svn/备份之类文件泄漏
防止ApacheBench之类压力测试工具的攻击
@ -16,31 +16,83 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
屏蔽图片附件类目录php执行权限
防止webshell上传
###效果图如下:
![sec](http://www.sectop.org/wp-content/uploads/2013/03/QQ截图20130323150826.jpg)
###推荐安装:
请自行给nginx安装ngx_lua模块需要lujit做lua支持
推荐使用lujit2.1做lua支持
请提前新建/data/logs/hack/目录攻击日志并赋予nginx用户对该目录的写入权限
ngx_lua如果是0.9.2以上版本建议正则过滤函数改为ngx.re.find匹配效率会提高三倍左右
###配置部分
###使用说明
编辑init.lua配置部分
logpath='/data/logs/hack/'
rulepath='/usr/local/nginx/conf/wafconf/'
syslogserver='127.0.0.1'
如果需要开启syslog传输请取消掉log函数部分的注释
filext是限制上传的文件后缀名
nginx安装路径假设为:/usr/local/nginx/conf/
在nginx.conf的http段添加
init_by_lua_file /usr/local/nginx/conf/init.lua;
access_by_lua_file /usr/local/nginx/conf/waf.lua;
注意:第一次安装配置好需要重启nginx
把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配置
###效果图如下:
![sec](http://i.imgur.com/wTgOcm2.png)
![sec](http://i.imgur.com/DqU30au.png)
###规则更新:
@ -54,8 +106,8 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
过滤规则在wafconf下可根据需求自行调整每条规则需换行,或者用|分割
global是全局过滤文件里面的规则对post和get都过滤
get是只在get请求过滤的规则
args里面的规则get参数进行过滤的
url是只在get请求url过滤的规则
post是只在post请求过滤的规则
whitelist是白名单里面的url匹配到不做过滤
user-agent是对user-agent的过滤规则
@ -66,10 +118,21 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用
日志文件名称格式如下:虚拟主机名_sec.log
###关于
## Copyright
欢迎大家到http://bbs.linuxtone.org 多多交流
weibo: [@ppla](http://weibo.com/opscode)
<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>
感谢ngx_lua模块的开发者[@agentzh](https://github.com/agentzh/),春哥是我所接触过开源精神最好的人

45
config.lua Normal file
View File

@ -0,0 +1,45 @@
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>
]]

335
init.lua
View File

@ -1,114 +1,245 @@
--配置部分
logpath='/data/logs/hack/'
rulepath='/usr/local/nginx/conf/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 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"
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(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")
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
end
return IP
end
--------------------------------------响应函数--------------------------------------------------------------------------------
function check()
ngx.header.content_type = "text/html"
ngx.print("just a joke hehe~ !!")
ngx.exit(200)
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(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.status = ngx.HTTP_FORBIDDEN
ngx.say(html)
ngx.exit(ngx.status)
end
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(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
regex=read_rule('global')
get=read_rule('get')
post=read_rule('post')
agent=read_rule('user-agent')
whitelist=read_rule('whitelist')

View File

@ -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

115
waf.lua
View File

@ -1,33 +1,88 @@
ngx.req.read_body()
if ngx.re.match(ngx.var.request_uri,whitelist,"isjo") then
return
else
if ngx.re.match(ngx.unescape_uri(ngx.var.request_uri),regex.."|"..get,"isjo") then
log('GET',ngx.unescape_uri(ngx.var.request_uri))
check()
-- elseif ngx.re.match(string.gsub(ngx.var.request_uri,"\\%",""),regex.."|"..get,"isjo") then
-- log('GET',ngx.var.request_uri)
-- check()
elseif ngx.re.match(ngx.var.request_uri,[[%00|%0b|%0d|%c0%ae|%0a]],"isjo") then
check()
elseif ngx.var.http_user_agent and ngx.re.match(ngx.var.http_user_agent,regex.."|"..agent,"isjo") then
log('USER-AGENT',ngx.unescape_uri(ngx.var.request_uri))
check()
elseif ngx.req.get_body_data() and ngx.re.match(ngx.req.get_body_data(),[[Content-Disposition: form-data;(.*)filename=]],"isjo") ==nil and ngx.re.match(ngx.unescape_uri(ngx.req.get_body_data()),regex.."|"..post,"isjo") then
log('POST',ngx.unescape_uri(ngx.var.request_uri),ngx.unescape_uri(ngx.req.get_body_data()))
check()
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
check()
end
-- elseif ngx.req.get_headers()["Cookie"] and ngx.re.match(ngx.unescape_uri(ngx.req.get_headers()["Cookie"]),regex,"isjo")then
-- log('COOKIE',ngx.unescape_uri(ngx.var.request_uri),ngx.unescape_uri(ngx.req.get_headers()["Cookie"]))
-- check()
elseif ngx.req.get_headers()['Acunetix-Aspect'] then
ngx.exit(400)
elseif ngx.req.get_headers()['X-Scan-Memo'] then
ngx.exit(400)
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
return
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

22
wafconf/args Normal file
View File

@ -0,0 +1,22 @@
\.\./
\:\$
\$\{
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)\=

20
wafconf/cookie Normal file
View File

@ -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)\[

View File

@ -1,33 +0,0 @@
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

View File

@ -1,39 +0,0 @@
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*:|&colon;|[\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)\[

View File

@ -1 +1,19 @@
\)\.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)\[
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)\=

6
wafconf/url Normal file
View File

@ -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)

View File

@ -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| SF/)

View File

@ -1 +0,0 @@
^/zcms/|^/discuz/

1
wafconf/whiteurl Normal file
View File

@ -0,0 +1 @@
^/123/$