文章总结: znaide1.0.3版本重写危险命令判定机制,从字符串匹配改为argv解析加目标路径规范化判定,解决旧实现中多空格绕过和具体路径误伤问题。新方案采用词法切分、变量替换、逐段取argv、按命令分派规则及目标路径规范化流水线,引入Blocked、Uncertain、Safe三态判定模型,并定义高危目标集。该更新提升了命令判定的准确性和安全性,建议用户升级至最新版本。 综合评分: 85 文章分类: 安全开发,安全工具,红队
[更新]主打一个听劝,znaide1.0.3源码+Releases已push
原创
zngeek zngeek
蓝极战队
2026年9月10日 12:18 贵州
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
事情是这样滴,昨天看到一个留言
我原本是想把功能完善了再继续优化安全边界和undo的,毕竟一个人精力有限,但是我主打一个听劝,先做部分优化吧,沙箱是下一步,慢慢来!
github和gitee已经同步推送
https://github.com/twowb/znaide
https://gitee.com/brother-ershui/znaide
#
#
znaide v1.0.3(2026-09-10)
危险命令判定重写。核心变化:不再对命令原文做子串匹配,改为把命令解析成 argv + 目标路径再判定。原先”多打一个空格就绕过”和”具体路径被误伤”这两类问题同时消失。
旧实现的问题
is_dangerous_command() 对整条命令字符串做 contains:
- 漏网:
"rm -rf /"是字面量,rm -rf /(多一个空格)、rm -r -f /、rm --recursive --force /、rm -rf "/"、sudo rm -rf /、mkfs -t ext4 /dev/sdb1(mkfs.的写法才拦)全部漏过;rm -rf ..(删父目录)不在表里。 - 误伤:
rm -rf /tmp/123/命中"rm -rf /"被硬拒;fdisk -l(只读列举)、dd if=x of=./img、git push --force-with-lease、echo "rm -rf /"同理。 - 不可覆盖:交互模式下命中即在弹确认框之前返回 Denied,人坐在旁边也无法放行(只有
yolo能过)。
根因是拿文本当语义:要判的是”目标路径规范化后是否落在高危集”,这是路径运算,不是字符串匹配。
新判定流水线
命令字符串
│
├─ 1. 词法切分 split_segments()
│ 按 ; && || | & 换行 切成"简单命令段";处理 '…' / "…" / 反斜杠转义;
│ > < 作为独立 token 保留(重定向目标单独判定);不做变量展开、不解析 $( )
│
├─ 2. 变量替换 collect_assignments() + expand_word()
│ 收集同一条命令串内的"字面赋值"(值里不含 $ 或反引号),预置 HOME / PWD;
│ 展开 $VAR 与 ${VAR};未知变量原样保留 → 后续走 Uncertain
│
├─ 3. 逐段取 argv,剥离前缀 strip_prefixes()
│ 跳过前置赋值 FOO=1 与 sudo / doas / env / command / builtin / exec /
│ nohup / setsid / time / nice / ionice / stdbuf / timeout(含 -u root 这类带值选项)
│ bash\|sh\|zsh… -c '…' 递归判定脚本文本(深度上限 3)
│
├─ 4. 按命令分派规则 judge_segment()
│ flag 集合(argv 层判定,空格数量、flag 顺序、合并写法都不影响)
│ + 目标路径(非选项参数)
│
└─ 5. 目标路径规范化 classify_target() / resolve_path()
展开 ~ → 相对路径按 cwd 绝对化 → 纯词法折叠 . 与 ..(不碰文件系统)
→ 与高危集比较 → Safe / Dangerous / Uncertain
多段命令取最严重的一段(Blocked > Uncertain > Safe);>``>>``2>``&> 后的目标若为块设备直接判高危。xargs rm … 的目标来自标准输入、判定时看不到 → Uncertain。
判定模型:三态
| 结果 | 含义 | 交互模式 | 无头模式 |
| — | — | — | — |
| Blocked | 目标解析出来确实高危 | 弹红色确认框,显示解析出的目标,只给单次放行(不提供”本会话都允许”) | 直接拒绝(bypassPermissions 也不放行) |
| Uncertain | 目标无法判定(未知变量 / 通配符与 .. 混用 / xargs rm 等间接调用),或属于需点头的中风险(shutdown、reboot) | 同样要人工点头,且不吃”本会话都允许” | 按档位:全自动放行,其余拒绝 |
| Safe | 没解析出危险点 | 按权限档位处理 | 按权限档位处理 |
超级 yolo 跳过以上全部判定。
高危目标集(dangerous_why):根目录 /、家目录 ~、当前工作目录或其上级(cwd.starts_with(p),所以 rm -rf .、rm -rf ..、rm -rf .* 都命中)、块设备(前缀表:/dev/sd* /dev/hd* /dev/vd* /dev/xvd* /dev/nvme* /dev/mmcblk* /dev/loop* /dev/mapper/ /dev/dm- /dev/disk* /dev/rdisk* /dev/fd0 /dev/ram* \\.\PhysicalDrive*)。
各命令规则
| 命令 | 判高危的条件 |
| — | — |
| rm | 带递归 flag(-r / -R / --recursive,任意顺序与合并写法)且目标落在高危集 |
| find | 带 -delete 或 -exec/-execdir rm…,且起始目录落在高危集 |
| dd | of= 的值是块设备(或无法判定) |
| mkfs* | 任意参数是块设备 / 高危路径(不要求 mkfs. 点号写法) |
| fdisk``sfdisk``parted``sgdisk``wipefs | 带 -l / --list → 放行(只读列举);否则目标含块设备 → 高危 |
| chmod``chown``chgrp``setfacl | 带 -R / --recursive 且目标落在高危集 |
| truncate``shred | 目标是块设备 |
| git push | 带 --force / -f 且不是 --force-with-lease |
| shutdown``reboot``poweroff``halt``init | 一律 Uncertain(降级为普通确认,不再当作”磁盘级破坏”) |
边界情况处理
- 通配符:取通配符之前的片段所在目录做判定。通配符不会匹配
./..,安全目录内的通配符爬不出去 →rm -rf /tmp/*放行、rm -rf /*与rm -rf .*拦;通配符与..混用(/tmp/*/../..)无法确定 → Uncertain。 - 简单变量:
T=/; rm -rf $T能解析出/→ 直接高危(比”未知变量一律 Uncertain”更强);D=./build; rm -rf $D解析成安全路径 → 放行。 - 引号:
echo "rm -rf /"、grep -rn 'rm -rf /' docs/现在按 argv 判定 → 放行(旧实现全部误伤)。
接口与接线变更
permissions::is_dangerous_command()删除,替换为permissions::inspect_command(cmd, cwd) -> CommandRisk。Permission::check_command()退化为纯档位判定(这个档位是否需要确认),不再内含风险判定——风险判定收敛到 session 层一处,否则交互模式下”用户已确认”的命令会在工具内被二次拒绝。session::check_permission()成为唯一风险闸门:判定 → 高危/无法判定时发PermissionRequest;SessionEvent::PermissionRequest新增warning: Option<String>,带warning时不设置command_always。tools/shell.rs的高危兜底改为只在ctx.events.is_none()(无头 / 宿主直调)时生效。- TUI:带
warning的确认框用红色边框 + “⚠ 高危命令确认”标题、弹窗加高、a(本会话都允许)键失效,并把解析出的目标/原因显示出来。
判定示例
| 命令 | 结果 |
| — | — |
| rm -rf / / rm -r -f / / rm --recursive --force / / rm -rfv / | Blocked(flag 与 argv 层判定,空格与顺序无关) |
| rm -rf "/" / sudo -u root rm -rf / / FOO=1 rm -rf / / bash -c 'rm -rf /' | Blocked |
| rm -rf .. / rm -rf . / rm -rf .* / rm -rf /tmp/../.. | Blocked(规范化后落在 cwd 上级 / 根) |
| T=/; rm -rf $T | Blocked(字面赋值可解析) |
| rm -rf /tmp/123/ / rm -rf ~/x / rm -rf ./build | Safe(具体路径) |
| rm -rf /tmp/* | Safe(通配符出不了 /tmp);rm -rf /* 为 Blocked |
| rm -rf $UNKNOWN_DIR / xargs rm -rf / shutdown -h now | Uncertain |
| dd if=/dev/zero of=/dev/sda | Blocked;dd if=x of=./img、of=/dev/null 放行 |
| mkfs -t ext4 /dev/sdb1 / chmod -R 777 / / find / -delete / echo x > /dev/sda | Blocked |
| fdisk -l / fdisk -l /dev/sda / chmod -R 755 ./dir | Safe |
| git push --force origin main、git push -f | Blocked;git push --force-with-lease、git push origin main 放行 |
已知边界(不宣称安全)
这是启发式减速带,不是安全边界。文本层看不穿:变量间接赋值链、命令替换 $(…)、xargs / make / python -c / npx rimraf 之类的间接调用、以及执行时才产生的值。undo 仍只管 write_file/edit真要限制进程能碰什么,需要内核级隔离(Landlock / 命名空间 / seccomp,见 docs/plan-sandbox.md,这是下一步计划~~~我太忙了)。
验证
cargo test --workspace:core 94 / mock-e2e 13 / tui 77,全绿(其中permissions12 个、tools::shell新增 2 个直接覆盖”无头高危拒绝”与”具体路径不误伤”)。cargo build --release通过,--version输出 1.0.3。- 未做:undo 快照仍只覆盖
write_file/edit(设计边界,使用说明 5.3 已如实描述)。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:蓝极战队 zngeek zngeek《[更新]主打一个听劝,znaide1.0.3源码+Releases已push》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。



![[更新]主打一个听劝,znaide1.0.3源码+Releases已push](/images/random/titlepic/5.jpg)






评论