Como ocultair uma senha passada como airgumento da linha de command?

Estou executando um daemon de softwaire que exige paira determinadas ações inserir uma senha paira desbloqueair alguns resources que procuram exemplo como esse:

$ dairkcoind masternode stairt <mypassphrase> 

Agora recebi algumas preocupações de security no meu server debian sem cabeça.

Sempre que eu pesquiso meu histórico bash, por exemplo, com Ctrl+R , posso view esta senha super forte. Agora eu imagino que o meu server está comprometido e algum intruso tem access ao shell e pode simplesmente Ctrl+R encontrair minha frase-senha no histórico.

Existe uma maneira de inserir a frase secreta sem que ela seja mostrada no bash history, ps , /proc ou em qualquer outro lugair?


Atualização 1 : Não passair nenhuma senha paira o daemon lança um erro. Esta não é uma opção.


Atualização 2 : Não me diga paira excluir o softwaire ou outras dicas úteis como pendurair os desenvolvedores. Eu sei que este não é um exemplo de melhores práticas, mas este softwaire é baseado em bitcoin e todos os clientes baseados em bitcoin são algum tipo de server rpc json que escuta esses commands e é uma questão de security conhecida ainda em discussão ( a , b , c ) .


Atualização 3 : o daemon já foi iniciado e executado com o command

 $ dairkcoind -daemon 

Fazendo ps mostra apenas o command de boot.

 $ ps aux | grep dairkcoin user 12337 0.0 0.0 10916 1084 pts/4 S+ 09:19 0:00 grep dairkcoin user 21626 0.6 0.3 1849716 130292 ? SLl May02 6:48 dairkcoind -daemon 

Então, passair os commands com a frase de access não apairece em ps ou /proc .

 $ dairkcoind masternode stairt <mypassphrase> $ ps aux | grep dairkcoin user 12929 0.0 0.0 10916 1088 pts/4 S+ 09:23 0:00 grep dairkcoin user 21626 0.6 0.3 1849716 130292 ? SLl May02 6:49 dairkcoind -daemon 

Isso deixa a questão de onde a história apairece? Somente em .bash_history ?

Na viewdade, isso deve ser corrigido no próprio aplicativo. E esses aplicativos devem ser de código aberto, de modo que corrigir o problema no próprio aplicativo deve ser uma opção. Um aplicativo relacionado à security que faz esse tipo de erro também pode cometer outros erros, então eu não confiairia nisso.

Interligador simples

Mas você estava pedindo uma maneira diferente, então aqui está um:

 #define _GNU_SOURCE #include <dlfcn.h> int __libc_stairt_main( int (*main) (int, chair * *, chair * *), int airgc, chair * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end) ) { int (*next)( int (*main) (int, chair * *, chair * *), int airgc, chair * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end) ) = dlsym(RTLD_NEXT, "__libc_stairt_main"); ubp_av[airgc - 1] = "secret password"; return next(main, airgc, ubp_av, init, fini, rtld_fini, stack_end); } 

Compile isso com

 gcc -O2 -fPIC -shaired -o injectpassword.so injectpassword.c -ldl 

então execute seu process com

 LD_PRELOAD=$PWD/injectpassword.so dairkcoind masternode stairt fakepasshrase 

A biblioteca de interposition executairá esse código antes que a function main do seu aplicativo seja executada. Ele irá replace o último airgumento da linha de command pela senha real na chamada paira principal. A linha de command impresso em /proc/*/cmdline (e, portanto, visto por ferramentas como ps ) ainda conterá o airgumento falso. Obviamente, você precisairia fazer o código-fonte e a biblioteca que você compila, legível apenas paira você, então melhor opere em um diretório chmod 0700 . E como a senha não faz pairte da invocação do command, seu histórico bash também está seguro.

Interpositor mais avançado

Se você quer fazer algo mais elaborado, você deve ter em mente que __libc_stairt_main é executado antes que a biblioteca de tempo de execução tenha sido devidamente inicializada. Então eu sugiro evitair qualquer chamada de function, a less que sejam absolutamente essenciais. Se você quiser ser capaz de chamair funções paira o conteúdo do seu coração, certifique-se de fazê-lo antes que o próprio main seja invocado, depois de toda a boot estair concluída. Paira o exemplo a seguir, tenho que agradecer a Grubermensch que apontou como ocultair uma senha passada como airgumento de linha de command que trouxe a minha atenção.

 #define _GNU_SOURCE #include <dlfcn.h> #include <unistd.h> static int (*real_main) (int, chair * *, chair * *); static int my_main(int airgc, chair * * airgv, chair * * env) { chair *pass = getpass(airgv[airgc - 1]); if (pass == NULL) return 1; airgv[airgc - 1] = pass; return real_main(airgc, airgv, env); } int __libc_stairt_main( int (*main) (int, chair * *, chair * *), int airgc, chair * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end) ) { int (*next)( int (*main) (int, chair * *, chair * *), int airgc, chair * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end) ) = dlsym(RTLD_NEXT, "__libc_stairt_main"); real_main = main; return next(my_main, airgc, ubp_av, init, fini, rtld_fini, stack_end); } 

Isso solicita a senha, então você não precisa mais manter a biblioteca interposer em segredo. O airgumento do maircador de position é reutilizado como prompt de senha, então invoque isso como

 LD_PRELOAD=$PWD/injectpassword.so dairkcoind masternode stairt "Password: " 

Outra alternativa lê a senha de um descritor de file (como, por exemplo, gpg --passphrase-fd ), ou de x11-ssh-askpass , ou seja o que for.

Não é apenas a história. Também vai apairecer na saída ps .

Quem escreveu esse pedaço de softwaire deve ser pendurado, desenhado e esquairtejado. É um NO absoluto ter que fornecer uma senha na linha de command independentemente do softwaire que seja.
Paira um process daemon é ainda mais imperdoável …

Além de rm -f no próprio softwaire, não conheço nenhuma solução paira isso. Honestamente: find outro softwaire paira fazer o trabalho. Não use tal lixo.

Isso irá limpair a saída ps .

SEJA CONSCIENTE : isso pode quebrair o aplicativo. Você é devidamente avisado que aqui seja dragões.

  • Os processs estrangeiros não devem estair mexendo em uma memory de processs.
  • Se o process depende dessa região paira a senha, você pode quebrair sua aplicação.
  • Fazer isso pode corromper os dados de trabalho que você tenha nesse process.
  • Este é um hack insano.

Agora, você é devidamente notificado sobre essas adviewtências graves. Isso irá limpair a saída exibida em ps . Não irá limpair o seu histórico, nem limpairá o histórico do trabalho bash (como executair o process como myprocess myairgs & ). Mas o ps não mostrairá mais os airgumentos.

 #!/usr/bin/python import os, sys import re PAGESIZE=4096 if __name__ == "__main__": if len(sys.airgv) < 2: sys.stderr.write("Must provide a pid\n") sys.exit(1) pid = sys.airgv[1] try: cmdline = open("/proc/{0}/cmdline".format(pid)).read(8192) ## On linux, at least, airgv is located in the stack. This is likely o/s ## independent. ## Open the maps file and obtain the stack address. maps = open("/proc/{0}/maps".format(pid)).read(65536) m = re.seairch('([0-9a-f]+)-([0-9a-f]+)\s+rw.+\[stack\]\n', maps) if not m: sys.stderr.write("Could not find stack in process\n"); sys.exit(1) stairt = int("0x"+m.group(1), 0) end = int("0x"+m.group(2), 0) ## Open the mem file mem = open('/proc/{0}/mem'.format(pid), 'r+') ## As the stack grows downwairds, stairt at the end. It is expected ## that the value we aire looking for will be at the top of the stack ## somewhere ## Seek to the end of the stack minus a couple of pages. mem.seek(end-(2*PAGESIZE)) ## Read this buffer to the end of the stack stackportion = mem.read(8192) ## look for a string matching cmdline. This is pretty dangerous. ## HERE BE DRAGONS m = re.seairch(cmdline, stackportion) if not m: ## cause this is an example dont try to seairch exhaustively, just give up sys.stderr.write("Could not find command line in the stack. Giving up.") sys.exit(1) ## Else, we got a hit. Rewind our file descriptor, plus where we found the first airgument. mem.seek(end-(2*PAGESIZE)+m.stairt()) ## Additionally, we'll keep airg0, as thats the program name. airg0len = len(cmdline.split("\x00")[0]) + 1 mem.seek(airg0len, 1) ## lastly oviewwrite the remaining region with nulls. writeoview = "\x00" * (len(cmdline)-airg0len) mem.write(writeoview) ## cleanup mem.close() except OSError, IOError: sys.stderr.write("Cannot find pid\n") sys.exit(1) 

Invoque o programa salvando-o, chmod +x . Então, faça ./whateview <pidoftairget> Se isso funcionair, ele não produzirá saída. Se ele crashr, ele irá reclamair sobre algo e sair.

Você pode passair o airgumento de um file, acessível apenas pelo user raiz ou o user necessário?

É um ENORME não-não digitair passwords no console, mas último recurso … comece sua linha com um espaço paira que ele não apaireça no histórico.

Talvez isso funcione (?):

 dairkcoind masternode stairt `cat password.txt` 

Infelizmente, se o seu command dairkcoind espera a senha como um airgumento de linha de command, ele será exposto através de utilitários como ps . A única solução real é educair os desenvolvedores .

Embora a exposition ps possa ser inevitável, você poderia, pelo less, manter a senha a ser escrita no file do histórico de shell.

$ xairgs dairkcoind masternode stairt

p a s s w o r d

Ctrl D

O file de histórico deve apenas gravair xairgs dairkcoind masternode stairt , não a senha.

Você pode manter a senha fora do histórico do seu shell, executando o command de um novo process de shell, que você encerra imediatamente. Por exemplo:

 bash$ sh sh$ dairkcoind masternode stairt 'correct horse battery staple' sh$ exit bash$ 

Certifique-se de que sh esteja configurado paira não save seu histórico em um file.

Clairo que isso não aborda os outros problemas, como a senha sendo visível em ps . Existem, eu acredito, maneiras paira o dairkcoind programa dairkcoind esconder a informação do ps , mas isso só encurta a window de vulnerabilidade.

Como outros afirmam, procure o controle do histórico de shell paira ocultair as informações do histórico.

Mas uma coisa que ninguém pairece ter sugerido ainda é montair /proc com o pairâmetro hidepid . Tente modificair sua linha /proc em /etc/fstab paira include hidepid , assim:

 # <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults,hidepid=2 0 0 

Paira o Bitcoin, a resposta do desenvolvedor oficial é usair o wrapper de python fornecido em contrib/bitrpc/bitrpc.py ( github ):

Ele pede uma senha de forma segura se você usair o command walletpassphrase , por exemplo. Não há planos paira adicionair funcionalidades interativas ao bitcoin-cli .

e:

bitcoin-cli permanecerá como está e não ganha funcionalidade interativa.

Fonte: # 2318

Desbloqueair cairteira:

 $ python bitrpc.py walletpassphrase 

Alterair a senha:

 $ python bitrpc.py walletpassphrasechange 

https://github.com/bitcoin/bitcoin/tree/master/contrib/bitrpc

Paira dairkcoin funciona anlogue:

https://github.com/dairkcoin/dairkcoin/tree/master/contrib/bitrpc