dejisec/niffler

GitHub: dejisec/niffler

Niffler:NFS共享凭据和机密查找工具

Stars: 4 | Forks: 0

# Niffler [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/0b00de468f020952.svg)](https://github.com/dejisec/niffler/actions/workflows/ci.yml) [![发布](https://img.shields.io/github/v/release/dejisec/niffler)](https://github.com/dejisec/niffler/releases) [![许可证:MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Rust](https://img.shields.io/badge/rust-1.95%2B-orange.svg)](https://www.rust-lang.org/) Niffler扫描NFS服务器以查找凭据、机密和配置错误。想象一下[Snaffler](https://github.com/SnaffCon/Snaffler),但针对NFS而不是SMB。 ## 为什么是NFS? NFS(尤其是v3)使用AUTH_SYS进行身份验证,这意味着客户端以明文形式发送UID/GID,服务器则接受其说法。没有密码,没有Kerberos票据,没有挑战-响应。到达NFS端口后,您可以声称自己是任何非root用户并读取他们的文件,或者如果设置了`no_root_squash`,则是root用户。 Niffler处理繁琐的部分:查找导出、遍历树、欺骗UID以及将文件内容与凭据模式库进行匹配。 ## 安装 三种获取它的方法: **预构建的二进制文件** — 从[发布](https://github.com/dejisec/niffler/releases)页面获取一个。 **Cargo**(需要[libnfs-dev](https://github.com/sahlberg/libnfs)): ``` cargo install --git https://github.com/dejisec/niffler ``` **从源代码**(需要[libnfs-dev](https://github.com/sahlberg/libnfs)): ``` git clone https://github.com/dejisec/niffler && cd niffler cargo build --release cp target/release/niffler . ``` ## 快速入门 ``` # 扫描单个NFS服务器 ./niffler scan -t 10.0.0.5 # 扫描整个子网 ./niffler scan -t 192.168.1.0/24 # 仅侦察:列出服务器、导出和错误配置,不读取文件 ./niffler scan -t 10.0.0.0/24 --mode recon # 在Web仪表板上查看结果 ./niffler serve --db niffler.db # 将发现导出为JSON ./niffler export --db niffler.db -f json ``` ## 操作模式 Niffler以三种模式运行,因此您可以调整深度: | 模式 | 执行的操作 | 使用场景... | |------|-------------|-------------| | `recon` | 查找NFS服务器,列出导出,检查配置错误 | 您想要一个安静的地形 | | `enum` | 以上 + 遍历目录树,将文件名与规则匹配 | 您想查看内容而不读取文件内容 | | `scan` | 以上 + 读取文件内容并应用正则表达式模式 | 您想获得完整的信息(默认) | ## 脚本 ``` # 仅显示高严重性发现(红色和黑色) ./niffler scan -t nfs-server.internal -b red # 以特定用户身份扫描(例如,侦察期间找到的UID) ./niffler scan -t nfs-server.internal --uid 1000 --gid 1000 # 通过SOCKS5代理路由 ./niffler scan -t 10.0.0.5 --proxy socks5://127.0.0.1:1080 # 扫描本地或已挂载的共享,跳过网络发现 ./niffler scan -i /mnt/nfs_share1 /mnt/nfs_share2 # 从文件中读取目标(每行一个,CIDR有效;使用-作为stdin) ./niffler scan -T targets.txt # 扫描子网但跳过一些主机 ./niffler scan -t 10.0.0.0/24 -x 10.0.0.5 10.0.0.99 # 将结果写入自定义数据库 ./niffler scan -t 10.0.0.0/24 -o engagement.db # 生成配置模板,编辑它,然后重用 ./niffler scan -z > niffler.toml ./niffler scan -c niffler.toml -t 10.0.0.0/24 # 在特定地址上提供仪表板 ./niffler serve --db niffler.db --port 9090 --bind 0.0.0.0 # 将红+发现导出为CSV,或将单个主机作为TSV ./niffler export --db niffler.db -f csv -b red ./niffler export --db niffler.db -f tsv --host 10.0.0.5 ``` 每个标志都在`niffler scan --help`(以及同样地`serve --help`和`export --help`)中进行了文档说明。 ## 输出 所有结果都存储在SQLite数据库中(默认为`niffler.db`)。 ### 实时仪表板 在交互式终端中,Niffler在扫描时显示全屏仪表板:阶段进度、实时严重性着色发现流(使用箭头/PgUp/PgDn滚动,使用`f`过滤,使用`p`暂停),以及日志面板。按`q`或Ctrl-C停止,并在退出时打印一个摘要卡片。 在终端外(管道、重定向、CI),它切换到纯行输出:心跳进度加每行一个发现输出到stdout,可以安全地管道。使用`--tui`或`--plain`强制任一模式。 ``` ./niffler scan -t 10.0.0.5 --plain | grep BLACK ``` ### 网页仪表板(`serve`) 启动本地Web UI以在浏览器中查看发现: ``` ./niffler serve --db niffler.db # 然后打开http://127.0.0.1:8080 ``` ### 导出(`export`) 将发现从数据库中拉出为JSON行、CSV或TSV: ``` ./niffler export --db niffler.db -f json # JSON lines to stdout ./niffler export --db niffler.db -f csv -b red # CSV, Red and Black only ./niffler export --db niffler.db -f tsv --host 10.0.0.5 # TSV, single host ``` ## 严重性级别 发现被分为四个级别。使用`-b`设置最小严重性阈值。 | 级别 | 意义 | 示例 | |-------|---------|----------| | **黑色** | 立即、直接影响 — 可用凭据或密钥材料 | SSH私钥、影子文件、Vault令牌、KeePass数据库 | | **红色** | 高价值 — 很可能包含机密,需要更仔细地查看 | 包含密码的`.env`文件、AWS访问密钥、数据库连接字符串 | | **黄色** | 有趣 — 值得注意但可能不是直接可利用的 | 配置文件、包含潜在信息的日志文件 | | **绿色** | 信息性 — 帮助描绘更大图画的上下文 | 脚本、文档、有趣导出的数据文件 | ``` ./niffler scan -t 10.0.0.5 -b red # Only Red and Black findings ./niffler scan -t 10.0.0.5 -b black # Only Black findings ``` ## 工作原理 Niffler作为一个多阶段异步管道运行: ``` Targets ──► Discovery ──► Tree Walker ──► File Scanner ──► Output │ │ │ find servers walk exports read content list exports parallel dirs match filenames harvest UIDs prune junk dirs match patterns detect misconfig retry on loss check for keys UID cycling retry on loss ``` **发现**查找NFS服务器(在111/2049端口上进行端口扫描),查询端口映射器和MOUNT服务以获取导出,从目录列表中收集UID,并检查配置错误。 **树遍历器**对每个导出执行并行递归READDIRPLUS遍历(`--parallel-dirs`并发目录列表),应用目录丢弃规则以提前剪枝不感兴趣的路径。 **文件扫描器**读取文件内容并通过连接池(`--max-connections-per-host`)将其通过规则引擎。当文件权限被拒绝时,Niffler通过收集的UID(AUTH_SYS欺骗)循环尝试以不同的用户读取它。失败的读取将使用指数退避(`--scan-retries`)重试。 **断路器**监视每个主机的错误率。如果某个服务器在滑动窗口内(至少`--error-threshold`事件后)的错误率超过80%,则暂停该主机,以便Niffler停止敲打不健康的服务器。第一次冷却时间为`--cooldown-secs`;每次重复行程加倍,最多64倍。 **UID循环**是秘密配方。当扫描器遇到权限墙时,它会尝试: 1. 主要UID(来自`--uid`/`--gid`,默认:nobody/65534) 2. 文件的所有者UID(来自stat — 最有可能成功) 3. 在发现期间收集的UID(来自目录列表) 每个尝试都会打开一个新的NFS连接,并带有新的AUTH_SYS凭据。NFS文件句柄在连接之间有效,因此遍历器获得的句柄可以在扫描器下以完全不同的UID读取。 ### NFSv4 Niffler通过[libnfs](https://github.com/sahlberg/libnfs)支持NFSv4。如果您不指定版本,它默认为NFSv3;如果目标仅公开v4或您想测试v4特定行为,则强制使用v4: ``` ./niffler scan -t 10.0.0.5 --nfs-version 4 ``` ## 规则引擎 规则在TOML中定义并编译到二进制文件中。引擎使用**中继链架构**(从Snaffler借用):便宜的规则控制昂贵的规则。 以名为`.env`的文件为例。它首先匹配文件名规则(即时)。该规则*中继*到内容规则,这些规则读取文件并应用正则表达式模式(昂贵)。因此,正则表达式仅在已很可能包含有趣内容的文件上运行。 ``` .env file found └─► FileEnumeration rule matches ".env" (Relay action) ├─► CredentialPatterns: scans for password=, api_key=, bearer tokens, etc. ├─► CloudKeyPatterns: scans for AKIA..., aws_secret_access_key, etc. └─► TokenPatterns: scans for Slack xox*, GitHub ghp_, JWT, etc. ``` 规则有四个作用域: - **ShareEnumeration** — 在发现期间应用于导出路径 - **DirectoryEnumeration** — 在树遍历期间应用于目录名 - **FileEnumeration** — 在扫描器中应用于文件名/扩展名/路径 - **ContentsEnumeration** — 在文件内容中应用(最昂贵,由中继控制) ### 自定义规则 完全替换默认规则或合并您自己的规则: ``` # 用您自己的规则替换所有内置规则 ./niffler scan -t 10.0.0.5 -r /path/to/my-rules/ # 保留默认设置并添加额外规则 ./niffler scan -t 10.0.0.5 -R /path/to/extra-rules/ ``` 规则是TOML文件,具有简单的结构: ``` [[rules]] name = "MyCustomPattern" scope = "ContentsEnumeration" match_location = "FileContentAsString" match_type = "Regex" patterns = ['(?i)internal_api_key\s*=\s*["\'][^"\']{16,}'] action = "Snaffle" triage = "Red" max_size = 1048576 context_bytes = 200 description = "Custom internal API key pattern" ``` ## 配置错误检测 在发现期间,Niffler对每个导出进行常见NFS配置错误的探测: | 检查 | 意义 | Niffler如何测试它 | |-------|---------------|---------------------| | **no_root_squash** | UID 0不被压缩,因此root可能能够读取或写入任何内容 | 以UID 0的身份连接并尝试在导出根上执行`getattr`。成功是一个强烈的暗示,但不是证据:被压缩的`nobody`仍然可以stat一个世界可读的根 | | **insecure** | 导出接受来自非特权端口的连接(>1024) | 从高端口连接,检查`getattr`是否成功 | | **subtree_check绕过** | 文件句柄可以逃离导出边界 | 从导出根查找`..`,检查返回的句柄是否不同 | 默认情况下,subtree绕过检查是关闭的,因为它为每个导出添加了额外的探测。使用`--check-subtree-bypass`打开它: ``` ./niffler scan -t 10.0.0.0/24 --check-subtree-bypass ```
标签:DNS解析, MIT 许可, NFS 安全, Rust 编程, UID/GID 欺骗, 代码构建, 凭证泄露检测, 可视化界面, 安全可观测性, 安全漏洞, 安全社区, 安全配置审计, 开源项目, 文件内容匹配, 文件系统安全, 版本控制, 系统配置检查, 红队平台, 网络扫描工具, 网络服务安全, 网络配置错误, 认证机制, 通知系统