我想表明通过输入密码read
是不安全的。
要将其嵌入到中途现实场景中,假设我使用以下命令提示用户输入密码并让 7z¹ 从中创建加密存档:
read -s -p "Enter password: " pass && 7z a test_file.zip test_file -p"$pass"; unset pass
我第一次尝试泄露密码是通过设置审计规则:
auditctl -a always,exit -F path=/bin/7z -F perm=x
果然,当我执行涉及read
and的命令7z
时,运行时有一个日志条目ausearch -f /bin/7z
:
time->Thu Jan 23 18:37:06 2020
type=PROCTITLE msg=audit(1579801026.734:2688): proctitle=2F62696E2F7368002F7573722F62696E2F377A006100746573745F66696C652E7A697000746573745F66696C65002D7074686973206973207665727920736563726574
type=PATH msg=audit(1579801026.734:2688): item=2 name="/lib64/ld-linux-x86-64.so.2" inode=1969104 dev=08:03 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1579801026.734:2688): item=1 name="/bin/sh" inode=1972625 dev=08:03 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1579801026.734:2688): item=0 name="/usr/bin/7z" inode=1998961 dev=08:03 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1579801026.734:2688): cwd="/home/mb/experiments"
type=EXECVE msg=audit(1579801026.734:2688): argc=6 a0="/bin/sh" a1="/usr/bin/7z" a2="a" a3="test_file.zip" a4="test_file" a5=2D7074686973206973207665727920736563726574
type=SYSCALL msg=audit(1579801026.734:2688): arch=c000003e syscall=59 success=yes exit=0 a0=563aa2479290 a1=563aa247d040 a2=563aa247fe10 a3=8 items=3 ppid=2690563 pid=2690868 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts17 ses=1 comm="7z" exe="/usr/bin/bash" key=(null)
这条线似乎最有希望:
type=EXECVE msg=audit(1579801026.734:2688): argc=6 a0="/bin/sh" a1="/usr/bin/7z" a2="a" a3="test_file.zip" a4="test_file" a5=2D7074686973206973207665727920736563726574
但是字符串2D7074686973206973207665727920736563726574
不是我输入的密码。
我的问题是双重的:
audit
获取密码的正确工具是什么?如果是这样,我需要对审计规则进行更改吗?- 除了 ,还有更简单的方法
audit
来获取密码吗?
¹我知道 7z 可以自行提示输入密码。
不安全的不是
read(2)
(从文件中读取数据的系统调用)。它甚至不是read(1)
(shell 内置从标准输入读取一行)。不安全的是在命令行上传递密码。当用户输入 shell 读取的内容时
read
,该内容对终端和 shell 都是可见的。它对其他用户不可见。使用read -s
,肩部冲浪者看不到它。命令行上传递的字符串在审计日志中可见。(字符串可能会被截断,我不确定,但如果是这样的话,它只会用于比密码长得多的字符串。)当它包含诸如空格之类的字符时,它只是以十六进制编码,这会使日志模棱两可解析。
这不是您不应该在命令行上传递秘密的主要原因。毕竟,应该只有管理员才能看到审计日志,而管理员可以根据需要查看所有内容。但是,在日志中包含秘密会更糟糕,因为以后可能会有更多人访问它们(例如通过不正确的安全备份)。
不应在命令行上传递秘密的主要原因是,在大多数系统上,其他用户也可以看到命令行。(有些强化的系统并非如此,但这通常不是默认设置。)在正确的时间运行
ps
,top
或cat /proc/*/cmdline
任何类似实用程序的任何人都可以看到密码。7z 程序在启动后不久就会覆盖密码(只要它能够制作内部副本),但这只会减少危险窗口,并不能消除漏洞。在环境变量中传递秘密是安全的。该环境对其他用户不可见。但我不认为 7z 支持这一点。要在不通过命令行显示的情况下传递密码,您需要将其作为输入传递,并且 7z 从终端读取,而不是从标准输入。您可以使用它
expect
来执行此操作(或者,如果您更喜欢 Python 而不是 TCL,或者Perl 或 Ruby 中的Expect.pm等,则可以使用pexpectexpect
)。未经测试: