IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Nginx 的 WAF 规则 LuaJIT 高危险版

    Teacher Du发表于 2023-12-22 16:40:01
    love 0

    前段时间杜老师发表了一篇《自建 CDN 服务器思路》其中介绍南墙 Web 应用防火墙,有些小伙伴们对其名字很感兴趣,而杜老师注意到了它的防护规则,感觉非常实用,顺手整理了下,分享给需要的小伙伴们。此篇为高危险防护规则!

    SQL报错检测

    过滤阶段:返回页面

    规则描述:返回页面的sql报错可能会泄露服务器敏感信息

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    local check = waf.plugins.sqlErrorDetection.check
    local rb = waf.respBody
    local rgx = waf.rgxMatch
    local has = waf.contains

    if waf.status == 500 then
    local m = check(rb)
    if m then
    if rgx(rb, "JET Database Engine|Access Database Engine|\\[Microsoft\\]\\[ODBC Microsoft Access Driver\\]", "jo") then
    return m, "Microsoft Access SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "ORA-[0-9][0-9][0-9][0-9]|java\\.sql\\.SQLException|Oracle error|Oracle.*Driver|Warning.*oci_.*|Warning.*ora_.*", "jo") then
    return m, "Oracle SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "DB2 SQL error:|\\[IBM\\]\\[CLI Driver\\]\\[DB2/6000\\]|CLI Driver.*DB2|DB2 SQL error|db2_\\w+\\(", "jo") then
    return m, "DB2 SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "\\[DM_QUERY_E_SYNTAX\\]|has occurred in the vicinity of:", "jo") then
    return m, "EMC SQL Information Leakage: " .. rb, true
    end
    if has(rb, "Dynamic SQL Error") then
    return m, "firebird SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "Exception (?:condition )?\\d+\\. Transaction rollback\\.", "jo") then
    return m, "Frontbase SQL Information Leakage: " .. rb, true
    end
    if has(rb, "org.hsqldb.jdbc") then
    return m, "hsqldb SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "An illegal character has been found in the statement|com\\.informix\\.jdbc|Exception.*Informix", "jo") then
    return m, "informix SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "Warning.*ingres_|Ingres SQLSTATE|Ingres\\W.*Driver", "jo") then
    return m, "ingres SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "<b>Warning</b>: ibase_|Unexpected end of command in statement", "jo") then
    return m, "interbase SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "SQL error.*POS[0-9]+|Warning.*maxdb", "jo") then
    return m, "maxDB SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "System\\.Data\\.OleDb\\.OleDbException|\\[Microsoft\\]\\[ODBC SQL Server Driver\\]|\\[Macromedia\\]\\[SQLServer JDBC Driver\\]|\\[SqlException|System\\.Data\\.SqlClient\\.SqlException|Unclosed quotation mark after the character string|'80040e14'|mssql_query\\(\\)|Microsoft OLE DB Provider for ODBC Drivers|Microsoft OLE DB Provider for SQL Server|Incorrect syntax near|Sintaxis incorrecta cerca de|Syntax error in string in query expression|Procedure or function .* expects parameter|Unclosed quotation mark before the character string|Syntax error .* in query expression|Data type mismatch in criteria expression\\.|ADODB\\.Field \\(0x800A0BCD\\)|the used select statements have different number of columns|OLE DB.*SQL Server|Warning.*mssql_.*|Driver.*SQL[ _-]*Server|SQL Server.*Driver|SQL Server.*[0-9a-fA-F]{8}|Exception.*\\WSystem\\.Data\\.SqlClient\\.", "jo") then
    return m, "Mssql SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "MyS(?:QL server version for the right syntax to use|qlClient\\.)|(?:supplied argument is not a valid |SQL syntax.*)MySQL|Column count doesn't match(?: value count at row)?|(?:Table '[^']+' doesn't exis|valid MySQL resul)t|You have an error in your SQL syntax(?: near|;)|Warning.{1,10}mysql_(?:[a-z_()]{1,26})?|ERROR [0-9]{4} \\([a-z0-9]{5}\\):|mysql_fetch_array\\(\\)|on MySQL result index|\\[MySQL\\]\\[ODBC", "jo") then
    return m, "Mysql SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "PostgreSQL query failed:|pg_query\\(\\) \\[:|pg_exec\\(\\) \\[:|PostgreSQL.{1,20}ERROR|Warning.*\\bpg_.*|valid PostgreSQL result|Npgsql\\.|PG::[a-zA-Z]*Error|Supplied argument is not a valid PostgreSQL .*? resource|Unable to connect to PostgreSQL server", "jo") then
    return m, "Postgres SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "Warning.*sqlite_|Warning.*SQLite3::|SQLite/JDBCDriver|SQLite\\.Exception|System\\.Data\\.SQLite\\.SQLiteException", "jo") then
    return m, "SQLite SQL Information Leakage: " .. rb, true
    end
    if rgx(rb, "Sybase message:|Warning.{2,20}sybase|Sybase.*Server message", "jo") then
    return m, "Sybase SQL Information Leakage: " .. rb, true
    end
    end
    end

    return false

    数据泄露检测

    过滤阶段:返回页面

    规则描述:从返回页面检测列目录漏洞和源代码泄露问题

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    local rgx = waf.rgxMatch
    local rb = waf.respBody

    local m = rgx(rb, "<(?:TITLE>Index of.*?<H|title>Index of.*?<h)1>Index of|>\\[To Parent Directory\\]</[Aa]><br>", "jo")
    if m then
    return m, "Directory Listing: " .. rb, true
    end

    m = rgx(rb, "^\\s*(?:#\\!\\s?/|<%|<\\?\\s*[^x]|<jsp:)", "jo")
    if m then
    return m, "Source code leak: " .. rb, true
    end

    return false

    固定会话(Session Fixation)攻击

    过滤阶段:请求阶段

    规则描述:会话固定攻击(session fixation attack)是利用应用系统在服务器的会话ID固定不变机制,借助他人用相同的会话ID获取认证和授权,然后利用该会话ID劫持他人的会话以成功冒充他人,造成会话固定攻击。参考:https://owasp.org/www-community/attacks/Session_fixation

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    local kvFilter = waf.kvFilter
    local rgx = waf.rgxMatch
    local referer = waf.referer
    local host = waf.host
    local endWith = waf.endWith

    local function sMatch(v)
    local m = rgx(v, "\\bhttp-equiv\\W+set-cookie\\b", "joi")
    if m then
    return m, v
    end
    return false
    end

    local function nMatch(v)
    local m = rgx(v, "^(?:jsessionid|aspsessionid|asp\\.net_sessionid|phpsession|phpsessid|weblogicsession|session_id|session-id|cfid|cftoken|cfsid|jservsession|jwsession)$", "joi")
    if m then
    return m, v
    end
    return false
    end

    local form = waf.form
    if form then
    local m, d = kvFilter(form["FORM"], sMatch)
    if m then
    return m, d, true
    end
    for k, v in pairs(form["FORM"]) do
    m, d = nMatch(k)
    if m then
    if not referer then
    if type(v) == "table" then
    v = table.concat(v)
    end
    return m, d .. ":" .. v, true
    else
    m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
    if m and not endWith(m[1], host) then
    if type(v) == "table" then
    v = table.concat(v)
    end
    return m, d .. ":" .. v, true
    end
    end
    end
    end
    end

    local queryString = waf.queryString
    if queryString then
    local m, d = kvFilter(queryString, sMatch)
    if m then
    return m, d, true
    end
    for k, v in pairs(queryString) do
    m, d = nMatch(k)
    if m then
    if not referer then
    if type(v) == "table" then
    v = table.concat(v)
    end
    return m, d .. ":" .. v, true
    else
    m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
    if m and not endWith(m[1], host) then
    if type(v) == "table" then
    v = table.concat(v)
    end
    return m, d .. ":" .. v, true
    end
    end
    end
    end
    end

    local cookies = waf.cookies
    if cookies then
    local m, d = kvFilter(cookies, sMatch)
    if m then
    return m, d, true
    end
    end

    return false

    通用攻击

    过滤阶段:请求阶段

    规则描述:本规则拦截ruby、node、js、perl注入和SSRF攻击

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    local kvFilter = waf.kvFilter
    local rgx = waf.rgxMatch

    local function sMatch(v)
    local m = rgx(v, "Process\\s*\\.\\s*spawn\\s*\\(", "jos")
    if m then
    return m, "Ruby Injection Attack: "..v
    end
    m = rgx(v, "t(?:his\\.constructor|runcateSync\\s*\\()|\\b(?:spawn|eval)\\s*\\(|_(?:\\$\\$ND_FUNC\\$\\$_|_js_function)|String\\s*\\.\\s*fromCharCode", "jos")
    if m then
    return m, "Node.js Injection Attack: "..v
    end
    m = rgx(v, "__proto__|constructor\\s*(?:\\.|\\[)\\s*prototype", "jos")
    if m then
    return m, "JavaScript Prototype Pollution: "..v
    end
    m = rgx(v, "(?:s(?:sh(?:2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?)?|m(?:[bs]|tps?)|vn(?:\\+ssh)?|n(?:ews|mp)|ips?|ftp|3)|p(?:op(?:3s?|2)|r(?:oxy|es)|h(?:ar|p)|aparazzi|syc)|c(?:ompress.(?:bzip2|zlib)|a(?:llto|p)|id|vs)|t(?:e(?:amspeak|lnet)|urns?|ftp)|f(?:i(?:nger|sh)|(?:ee)?d|tps?)|i(?:rc[6s]?|maps?|pps?|cap|ax)|d(?:a(?:ta|v)|n(?:tp|s)|ict)|m(?:a(?:ilto|ven)|umble|ms)|n(?:e(?:tdoc|ws)|ntps?|fs)|r(?:tm(?:f?p)?|sync|ar|mi)|v(?:iew-source|entrilo|nc)|a(?:ttachment|f[ps]|cap)|b(?:eshare|itcoin|lob)|g(?:o(?:pher)?|lob|it)|u(?:nreal|t2004|dp)|e(?:xpect|d2k)|h(?:ttps?|323)|w(?:ebcal|s?s)|ja(?:bbe)?r|x(?:mpp|ri)|ldap[is]?|ogg|zip):\\/\\/(?:(?:[\\d.]{0,11}(?:(?:\\xe2(?:\\x92(?:[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5]|[\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]|[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87])|\\x93(?:[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f]|[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9]|[\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xbf\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe]|[\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4])|\\x91(?:[\\xaa\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3]|[\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]))|\\xe3\\x80\\x82))+)|[a-z][\\w\\-\\.]{1,255}:\\d{1,5}(?:#?\\s*&?@(?:(?:\\d{1,3}\\.){3,3}\\d{1,3}|[a-z][\\w\\-\\.]{1,255}):\\d{1,5}\\/?)+|(?:0x[a-f0-9]{2}\\.){3}0x[a-f0-9]{2}|(?:0{1,4}\\d{1,3}\\.){3}0{1,4}\\d{1,3}|\\d{1,3}\\.(?:\\d{1,3}\\.\\d{5}|\\d{8})|0x(?:[a-f0-9]{16}|[a-f0-9]{8})|\\[[a-f\\d:]+(?:[\\d.]+|%\\w+)?\\]|(?:\\x5c\\x5c[a-z\\d-]\\.?_?)+|\\d{10})", "josi")
    if m then
    return m, "Possible Server Side Request Forgery (SSRF) Attack: "..v
    end
    m = rgx(v, "\\@\\{.*?\\}", "jos")
    if m then
    return m, "Perl Injection Attack: "..v
    end
    return false
    end

    local form = waf.form
    if form then
    local m, d = kvFilter(form["FORM"], sMatch)
    if m then
    return m, d, true
    end
    end

    local queryString = waf.queryString
    if queryString then
    local m, d = kvFilter(queryString, sMatch)
    if m then
    return m, d, true
    end
    end

    local cookies = waf.cookies
    if cookies then
    local m, d = kvFilter(cookies, sMatch)
    if m then
    return m, d, true
    end
    end

    local m, d = kvFilter(waf.reqHeaders, sMatch)
    if m then
    return m, d, true
    end
    return false

    php安全规则集

    过滤阶段:请求阶段

    规则描述:检测php相关的对象序列化等漏洞

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    local kvFilter = waf.kvFilter
    local rgx = waf.rgxMatch

    local function sMatch(v)
    local m = rgx(v, "php://(?:std(?:in|out|err)|(?:in|out)put|fd|memory|temp|filter)|(?:ssh2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?|z(?:lib|ip)|(?:ph|r)ar|expect|bzip2|glob|ogg)://", "joi")
    if m then
    return m, v
    end
    m = rgx(v, "[oOcC]:\\d+:\"\\w+\":\\d+:{.*?}", "jos")
    if m then
    return m, v
    end
    return false
    end

    local function fileContentMatch(v)
    local m = rgx(v, "<\\?.+?\\$_(?:GET|POST|COOKIE|REQUEST|SERVER|FILES|SESSION)|<\\?php", "jos")
    if m then
    return m, v
    end
    return false
    end

    local form = waf.form
    if form then
    local m, d = kvFilter(form["FORM"], sMatch)
    if m then
    return m, d, true
    end
    m, d = waf.knFilter(form["FILES"], fileContentMatch, 0)
    if m then
    return m, d, true
    end
    end

    local queryString = waf.queryString
    if queryString then
    local m, d = kvFilter(queryString, sMatch)
    if m then
    return m, d, true
    end
    end

    local cookies = waf.cookies
    if cookies then
    local m, d = kvFilter(cookies, sMatch)
    if m then
    return m, d, true
    end
    end

    local m, d = kvFilter(waf.reqHeaders, sMatch)
    if m then
    return m, d, true
    end
    return false

    路径遍历攻击

    过滤阶段:请求阶段

    规则描述:检测url、上传文件或参数中的路径遍历攻击。采用LFI语义检测引擎,可以检查如://///…\…\etc///passwd等变形攻击。

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    local checkPT = waf.checkPT
    local kvFilter = waf.kvFilter

    local function ptMatch(v)
    local m = checkPT(v)
    if m then
    return m, v
    end
    return false
    end

    local url = waf.urlDecode(waf.reqUri)
    if checkPT(url) then
    return true, url, true
    end

    local form = waf.form
    if form then
    local m, d = kvFilter(form["FORM"], ptMatch)
    if m then
    return m, d, true
    end
    m, d = waf.knFilter(waf.form["FILES"], ptMatch, 1)
    if m then
    return m, d, true
    end
    end

    local queryString = waf.queryString
    if queryString then
    local m, d = kvFilter(queryString, ptMatch)
    if m then
    return m, d, true
    end
    end

    return false

    异常请求字符编码拦截

    过滤阶段:请求阶段

    规则描述:黑客通常会在Content-Type头中使用异常的charset定义字符集编码来绕过waf保护,如IBM037, IBM500, cp875等

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    local rct = waf.reqContentType
    local has = waf.contains
    local counter = waf.strCounter
    local rgx = waf.rgxMatch
    if rct then
    rct = waf.toLower(rct)
    if has(rct, "charset") and (not rgx(rct, "charset\\s*=\\s*(utf\\-8|gbk|gb2312|iso\\-8859\\-1|iso\\-8859\\-15|windows\\-1252)","jo") or counter(rct, "charset") > 1) then
    return true, rct, true
    end
    end
    return false

    代理头sql注入

    过滤阶段:请求阶段

    规则描述:过滤http请求中X-Forwarded-For、Client-IP请求头中单引号sql注入

    规则内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    local rip=waf.reqHeaders.x_forwarded_for
    if rip then
    if type(rip) ~= "string" then
    return true,"Malform X-Forwarded-For",true
    elseif waf.contains(rip,"'") then
    return true,rip,true
    end
    end
    rip=waf.reqHeaders.client_ip
    if rip then
    if type(rip) ~= "string" then
    return true,"Malform Client-IP",true
    elseif waf.contains(rip,"'") then
    return true,rip,true
    end
    end
    return false

    Invalid protocol

    过滤阶段:请求阶段

    规则描述:cookie参数过多

    规则内容:

    1
    2
    3
    4
    if waf.cookies==nil then
    return true,waf.cErr,true
    end
    return false

    Invalid protocol

    过滤阶段:请求阶段

    规则描述:querystring参数过多

    规则内容:

    1
    2
    3
    4
    if waf.queryString==nil then
    return true,waf.qErr,true
    end
    return false


沪ICP备19023445号-2号
友情链接