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,欢迎和我一起完善。 | ||||
| 
 | ||||
| ###用途: | ||||
| 		 | ||||
|     	 | ||||
| 	防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击 | ||||
| 	防止svn/备份之类文件泄漏 | ||||
| 	防止ApacheBench之类压力测试工具的攻击 | ||||
|  | @ -18,29 +18,60 @@ ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用 | |||
| 
 | ||||
| ###效果图如下: | ||||
| 
 | ||||
|  | ||||
|  | ||||
| 
 | ||||
| ###推荐安装: | ||||
| 
 | ||||
| 请自行给nginx安装ngx_lua模块,需要lujit做lua支持 | ||||
| 
 | ||||
| 请提前新建/data/logs/hack/目录攻击日志,并赋予nginx用户对该目录的写入权限。 | ||||
| 请自行给nginx安装ngx_lua模块,推荐使用lujit做lua支持 | ||||
| 
 | ||||
| 
 | ||||
| ###配置部分: | ||||
| ###使用说明: | ||||
| 
 | ||||
| 	编辑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/" | ||||
| 
 | ||||
| 绝对路径如有变动,需对应修改 | ||||
| 
 | ||||
| ###配置文件详细说明: | ||||
| 
 | ||||
|     	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 @@ | |||
| --配置部分 | ||||
| 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" | ||||
| 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") | ||||
| 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) | ||||
| CCrate = CCrate | ||||
| Redirect=optionIsOn(Redirect) | ||||
| ipWhitelist=ipWhitelist | ||||
| function getClientIp() | ||||
|         IP = ngx.req.get_headers()["X-Real-IP"] | ||||
|         if IP == nil then | ||||
|                 IP  = ngx.var.remote_addr  | ||||
|         end | ||||
|     end | ||||
|         if IP == nil then | ||||
|                 IP  = "unknown" | ||||
|         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) | ||||
|  | @ -71,10 +56,149 @@ function read_rule(var) | |||
|         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.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 | ||||
| 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() | ||||
| 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.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.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 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) | ||||
|     else | ||||
|         return | ||||
|  local upload = require "upload" | ||||
|  local content_length=tonumber(ngx.req.get_headers()['content-length']) | ||||
| local method=ngx.req.get_method() | ||||
| if whiteip() 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 form = upload:new(500) | ||||
|             if not form then | ||||
|                 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 | ||||
| else | ||||
|     return | ||||
| 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\/) | ||||
| (gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data|expect)\:\/ | ||||
| \$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[ | ||||
| java\.lang\.Process | ||||
| java\.io\.File | ||||
| \/proc\/(\d+|self)\/environ | ||||
| \<(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
	
	 kindle
						kindle