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.
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 按产品名拉 CVE + PoC 链接(§01 情报源的封装)
5
+
6
+ 用法:
7
+ python3 cvefetch.py nginx
8
+ python3 cvefetch.py "new api" --limit 20
9
+ python3 cvefetch.py wordpress --json
10
+
11
+ 数据源(按顺序尝试):
12
+ 1. cve.circl.lu 最快,响应简洁
13
+ 2. NVD 官方,最全
14
+ 3. GitHub 相关 PoC 仓库
15
+ """
16
+ import argparse, json, ssl, sys, urllib.parse
17
+ import urllib.request, urllib.error
18
+
19
+ CTX = ssl.create_default_context()
20
+ CTX.check_hostname = False
21
+ CTX.verify_mode = ssl.CERT_NONE
22
+ UA = "pentest-pro-cvefetch/1.0"
23
+
24
+
25
+ def get(url, timeout=25):
26
+ try:
27
+ r = urllib.request.Request(url, headers={"User-Agent": UA,
28
+ "Accept": "application/json"})
29
+ with urllib.request.urlopen(r, timeout=timeout, context=CTX) as x:
30
+ return json.loads(x.read(3000000).decode("utf-8", "ignore"))
31
+ except Exception as e:
32
+ return {"_error": str(e)[:80]}
33
+
34
+
35
+ def from_circl(kw, limit):
36
+ """CVE 搜索 — circl(注意:API 端点已变更,失败则返回空,自动回退 NVD)"""
37
+ # 旧端点已失效,尝试新端点
38
+ for u in (f"https://vulnerability.circl.lu/api/search/{urllib.parse.quote(kw)}",
39
+ f"https://cve.circl.lu/api/search/{urllib.parse.quote(kw)}"):
40
+ d = get(u, timeout=20)
41
+ if isinstance(d, dict) and "_error" in d:
42
+ continue
43
+ if isinstance(d, str):
44
+ continue
45
+ items = d if isinstance(d, list) else d.get("data", [])
46
+ if not items:
47
+ continue
48
+ out = []
49
+ for it in items[:limit]:
50
+ cid = it.get("id") or it.get("cve")
51
+ if not cid or not str(cid).startswith("CVE"):
52
+ continue
53
+ out.append({
54
+ "cve": cid,
55
+ "cvss": it.get("cvss") or it.get("cvss31"),
56
+ "summary": (it.get("summary") or it.get("details") or "")[:220],
57
+ "published": (it.get("Published") or it.get("published") or "")[:10],
58
+ "refs": [r if isinstance(r, str) else r.get("url", "")
59
+ for r in (it.get("references") or [])][:3],
60
+ })
61
+ if out:
62
+ return out
63
+ return []
64
+
65
+
66
+ def from_nvd(kw, limit, retries=2):
67
+ u = ("https://services.nvd.nist.gov/rest/json/cves/2.0?"
68
+ f"keywordSearch={urllib.parse.quote(kw)}&resultsPerPage={limit}")
69
+ d = {}
70
+ for _ in range(retries + 1):
71
+ d = get(u, timeout=60)
72
+ if "_error" not in d and "vulnerabilities" in d:
73
+ break
74
+ if "_error" in d or "vulnerabilities" not in d:
75
+ print(f" [NVD 错误] {d.get('_error', 'no vulnerabilities key')}",
76
+ file=sys.stderr)
77
+ return []
78
+ out = []
79
+ for v in d["vulnerabilities"]:
80
+ c = v["cve"]
81
+ metrics = c.get("metrics", {})
82
+ score = None
83
+ for k in ("cvssMetricV31", "cvssMetricV30", "cvssMetricV2"):
84
+ if k in metrics and metrics[k]:
85
+ score = metrics[k][0].get("cvssData", {}).get("baseScore")
86
+ break
87
+ out.append({
88
+ "cve": c["id"],
89
+ "cvss": score,
90
+ "summary": next((d2["value"] for d2 in c.get("descriptions", [])
91
+ if d2["lang"] == "en"), "")[:220],
92
+ "published": c.get("published", "")[:10],
93
+ "refs": [r["url"] for r in c.get("references", [])][:3],
94
+ })
95
+ return out
96
+
97
+
98
+ def from_github(kw, limit):
99
+ """找 PoC 仓库"""
100
+ q = urllib.parse.quote(f"{kw} exploit OR poc OR cve")
101
+ u = f"https://api.github.com/search/repositories?q={q}&sort=stars&per_page={limit}"
102
+ d = get(u)
103
+ if "_error" in d or "items" not in d:
104
+ return []
105
+ return [{"repo": it["full_name"], "stars": it["stargazers_count"],
106
+ "desc": (it.get("description") or "")[:100],
107
+ "url": it["html_url"]}
108
+ for it in d["items"]]
109
+
110
+
111
+ def main():
112
+ ap = argparse.ArgumentParser(description="按产品名拉 CVE + PoC")
113
+ ap.add_argument("keyword")
114
+ ap.add_argument("--limit", type=int, default=15)
115
+ ap.add_argument("--json", action="store_true")
116
+ ap.add_argument("--source", choices=["circl", "nvd", "github", "all"],
117
+ default="all")
118
+ a = ap.parse_args()
119
+
120
+ # ── 先全部取数据,再统一打印(避免流式打印与请求耗时错位)──
121
+ results = {}
122
+ if a.source in ("nvd", "all"):
123
+ print("[*] 查询 NVD...", file=sys.stderr)
124
+ results["nvd"] = from_nvd(a.keyword, a.limit)
125
+ if a.source in ("circl", "all"):
126
+ print("[*] 查询 circl...", file=sys.stderr)
127
+ results["circl"] = from_circl(a.keyword, a.limit)
128
+ if a.source in ("github", "all"):
129
+ print("[*] 查询 GitHub PoC...", file=sys.stderr)
130
+ results["github"] = from_github(a.keyword, min(a.limit, 10))
131
+
132
+ labels = {"nvd": "CVE (NVD)", "circl": "CVE (circl.lu)",
133
+ "github": "PoC 仓库 (GitHub)"}
134
+ i = 0
135
+ for src in ("nvd", "circl", "github"):
136
+ if src not in results:
137
+ continue
138
+ i += 1
139
+ print(f"\n{'='*60}\n[{i}] {labels[src]} — {a.keyword}\n{'='*60}",
140
+ file=sys.stderr)
141
+ rows = results[src]
142
+ if not rows:
143
+ print(" (无结果 / 源不可用)", file=sys.stderr)
144
+ for c in rows:
145
+ if a.json:
146
+ print(json.dumps({"source": src, **c}, ensure_ascii=False))
147
+ elif src == "github":
148
+ print(f"★{c['stars']:<5} {c['repo']}\n {c['desc']}\n {c['url']}")
149
+ else:
150
+ print(f"{c['cve']} CVSS={c['cvss']} {c['published']}\n {c['summary']}")
151
+ for r in c["refs"][:2]:
152
+ print(f" → {r}")
153
+
154
+
155
+ if __name__ == "__main__":
156
+ main()
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 牌组管理器(§01 Step 5.5 · 攻击面牌化)
5
+
6
+ 把每轮攻击收集到的信息变成"牌",供模型自己推演组合。
7
+
8
+ ★ 设计原则:本工具不规定组合规则。
9
+ 只做三件事:① 存牌 ② 呈现牌面 ③ 给思考提示
10
+ 组合效果由模型自己推理 —— 规则写死了就只会那几种。
11
+
12
+ 用法:
13
+ python3 deck.py add --type cred --value "user:pass" --note "普通用户" --from "/api/login"
14
+ python3 deck.py show # 看手里的牌(含牌面分析)
15
+ python3 deck.py show --type cred
16
+ python3 deck.py matrix # 输出组合矩阵(类型交叉表)
17
+ python3 deck.py prompt # 输出推演提示(给模型看的思考题)
18
+ python3 deck.py rm --id 3
19
+ python3 deck.py clear
20
+ python3 deck.py next-round
21
+ """
22
+ import argparse, json, os
23
+ from datetime import datetime, timezone, timedelta
24
+
25
+ BASE = os.path.dirname(os.path.abspath(__file__))
26
+ DECK = os.path.join(BASE, "..", "deck.json")
27
+ CST = timezone(timedelta(hours=8))
28
+
29
+ # ── 牌型定义(只描述"是什么",不规定"能组合出什么")──
30
+ TYPES = {
31
+ "cred": ("凭据", "账号/密码/token/session/cookie/API key"),
32
+ "endpoint": ("端点", "URL/接口/路径(含 403、隐藏的、未授权的)"),
33
+ "leak": ("泄露", "配置/密钥/源码/报错/内网地址"),
34
+ "tech": ("技术栈", "框架/中间件/版本/组件"),
35
+ "vuln": ("弱点", "已确认存在的缺陷(未完全利用)"),
36
+ "perm": ("权限", "角色/授权级别/可访问范围"),
37
+ "data": ("数据", "拿到的业务数据(用户列表/订单/配置)"),
38
+ "bypass": ("绕过", "已验证有效的绕过手法"),
39
+ "infra": ("基建", "IP/端口/子域/证书/云资源"),
40
+ "logic": ("逻辑", "业务流程/状态机/时序特征"),
41
+ "timing": ("时序", "时间窗口/竞态条件/过期策略"),
42
+ "signal": ("信号", "报错模式/响应差异/行为异常"),
43
+ }
44
+
45
+
46
+ def load():
47
+ if os.path.exists(DECK):
48
+ try:
49
+ return json.load(open(DECK))
50
+ except Exception:
51
+ return {"cards": [], "round": 1}
52
+ return {"cards": [], "round": 1}
53
+
54
+
55
+ def save(d):
56
+ json.dump(d, open(DECK, "w"), ensure_ascii=False, indent=1)
57
+
58
+
59
+ def add_card(args):
60
+ d = load()
61
+ cid = max([c["id"] for c in d["cards"]], default=0) + 1
62
+ card = {
63
+ "id": cid, "type": args.type, "value": args.value,
64
+ "note": args.note or "", "source": args.source or "",
65
+ "layer": args.layer or "?", # 逻辑链坐标:在哪一层
66
+ "role": args.role or "?", # 角色:消费者/提供者/中间人
67
+ "conn": args.conn or "", # 连向:上下游是谁
68
+ "round": args.round if args.round else d["round"],
69
+ "ts": datetime.now(CST).strftime("%Y-%m-%d %H:%M"),
70
+ "used": False,
71
+ }
72
+ d["cards"].append(card)
73
+ save(d)
74
+ tname = TYPES.get(args.type, (args.type,))[0]
75
+ print(f"✓ 新增牌 #{cid} [{tname}] {args.value}")
76
+ if card["note"]:
77
+ print(f" 备注: {card['note']}")
78
+ if card["source"]:
79
+ print(f" 来源: {card['source']}")
80
+ if card["layer"] != "?" or card["conn"]:
81
+ print(f" 坐标: {card['layer']} / {card['role']}"
82
+ + (f" / 连向 {card['conn']}" if card["conn"] else ""))
83
+
84
+
85
+ def show(args):
86
+ d = load()
87
+ cards = d["cards"]
88
+ if args.type:
89
+ cards = [c for c in cards if c["type"] == args.type]
90
+ if not cards:
91
+ print("(手里没有牌)")
92
+ return
93
+
94
+ groups = {}
95
+ for c in cards:
96
+ groups.setdefault(c["type"], []).append(c)
97
+
98
+ print("=" * 72)
99
+ print(f" 牌组 — {len(cards)} 张(第 {d['round']} 轮)")
100
+ print("=" * 72)
101
+ for t, items in sorted(groups.items()):
102
+ tname, tdesc = TYPES.get(t, (t, ""))
103
+ print(f"\n【{tname}】{len(items)} 张 — {tdesc}")
104
+ for c in items:
105
+ mark = "✓" if c["used"] else " "
106
+ coord = ""
107
+ if c.get("layer") and c["layer"] != "?":
108
+ coord = f" [{c['layer']}"
109
+ if c.get("role") and c["role"] != "?":
110
+ coord += f"/{c['role']}"
111
+ coord += "]"
112
+ print(f" {mark} #{c['id']:<3} {c['value'][:58]}{coord}")
113
+ if c["note"]:
114
+ print(f" └ {c['note'][:66]}")
115
+ if c.get("conn"):
116
+ print(f" ↕ 连向: {c['conn'][:60]}")
117
+
118
+ # 牌面统计(不是规则,是观察)
119
+ print("\n" + "=" * 72)
120
+ print(" 牌面分析")
121
+ print("=" * 72)
122
+ have = set(groups.keys())
123
+ missing = [t for t in TYPES if t not in have]
124
+ print(f" 已有类型: {', '.join(TYPES.get(t, (t,))[0] for t in have)}")
125
+ print(f" 缺失类型: {', '.join(TYPES.get(t, (t,))[0] for t in missing) or '无'}")
126
+ print(f" 未使用: {len([c for c in cards if not c['used']])} 张")
127
+
128
+
129
+ def matrix(args):
130
+ """输出类型交叉矩阵 —— 只给结构,不给结论"""
131
+ d = load()
132
+ cards = d["cards"]
133
+ if len(cards) < 2:
134
+ print("(牌不足 2 张)")
135
+ return
136
+
137
+ bytype = {}
138
+ for c in cards:
139
+ bytype.setdefault(c["type"], []).append(c)
140
+ ts = sorted(bytype.keys())
141
+
142
+ print("=" * 72)
143
+ print(" 组合矩阵(交叉点 = 该类型对的牌数乘积,供你逐个思考)")
144
+ print("=" * 72)
145
+ hdr = " " + "".join(f"{TYPES.get(t,(t,))[0]:>8}" for t in ts)
146
+ print(hdr)
147
+ for a in ts:
148
+ row = f"{TYPES.get(a,(a,))[0]:>8}"
149
+ for b in ts:
150
+ if a == b:
151
+ n = len(bytype[a]) * (len(bytype[a]) - 1) // 2
152
+ else:
153
+ n = len(bytype[a]) * len(bytype[b])
154
+ row += f"{n:>8}"
155
+ print(row)
156
+
157
+ print(f"\n 共 {len(ts)} 种牌型,{sum(len(bytype[a])*(len(bytype[b])) for a in ts for b in ts if a!=b)//2 + sum(len(bytype[a])*(len(bytype[a])-1)//2 for a in ts)} 个可能的两两组合")
158
+ print("\n 下一步: 用 `deck.py prompt` 拿到思考题,逐个推演")
159
+
160
+
161
+ def prompt(args):
162
+ """输出推演提示 —— 引导思考,不给答案"""
163
+ d = load()
164
+ cards = d["cards"]
165
+ if len(cards) < 2:
166
+ print("(牌不足 2 张)")
167
+ return
168
+
169
+ bytype = {}
170
+ for c in cards:
171
+ bytype.setdefault(c["type"], []).append(c)
172
+
173
+ print("=" * 72)
174
+ print(" 牌组推演提示(★ 组合效果由你自己推理,这里只给思考框架)")
175
+ print("=" * 72)
176
+
177
+ print("""
178
+ ━━━ 第零层:逻辑链坐标(★ 先定位,再推演)━━━
179
+
180
+ 每张牌在产业链上有位置,位置决定它能影响谁:
181
+
182
+ L0 源头/资源层 真实资源提供者
183
+ L1 生产/供给层 把资源加工成商品
184
+ L2 平台/中转层 技术封装
185
+ L3 分销/零售层 面向终端(防护通常最弱)
186
+ L4 终端层 最终用户
187
+
188
+ """)
189
+ for c in cards:
190
+ tname = TYPES.get(c["type"], (c["type"],))[0]
191
+ lay = c.get("layer", "?")
192
+ role = c.get("role", "?")
193
+ conn = c.get("conn", "")
194
+ print(f" #{c['id']} [{tname}] {c['value'][:45]}")
195
+ print(f" 坐标: {lay} / {role}" + (f" / 连向 {conn}" if conn else ""))
196
+ if lay == "?":
197
+ print(" ⚠ 未标注坐标 —— 先想清楚它在链上哪里")
198
+
199
+ print("""
200
+ ━━━ 沿链推演(五个方向,逐个自问)━━━
201
+
202
+ ① ⬆ 向上(最优先)
203
+ 这张牌能不能让我接触它的上游?上游是谁?能不能绕过中间直接打?
204
+ 线索:配置里的上游地址/凭据、报错里的上游域名、代理执行器接口
205
+
206
+ ② ↔ 平行
207
+ 同层其他节点能不能用同样方法打?同款系统?共享凭据?
208
+
209
+ ③ ⬇ 向下
210
+ 能不能影响下游?篡改下发内容?伪造回调?读下游数据?
211
+
212
+ ④ ↺ 自身
213
+ 这张牌本身还能挖多深?权限能不能提?数据能不能扩?隐藏功能?
214
+
215
+ ⑤ ⤴ 跳板(跨层)
216
+ 能不能作为跳板够到其他层?一点撬动整条链?
217
+
218
+ """)
219
+ print(" 你的推演(自己填):\n")
220
+ for c in cards:
221
+ tname = TYPES.get(c["type"], (c["type"],))[0]
222
+ print(f" #{c['id']} [{tname}] {c['value'][:40]}")
223
+ print(" ①向上: ②平行: ③向下: ④自身: ⑤跳板:")
224
+
225
+ print("""
226
+ ━━━ 单张牌的"半成品属性" ━━━
227
+
228
+ 每张牌都是半成品,先问自己:这张牌"还差什么"才能变成完整能力?
229
+
230
+ """)
231
+ for c in cards:
232
+ tname = TYPES.get(c["type"], (c["type"],))[0]
233
+ print(f" #{c['id']} [{tname}] {c['value'][:50]}")
234
+ print(" → 它现在能干什么?还缺什么?")
235
+
236
+ print("""
237
+ ━━━ 第二层:两两组合(自问自答)━━━
238
+
239
+ 对每一对牌,问这四个问题:
240
+
241
+ ① 能不能拼成一条完整攻击链?
242
+ (A 提供"钥匙",B 提供"锁"?)
243
+
244
+ ② A 能不能帮 B 绕过限制?
245
+ (B 被什么挡住?A 里有能解开它的东西吗?)
246
+
247
+ ③ A 能不能扩大 B 的效果?
248
+ (B 只能打一个点,A 能不能让它打一片?)
249
+
250
+ ④ A 和 B 指向的是不是同一个目标?
251
+ (同一个系统/同一个用户/同一条数据流?)
252
+
253
+ """)
254
+ ts = sorted(bytype.keys())
255
+ print(" 你的牌型组合(自己填结论):\n")
256
+ for i, a in enumerate(ts):
257
+ for b in ts[i:]:
258
+ na = TYPES.get(a, (a,))[0]
259
+ nb = TYPES.get(b, (b,))[0]
260
+ if a == b and len(bytype[a]) < 2:
261
+ continue
262
+ print(f" [{na}] × [{nb}]")
263
+ print(" ① 完整链? ② 绕过? ③ 放大? ④ 同目标?")
264
+ print(" → 结论: ")
265
+
266
+ print("""
267
+ ━━━ 第三层:三张以上(链式推演)━━━
268
+
269
+ 如果两两组合都不通,试三张:
270
+ A 打不开 B,但 A + C 可以先拿到 D,再用 D 打开 B
271
+
272
+ 问自己:
273
+ · 我手里有没有"中间态"的牌,能当作跳板?
274
+ · 有没有哪张牌可以"放大"另一张的效果?
275
+ · 所有牌指向的目标之间,有没有信任关系?
276
+
277
+ ━━━ 第四层:缺牌分析 ━━━
278
+
279
+ 推演中如果反复卡在"需要某样东西但我没有":
280
+ → 那就是你的下一张目标牌
281
+ → 回到 §1.6 侧枝探测,专门去搞这张牌
282
+
283
+ ━━━ 第五层:组合的代价 ━━━
284
+
285
+ 每个组合都问:
286
+ · 这个组合会留多少痕迹?(响度)
287
+ · 失败了会不会暴露意图?(可逆性)
288
+ · 有没有更隐蔽的组合能达到同样效果?
289
+ """)
290
+
291
+
292
+ def rm_card(args):
293
+ d = load()
294
+ before = len(d["cards"])
295
+ d["cards"] = [c for c in d["cards"] if c["id"] != args.id]
296
+ save(d)
297
+ print(f"✓ 删除 {before - len(d['cards'])} 张牌")
298
+
299
+
300
+ def clear(args):
301
+ d = load()
302
+ d["cards"] = []
303
+ d["round"] = 1
304
+ save(d)
305
+ print("✓ 牌组已清空")
306
+
307
+
308
+ def next_round(args):
309
+ d = load()
310
+ d["round"] += 1
311
+ for c in d["cards"]:
312
+ c["used"] = False
313
+ save(d)
314
+ print(f"✓ 进入第 {d['round']} 轮(所有牌重置为未使用)")
315
+
316
+
317
+ def main():
318
+ ap = argparse.ArgumentParser(description="牌组管理器 — 攻击面牌化(不规定组合规则)")
319
+ sub = ap.add_subparsers(dest="cmd")
320
+
321
+ p = sub.add_parser("add", help="添加一张牌")
322
+ p.add_argument("--type", required=True, choices=list(TYPES.keys()))
323
+ p.add_argument("--value", required=True)
324
+ p.add_argument("--note", default="")
325
+ p.add_argument("--from", dest="source", default="")
326
+ p.add_argument("--layer", default="", help="逻辑链坐标:L0源头/L1供给/L2平台/L3分销/L4终端")
327
+ p.add_argument("--role", default="", help="角色:消费者/提供者/中间人/旁观者")
328
+ p.add_argument("--conn", default="", help="连向:上游是谁 / 下游是谁")
329
+ p.add_argument("--round", type=int)
330
+ p.set_defaults(func=add_card)
331
+
332
+ p = sub.add_parser("show", help="查看牌组 + 牌面分析")
333
+ p.add_argument("--type")
334
+ p.set_defaults(func=show)
335
+
336
+ p = sub.add_parser("matrix", help="类型交叉矩阵")
337
+ p.set_defaults(func=matrix)
338
+
339
+ p = sub.add_parser("prompt", help="★ 输出推演提示(思考框架)")
340
+ p.set_defaults(func=prompt)
341
+
342
+ p = sub.add_parser("rm", help="删除一张牌")
343
+ p.add_argument("--id", type=int, required=True)
344
+ p.set_defaults(func=rm_card)
345
+
346
+ p = sub.add_parser("clear", help="清空牌组")
347
+ p.set_defaults(func=clear)
348
+
349
+ p = sub.add_parser("next-round", help="进入下一轮")
350
+ p.set_defaults(func=next_round)
351
+
352
+ a = ap.parse_args()
353
+ if not a.cmd:
354
+ ap.print_help()
355
+ print("\n牌型说明:")
356
+ for t, (n, d2) in TYPES.items():
357
+ print(f" {t:<10} {n:<6} {d2}")
358
+ print("\n★ 本工具不规定组合规则 —— 用 `prompt` 拿思考框架,自己推演")
359
+ return
360
+ a.func(a)
361
+
362
+
363
+ if __name__ == "__main__":
364
+ main()