Eu gostaria de mostrar que inserir senhas via read
é inseguro.
Para incorporar isso em um cenário meio realista, digamos que eu use o seguinte comando para solicitar uma senha ao usuário e fazer com que o 7z¹ crie um arquivo criptografado a partir dele:
read -s -p "Enter password: " pass && 7z a test_file.zip test_file -p"$pass"; unset pass
Minha primeira tentativa de revelar a senha foi configurando uma regra de auditoria :
auditctl -a always,exit -F path=/bin/7z -F perm=x
Com certeza, quando executo o comando envolvendo read
and 7z
, há uma entrada de log ao executar 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)
Esta linha parecia a mais promissora:
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
Mas a string 2D7074686973206973207665727920736563726574
não é a senha que eu digitei.
Minha pergunta é dupla:
- É
audit
a ferramenta certa para obter a senha? Em caso afirmativo, há algo que devo mudar na regra de auditoria? - Existe uma maneira mais fácil, além de
audit
, para obter a senha?
¹ Estou ciente de que o 7z pode solicitar senhas sozinho.
O que é inseguro não é
read(2)
(a chamada do sistema para ler dados de um arquivo). Não é mesmoread(1)
(o shell embutido para ler uma linha da entrada padrão). O que é inseguro é passar a senha na linha de comando.Quando o usuário insere algo que o shell lê com
read
, essa coisa fica visível para o terminal e para o shell. Não é visível para outros usuários. Comread -s
, não é visível para surfistas de ombro.A string passada na linha de comando é visível nos logs de auditoria. (A string pode estar truncada, não tenho certeza sobre isso, mas se for, seria apenas para strings muito mais longas do que uma senha.) Ela é codificada apenas em hexadecimal quando contém caracteres como espaços que tornariam o log ambíguo para analisar.
Essa não é a principal razão pela qual você não deve passar um segredo na linha de comando. Afinal, apenas o administrador deve poder ver os logs de auditoria, e o administrador pode ver tudo, se quiser. No entanto, é pior ter o segredo nos logs, porque eles podem ser acessíveis a mais pessoas posteriormente (por exemplo, por meio de um backup protegido incorretamente).
A principal razão pela qual você não deve passar um segredo na linha de comando é que na maioria dos sistemas a linha de comando também é visível para outros usuários. (Existem sistemas protegidos onde este não é o caso, mas normalmente não é o padrão.) Qualquer pessoa executando
ps
,top
,cat /proc/*/cmdline
ou qualquer utilitário similar no momento certo pode ver a senha. O programa 7z substitui a senha logo após iniciar (assim que consegue fazer uma cópia interna), mas isso apenas reduz a janela de perigo, não remove a vulnerabilidade.Passar um segredo em uma variável de ambiente é seguro. O ambiente não é visível para outros usuários. Mas eu não acho que 7z suporta isso. Para passar a senha sem torná-la visível pela linha de comando, você precisa passá-la como entrada e o 7z lê do terminal, não do stdin. Você pode usar
expect
para fazer isso (ou esperar se preferir Python a TCL, ou Expect.pm em Perl, ouexpect
em Ruby, etc.). Não testado: