这篇文章的开头并不像您所期望或每天看到的那样,这是我的 root 密码::4\g&8n:6_F[`9Touc8Ls+L'8)>6!3,nNmUzR&Ub~w7NTd'^Lb0]`0`."u>tP\>XAspMLTt!@}=F6CP)NsSMYY7*xm'A!7`!n'tmAaGWoBhS|u4{k$*v/o|'%)mbXMw
很难记住,对吗?好吧,这不是问题。在你对我大喊大叫之前,是的,我改变了它。我现在有一个dummy_root
具有该密码的用户进行测试。
长话短说
我破坏了 zsh 将此密码传递给标准输入上的 sudo
(非常)长的版本
所以这是错误的:我使用sudo
withtargetpw
标志,这意味着 sudo 询问的密码是目标用户的密码,而不是我的密码。我使用pass
密码管理器(地点)的一切,包括我所有计算机/服务器的 root 密码。出于明显的安全原因,该密码是由 128 个字符的 pass 随机生成的(因为为什么不呢)。作为一个懒人(我相信你也是),我想使用以下别名:
alias sudo='pass mydomain.tld/hostname/users/root/password | sudo --stdin'
对于那些不熟悉 pass 的人来说,它基本上使用 GnuPG 对目录树中的密码进行加密,然后调用pass directory/subdirectory/password
解密密码并将其打印到 stdout (当然,目录是可选的,您可以将所有内容无序地存储在根目录中,但不鼓励这样做)。别名的目的是避免每天执行数十次:
$ pass --clip root_password #Copy root password to clipboard
$ sudo command
[sudo] password for root: paste
#command output (if the password is right of course)
但是测试别名命令,会发生什么:
$ pass root_password | sudo --stdin --shell
[sudo] password for root: %
$
在这里,%
标志是颜色反转的:我的终端是黑底白字,%
白底黑字,有点白色突出显示,并在密码解密后打印。在打印[sudo] password for root:
和打印 this之间%
,GPG 要求我提供私钥密码。我已经在某些情况下注意到了倒置的百分号,并且从我看到它的位置和时间,我相信它是打印EOF
(这里小心,我根本不确定这一点,请参阅帖子末尾的方法打印这个%
)。请注意,在这个奇怪的标志之后,我不是 root,而是echo $?
返回0
...
所以我对输出进行了十六进制转储,pass root_password
看看是否可以获得有关该角色的更多信息。结果如下:
$ pass root_password
:4\?g&8n:6_F[`9Touc8Ls+L'8)>6!3,nNmUzR&Ub~w7NTd'^Lb0]`0`."u>tP\>XAspMLTt!@}=F6CP)NsSMYY7*xm'A!7`!n'tmAaGWoBhS|u4{k$*v/o|'%)mbXMw
$ pass root_password | hexdump -C
00000000 3a 34 5c 3f 67 26 38 6e 3a 36 5f 46 5b 60 39 54 |:4\?g&8n:6_F[`9T|
00000010 6f 75 63 38 4c 73 2b 4c 27 38 29 3e 36 21 33 2c |ouc8Ls+L'8)>6!3,|
00000020 6e 4e 6d 55 7a 52 26 55 62 7e 77 37 4e 54 64 27 |nNmUzR&Ub~w7NTd'|
00000030 5e 4c 62 30 5d 60 30 60 2e 22 75 3e 74 50 5c 3e |^Lb0]`0`."u>tP\>|
00000040 58 41 73 70 4d 4c 54 74 21 40 7d 3d 46 36 43 50 |XAspMLTt!@}=F6CP|
00000050 29 4e 73 53 4d 59 59 37 2a 78 6d 27 41 21 37 60 |)NsSMYY7*xm'A!7`|
00000060 21 6e 27 74 6d 41 61 47 57 6f 42 68 53 7c 75 34 |!n'tmAaGWoBhS|u4|
00000070 7b 6b 24 2a 76 2f 6f 7c 27 25 29 6d 62 58 4d 77 |{k$*v/o|'%)mbXMw|
00000080 0a |.|
00000081
0a
是NL
根据man ascii
.您可以注意到此处%
没有该符号,而是 sudo 所需的换行符(请参阅man sudo
)在这里。
但是等一下,现在有趣的事情开始了:当我在新启动的终结器窗口或 tty 上运行命令两次时,会发生以下情况:
$ pass root_password | sudo --stdin --shell
[sudo] password for root: %
$ pass root_password | sudo --stdin --shell
zsh: parse error near `)'
$
从那时起,zsh 似乎就被破坏了。看起来它想执行第一个命令的输出,但只是sudo
第二个命令。以下是这个“损坏”外壳的一些示例:
$ echo testpw | sudo --stdin --shell
zsh: command not found: testpw
$ echo testpw | cat
testpw
$ echo testpw | wc --bytes
11
$ echo anothertestpw | sudo --stdin --shell
zsh: command not found: anothertestpw
$ pass root_password | sudo --stdin --shell
zsh: parse error near `)'
$ exec zsh
$ echo testpw | sudo --stdin --shell
zsh: command not found:testpw
这里发生了什么?如图所示,evec 用另一个 ( ) 替换 zsh 实例exec zsh
并不能解决此问题。这里真正损坏的是什么?通过、zsh 或 sudo ?
所以让我们继续,让我们测试更多,让我们在新的终端窗口中进行另一个十六进制转储(因为显然我不知道如何将 zsh 恢复到“正常”状态):
$ pass root_password | sudo --stdin --shell 2>&1 | hexdump -C
00000000 5b 73 75 64 6f 5d 20 70 61 73 73 77 6f 72 64 20 |[sudo] password |
00000010 66 6f 72 20 72 6f 6f 74 3a 20 |for root: |
0000001a
$
这个百分号到哪里去了?不知道。它只是不在这里,而且我仍然不是 root,但 shell 现在处于损坏状态(我绝对不知道如何正确命名这个“损坏状态”)。在这之后运行该pass root_password | sudo --stdin --shell
命令会引发与之前相同的错误消息。值得注意的是,tty 和终结者上的一切都是一样的,即使是这个邪恶的%
角色。
这是我能想到的可能需要帮助我的所有信息。我使用的是 Arch Linux,所有提到的软件包都是截至今天的最新版本(2017 年 4 月 16 日或 15 日,具体取决于您在地球上的哪个位置,目前法国凌晨 4 点),这意味着(pacman -Q
输出):
- 内核:4.10.9-1
- zsh:5.3.1-2
- 须藤:1.8.19.p2-1
- 通过:1.7.1-1
- gnupg:2.1.20-1
- 终结者:1.91-5
这里有一个关联对于我的 .zshrc,它也可能有帮助。
正如所承诺的,这里有一些步骤来获取这个恶意%
标志pass
。只需创建一个多行密码,然后按Ctrl+D完成密码而不添加尾随新行即可打印该字符。我注意到,在文本行末尾点击Ctrl+是不够的,您必须执行两次。D但是,如果您向该多行密码添加尾随行,则单击它一次将结束密码输入而不显示此内容。
$ pass insert --multiline test_evil_percent
Enter contents of test_evil_percent and press Ctrl+D when finished:
fooReturn
barCtrl+DCtrl+D%
就在那里!
但如果有尾行,它就不会出现,当我们只按Ctrl+D一次时,我们就会得到提示。
$ pass insert --multiline test_evil_percent
Enter contents of test_evil_percent and press Ctrl+D when finished:
fooReturn
barReturn
Ctrl+D
$
所以最根本的问题是:如何让我的别名发挥作用?对于那些想知道的人,我只是在我的自定义脚本目录中编写了一行脚本,调用pass root_password
并将环境变量设置SUDO_ASKPASS
为我的文件中该脚本的传递.zshrc
另一个问题可能是:这里的 zsh 和 sudo 到底是怎么回事?
编辑2017-04-16:解决方案
谢谢迈克尔·霍默我为我的问题选择了这个解决方案:
askpass-sudo
编写一个名为which 调用的一行脚本pass root_password
SUDO_ASKPASS
将my中的环境变量设置.zprofile
为该脚本的路径- 将该行添加
alias sudo='sudo -A'
到我的.zshrc
瞧!现在调用会sudo command
根据需要询问我的 GnuPG 密钥密码来解密 root 密码,这样sudo --shell
我就可以正确获得 root shell。
答案1
pass root_password | sudo --stdin --shell
成功了。pass
打印密码并sudo
读取它并启动 shell;结束的输出,意味着shellpass
用于输出和输入的流已关闭; pass
shell 在 EOF 时成功退出。
随后的执行sudo
超时窗口不需要身份验证,因此 shell 收到密码本身并尝试将其作为命令执行,从而给出该错误。
如果您想要一个 shell 或运行一些从 stdin 读取的命令,则您的别名可能无法工作(但对于不需要的命令则可以)。如果需要,您可以设置一个运行的别名pass root_password | sudo --stdin true
,然后依靠超时来运行没有密码的命令。
您还可以构建某种askpass 帮助程序来提供您想要的行为。它将通过pass
以下方式提供密码问为它由sudo
.