totekuh/snaffler-ng

GitHub: totekuh/snaffler-ng

snaffler-ng 是一款基于 Python/Impacket 的后渗透敏感信息发现工具,用于在 Windows 网络中自动扫描 SMB 共享、FTP 服务器和本地文件系统以识别凭据和敏感数据。

Stars: 3 | Forks: 1

# snaffler-ng [Snaffler](https://github.com/SnaffCon/Snaffler) 的 Impactor 移植版本。 **snaffler-ng** 是一款后渗透工具,用于发现可读的 SMB 共享,遍历目录树,并识别 Windows 网络中的凭据和敏感数据。同时支持扫描 FTP 服务器、本地文件系统,并可作为 Python 库用于 C2 集成。 ## 安装 ``` pip install snaffler-ng # 或 pipx install snaffler-ng ``` 针对 Linux x86_64、Linux aarch64 和 Windows x86_64 的预编译二进制文件(无需 Python)可在 [Releases](https://github.com/totekuh/snaffler-ng/releases) 页面获取。Debian/Kali:`sudo dpkg -i snaffler-ng_*.deb`。 可选扩展: ``` pip install snaffler-ng[socks] # SOCKS proxy support pip install snaffler-ng[web] # live web dashboard pip install snaffler-ng[7z,rar] # 7z/RAR archive peeking ``` ## 快速入门 ``` # 完整域发现 — 查找计算机、解析 DNS、枚举共享、扫描所有内容 snaffler -u USER -p PASS -d DOMAIN.LOCAL # 使用 ccache 的 Kerberos snaffler -k --use-kcache -d DOMAIN.LOCAL --dc-host CORP-DC02 # 扫描特定 UNC 路径 snaffler -u USER -p PASS --unc //10.0.0.5/Share --unc //10.0.0.6/Data # 扫描特定计算机 (启用共享发现) snaffler -u USER -p PASS --computer 10.0.0.5 --computer 10.0.0.6 # 本地文件系统 (无需认证) snaffler --local-fs /mnt/share # FTP 服务器 (匿名) snaffler --ftp ftp://10.0.0.5 ``` ![snaffler-ng 运行截图](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/8bbe27924f055323.png) ## 目标模式 ### 域发现 (`-d`) 查询 AD 获取计算机 + DFS 命名空间,解析 DNS,探测 445 端口,枚举共享,然后扫描: ``` snaffler -u USER -p PASS -d DOMAIN.LOCAL snaffler -u USER -p PASS -d DOMAIN.LOCAL --max-hosts 50 # cap at 50 hosts snaffler -u USER -p PASS -d DOMAIN.LOCAL --shares-only # enumerate shares without scanning ``` ### 计算机列表 (`--computer` / `--computer-file`) 跳过 LDAP 发现,定位特定主机: ``` snaffler -u USER -p PASS --computer 10.0.0.5 --computer 10.0.0.6 snaffler -u USER -p PASS --computer-file targets.txt ``` ### UNC 路径 (`--unc`) 跳过共享发现,直接扫描特定路径: ``` snaffler -u USER -p PASS --unc //10.0.0.5/Share --unc //10.0.0.6/IT ``` ### 来自 NetExec 的管道输入 (`--stdin`) ``` nxc smb 10.0.0.0/24 -u user -p pass --shares | snaffler -u user -p pass --stdin ``` ### FTP 服务器 (`--ftp` / `--ftp-file`) 同样的分类引擎,包含所有 106 条规则,支持内容扫描、恢复和下载: ``` snaffler --ftp ftp://10.0.0.5 # anonymous snaffler --ftp ftp://10.0.0.5/Data -u ftpuser -p ftppass # with creds + subpath snaffler --ftp ftp://10.0.0.5:2121 --ftp-tls # custom port + TLS snaffler --ftp-file ftp_targets.txt -u ftpuser -p ftppass # load from file ``` 支持裸主机名:`--ftp 10.0.0.5` 会被视为 `ftp://10.0.0.5`。若未指定 `-u`/`-p`,将尝试匿名登录。 ### 本地文件系统 (`--local-fs`) 无网络,无认证 —— 适用于挂载的共享、解压的文件系统或测试规则: ``` snaffler --local-fs /mnt/share snaffler --local-fs /tmp/extracted --local-fs /home/user/Documents ``` ### 重新扫描不可读共享 (`--rescan-unreadable`) 使用新凭据重新测试此前拒绝访问的共享 —— 适用于密码喷洒之后: ``` # 使用低权限凭据进行初始扫描 snaffler -u lowpriv -p 'Password1' -d CORP.LOCAL --state scan.db # 随后,使用更高权限凭据 snaffler --rescan-unreadable -u highpriv -p 'NewPass!' --state scan.db ``` 初始扫描会将所有发现的共享(可读和不可读)存储在状态数据库中。`--rescan-unreadable` 仅加载此前被拒绝的共享,使用当前凭据重新测试,并扫描那些现在已可访问的共享。遵循 `--share`、`--exclude-share` 和 `--exclusions` 过滤器。 ## 过滤 ``` # 仅扫描特定共享 snaffler ... --share "SYSVOL" --share "IT*" # 排除共享 snaffler ... --exclude-share "IPC$" --exclude-share "print$" # 排除路径 (glob,适用于所有模式) snaffler ... --exclude-path "*/Windows/*" --exclude-path "*/.snapshot/*" # 限制目录递归深度 snaffler ... --max-depth 5 # 对结果进行 Regex 后过滤 (匹配路径、规则名称、内容) snaffler ... --match "password|connectionstring" # 跳过特定主机 snaffler ... --exclusions hosts_to_skip.txt # 在 N 台主机后停止 snaffler ... --max-hosts 50 ``` ## 输出 ### 格式 三种输出格式:**plain**(默认)、**JSON**、**TSV**。根据 `-o` 文件扩展名自动检测: ``` snaffler ... -o findings.json # JSON snaffler ... -o findings.tsv # TSV snaffler ... -o findings.txt # plain snaffler ... -o out.log -t json # explicit override ``` ### 恢复 扫描状态通过 SQLite (`snaffler.db`) 跟踪。当数据库存在时,扫描会自动恢复: ``` snaffler -u USER -p PASS -d DOMAIN.LOCAL # creates snaffler.db # 被中断?重新运行相同的命令 — 从中断处继续 snaffler -u USER -p PASS -d DOMAIN.LOCAL # resumes snaffler ... --state /tmp/scan1.db # custom DB path snaffler ... --fresh # ignore existing state ``` ### 查询结果 ``` snaffler results # plain text summary snaffler results -f json # JSON snaffler results -f html > report.html # self-contained HTML report snaffler results -b 2 # Red+ severity only snaffler results -s /path/to/snaffler.db # custom DB path ``` ### Web 仪表盘 用于监控扫描进度和发现结果的实时浏览器仪表盘: ``` snaffler ... --web --web-port 8080 ``` 需要安装 `pip install snaffler-ng[web]`。 ### 归档文件查看 无需解压即可扫描 ZIP、7z 和 RAR 归档内的文件名: ``` pip install snaffler-ng[7z,rar] # ZIP works out of the box ``` ## 认证与网络 | 标志 | 描述 | |------|-------------| | `-u` / `-p` | NTLM 用户名/密码 | | `--hash` | NTLM Pass-the-Hash | | `-k` | Kerberos 认证 | | `--use-kcache` | 通过现有 ccache 进行 Kerberos 认证 (`KRB5CCNAME`) | | `--socks` | SOCKS 代理 pivoting (`socks5://127.0.0.1:1080`) | | `--nameserver` / `--ns` | 自定义 DNS 服务器(使用 TCP,支持通过 SOCKS) | | `--dc-host` | 域控制器主机名或 IP | | `--stealth` | OPSEC 模式:填充 LDAP 查询以绕过 IDS 特征检测 | ``` # SOCKS + 通过隧道的自定义 DNS snaffler -u USER -p PASS -d DOMAIN.LOCAL \ --socks socks5://127.0.0.1:1080 --ns 192.168.201.11 --dc-host 192.168.201.11 ``` ### 运行时热键 扫描期间,按 `d` 开启 DEBUG 输出,按 `i` 切回 INFO。 ## 库 API ### 遍历目录 ``` from snaffler import Snaffler for finding in Snaffler().walk("/mnt/share"): print(f"[{finding.triage.label}] {finding.file_path}") if finding.match: print(f" matched: {finding.match}") ``` ### 两阶段分类(C2 集成) 最小化 beacon 流量 —— 大多数文件在阶段 1 即被跳过(仅元数据,零 I/O): ``` from snaffler import Snaffler from snaffler.api import FileCheckStatus s = Snaffler() # 阶段 1:仅 metadata — 即时,无文件读取 check = s.check_file(path, size=4096, mtime_epoch=1700000000.0) if check.status == FileCheckStatus.NEEDS_CONTENT: # Phase 2: only download + classify when needed result = s.scan_content(file_bytes, prior=check) elif check.status == FileCheckStatus.MATCHED: result = check.result # matched on filename alone (e.g. ntds.dit) ``` ### 自定义传输(鸭子类型) 插入任何传输层 —— 无需 ABC(抽象基类),只需实现 `walk_directory` 和 `read`: ``` class BeaconWalker: def walk_directory(self, path, on_file=None, on_dir=None, cancel=None): for entry in beacon.ls(path): if entry.is_dir: if on_dir: on_dir(entry.path) elif on_file: on_file(entry.path, entry.size, entry.mtime) return [e.path for e in beacon.ls(path) if e.is_dir] class BeaconReader: def read(self, path, max_bytes=None): return beacon.download(path, max_bytes) s = Snaffler(walker=BeaconWalker(), reader=BeaconReader()) for finding in s.walk("C:\\Users"): beacon.report(finding.file_path, finding.triage.label) ``` ### 构造函数参数 | 参数 | 默认值 | 描述 | |-----------|---------|-------------| | `walker` | `LocalTreeWalker()` | 目录列表提供者 | | `reader` | `LocalFileAccessor()` | 文件内容读取器 | | `rule_dir` | `None` | 自定义 TOML 规则目录 | | `min_interest` | `0` | 最低严重级别(0=全部,3=仅 Black) | | `max_read_bytes` | `2MB` | 内容扫描字节限制 | | `match_context_bytes` | `200` | 正则匹配周围的上下文字节 | | `cert_passwords` | 内置列表 | 尝试用于 PKCS12 证书的密码 | | `exclude_unc` | `None` | 用于跳过目录的 Glob 模式 | | `match_filter` | `None` | 对发现结果进行正则后过滤 | | `max_depth` | `None` | 最大目录递归深度 |
标签:Active Directory, C2集成, FTP扫描, HTTP, Impacket, PE 加载器, Plaso, Python, SMB, Snaffler移植, SOCKS代理, StruQ, 代码生成, 共享文件夹扫描, 凭证发现, 敏感数据检测, 文件系统审计, 无后门, 渗透测试工具, 网络安全审计, 逆向工具, 错误配置检测