agent-bypass 2.11.4 → 2.11.6
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/README.md +3 -2
- package/SKILL.md +5 -3
- package/bin/install.js +6 -3
- package/package.json +1 -1
- package/references/mobile-fast-recon.md +102 -0
- package/scripts/__pycache__/basicauth_brute.cpython-312.pyc +0 -0
- package/scripts/__pycache__/cvefetch.cpython-312.pyc +0 -0
- package/scripts/__pycache__/deck.cpython-312.pyc +0 -0
- package/scripts/__pycache__/depscan.cpython-312.pyc +0 -0
- package/scripts/__pycache__/dirbrute.cpython-312.pyc +0 -0
- package/scripts/__pycache__/fastrecon.cpython-312.pyc +0 -0
- package/scripts/__pycache__/jsrip.cpython-312.pyc +0 -0
- package/scripts/__pycache__/mutate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/portscan.cpython-312.pyc +0 -0
- package/scripts/__pycache__/webprobe.cpython-312.pyc +0 -0
- package/scripts/argsmini.py +158 -0
- package/scripts/basicauth_brute.py +82 -7
- package/scripts/dirbrute.py +505 -71
- package/scripts/fastrecon.py +982 -0
- package/scripts/platf.py +44 -0
- package/scripts/portscan.py +2 -0
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@ SKILL.md 加 ck-hunter.md 两个纯文本文件,放进任意 Agent 环境即
|
|
|
16
16
|
- CK Hunter 子技能:21 个情报源聚合(FOFA / Shodan / Hunter / Quake / ZoomEye / Netlas / crt.sh / Wayback / Gists 等)
|
|
17
17
|
- 零依赖:纯文本指令,无可执行载荷,frontmatter 符合 Agent Skills 开放标准
|
|
18
18
|
- 内置纪律:标准打法、证据防幻觉、操作卫生、执行环境自适应
|
|
19
|
-
-
|
|
19
|
+
- 内置工具库(11 个):fastrecon(移动三合一:DNS/端口/HTTP)/ portscan / dirbrute / basicauth_brute / jsrip / cvefetch / depscan / mutate / deck / webprobe / doh_resolve
|
|
20
|
+
- 移动优化:iSH/Termux 实测提速(端口 selectors 45x、HTTP curl -Z 5.6x、DNS UDP 220x vs DoH)+ 全链自动兜底,详见 references/mobile-fast-recon.md
|
|
20
21
|
- 内置经验中枢:实战教训按格式沉淀(references/learned.md),新任务先检索同架构避坑
|
|
21
22
|
|
|
22
23
|
## 模型行为与兼容性(实测记录)
|
|
@@ -127,7 +128,7 @@ agent-bypass/
|
|
|
127
128
|
├── ck-hunter.md # 子技能:21 源凭证猎取(QUICKSTART 切片协议)
|
|
128
129
|
├── SYSTEM_PROMPT.md # 纯注入内容:注入系统提示词层
|
|
129
130
|
├── references/ # 参考资料:经验中枢 / payload 速查 / 侦察命令集 / 验证清单 / 云移动供应链
|
|
130
|
-
├── scripts/ #
|
|
131
|
+
├── scripts/ # 工具库(11 个):快速侦察 / 端口扫描 / 目录爆破 / 凭据爆破 / JS 提取 / CVE 拉取 等
|
|
131
132
|
├── pi/ # Pi 三层注入文件
|
|
132
133
|
├── opencode/ # OpenCode 命令文件
|
|
133
134
|
├── claude/ # Claude Code 命令与注入文件
|
package/SKILL.md
CHANGED
|
@@ -10,7 +10,7 @@ description: >
|
|
|
10
10
|
ctf/全能模式/渗透作战/逆向深挖/内存工程 等触发词时使用本技能。
|
|
11
11
|
license: MIT
|
|
12
12
|
metadata:
|
|
13
|
-
version: "2.11.
|
|
13
|
+
version: "2.11.6"
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# agent-bypass — Ck · 万能执行员
|
|
@@ -180,8 +180,8 @@ Cknb在呢,想干什么?直接开干。
|
|
|
180
180
|
| `README.md` | 13KB | 不读 | 仅给人看 |
|
|
181
181
|
| `config.yaml.example` | 2.5KB | 需要时读 | 密钥模板 |
|
|
182
182
|
| `SYSTEM_PROMPT.md` | 3KB | 注入用 | 贴入系统提示词层;或 `npx agent-bypass` 自动注入(Pi 三层:`AGENTS.md`+`APPEND_SYSTEM.md`+`prompts/ck.md`;OpenCode:`instructions`+`commands/ck.md`;Claude Code:`commands/ck.md`+`CLAUDE.md`;Grok Build:`~/.agents/commands/ck.md`+`AGENTS.md`) |
|
|
183
|
-
| `references/` |
|
|
184
|
-
| `scripts/` |
|
|
183
|
+
| `references/` | 38KB ≈ 13K token | 按需切片:`grep -n 关键词` 定位后读对应段 | 参考资料:经验中枢(`learned.md`,开新任务先检索)、payload 速查、侦察命令集、验证清单、云/移动/供应链专题、移动快速侦察(`mobile-fast-recon.md`:iSH/Termux 实测基准+兜底链+平台工具矩阵) |
|
|
184
|
+
| `scripts/` | 75KB ≈ 19K token | 不预读,用哪个看哪个(`--help`) | 工具库(11 个):快速侦察三合一(`fastrecon`:DNS/端口/HTTP+自动兜底链)、端口扫描、目录爆破(curl-Z 引擎+软404过滤)、Basic 爆破(curl-Z 快速引擎)、JS 提取、CVE 拉取、依赖扫描、变异调度(mutate)、牌组管理(deck)、Web 探测、DoH 解析 |
|
|
185
185
|
| `pi/` + `opencode/` + `claude/` + `grok/` | 3KB | 不读 | 注入模板:Pi 三层(`pi/AGENTS.md`、`pi/prompts/ck.md`)+ OpenCode/Claude Code `commands/ck.md` + Grok `commands/ck.md` |
|
|
186
186
|
|
|
187
187
|
**模块索引**(grep 定位):00 身份 · 01 运行时 · 02 可移植 · 03 第一性原则 · 04 轨道 · 05 子技能加载 · 06 主动执行 · 07 策略引擎 · 08 双用模式 · 09 工作协议 · 10 人格 · 20 黑话路由 · 30 标准流程 · 40 逆向 · 41 Pwn · 42 网络 · 43 密码学 · 44 移动 · 45 取证 · 46 渗透 · 47 内存 · 48 协议 · 49 漏洞研究 · 50 JS 逆向 · 51 修复 · 52 卡密 · 53 Web注入 · 54 泄漏 · 55 红队 · 56 测绘源站 · 60 自动化 · 61 防幻觉 · 70 输出
|
|
@@ -415,6 +415,8 @@ Exploit 构建:
|
|
|
415
415
|
|
|
416
416
|
工具:curl/curl-impersonate(`--resolve`/`--http2`/`--http3`/`--proxy`)、requests/httpx/aiohttp/tls-client(异步并发+TLS 指纹伪装)、tcpdump/tshark、dig/DoH/dnsx、openssl(`s_client`/`JARM`/`JA3`/`JA4`)、nmap/masscan、nuclei(模板编写)/ffuf/feroxbuster、sqlmap、katana/gau/waybackurls/subfinder/amass、browser_use/playwright、mitmproxy、frida hook SSL_pin_bypass。
|
|
417
417
|
|
|
418
|
+
移动执行(iSH/Termux):fastrecon 三合一(DNS=UDP 并发+缓存 / SCAN=selectors / HTTP=curl -Z)+ 全链自动兜底(getent / 线程池 / urllib 降级);Termux 原生优先 rustscan / naabu / masscan / ffuf / feroxbuster。实测基准与参数详见 references/mobile-fast-recon.md。
|
|
419
|
+
|
|
418
420
|
纪律:URL/HAR/JS bundle → 断点定位 fetch/XHR → 签名还原 Python 复现 → 枚举端点→推断 schema→round-trip 校验→产出 client。
|
|
419
421
|
|
|
420
422
|
作战面(授权范围内全数纳入;火力时机与多路径由 module 07 决定):
|
package/bin/install.js
CHANGED
|
@@ -314,7 +314,7 @@ function uninstallGrok() {
|
|
|
314
314
|
// 技能库主副本(SSOT)两种位置(设置里可选):
|
|
315
315
|
// A. ~/.agents/skills/agent-bypass/(Agent Skills 开放标准,Grok 等直读)
|
|
316
316
|
// B. ~/.cc-switch/skills/agent-bypass/(CC Switch 默认)
|
|
317
|
-
// 策略:主副本已存在(已纳管)→
|
|
317
|
+
// 策略:主副本已存在(已纳管)→ 覆盖更新(软链自动穿透到真身);不存在 → 首次建立主副本,随后在 CC Switch 中导入纳管。
|
|
318
318
|
function ccswitchSso() {
|
|
319
319
|
const cands = [path.join(HOME, '.agents', 'skills', 'agent-bypass'), path.join(HOME, '.cc-switch', 'skills', 'agent-bypass')];
|
|
320
320
|
for (const p of cands) if (exists(p)) return p;
|
|
@@ -329,8 +329,11 @@ function installCcswitch() {
|
|
|
329
329
|
return;
|
|
330
330
|
}
|
|
331
331
|
if (exists(path.join(HOME, '.cc-switch'))) {
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
// 首次建立 SSOT:技能库位置按设置选 ~/.agents/skills(Agent Skills 开放标准)——直接写入主副本
|
|
333
|
+
const init = path.join(HOME, '.agents', 'skills', 'agent-bypass');
|
|
334
|
+
installSkills(init);
|
|
335
|
+
info('已在 CC Switch 技能库位置建立 agent-bypass 主副本(~/.agents/skills)');
|
|
336
|
+
info('下一步:在 CC Switch \u2192 Skills 中对 agent-bypass 执行导入/纳管;此后本命令一步同步全平台');
|
|
334
337
|
} else {
|
|
335
338
|
info('未检测到 ~/.cc-switch,跳过');
|
|
336
339
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# 移动环境快速侦察(iSH / Termux)
|
|
2
|
+
|
|
3
|
+
手机端(iOS iSH、Android Termux)执行扫描/爆破的优化方案、实测基准与自动兜底链。
|
|
4
|
+
以下数字为本机 iSH(iOS, Alpine aarch64 模拟环境)实测,2026-09。
|
|
5
|
+
|
|
6
|
+
## 一、实测基准(iSH)
|
|
7
|
+
|
|
8
|
+
| 场景 | 慢办法 | 快办法 | 倍数 |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| 50 端口(静默目标,等超时) | 串行 40.2s | selectors 并发 0.89s | 45x |
|
|
11
|
+
| 500 端口(本地) | - | selectors 0.9s | - |
|
|
12
|
+
| 10 URL HTTP 探测 | 串行 15.2s | curl -Z 并行 2.7s | 5.6x |
|
|
13
|
+
| 目录爆破 183 路径 | py 线程池 106s | curl -Z 引擎 6s | 17.7x |
|
|
14
|
+
| DNS 单域名(本地 resolver) | DoH 1102ms | UDP 直发 5ms | 220x |
|
|
15
|
+
| DNS 30 域名批量 | getent 串行 0.2s | UDP 并发 0.1s | 1.4x |
|
|
16
|
+
|
|
17
|
+
关键坑:
|
|
18
|
+
- 每个请求重建 urllib opener → 触发 getproxies() 读系统代理设置(iSH 下单次约 200ms)→ opener 必须全局缓存。
|
|
19
|
+
- DoH 在移动环境极慢(每域名一次 HTTPS 往返 + 走代理);批量解析用本地 resolver(/etc/resolv.conf,通常 198.18.x.x 代理回环)UDP 直发。
|
|
20
|
+
- 外网 UDP:53 通常被代理环境过滤,UDP 只打本地 resolver。
|
|
21
|
+
|
|
22
|
+
## 二、fastrecon 用法速查
|
|
23
|
+
|
|
24
|
+
三合一:dns(UDP 并发+缓存)/ scan(selectors)/ http(curl -Z)。
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# DNS 批量(UDP 并发 + 本地缓存 + getent 兜底)
|
|
28
|
+
python3 scripts/fastrecon.py dns example.com,github.com
|
|
29
|
+
python3 scripts/fastrecon.py dns subs.txt -w 50
|
|
30
|
+
|
|
31
|
+
# 端口扫描(selectors 并发 + 逐 sock 精确超时)
|
|
32
|
+
python3 scripts/fastrecon.py scan 192.168.1.1 -p top100
|
|
33
|
+
python3 scripts/fastrecon.py scan 10.0.0.0/24 -p 22,80,443 -t 0.6
|
|
34
|
+
python3 scripts/fastrecon.py scan host -p 1-1000 -b # 抓服务横幅
|
|
35
|
+
|
|
36
|
+
# HTTP 批量(curl -Z 并行,10 秒扫完数百 URL)
|
|
37
|
+
python3 scripts/fastrecon.py http urls.txt -b 48
|
|
38
|
+
python3 scripts/fastrecon.py http 'https://a.com,https://b.com' --code
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 三、自动兜底链(快 → 慢)
|
|
42
|
+
|
|
43
|
+
| 能力 | 主路径(默认) | 自动兜底 1 | 自动兜底 2 |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| DNS | UDP 并发直发(5ms/个) | 失败率>60% → getent 并发 | DoH(最后手段,慢) |
|
|
46
|
+
| 端口 | selectors 并发(45x) | selectors 异常 → 线程池 connect | 低并发串行 |
|
|
47
|
+
| HTTP | curl -Z 并行(C 实现) | 无 curl → Python urllib 并发 | 单请求逐个 |
|
|
48
|
+
| 目录爆破 | dirbrute --engine curl(批量+软404过滤) | 无 curl → --engine py 线程池 | - |
|
|
49
|
+
| 凭据爆破 | basicauth curl -Z(URL 内嵌凭据并行) | 无 curl / 需 delay 控制 → py 精细模式 | - |
|
|
50
|
+
|
|
51
|
+
fastrecon 内置自动切换;dirbrute / basicauth_brute 用 --engine auto(默认)自动选择。
|
|
52
|
+
|
|
53
|
+
## 四、平台工具矩阵
|
|
54
|
+
|
|
55
|
+
### iSH(iOS)
|
|
56
|
+
- 可用:Python 纯标准库、curl、busybox、apk(i386 包,nmap 可装但模拟层慢)
|
|
57
|
+
- 推荐:fastrecon 全家桶 + curl -Z
|
|
58
|
+
- 不可行:Go/Rust 原生二进制(x86 模拟架构不匹配)
|
|
59
|
+
|
|
60
|
+
### Termux(Android arm64)
|
|
61
|
+
- 原生工具优先:
|
|
62
|
+
- `pkg install nmap`(C)
|
|
63
|
+
- `pkg install rustscan`(Rust,65k 端口 3 秒级,依赖 nmap)
|
|
64
|
+
- `pkg install masscan`(C,SYN 异步高速;或 anasfanani/masscan-termux-android)
|
|
65
|
+
- `pkg install ffuf`、`pkg install feroxbuster`(内容发现)
|
|
66
|
+
- naabu(Go,ProjectDiscovery release 直接下载 arm64)
|
|
67
|
+
- 无 root:SYN 半开不可用(masscan/nmap -sS 需 root);TCP connect(rustscan/naabu/fastrecon)通用。
|
|
68
|
+
- 兜底:原生工具不可用时回退 fastrecon / dirbrute(Python 版照常可跑)。
|
|
69
|
+
|
|
70
|
+
## 五、性能技巧清单
|
|
71
|
+
|
|
72
|
+
1. 并发模型优先级:selectors(单线程 IO 多路复用)> 线程池 > 串行。iSH 线程切换开销大,selectors 最稳。
|
|
73
|
+
2. 超时管理:非阻塞 connect 超时不会触发 select 事件——必须逐 socket 计时清理,否则整轮扫描被拖到兜底超时。
|
|
74
|
+
3. DNS:批量 UDP 并发 + 本地缓存文件;避免 DoH;getent 兜底。
|
|
75
|
+
4. HTTP:curl -Z(--parallel-max)是 C 级并行,比 Python 快一个数量级;每个 URL 必须配对 -o /dev/null(否则多余 body 污染 stdout)。
|
|
76
|
+
5. urllib:opener 全局缓存(getproxies 系统调用是隐藏杀手)。
|
|
77
|
+
6. 测试方法:单线程测试服务器会制造假象(客户端背锅);并发测试用多线程服务器。
|
|
78
|
+
7. 软404:目标返回"200 假页面"时,先探测随机路径取基线(状态码+大小),过滤假阳性(dirbrute curl 引擎内置此逻辑)。
|
|
79
|
+
8. 大范围扫描:先用 top100 快扫定位存活,再做全端口深扫;CIDR 用 /24 以内切片分次跑。
|
|
80
|
+
|
|
81
|
+
## v2.11.6 提速与自适配(2026-09-28)
|
|
82
|
+
|
|
83
|
+
### iSH import 成本实测与懒加载策略
|
|
84
|
+
- 实测(每次调用固定成本):urllib.request 5s、subprocess 3s、concurrent.futures 2s、argparse 1.8s、json 1.8s、ssl 1s、socket/selectors 各 1s
|
|
85
|
+
- 策略:重模块全部懒加载(首次用才 import);argparse 换 argsmini.py 极简解析(0 成本);curl 调用改 os.popen(免 subprocess 3s);dns 线程池自研(免 cf 2s)
|
|
86
|
+
- 自适配:platf.py 探测 iSH/Termux/RPi/Linux/macOS/Windows → 并发/超时自动调参
|
|
87
|
+
|
|
88
|
+
### 耗时对比(iSH 实测,含 Python 启动)
|
|
89
|
+
| 命令 | 改造前 | v2.11.6 |
|
|
90
|
+
|------|--------|---------|
|
|
91
|
+
| scan | 4-7s | 1s |
|
|
92
|
+
| dns | 7s | 2s |
|
|
93
|
+
| dirbrute | 7-8s | 3s |
|
|
94
|
+
| basicauth | 8s | 5s |
|
|
95
|
+
|
|
96
|
+
### DoT(DNS over TLS)
|
|
97
|
+
- `fastrecon dns example.com --via dot --resolver 1.1.1.1`(RFC 7858:TCP 853+TLS,帧格式同 TCP)
|
|
98
|
+
- `--via auto`:UDP 失败自动切 DoT;论文实测 DoT 优于 DoH、Do53 最快
|
|
99
|
+
- 解析链:UDP →(auto 时)DoT → getent → DoH
|
|
100
|
+
|
|
101
|
+
### 摄像头端口组(-p cam)
|
|
102
|
+
80/81/88/443/554/8554/8000/8080/8081/8899/34567/37777/9527/2000/2020/1935/5000/5001/5540/7070/7447/4520/8787——覆盖 Hikvision/Dahua/XMeye/Axis/Reolink 等相机与 NVR。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""argparse 极简兼容层(iSH 上省 ~1.8s import 成本)。
|
|
2
|
+
覆盖三工具用到的子集:位置参数、--opt 值、type、default、choices、
|
|
3
|
+
store_true、subparsers(dest)、parse_args、error、-h。
|
|
4
|
+
不支持:前缀缩写、nargs、metavar、互斥组等(三工具未用)。"""
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _basename(p):
|
|
9
|
+
return p.rsplit('/', 1)[-1] or p
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _NS:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ArgumentParser:
|
|
17
|
+
def __init__(self, prog=None, description=None, **kw):
|
|
18
|
+
self.prog = prog or _basename(sys.argv[0])
|
|
19
|
+
self.description = description or ''
|
|
20
|
+
self._opts = []
|
|
21
|
+
self._sub_dest = None
|
|
22
|
+
self._sub_parsers = {}
|
|
23
|
+
|
|
24
|
+
def add_argument(self, *names, **kw):
|
|
25
|
+
flag = kw.get('action') == 'store_true'
|
|
26
|
+
if len(names) == 1 and not names[0].startswith('-'):
|
|
27
|
+
o = dict(dest=names[0], flags=None, pos=True, is_flag=False,
|
|
28
|
+
type=kw.get('type', str), default=kw.get('default'),
|
|
29
|
+
choices=kw.get('choices'), help=kw.get('help', ''))
|
|
30
|
+
else:
|
|
31
|
+
longs = [n for n in names if n.startswith('--')]
|
|
32
|
+
dest = (longs[0] if longs else names[0]).lstrip('-').replace('-', '_')
|
|
33
|
+
o = dict(dest=dest, flags=list(names), pos=False, is_flag=flag,
|
|
34
|
+
type=kw.get('type', str),
|
|
35
|
+
default=kw.get('default', False if flag else None),
|
|
36
|
+
choices=kw.get('choices'), help=kw.get('help', ''))
|
|
37
|
+
self._opts.append(o)
|
|
38
|
+
|
|
39
|
+
def add_subparsers(self, dest=None, **kw):
|
|
40
|
+
self._sub_dest = dest or 'cmd'
|
|
41
|
+
holder = self
|
|
42
|
+
|
|
43
|
+
class _Sub:
|
|
44
|
+
def add_parser(self, name, help=''):
|
|
45
|
+
p = ArgumentParser(prog='%s %s' % (holder.prog, name), description=help)
|
|
46
|
+
holder._sub_parsers[name] = p
|
|
47
|
+
return p
|
|
48
|
+
return _Sub()
|
|
49
|
+
def parse_args(self, argv=None):
|
|
50
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
51
|
+
if self._sub_parsers:
|
|
52
|
+
if not argv:
|
|
53
|
+
ns = _NS()
|
|
54
|
+
setattr(ns, self._sub_dest, None)
|
|
55
|
+
return ns
|
|
56
|
+
for i, t in enumerate(argv):
|
|
57
|
+
if not t.startswith('-'):
|
|
58
|
+
name, rest = t, argv[:i] + argv[i + 1:]
|
|
59
|
+
break
|
|
60
|
+
else:
|
|
61
|
+
if argv[0] in ('-h', '--help'):
|
|
62
|
+
self.print_help()
|
|
63
|
+
raise SystemExit(0)
|
|
64
|
+
self.error('unrecognized arguments: %s' % argv[0])
|
|
65
|
+
sp = self._sub_parsers.get(name)
|
|
66
|
+
if sp is None:
|
|
67
|
+
self.error('无效命令: %s(可选: %s)' % (name, ', '.join(sorted(self._sub_parsers))))
|
|
68
|
+
ns = sp.parse_args(rest)
|
|
69
|
+
setattr(ns, self._sub_dest, name)
|
|
70
|
+
return ns
|
|
71
|
+
ns = _NS()
|
|
72
|
+
for o in self._opts:
|
|
73
|
+
setattr(ns, o['dest'], o['default'])
|
|
74
|
+
pos_order = [o for o in self._opts if o['pos']]
|
|
75
|
+
pos_idx = 0
|
|
76
|
+
i = 0
|
|
77
|
+
while i < len(argv):
|
|
78
|
+
t = argv[i]
|
|
79
|
+
if t in ('-h', '--help'):
|
|
80
|
+
self.print_help()
|
|
81
|
+
raise SystemExit(0)
|
|
82
|
+
if t.startswith('-') and t != '-':
|
|
83
|
+
o = self._find(t)
|
|
84
|
+
if o is None:
|
|
85
|
+
self.error('unrecognized arguments: %s' % t)
|
|
86
|
+
if o['is_flag']:
|
|
87
|
+
setattr(ns, o['dest'], True)
|
|
88
|
+
i += 1
|
|
89
|
+
else:
|
|
90
|
+
if i + 1 >= len(argv):
|
|
91
|
+
self.error('argument %s: expected one argument' % t)
|
|
92
|
+
setattr(ns, o['dest'], self._conv(o, argv[i + 1], t))
|
|
93
|
+
i += 2
|
|
94
|
+
else:
|
|
95
|
+
if pos_idx >= len(pos_order):
|
|
96
|
+
self.error('unrecognized arguments: %s' % t)
|
|
97
|
+
o = pos_order[pos_idx]
|
|
98
|
+
setattr(ns, o['dest'], self._conv(o, t, o['dest']))
|
|
99
|
+
pos_idx += 1
|
|
100
|
+
i += 1
|
|
101
|
+
for o in pos_order[pos_idx:]:
|
|
102
|
+
if o['default'] is None:
|
|
103
|
+
self.error('the following arguments are required: %s' % o['dest'])
|
|
104
|
+
return ns
|
|
105
|
+
|
|
106
|
+
def _find(self, flag):
|
|
107
|
+
for o in self._opts:
|
|
108
|
+
if o['flags'] and flag in o['flags']:
|
|
109
|
+
return o
|
|
110
|
+
return None
|
|
111
|
+
def _conv(self, o, raw, shown):
|
|
112
|
+
if o['type'] is not str:
|
|
113
|
+
try:
|
|
114
|
+
v = o['type'](raw)
|
|
115
|
+
except (ValueError, TypeError):
|
|
116
|
+
self.error('argument %s: invalid %s value: %r' % (shown, o['type'].__name__, raw))
|
|
117
|
+
return None
|
|
118
|
+
else:
|
|
119
|
+
v = raw
|
|
120
|
+
if o['choices'] is not None and v not in o['choices']:
|
|
121
|
+
self.error('argument %s: invalid choice: %r (choose from %s)' % (
|
|
122
|
+
shown, v, ', '.join(map(repr, o['choices']))))
|
|
123
|
+
return v
|
|
124
|
+
|
|
125
|
+
def print_help(self, out=None):
|
|
126
|
+
out = out if out is not None else sys.stdout
|
|
127
|
+
w = out.write
|
|
128
|
+
w('usage: %s [-h] [options]\n' % self.prog)
|
|
129
|
+
if self.description:
|
|
130
|
+
w('\n%s\n' % self.description)
|
|
131
|
+
w('\noptions:\n')
|
|
132
|
+
for o in self._opts:
|
|
133
|
+
if o['flags']:
|
|
134
|
+
w(' %s %s\n' % (', '.join(o['flags']), o['help']))
|
|
135
|
+
else:
|
|
136
|
+
w(' %s %s\n' % (o['dest'], o['help']))
|
|
137
|
+
if self._sub_parsers:
|
|
138
|
+
w('\ncommands:\n')
|
|
139
|
+
for n, p in sorted(self._sub_parsers.items()):
|
|
140
|
+
w(' %s %s\n' % (n, p.description))
|
|
141
|
+
w(' -h, --help show this help message and exit\n')
|
|
142
|
+
|
|
143
|
+
def error(self, message):
|
|
144
|
+
sys.stderr.write('%s: error: %s\n' % (self.prog, message))
|
|
145
|
+
raise SystemExit(2)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == '__main__':
|
|
149
|
+
ap = ArgumentParser(prog='amtest', description='argsmini 自测')
|
|
150
|
+
sub = ap.add_subparsers(dest='cmd')
|
|
151
|
+
d = sub.add_parser('dns', help='dns test')
|
|
152
|
+
d.add_argument('target', help='域名')
|
|
153
|
+
d.add_argument('-w', '--workers', type=int, default=8, help='并发')
|
|
154
|
+
d.add_argument('--dot', action='store_true', help='DoT')
|
|
155
|
+
d.add_argument('--via', choices=['udp', 'dot'], default='udp', help='通道')
|
|
156
|
+
ns = ap.parse_args()
|
|
157
|
+
print('cmd=%s target=%s workers=%r dot=%r via=%s' % (
|
|
158
|
+
ns.cmd, ns.target, ns.workers, ns.dot, ns.via))
|
|
@@ -4,23 +4,94 @@
|
|
|
4
4
|
HTTP Basic Auth 爆破(低并发 + 退避,避免触发 WAF/封 IP)
|
|
5
5
|
用法: python3 basicauth_brute.py <url> <userlist> <passlist> [--conc 4] [--delay 0.15]
|
|
6
6
|
"""
|
|
7
|
-
import
|
|
7
|
+
import os, sys, base64, time, json, shutil, re
|
|
8
|
+
import argsmini as argparse
|
|
9
|
+
|
|
10
|
+
# ---- 懒加载/popen 优化:ssl/urllib/concurrent import 各耗 1-5s(iSH),仅首次用时载入 ----
|
|
11
|
+
_ssl_m = None
|
|
12
|
+
def _get_ssl():
|
|
13
|
+
global _ssl_m
|
|
14
|
+
if _ssl_m is None: import ssl as _s; _ssl_m = _s
|
|
15
|
+
return _ssl_m
|
|
16
|
+
_url_m = None
|
|
17
|
+
def _get_urllib():
|
|
18
|
+
global _url_m
|
|
19
|
+
if _url_m is None: import urllib.request as _r; import urllib.error as _e; _url_m = (_r, _e)
|
|
20
|
+
return _url_m
|
|
21
|
+
_cf_m = None
|
|
22
|
+
def _get_cf():
|
|
23
|
+
global _cf_m
|
|
24
|
+
if _cf_m is None: import concurrent.futures as _c; _cf_m = _c
|
|
25
|
+
return _cf_m
|
|
26
|
+
def _quote(s):
|
|
27
|
+
import urllib.parse as _p
|
|
28
|
+
return _p.quote(s, safe='')
|
|
29
|
+
def _unquote(s):
|
|
30
|
+
import urllib.parse as _p
|
|
31
|
+
return _p.unquote(s)
|
|
32
|
+
_SAFE = frozenset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@%_+=:,./-")
|
|
33
|
+
def _shq(s):
|
|
34
|
+
if s and all(c in _SAFE for c in s): return s
|
|
35
|
+
return "'%s'" % s.replace("'", "'" + chr(92) + "'" + "'")
|
|
36
|
+
def _run_curl(cargs):
|
|
37
|
+
p = os.popen(" ".join(_shq(a) for a in cargs) + " 2>/dev/null")
|
|
38
|
+
out = p.read(); p.close(); return out
|
|
39
|
+
_CTX = None
|
|
40
|
+
def _ctx():
|
|
41
|
+
global _CTX
|
|
42
|
+
if _CTX is None:
|
|
43
|
+
_s = _get_ssl()
|
|
44
|
+
c = _s.SSLContext(_s.PROTOCOL_TLS_CLIENT)
|
|
45
|
+
c.check_hostname = False
|
|
46
|
+
c.verify_mode = _s.CERT_NONE
|
|
47
|
+
_CTX = c
|
|
48
|
+
return _CTX
|
|
8
49
|
|
|
9
50
|
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
51
|
|
|
12
52
|
def try_one(url, user, pwd, delay):
|
|
53
|
+
_r, _e = _get_urllib()
|
|
13
54
|
if delay: time.sleep(delay)
|
|
14
55
|
tok = base64.b64encode(f"{user}:{pwd}".encode()).decode()
|
|
15
|
-
r =
|
|
56
|
+
r = _r.Request(url, headers={"User-Agent": UA, "Authorization": f"Basic {tok}"})
|
|
16
57
|
try:
|
|
17
|
-
with
|
|
58
|
+
with _r.urlopen(r, timeout=10, context=_ctx()) as resp:
|
|
18
59
|
return (user, pwd, resp.status, resp.read(200))
|
|
19
|
-
except
|
|
60
|
+
except _e.HTTPError as e:
|
|
20
61
|
return (user, pwd, e.code, b"")
|
|
21
62
|
except Exception as e:
|
|
22
63
|
return (user, pwd, 0, str(e).encode()[:100])
|
|
23
64
|
|
|
65
|
+
def brute_curl(url, users, passes, batch, timeout):
|
|
66
|
+
"""快速引擎:curl -Z 批量(URL 内嵌凭据,状态码区分)"""
|
|
67
|
+
pairs = [(u, p) for u in users for p in passes]
|
|
68
|
+
scheme, _, rest = url.partition('://')
|
|
69
|
+
hits = 0
|
|
70
|
+
for i in range(0, len(pairs), batch):
|
|
71
|
+
chunk = pairs[i:i + batch]
|
|
72
|
+
cargs = ['curl', '-sZ', '--parallel-max', str(batch), '-m', str(timeout),
|
|
73
|
+
'-w', '%{http_code} %{url_effective}\n']
|
|
74
|
+
for u, p in chunk:
|
|
75
|
+
cargs += ['-o', '/dev/null', f"{scheme}://{_quote(u)}:{_quote(p)}@{rest}"]
|
|
76
|
+
try:
|
|
77
|
+
out = _run_curl(cargs)
|
|
78
|
+
except OSError:
|
|
79
|
+
continue
|
|
80
|
+
for line in out.splitlines():
|
|
81
|
+
code_s, _, eff = line.partition(' ')
|
|
82
|
+
code = int(code_s) if code_s.isdigit() else 0
|
|
83
|
+
m = re.match(r'^[a-zA-Z]+://([^@]+)@', eff)
|
|
84
|
+
cred = _unquote(m.group(1)) if m else ''
|
|
85
|
+
u, _, p = cred.partition(':')
|
|
86
|
+
if code in (200, 301, 302):
|
|
87
|
+
hits += 1
|
|
88
|
+
print(json.dumps({"HIT": True, "user": u, "pass": p, "status": code}))
|
|
89
|
+
elif code not in (401, 0):
|
|
90
|
+
print(json.dumps({"odd": True, "user": u, "pass": p, "status": code}))
|
|
91
|
+
print(f"[*] {min(i + batch, len(pairs))}/{len(pairs)} done", file=sys.stderr)
|
|
92
|
+
print(json.dumps({"done": True, "attempts": len(pairs), "hits": hits}))
|
|
93
|
+
|
|
94
|
+
|
|
24
95
|
def main():
|
|
25
96
|
ap = argparse.ArgumentParser()
|
|
26
97
|
ap.add_argument("url"); ap.add_argument("users"); ap.add_argument("passes")
|
|
@@ -29,10 +100,14 @@ def main():
|
|
|
29
100
|
users = [l.strip() for l in open(a.users) if l.strip()]
|
|
30
101
|
passes = [l.strip() for l in open(a.passes) if l.strip()]
|
|
31
102
|
print(f"[*] {len(users)} users x {len(passes)} passes = {len(users)*len(passes)} attempts", file=sys.stderr)
|
|
103
|
+
if (not a.delay or a.delay <= 0) and shutil.which("curl"):
|
|
104
|
+
print("[*] 快速模式: curl -Z 批量(无 curl 或缺 delay 控制需求时自动改用线程池)", file=sys.stderr)
|
|
105
|
+
brute_curl(a.url, users, passes, 48, 10)
|
|
106
|
+
return
|
|
32
107
|
n = 0
|
|
33
|
-
with
|
|
108
|
+
with _get_cf().ThreadPoolExecutor(max_workers=a.conc) as ex:
|
|
34
109
|
futs = [ex.submit(try_one, a.url, u, p, a.delay) for u in users for p in passes]
|
|
35
|
-
for f in
|
|
110
|
+
for f in _get_cf().as_completed(futs):
|
|
36
111
|
u, p, st, body = f.result()
|
|
37
112
|
n += 1
|
|
38
113
|
if st in (200, 302, 301):
|