使用 read 輸入嗅探密碼並作為命令行參數傳遞
我想表明通過輸入密碼
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
,肩部衝浪者看不到它。命令行上傳遞的字元串在審計日誌中可見。(字元串可能會被截斷,我不確定,但如果是這樣的話,它只會用於比密碼長得多的字元串。)當它包含諸如空格之類的字元時,它只是以十六進制編碼,會使日誌模棱兩可解析。
$ echo 2D7074686973206973207665727920736563726574 | xxd -r -p; echo -pthis is very secret $ perl -l -e 'print pack "H*", @ARGV' 2D7074686973206973207665727920736563726574 -pthis is very secret
這不是您不應該在命令行上傳遞秘密的主要原因。畢竟,應該只有管理員才能看到審計日誌,而管理員可以根據需要查看所有內容。但是,在日誌中包含秘密會更糟糕,因為以後可能會有更多人訪問它們(例如通過不正確的安全備份)。
不應在命令行上傳遞秘密的主要原因是,在大多數係統上,其他使用者也可以看到命令行。(有些強化系統不是這種情況,但這通常不是預設設置。)任何人在正確的時間執行
ps
,top
或cat /proc/*/cmdline
任何類似的實用程序都可以看到密碼。7z 程序在啟動後不久就會覆蓋密碼(只要它能夠製作內部副本),但這只會減少危險視窗,並不能消除漏洞。在環境變數中傳遞秘密是安全的。該環境對其他使用者不可見。但我不認為 7z 支持這一點。要在不通過命令行顯示的情況下傳遞密碼,您需要將其作為輸入傳遞,並且 7z 從終端讀取,而不是從標準輸入。您可以使用它
expect
來執行此操作(或者,如果您更喜歡 Python 而不是 TCL,或者Perl 或 Ruby 中的Expect.pm等,則可以使用pexpectexpect
)。未經測試:read -s -p "Enter password: " pass pass=$pass expect \ -c 'spawn 7z a -p test_file.zip test_file' \ -c 'expect "assword:" {send $::env(pass)}' \ -c 'expect eof' -c 'catch wait result' unset pass