安全与隐私defensecode.com
Unix 通配符也疯狂
Unix Wildcards Gone Wild
2014 — 2020,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这篇白皮书介绍了一种经典的 Unix 通配符注入技巧:当 shell 用通配符(如 *)展开文件名时,以连字符开头的文件名会被当作命令行选项传给被执行的程序,攻击者可借此构造恶意文件名,在管理员执行 tar、rsync、chown 等命令时触发任意选项甚至提权。文章演示了多种利用场景,并讨论了防范思路。
为什么经久不衰:它揭示了一个看似无害的 shell 习惯背后的安全隐患,且问题至今仍普遍存在,是理解命令行参数安全与文件名处理陷阱的经典教材。
HN 评论精选
推荐 Wheeler 关于 shell 文件名安全的文章,并给出 ./ 前缀和 -- 两个实用规避方法
FOSS 与安全领域的知名人物 David A. Wheeler(也是 sloccount 的作者)有一篇很好的文章,讲如何在 shell 脚本中安全、可移植地处理路径(剧透:很难)。强烈推荐他的其他文章。补充:一个简单的规避方法是在通配符前加 ./(展开的文件名会以 ./ 开头而不是 - 或 --),GNU 系统上还可以在通配符前放 --,告诉工具后面的参数不是选项。
AceJohnny2查看英文原文
David A. Wheeler, FOSS (and occasionally security) luminary, who also happens to be creator of the popular sloccount tool, has an excellent page that covers this topic and how to use paths safely and portably in shell scripts (spoiler: it's hard) : http://www.dwheeler.com/essays/filenames-in-shell.html I strongly recommend his many other essays to HN readers: http://www.dwheeler.com/ Edit: a simple way to avoid these problems is to prepend the wildcard with ./ (so globbed files won't start with - or -- but with the path ./) and on GNU systems put -- before the wildcard, telling the tool that following arguments are not options.
纠正误解:这不是 shell 的解释行为,任何语言向外部程序传参都有同样问题
需要澄清:shell 并没有在'解释'什么——它完全不了解所运行程序的参数约定,只是把参数列表传给可执行文件,如何处理由程序自己决定。这也不只是 shell 的问题:在任何语言中把任意参数传给外部工具都有此风险。比如用 exec/subprocess 调用 grep,虽然不存在 shell 命令注入,但如果输入以连字符开头,依然会出问题。所以务必用 '--' 标记选项处理结束。
okdana查看英文原文
>Simple trick behind this technique is that when using shell wildcards, especially asterisk (...), Unix shell will interpret files beginning with hyphen (-) character as command line arguments to executed command/program. To be clear, the shell isn't really 'interpreting' anything here — it knows absolutely nothing about the argument conventions of whatever program you're running[0]. All it's doing is passing a list of arguments to an executable; how the executable deals with that is up to it. And this isn't only a shell problem — it's an issue when you pass arbitrary arguments to ANY external utility in ANY language. For example, maybe you have some kind of tool that calls grep: # Perl exec '/usr/bin/grep', '-R', $input, 'mydir'; # PHP (with Symfony Process) (new Process(['/usr/bin/grep', '-R', $input, 'mydir']))->run(); # Python subprocess.run(['/usr/bin/grep', '-R', input, 'mydir']) # C execv("/usr/bin/grep", (char *[]) {"grep", "-R", input, "mydir", NULL}); All of these are safe in the sense that there's no risk of shell command injection (in fact, only the PHP one even calls the shell), but NONE of them are safe against this problem, where the input value might begin with a hyphen. In this grep scenario it's probably not a security issue, but it can produce confusing results for the user if nothing else. As others mentioned, you must ALWAYS use '--' to mark the end of option processing when you do something like this. [0] Technically the shell knows about the conventions of its built-ins, but even those mostly handle arguments in a similar fashion to external utilities, where an arbitrary argv is fed to a function and then parsed using some getopts-like method.
指出标准对策:在用户参数前加 -- 防止被解析为选项
文章没提到的一点:在自己的脚本中,可以在用户提供参数前加 --,防止它们被当作选项。例如 rm -- -rf 会把 '-rf' 当作文件名处理(参见 POSIX 指南第 10 条)。
Pete_D查看英文原文
I didn't see this mentioned in the article, but you can protect against this in your own scripts by including a -- before user-supplied parameters, which prevents them from being treated as flags. $ rm -- -rf rm: cannot remove '-rf': No such file or directory (see Guideline 10, http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02)
认为文件名陷阱是 shell 脚本的分水岭:复杂文件处理应改用脚本语言
这个问题,加上处理含空格、换行、制表符的文件名的麻烦,划清了我'愿意用 shell 脚本'和'改用带文件操作系统调用的脚本语言'的界限。只接收一个文件参数的三行脚本?用 bash 没问题。处理 N 个文件、处理 stdin 传入的文件列表、还要对文件做分支逻辑?bash 就出局了。除非目标是 PDP-11 或 initramfs 里的 Busybox sh,否则 shell 真是最佳选择吗?
derefr查看英文原文
This, plus the problem of dealing with files with spaces, newlines, tabs, etc. in their names, are what draw the line for me between "things I am willing to write as a shell script" and "things that will make me use a scripting language† with its own file-manipulation system-call builtins." A three-line script that takes one file as an argument? Sure, write that in bash. A script that processes N files passed as arguments? Or that processes a listing of files piped in from stdin? And uses branching logic on the files themselves? Bash goes out the window. Sure, it's possible to write shell scripts to do that. But why? Unless you're targeting a PDP11 or the Busybox-linked /bin/sh in your initramfs, is shell scripting really the best option? --- † Personally, I reach for Ruby in these cases; its stdlib Pathname and FileUtils classes are pretty solid for this use-case, and Ruby interpreters are now roughly everywhere I want to deploy. Ruby is kind of clumsy for doing all the command piping parts of scripting, though; especially since there's no easy way short of wrapping Kernel.system in your own function to make a Ruby script crash on a nonzero subshell exit status. I'd love to know if there was a language that was like Ruby in terms of the syntax and semantics around strings, arrays, and files; but then was "just like writing a shell script" in the sense of being able to just use binary names to make "function calls" that are really synchronous subshell spawns and exit-code checks in one (but which still use the variable-passing semantics of the language where the resulting exec(2) ARGV is concerned.) Probably a Ruby DSL is the simplest way to get that—but if it's not in the stdlib, I'm not going to be able to use it for DevOps scripting :/
历次讨论
同类还值得读
非法素数
Illegal prime
维基百科条目,介绍“非法素数”:某些素数之所以被称为“非法”,是因为它们经特定编码后,恰好对应一段被法律禁止传播的数据——最著名的是 DVD 解密程序 DeCSS 的代码,有人把…
安全与隐私上首页 5 次 · 2010–2021en.wikipedia.org编辑精选关于 /dev/urandom 的常见误区
Myths about /dev/urandom
(Thomas Hühn 撰写,2014 年首发并持续更新)逐条反驳关于 /dev/urandom 的常见误解:它与 /dev/random 使用的是同一个 CSPRNG,一旦完…
安全与隐私上首页 5 次 · 2014–20202uo.de编辑精选AES 高级加密标准火柴人图解
A Stick Figure Guide to the Advanced Encryption Standard (AES)
一篇用火柴人漫画形式讲解 AES(高级加密标准)算法的经典科普文章。
安全与隐私上首页 5 次 · 2009–2022moserware.com编辑精选指纹是用户名,不是密码
Fingerprints are Usernames, not Passwords
作者(eCryptfs 维护者、Ubuntu 安全工程师)认为指纹等生物特征是公开、不可更改的标识,应视作用户名而非密码,不能当作秘密凭据用于认证。
安全与隐私上首页 4 次 · 2013–2017blog.dustinkirkland.comHTTPS 连接的最初几毫秒(2009)
The First Few Milliseconds of an HTTPS Connection (2009)
逐毫秒拆解一次 HTTPS 连接建立时发生了什么,重点讲 TLS 握手、证书验证、RSA 签名与密钥协商等机制,面向不熟悉该领域的读者。
安全与隐私上首页 4 次 · 2009–2020moserware.com编辑精选