這篇文章的開頭並不像您所期望或每天看到的那樣,這是我的 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
.