Comportamento padrão ao receber um sinal ... O que essas palavras tranquilizadoras significam? Não o que você esperava, com certeza. O wiki diz que os 28 manipuladores de sinal padrão (existem outros!) São os seguintes: 2 são ignorados, 4 fazem o processo parar, 1 para continuar, 11 para terminar, 10 para terminar com um despejo de memória. Agora isso é interessante! Então, a situação é a seguinte: mesmo que seu programa não mencione sinais de forma alguma no código-fonte, na verdade ele os usa, e de forma muito dramática.
De agora em diante, teremos que cavar mais fundo. Quem pode enviar sinais e para quem? O wiki diz: "Um processo (ou um usuário de um shell) com um UID efetivo diferente de 0 (o UID do superusuário) só pode enviar sinais para processos com o mesmo UID." Portanto, se você executar 100 programas, qualquer um deles pode facilmente matar todos esses 100 programas usando a API do sistema, mesmo se todos os programas (exceto o assassino) não mencionaram os sinais de nenhuma forma em seu código-fonte. Se você trabalhou com a conta root, então não importa quem iniciou certos processos, você ainda pode encerrá-los facilmente. Obviamente, é possível descobrir o pid de um determinado processo e executar seu "assassinato por contrato", mas é ainda mais fácil matar todos que podem ser simplesmente pid-s de força bruta.
“Espere, espere, não dirija os cavalos. Você mencionou que os sinais podem ser processados e ignorados! " - Eu ouço a voz do meu leitor. O que a Vicki vai dizer? "Para tratamento alternativo de todos os sinais, exceto SIGKILL e SIGSTOP, um processo pode atribuir seu próprio manipulador ou ignorar sua ocorrência, modificando sua máscara de sinal." Observamos as ações padrão ao receber esses sinais e vemos: "Encerramento do processo", "Encerramento do processo". Acontece que podemos fazer essas duas ações sempre que enviar sinais SIGKILL e SIGSTOP para a vítima for, em princípio, possível. "A única exceção é um processo com pid 1 (init), que tem permissão para ignorar ou lidar com quaisquer sinais, incluindo KILL e STOP."Podemos nem mesmo ser capazes de matar um dos processos mais importantes do sistema como root, mas de uma forma amigável, isso requer pesquisas adicionais.
Bem, o quadro ficou um pouco mais positivo, mas ainda é sombrio. Se você iniciar um processo, é garantido que ele pode encerrar e interromper vários outros processos. Quando uma condição muito simples é atendida, "os desenvolvedores do processo de recebimento se esqueceram de ignorar ou de alguma forma manipular um dos muitos outros sinais", o aplicativo maníaco será capaz de fazer com que o processo termine com um despejo de memória ou continuar o processo após parar. Se os desenvolvedores do aplicativo receptor travaram seus manipuladores em alguns sinais, você pode tentar interferir no funcionamento desse aplicativo enviando sinais para ele. Este último é um tópico para uma discussão separada, porque devido à execução assíncrona de manipuladores, corridas e comportamento indefinido são possíveis ...
“O raciocínio abstrato é muito legal, mas vamos nos aproximar dos detalhes”, um leitor exigente me dirá. Ok, sem problemas! Qualquer usuário * nix está familiarizado com um programa como o bash. Este programa vem se desenvolvendo há quase 30 anos e tem uma montanha de possibilidades. Vamos enchê-la para maior clareza e tirar um pouco de sua memória gostosa!
Eu levo meu Ubuntu 16.04.2 para casa e executo duas cópias do bash 4.3.46 nele. Em um deles, irei executar um comando hipotético com dados secretos: export password = SECRET. Vamos esquecer um pouco o arquivo com o histórico de comandos, no qual a senha também seria gravada. Na mesma janela, digite o comando ps para descobrir o pid desse processo - digamos, 3580.
Sem fechar a primeira janela, vamos para a segunda. O comando ps nele fornecerá outro pid desta instância do bash - digamos, 5378. Apenas para clareza, é a partir desse segundo bash que enviaremos um sinal para o primeiro comando kill -SIGFPE 3580. Sim, caro leitor, isso é um absurdo completo: o processo 2 não diz nada relacionado a para o processo 1, que neste mesmo processo 1 ocorreu uma operação aritmética errônea. A seguinte janela aparecerá na tela: A

anormalidade desejada ocorreu com a criação de um dump de memória, ou seja, o bash parece não processar ou ignorar este sinal. Pesquisando onde procuro o depósito, encontrei uma resposta detalhada ( um , dois) No meu Ubuntu, a situação é a seguinte: se um aplicativo do pacote padrão travar devido a um sinal diferente do SIGABRT, o dump é transferido para o programa Apport. Este é apenas o nosso caso! Este programa monta um arquivo com informações de diagnóstico e exibe a janela mostrada acima. O site oficial afirma com orgulho: “O Apport coleta dados potencialmente sensíveis, como core dumps, rastreamentos de pilha e arquivos de log. Eles podem conter senhas, números de cartão de crédito, números de série e outros materiais privados. " Bem, bem, eu me pergunto onde temos esse arquivo? Sim, /var/crash/_bin_bash.1000.crash. Vamos colocar seu conteúdo na pasta algumedir: apport-unpack /var/crash/_bin_bash.1000.crash algumedir. Além de várias pequenas coisas desinteressantes, haverá um despejo de memória cobiçado chamado CoreDump.
Aqui está, o momento da verdade! Vamos procurar neste arquivo a string de senha e ver o que ficamos interessantes em resposta. Comando Strings CoreDump | A senha grep lembrará o hacker esquecido de que a senha é SECRETA. Maravilhoso!
Fiz o mesmo com meu editor de texto favorito, gedit, começando a digitar no buffer e depois a ler no dump. Sem problemas! Nesse ponto, Vicki sussurrou em seu ouvido em advertência: "Às vezes (por exemplo, para programas executados em nome do superusuário), um despejo de memória não é criado por motivos de segurança." Entããão, vamos verificar ... Ao receber um sinal do bash root, o segundo bash root travou com a criação de um despejo de memória, mas por causa das permissões (-rw-r ----- com o dono do root) não é mais tão fácil de ler como os anteriores pertencente à minha conta de usuário. Bem, se o programa assassino hipotético conseguiu enviar um sinal do UID do superusuário, ele pode tocar em tal dump.
O leitor meticuloso pode comentar: "Foi muito fácil para você encontrar os dados que procurava no mar de lixo". É verdade, mas tenho certeza: se você sabe que tipo de peixe quer pescar e onde ele nada, encontrá-lo nas redes de despejo deve ser quase sempre realista. Por exemplo, ninguém se preocupa em baixar um pacote com informações de depuração para um programa com falha e descobrir o conteúdo das variáveis nas quais você está interessado no GDB por depuração post-mortem.
Tudo isso pode parecer inofensivo, mas na verdade não é. Todas as ações que descrevi podem ser facilmente realizadas por um programa ou script executado no modo de usuário, sem mencionar um nível de acesso mais privilegiado. O resultado final é que um executável malicioso pode facilmente dividir programas à direita e à esquerda e, muitas vezes, também ler livremente toda a sua memória. Aqui estão os sinais e relatórios de erros! Tenho certeza de que em outras plataformas * nix e com outros programas destinatários a situação é semelhante, mas é claro que não vou verificar.
A objeção pode surgir: o malware pode simplesmente usar as ferramentas de depuração para extrair dados interessantes do aplicativo. É realmente. Por que, então, é esta postagem? Meu ponto é o seguinte: a primeira coisa que vem à mente ao tentar impedir o roubo de dados de aplicativos são apenas as limitações das ferramentas de depuração. Certamente as ferramentas de antivírus detectam o uso de ptrace () em primeiro lugar - este é um evento muito suspeito. Os sinais são outra questão. Um processo envia a outro um sinal padrão - e daí? À primeira vista, este é um evento completamente normal. Mas, como já vimos, isso pode levar a um encerramento anormal do aplicativo, criando um dump de núcleo em alguma pasta, de onde você pode tentar extraí-lo.
Quando tentei abrir a página de login do vk.com e despejar o Firefox com o mesmo sinal fatal, ele travou, mas chamou seu manipulador de despejo. Despejos no formato complicado de minidespejo são salvos em ~ / .mozilla / firefox / Crash Reports / {pendente ou enviado} e requerem investigação adicional. Aqui está o que você descobrirá se, na janela de configurações, clicar em "Saiba mais" ao lado da marca de seleção (o texto abaixo costumava ser exibido em www.mozilla.org/ru/privacy/firefox/#crash-reporter ):

« Mozilla Firefox. , Firefox, , URL- , . , , . crash-stats.mozilla.com. . .»Raramente há algo realmente saboroso em URLs, mas se os despejos contêm senhas ou cookies é uma boa pergunta!
Com esta nota misteriosa e intrigante, vou terminar. Recebi um sinal que esqueci de processar explicitamente.
PS Eu escrevi um programa simples com um manipulador de sinais SIGUSR1: imprima a string "1" na tela, entre em um loop infinito. Eu esperava que, se você enviar o sinal SIGUSR1 várias vezes para este programa, o manipulador seja chamado muitas vezes, o que causará um estouro de pilha. Infelizmente para mim, o manipulador foi chamado apenas uma vez. Ok, vamos escrever um manipulador semelhante para o sinal SIGUSR2 e enviar dois sinais diferentes na esperança de que isso despeje a vítima ... Infelizmente, também não ajudou: cada manipulador foi chamado apenas uma vez. Transbordou, transbordou, mas não transbordou!
PS 2. No mundo do Windows existe uma espécie de sinais - mensagens que podem ser enviadas para o Windows . É muito provável que possam ser usados para diversão e lucro também!
O original foi publicado no meu blog 05.05.17.