Atividade e memória
Alt-M ou Comando → Monitor de atividade abre o monitor de processos. Faz parte do plugin Sistema incluído, que está ativo por omissão e pode ser desativado em Opções → Plugins. A lista de processos ocupa o painel ativo, e o outro painel mostra um resumo da memória do processo selecionado. Enter ou um duplo clique abre esse processo numa janela sobre o monitor, com o mapa de memória de um lado e uma pré-visualização dos bytes da região selecionada do outro. Esc fecha-a e Tab alterna entre os dois lados. Alt-W ou o botão [+] maximiza o painel com o foco, [=] restaura a divisão e [-] oculta o monitor. O monitor recolhe amostras uma vez por segundo enquanto está aberto e para quando o fecha. A amostragem fica em pausa enquanto decorre uma inspeção de memória e é retomada quando chega o resultado.
A lista mostra CPU, memória residente, crescimento da memória e débitos de leitura e escrita em disco. CPU a 100% corresponde a um núcleo totalmente ocupado. As páginas residentes partilhadas entre processos contam para cada um deles, pelo que somar a RAM de todos os processos não dá o total do sistema. Os débitos de CPU e de disco aparecem a partir da segunda amostra.
A CPU é uma média dos últimos segundos em que a utilização mais antiga vai perdendo peso, como no
top, pelo que uma lista ordenada por CPU fica parada enquanto um processo trabalha em rajadas
curtas. O resumo e a CPU de todo o sistema no topo do monitor são calculados da mesma forma. H
oculta os processos que não usaram CPU nesse tempo, e a linha do filtro indica quantos estão
ocultos. Um processo que fica parado continua na lista até a sua média descer a 0.0. Na árvore,
os processos de que descende um processo ocupado continuam na lista com ele. Prima H outra vez
para voltar a mostrar todos.
| Tecla | Ação |
|---|---|
| Enter | Abrir o mapa de memória do processo / passar para a pré-visualização da região |
/ |
Filtrar por nome ou PID; ↑↓ continuam a mover, Enter mantém o filtro, Esc limpa-o |
| C / M / G / N / P | Ordenar por CPU / RAM / crescimento / nome / PID; prima de novo para inverter |
| I / O | Ordenar por débito de leitura / escrita |
| T | Mostrar ou ocultar a árvore de processos |
| H | Ocultar ou mostrar os processos que não usaram CPU nos últimos segundos |
| Left / Right | Na árvore, recolher ou expandir o ramo do processo selecionado |
| K | Enviar um sinal ou alterar a prioridade, também a partir da janela do processo |
| E | Procurar entropia alta em todos os processos |
| Alt-N | Mostrar o tráfego do processo selecionado no ecrã de rede |
| Alt-O | Abrir a pasta do programa selecionado ao lado da lista |
| Space | Pausar ou retomar a amostragem |
| R | Atualizar a vista atual |
| Esc | Voltar; na lista de processos, fechar o monitor ou regressar ao ecrã de rede |
Alt-O abre a pasta do programa do processo selecionado no outro painel, com o cursor no programa, e os ficheiros passam a receber as teclas. A lista mantém o filtro, a ordem e o processo que selecionou. Tab passa as teclas entre a lista e os ficheiros, e Alt-O noutra linha leva os ficheiros para lá. Nesses ficheiros pode ver, editar, apagar, comprimir e extrair, e criar pastas. Copiar e mover precisam do outro painel, por isso esperam que o monitor feche. Esc na lista, ou Alt-M, traz de volta o resumo, e Alt-M outra vez fecha o monitor. Nos ficheiros abertos e no mapa de memória, Alt-O mostra o ficheiro aberto selecionado ou o ficheiro que a região mapeia. Quando o programa foi eliminado enquanto corre, a sua pasta abre com um aviso. Um aviso indica também quando o ficheiro não está na sua pasta neste computador, como acontece com um programa que corre dentro de um contentor. Os alertas, os itens de arranque e a vista Docker funcionam da mesma forma.
Cada ecrã guarda o filtro quando o fecha e volta a mostrá-lo quando o abre. Para limpar um filtro, prima / e depois Esc.
Clique no cabeçalho de uma coluna para ordenar, e faça duplo clique num processo para abrir o seu mapa de memória. O resumo mostra a memória residente atual, o valor mais alto observado, a variação desde o início da monitorização, a CPU, o espaço de endereçamento virtual e um gráfico da memória residente nos últimos 60 segundos. Os totais de memória usada, em swap, privada e partilhada aparecem depois de o mapa de memória ser lido, se o sistema os indicar. Enter no painel de memória abre o mapa de memória. O mapa só é lido quando o pede; prima R para o voltar a ler depois de o processo alterar os seus mapeamentos.
Por baixo do gráfico, Árvore de processos lista os processos de que o selecionado descende, o próprio processo e tudo o que ele iniciou, cada um indentado por baixo daquele que o iniciou e com a sua memória residente. Quando não cabem todos, a última linha indica quantos ficaram de fora.
Na árvore que T mostra, cada processo aparece por baixo daquele que o iniciou, e ▾ assinala um processo com outros por baixo. Left recolhe o ramo do processo selecionado; num processo sem nada por baixo, Left recolhe o ramo a que ele pertence e seleciona o processo que o iniciou. Right expande um ramo recolhido e, num ramo aberto, passa para o primeiro processo desse ramo. Um processo recolhido mostra ▸ e quantos processos esconde. Um ramo fica recolhido até o seu processo terminar. Enquanto um filtro está aplicado, a lista é plana.
Sinais e prioridade
Seção intitulada “Sinais e prioridade”K abre Sinal ou prioridade para o processo selecionado, na lista e na janela do processo com o mapa de memória ou os ficheiros abertos. Prima a letra de uma opção, ou desloque-se até ela e prima Enter. Esc fecha a caixa de diálogo sem enviar nada.
| Tecla | Opção | O que faz |
|---|---|---|
| T | Terminar | Envia TERM, que pede ao processo que saia |
| I | Interromper | Envia INT, o mesmo que Ctrl-C no seu terminal |
| H | Desligar | Envia HUP; muitos serviços voltam a ler as definições |
| K | Matar | Envia KILL, que termina o processo de imediato sem lhe dar tempo para limpar |
| S | Parar | Envia STOP, que coloca o processo em pausa |
| C | Continuar | Envia CONT, que retoma um processo parado |
| L | Baixar prioridade | Sobe o valor nice em 5, até 19, para que espere mais pela CPU quando o sistema está ocupado |
| R | Subir prioridade | Desce o valor nice em 5, até -20 |
Imediatamente antes de enviar, o Borg confirma que o PID ainda pertence ao processo que escolheu, iniciado à mesma hora, para que um processo novo que tenha reutilizado o PID fique intacto. A linha de estado confirma o que foi enviado e a lista volta a ser amostrada de imediato. A visão geral indica quando um processo está parado e mostra o seu valor Nice quando não é 0.
Pode enviar sinais aos seus próprios processos e baixar a prioridade deles. O sistema recusa o resto: processos de outro utilizador e subir uma prioridade, que só um administrador pode fazer. Nesse caso, o Borg oferece A Administrador, que envia a mesma opção através do auxiliar descrito em Acesso de administrador. O Borg não envia sinais a si próprio; F10 fecha-o.
Mapa de memória
Seção intitulada “Mapa de memória”O mapa tem três colunas:
- Memória usada é a memória imputada apenas a este processo: as páginas que escreveu, mais as páginas enviadas para swap ou comprimidas. É o valor a vigiar para detetar fugas de memória e, no macOS, coincide com a coluna Memória do Monitor de Atividade.
- Residente são as páginas que estão neste momento na RAM, incluindo as partilhadas com outros processos.
- Mapeada é espaço de endereçamento, incluindo reservas. Não diz nada sobre o uso de RAM.
Um processo pode mapear gigabytes, sobretudo bibliotecas do sistema partilhadas com todos os outros processos, e ter uma memória usada de apenas alguns megabytes. Inicialmente, as regiões aparecem agrupadas por finalidade: heap e alocações, pilhas das threads, código e dados do próprio programa, bibliotecas partilhadas, ficheiros mapeados, memória partilhada, alocações do sistema e outras, e intervalos reservados e páginas de guarda. Os grupos e as regiões dentro deles são ordenados pela memória usada, com as reservas no fim. As bibliotecas e os ficheiros mapeados têm uma linha por ficheiro; expanda um ficheiro para ver as suas regiões. Os nomes dos grupos são deduzidos das etiquetas atribuídas pelo sistema operativo. Selecionar um grupo ou ficheiro explica o que é e mostra a sua parte da memória usada e os seus maiores membros. Enter ou Right expandem um grupo ou ficheiro; Left recolhe-o, ou recolhe o que contém a linha selecionada. G alterna entre a lista agrupada e a lista em bruto.
Ficheiros abertos
Seção intitulada “Ficheiros abertos”1 Memória e 2 Ficheiros abertos alternam entre os separadores de inspeção; também pode
clicar neles. A lista de ficheiros abertos mostra cada descritor, o modo de acesso, o tipo e o
caminho ou o ponto de rede; o outro painel mostra os detalhes completos, o tamanho do ficheiro e o
deslocamento atual, quando estão disponíveis. No macOS inclui também entradas como cwd
(diretório atual) e txt (executável mapeado). R atualiza a lista. Cada separador mantém a sua
posição na lista quando muda de separador. Quando o acesso é restrito, o Borg propõe tentar de
novo como administrador. Num ficheiro normal, os detalhes mostram também uma pré-visualização do
conteúdo, como a pré-visualização dos painéis: Tab entra na pré-visualização para a poder
percorrer, e F3 abre o ficheiro no visualizador. O Borg abre o ficheiro pelo caminho, com as
suas próprias permissões, e deixa o descritor do processo em paz.
Pré-visualização de regiões
Seção intitulada “Pré-visualização de regiões”Quando seleciona uma região legível, o Borg captura até 64 KiB dela no outro painel. Se o início da região contiver apenas zeros, a captura avança até à primeira página com dados, e a linha por cima dos bytes indica em que ponto da região está a janela. Cada linha começa pela sua posição a contar do início da região, e um painel largo mostra mais bytes por linha. Quando se move depressa, o Borg espera um momento antes de ler; selecionar outra região limpa a pré-visualização anterior e cancela a leitura pendente. As regiões que não podem ser lidas mostram uma mensagem. Prima Tab ou Enter para percorrer a pré-visualização. Esc aí volta à lista, e Esc no mapa volta à lista de processos com o cursor e o filtro como estavam.
As sequências de linhas a zero recolhem-se numa única linha, como “· 60K bytes a zero ·”. ] e [ saltam para o bloco de dados seguinte e anterior, e > e < capturam os 64 KiB seguintes e anteriores da região. H alterna entre hexadecimal e texto, R volta a capturar a janela mostrada e D realça o que mudou desde a captura anterior do mesmo processo e endereço. A vista de texto mostra ASCII imprimível e substitui os outros bytes por pontos. As capturas são feitas sobre o processo em execução sem o pausar, pelo que uma captura não é uma imagem consistente de todo o processo. Ficam em memória, a menos que as exporte. E guarda os bytes em bruto num ficheiro novo na pasta do painel de ficheiros ativo, legível apenas pelo utilizador. Os ficheiros existentes nunca são substituídos.
M alterna a pré-visualização entre bytes e um mapa de páginas da região: uma célula por página de 4 KiB, ou por sequência de páginas numa região grande, assinalada conforme o que contém: ponteiros para a memória do próprio processo, texto, texto UTF-16, código, dados comprimidos ou cifrados, outros dados, enchimento, zeros e páginas que não estão em memória. Uma legenda mostra a proporção de cada tipo na região. Com o mapa em foco, as setas, PgUp, PgDn, Home e End movem um cursor, e Enter abre como bytes a página sob o cursor. As regiões com mais de 16 384 páginas são amostradas de forma uniforme. No Linux, o mapa pergunta ao sistema que páginas estão em memória e não lê as restantes, pelo que não traz de volta páginas em swap nem toca em páginas novas; no macOS, as páginas nunca usadas são lidas como zeros. Os tipos são deduzidos apenas a partir dos bytes, por isso encare-os como uma indicação.
As páginas cuja entropia chega a 7,2 bits por byte são desenhadas a vermelho e negrito, ou só a negrito onde o vermelho seria difícil de ler, seja qual for o seu tipo. Assim, o código empacotado ou cifrado destaca-se numa região executável, onde o Borg conta como código todas as páginas que não são zeros nem enchimento. A legenda mostra a sua proporção como entropia alta, a linha do cursor acrescenta a entropia da página sob ele, e a mesma linha termina com a entropia mais alta da região. Uma nota sob a legenda explica o que a entropia alta e a baixa costumam significar. As caches comprimidas, as imagens, os arquivos e as chaves também têm entropia alta, por isso veja o que a região contém antes de suspeitar dela.
Pesquisa de memória
Seção intitulada “Pesquisa de memória”Prima / no painel de memória, ou Ctrl-F em qualquer dos painéis, para pesquisar a
memória. Escolha um modo, se as maiúsculas e minúsculas têm de coincidir, e se quer pesquisar a
memória legível do processo ou a captura atual. O formulário abre com o que tinha quando o fechou
da última vez. Texto pesquisa UTF-8, UTF-16 (nas duas ordens de bytes) e UTF-32 (nas duas ordens de bytes). Unicode normaliza também os caracteres de
compatibilidade e as sequências combinadas: por exemplo,
𝐁𝐨𝐫𝐠 corresponde a Borg. Não trata como iguais letras diferentes só por serem parecidas.
Bytes hexadecimais aceita pares de bytes como 42 6F 72 67.
Cadeias e Indicadores só leem a memória que o próprio processo preencheu: memória que não provém de um ficheiro e em que o processo pode escrever; no macOS, as regiões em que nunca escreveu também são ignoradas. Cadeias lista uma vez cada sequência de pelo menos seis caracteres ASCII imprimíveis ou UTF-16LE, com o número de cópias em memória, e ignora enchimento como caracteres ou pontuação repetidos; se indicar uma pesquisa, mantém apenas as cadeias que a contêm. Indicadores mantém as cadeias que parecem um URL, um endereço IP, um endereço de email, um caminho de ficheiro, uma linha de comando, um segredo (uma chave privada, um token de acesso ou a atribuição de uma palavra-passe) ou uma sequência longa de base64, e classifica cada uma.
O Borg lê também as cadeias dos ficheiros que o processo mapeou, até 1 GiB, e assinala com • as cadeias encontradas apenas em memória: texto que o processo construiu, recebeu ou descodificou e que nenhum dos seus ficheiros contém. Os indicadores aparecem primeiro, depois as cadeias encontradas apenas em memória e, por fim, as que também existem nos ficheiros; dentro de cada grupo, as cadeias que parecem palavras vêm antes das restantes. A lista guarda as 2000 melhores. Enquanto as outras correspondências mostram a sua região, aqui cada linha mostra o tipo e o número de cópias, e a pré-visualização mostra a cadeia no seu contexto; C percorre as cópias. Encare estes resultados como pistas que merecem um olhar mais atento. Os programas comuns também contêm muitos URL, caminhos e chaves.
As correspondências ocupam o painel da lista e mostram o endereço, a codificação e a região. Selecionar uma correspondência pré-visualiza os bytes à volta dela no outro painel, com a correspondência realçada. Enter entra na pré-visualização e Esc volta às correspondências. Esc nas correspondências regressa ao mapa de memória ou à lista de processos de onde veio. Pesquisar uma captura guardada usa os bytes dela sem ler o processo em execução. As pesquisas em processos leem a memória por partes, indicam os bytes que não conseguiram ler e param ao fim de 2000 correspondências ou 60 segundos. N continua a partir do ponto onde a pesquisa parou, e Ctrl-C interrompe-a e mantém os resultados. O relatório de cobertura distingue os bytes pesquisados dos ilegíveis. Um processo pode alterar a sua memória enquanto está a ser pesquisado.
Verificação de integridade do código
Seção intitulada “Verificação de integridade do código”I, no mapa de memória ou nas correspondências de uma pesquisa, verifica se o processo está a
executar o código que os seus ficheiros contêm. Compara o código em memória com os ficheiros a
partir dos quais foi mapeado e indica as páginas que diferem, procura cabeçalhos de imagens
executáveis (ELF, Mach-O e PE) na memória que não provém de ficheiros, e lista a memória
executável que não provém de ficheiros, a memória que é simultaneamente gravável e executável, e o
código de ficheiros eliminados, sem nome ou temporários. Verifica também o processo no seu todo:
bibliotecas injetadas através de LD_PRELOAD, LD_AUDIT, DYLD_INSERT_LIBRARIES
ou /etc/ld.so.preload, caminhos de pesquisa de bibliotecas, um tracer no Linux, um programa cujo
ficheiro foi eliminado ou substituído, e um nome de processo diferente do nome do programa.
As conclusões ocupam o painel da lista, com os alertas primeiro, depois os avisos e por fim as notas. Selecionar uma pré-visualiza os bytes a que se refere, com as provas realçadas, e as linhas por baixo da lista indicam o que mais a poderia explicar. Os programas que compilam código enquanto correm, como os browsers e os motores de Java e JavaScript, contêm sempre código que não provém de nenhum ficheiro, por isso, nesses casos, essas conclusões são apenas notas. R verifica de novo, Ctrl-C interrompe uma verificação e mantém o que encontrou até então, e Esc volta atrás. Uma verificação lê no máximo 512 MiB de código e 1 GiB de outra memória, durante até 45 segundos, e indica se parou antes do fim.
No Linux, as tabelas de páginas mostram que páginas de código um processo alterou, pelo que só essas são lidas; no macOS, as regiões sem páginas modificadas também não são lidas. O código da cache partilhada do macOS não tem um ficheiro próprio e não é comparado. A memória que uma verificação não consegue ler é contabilizada, e o Borg oferece A Administrador. Encare as conclusões como pistas, porque depuradores, profilers, atualizadores e ferramentas de segurança deixam os mesmos vestígios.
Analisar a memória com regras
Seção intitulada “Analisar a memória com regras”Y, no mapa de memória ou nas correspondências de uma pesquisa, analisa a memória que o próprio processo preencheu com as mesmas regras de uma análise de ficheiros: as do Borg e as da sua pasta de regras (consulte Analisar ficheiros com regras). Tal como Cadeias, lê a memória que não provém de ficheiros e a memória em que o processo pode escrever; no macOS, as regiões em que nunca escreveu também são ignoradas. Uma região sem nenhuma página em memória ou na swap não é lida, e no Linux as tabelas de páginas mostram que páginas o processo nunca tocou, pelo que essas também não são lidas. As páginas na swap são lidas, porque um payload pode esperar aí. A memória é lida em blocos de 16 MiB que se sobrepõem em 4 KiB, por isso uma correspondência que passa de um bloco para o seguinte continua a ser encontrada. Cada regra aparece uma vez por região, na sua primeira correspondência.
As correspondências ocupam o painel da lista, com os alertas primeiro. Cada uma indica a regra e de onde vem, regras do Borg ou o seu ficheiro, depois os bytes que encontrou e o que a regra procura, e as linhas por baixo da lista indicam o que mais a poderia explicar. Selecionar uma correspondência pré-visualiza os bytes à sua volta, com a correspondência realçada. Os ficheiros de regras deixados de fora aparecem no fim, com a mensagem do compilador. R analisa de novo, Ctrl-C interrompe a análise e mantém o que encontrou, e Esc volta atrás. Uma análise lê no máximo 1 GiB, durante até 45 segundos, lista até 2000 correspondências e indica se parou antes do fim. A memória que não consegue ler é contabilizada, e o Borg oferece A Administrador, que corre a análise no programa auxiliar com a sua pasta de regras.
Uma análise com regras é uma triagem: um olhar rápido sobre um processo ou uma pasta à procura de padrões que alguém descreveu. Não vigia o sistema, não bloqueia nada nem limpa, que é o papel da proteção de endpoints. Algumas coisas ficam fora do seu alcance:
- O macOS protege a memória dos seus próprios programas e dos programas criados com o Hardened Runtime contra todos os outros programas, administradores incluídos (consulte Acesso de administrador).
- No Linux,
kernel.yama.ptrace_scopedecide de quem pode ler a memória. Com 1, como no Ubuntu, só pode ler os seus próprios processos filhos, por isso o Borg oferece A Administrador para os restantes. Com 3, ninguém pode ler outro processo, administradores incluídos. - Um rootkit de kernel pode esconder memória, ficheiros e processos de todos os programas, incluindo o Borg, por isso uma análise limpa prova pouco.
- Um programa comprimido ou cifrado só mostra o seu código real enquanto corre. Analisar a sua memória nessa altura vê o que uma análise do seu ficheiro não consegue ver.
O Borg lê a memória sem se ligar como depurador, com process_vm_readv no Linux e mach_vm_read no
macOS, por isso o processo não vê nenhum tracer, que é o que a maioria das verificações
anti-depuração procura. Os monitores que correm como administrador, como o auditd, as ferramentas
eBPF e os clientes do Endpoint Security do macOS, podem mesmo assim registar as leituras. Uma
análise de ficheiros abre todos os ficheiros que lê, o que inotify e fanotify reportam. No
Linux, deixa como estava a hora de acesso dos ficheiros que lhe pertencem.
Análise de entropia de todos os processos
Seção intitulada “Análise de entropia de todos os processos”E na lista de processos abre a Análise de entropia, que lê uma amostra das páginas de todos os processos à procura de bytes tão densos como código compactado. Prima a letra de uma opção, ou desloque-se até ela e prima Enter. Esc fecha a caixa de diálogo.
| Tecla | Opção | O que lê |
|---|---|---|
| C | Código de todos os processos | As regiões executáveis, onde aparece código compactado ou cifrado |
| M | Toda a memória de todos os processos | Todas as regiões legíveis, portanto também dados como chaves e ficheiros comprimidos |
| L | Últimos resultados | Nada de novo: mostra outra vez as ocorrências da última análise |
O Borg lê até 1024 páginas de 4 KiB de uma região e 32 768 de um processo, distribuídas uniformemente. Um processo com muitas regiões recebe menos páginas por região, mas nunca menos de 16. Uma região com pelo menos uma página de 7,2 bits por byte ou mais é uma ocorrência. As ocorrências ocupam o painel da lista: primeiro o código, depois a memória que o processo escreveu e por fim os ficheiros mapeados tal como estão no disco, e dentro de cada grupo primeiro a região com maior percentagem de páginas com entropia alta. O código com 70% ou mais das páginas com entropia alta aparece em negrito, segundo a mesma regra da pesquisa de executáveis compactados. Cada linha indica o tipo (código, escrita ou ficheiro), essa percentagem com a entropia mais alta, e o nome do processo, o PID e a região. O outro painel mostra os endereços, o tamanho e o acesso da região, quantas páginas da amostra têm entropia alta, onde começa a primeira delas e o que esses bytes costumam ser. São mantidas as 2000 ocorrências mais fortes, e o resumo conta as mais fracas deixadas de fora.
Enter numa ocorrência abre o mapa de memória do processo nessa região, com o mapa de páginas ativo e o cursor na primeira página densa da amostra, para poder ver os bytes à sua volta. Esc volta ao mapa e, de novo, às ocorrências.
O Borg lê 4 processos de cada vez. Uma região sem nenhuma página em memória ou na swap não é lida, e no Linux as tabelas de páginas mostram que páginas estão em memória, pelo que a análise não toca em páginas novas nem traz de volta as que estão na swap. As caches que todos os processos mapeiam da mesma forma ficam de fora: a cache partilhada do dyld no macOS e as páginas que o kernel mapeia em todos os processos no Linux. Um ficheiro mapeado sem alterações, como uma biblioteca partilhada, só é lido no primeiro processo que o mapeia.
Uma análise para ao fim de 90 segundos e deixa o resto para N, que continua com os processos a que não chegou. Ctrl-C interrompe-a mais cedo e mantém as ocorrências, e R analisa de novo desde o início. Acima das ocorrências, uma linha conta os processos analisados e as ocorrências, e a seguinte os processos deixados de fora: ilegíveis, protegidos e não alcançados. No macOS, o vmmap demora alguns segundos a listar as regiões de um processo, por isso analisar todos os processos pode exigir várias rondas de N.
Os processos cuja memória o macOS protege são contados e ignorados, porque ninguém os pode ler. Para os processos que o Borg não conseguiu ler, oferece A Administrador, que os analisa no programa auxiliar durante no máximo 60 segundos, para que o auxiliar termine dentro do seu limite de 2 minutos mesmo depois de um pedido de palavra-passe demorado. Bytes densos são comuns: caches comprimidas, imagens, tipos de letra e chaves têm entropia alta por natureza, por isso encare as ocorrências como pistas e leia os detalhes antes de suspeitar de um processo.
Acesso de administrador
Seção intitulada “Acesso de administrador”Quando a leitura de um mapa de memória ou de uma captura está restrita, uma pesquisa não
conseguiu ler parte da memória, uma análise de entropia não conseguiu ler alguns processos, ou o
sistema recusa um sinal ou uma alteração de prioridade, o Borg
oferece A Administrador. No macOS, isto abre o pedido
de autorização do sistema; no Linux, usa pkexec e precisa de um agente de autorização em
execução. Apenas um auxiliar de curta duração corre com privilégios elevados. O próprio Borg
continua a correr normalmente, e o auxiliar devolve apenas dados do mapa, um número limitado de
bytes ou as ocorrências de uma análise, ou envia o sinal ou a prioridade que escolheu.
O macOS protege a memória dos seus próprios programas (System Integrity Protection) e dos programas compilados com o Hardened Runtime contra todos os outros programas, incluindo os administradores. O Borg obtém esta informação a partir da assinatura do programa: os detalhes do processo indicam Memória protegida, uma leitura recusada explica porquê, e A Administrador não é oferecido, porque não ajudaria. Os mapas de memória e os ficheiros abertos destes programas continuam a ser mostrados. Também não é oferecido quando o Borg já está a correr como administrador. No Linux, a política de segurança pode ainda assim negar o acesso; o Borg mostra o erro e o monitor de processos continua a funcionar normalmente.
Um processo é identificado em conjunto com a sua hora de início, pelo que um processo novo que reutilize um PID não herda o histórico de outro processo. Os mapas de memória, os resultados de inspeção, as capturas e o histórico têm todos limites de tamanho. O nome Borg Commander fica visível no canto inferior direito em todo o lado, incluindo a consola, o visualizador, o monitor, as caixas de diálogo e a proteção de ecrã.
Alertas
Seção intitulada “Alertas”O Borg pode observar o que arranca numa máquina e avisá-lo quando algo parece errado. Ative Vigiar: arranques de processos invulgares em F9 → Opções → Plugins. O observador vive no serviço em segundo plano que todos os seus Borg na máquina partilham, por isso todos os Borg leem os mesmos alertas. Esse serviço corre enquanto houver um Borg aberto. Para continuar a observar sem nenhum terminal aberto, inicie o serviço no arranque do sistema como descreve Sessões com nome e serviço em segundo plano.
Os alertas ficam nessa máquina até indicar um destino para eles, e a página avisa enquanto assim for (consulte Alertas fora da máquina).
Alt-L ou Comando → Alertas abre a página. A lista ocupa o painel ativo, com o alerta mais recente primeiro, e o outro painel mostra o alerta selecionado por inteiro. Cada linha mostra a hora, a regra que disparou, o programa, o processo-pai que o iniciou, o utilizador com que correu e o que é do processo agora. A linha acima da lista conta os alertas e quantos ainda ninguém leu.
Os detalhes dizem numa frase por que a regra disparou e depois o comando, o programa, o processo-pai, o utilizador, para onde levavam os fluxos padrão e onde o processo se encontra agora. Em Árvore de processos cada pai aparece acima do seu filho, para que possa ler o caminho de um serviço até ao comando que o preocupa. Ligações lista os sockets que o processo tinha naquele momento, Hash do programa é o SHA-256 do seu programa e Regras mostra o que as regras do Borg e as suas encontraram nesse programa (veja Analisar ficheiros com regras).
Um comando com mais de 2 KiB guarda o início e o fim, 2 KiB ao todo, com … entre eles. Os comandos
dos processos-pai e os valores das variáveis de pré-carregamento são cortados da mesma forma. Assim os
200 alertas mais recentes cabem no registo, por mais longos que sejam os comandos, e um primeiro
argumento comprido não consegue tirar de vista o fim de um comando. Ctrl-C copia o comando tal como o
registo o guarda.
| Tecla | Ação |
|---|---|
| Enter | Mostrar o processo no monitor de atividade |
| C | Deixar um processo congelado continuar a correr |
| K | Terminar o processo, depois de uma pergunta |
| A | Permitir arranques como este a partir de agora |
| Alt-O | Abrir a pasta do programa do alerta ao lado da lista |
/ |
Filtrar as linhas; ↑↓ continuam a mover, Enter mantém o filtro, Esc limpa-o |
| R | Ler o registo de novo |
| Ctrl-C | Copiar o comando que o processo correu |
| Alt-W | Maximizar a lista |
| Esc | Fechar a página, que guarda o filtro |
O filtro mantém os alertas que contêm todas as palavras que escrever, na regra, no seu nome curto,
no motivo, no programa, no processo-pai, no utilizador, no comando e no que o Borg fez. Ponha !
antes de uma palavra para deixar de fora o que ela apanha: shell-on-socket !root mantém as
shells remotas de todos os outros utilizadores.
Os alertas vivem em alerts.json na pasta de estado, acessível só ao dono, os 200 mais recentes.
Um alerta sobre um processo que continua congelado fica para além desse limite, para que possa
sempre deixá-lo continuar ou terminá-lo. O Borg mantém o ficheiro dentro de 8 MiB, o máximo que lê de volta, e deixa de fora os alertas mais
antigos quando não cabem. A janela Ficheiros do Borg conta-os em Estado (veja
Ficheiros do Borg). Abrir a página marca como lidos os alertas que ela mostra, e a
contagem de alertas não lidos acompanha o registo enquanto o Borg estiver aberto, esteja a página
aberta ou não.
Quando o Borg encontra um alerts.json que não consegue ler, como um que uma versão anterior deixou
passar dos 8 MiB, muda o nome do ficheiro para alerts-unreadable.json antes de escrever um registo
novo, para que os alertas nele fiquem no disco. Um seguinte recebe um nome numerado como
alerts-unreadable (2).json. A página de alertas indica o ficheiro por baixo da lista enquanto ele
lá estiver, por isso apague-o depois de o rever.
O que o observador procura
Seção intitulada “O que o observador procura”Cada regra nomeia uma coisa estranha num processo que acabou de arrancar. O nível diz quanto isso significa: alerta raramente é inocente, aviso tem muitas vezes um motivo comum, nota está lá para o retrato ficar completo.
| Regra | O que a faz disparar | Nível |
|---|---|---|
| Shell num socket de rede | Uma shell cuja entrada, saída ou erros vão para um socket de rede, que é o aspeto de uma shell remota. Um socket que fica na máquina, como o que o systemd dá à saída de um serviço para o journal, não conta |
alerta |
| Shell remota num terminal | Uma shell num terminal que um programa abriu para ela, em que a entrada, a saída ou os erros desse programa vão para um socket de rede, ou o programa é um retransmissor como o socat ou o nc. É uma shell remota transformada num terminal completo, como a que o pty.spawn do Python cria |
alerta |
| Programa apagado enquanto corre | O ficheiro do programa já não existe, por isso nada no disco diz o que o processo é | alerta |
| Programa sem ficheiro | O Borg não encontra nenhum ficheiro de programa para o processo | alerta |
| Biblioteca imposta a um programa | LD_PRELOAD, LD_AUDIT ou DYLD_INSERT_LIBRARIES está definido no seu ambiente |
alerta |
| Shell a partir de um serviço | Um servidor web, um ambiente de execução de aplicações ou uma base de dados iniciou uma shell | aviso |
| Shell sem terminal | Uma shell sem terminal de nenhum dos lados, por isso ninguém a escreveu | aviso |
| Shell no terminal de um programa | Uma shell num terminal que um programa abriu para si próprio e em que ninguém iniciou sessão, como o que o expect ou o docker exec abrem |
aviso |
| Exploração da máquina | Quatro comandos diferentes como whoami, id, uname e ss do mesmo programa no espaço de uma hora, sem ninguém com sessão iniciada no terminal onde correm. Os comandos que ele corre através de uma shell atrás de outra contam juntos, por isso uma web shell que inicia sh -c para cada comando também é apanhada |
aviso |
| Programa numa pasta temporária | O programa está em /tmp, /var/tmp, /dev/shm ou /run/shm |
aviso |
| Nome diferente do programa | O processo chama-se uma coisa e corre outra | aviso |
| O pai nunca o iniciou antes | Este pai nunca iniciou este programa nesta máquina | nota |
De cada processo o Borg lê o programa que corre e se o seu ficheiro foi apagado, o comando, o utilizador, o terminal a que pertence e quem o abriu, para onde levam a sua entrada, saída e erros padrão, as variáveis de pré-carregamento no seu ambiente e a cadeia de pais acima dele. Um socket conta como socket de rede quando a rede do processo o lista como TCP ou UDP.
Se alguém iniciou sessão num terminal decide-se da mesma forma que para congelar (veja
Congelar um processo): por SSH, na consola, no tmux ou no screen, através
do sudo ou do su, ou numa janela de terminal. Um terminal que um programa abriu para si próprio
não conta, quer tenha sido o servidor remoto de um editor, o docker exec ou uma shell reversa a
abri-lo.
O Borg aprende a máquina antes de agir. Nos primeiros 7 dias regista qual pai inicia qual programa
aqui e não congela nada, e a coluna Resposta diz Teria congelado onde o teria feito. Depois
disso, um par que já viu fica em silêncio para as regras que se podem aprender: as três regras das
shells, o nome diferente e o pai que nunca o iniciou. A série de comandos aprende-se pelo programa de
onde vem: fica em silêncio quando esse programa correu cada um dos seus comandos durante a semana de
aprendizagem, por isso um agente de monitorização que corre df e ps o dia todo fica em silêncio,
e um servidor web que nunca correu id não fica. As cinco regras de nível alerta disparam sempre, porque uma shell num socket ou uma biblioteca imposta nunca se tornam
normais por acontecerem muitas vezes. Tudo o que corre nessa semana conta como normal, por isso
ligue o observador enquanto confia na máquina. Os arranques em que disparou uma regra que a
aprendizagem não consegue silenciar ficam fora do que o Borg aprende.
A num alerta permite arranques como aquele a partir daí, pelo seu programa e pelo seu pai. Essas
permissões ficam em watch-allowed.json na pasta de estado, que o observador lê e adota no espaço
de um minuto. A secção [watch] da configuração guarda o mesmo à mão (veja
Configuração). O Borg escreve no máximo 20 processos por minuto e congela no
máximo 5, e a linha acima da lista diz quantas deteções deixou de fora quando mais dispararam ao
mesmo tempo. Um processo que o Borg congela fica sempre registado, por muitos alertas que tenham
vindo antes, para que o possa deixar continuar. As notas contam à parte, para que uma série delas
nunca ocupe o lugar de um aviso, e até 20 processos por minuto que o Borg teria congelado além do
limite de 5 também ficam registados.
Congelar um processo
Seção intitulada “Congelar um processo”Terminado o período de aprendizagem, o Borg congela o processo em que disparou uma regra de nível
alerta ou aviso. Congelar envia um sinal de paragem ao processo e a tudo abaixo dele. Um processo
congelado não terminou, por isso o seu serviço continua a correr, o systemd e o Docker não têm
nada para reiniciar, e o que ele estava a ponto de fazer espera onde está até você ver. A coluna
Resposta diz Congelado, C deixa-o continuar e K termina-o. Terminar é definitivo, por
isso o Borg pergunta primeiro.
O congelamento começa quando tiver visto todos os alertas da semana de aprendizagem que dizem Teria congelado, ou 3 dias depois de a semana terminar, o que acontecer primeiro. Abrir a página de alertas marca-os como lidos, e o observador nota-o no espaço de um minuto. Assim pode verificar o que a semana apanhou e permitir um programa inofensivo com A antes de algo parar, e uma máquina que ninguém vê continua protegida. Até lá, o rodapé da página diz até quando o congelamento espera, e os detalhes de um novo alerta dizem que está à espera.
O Borg nunca congela o primeiro processo do sistema, nem a si mesmo nem nada que tenha iniciado, nem
um programa da lista que nunca congela (init, systemd, sshd, sudo, su, login e
semelhantes, mais qualquer nome que acrescente em keep-running), nem um processo num terminal em
que alguém iniciou sessão, nem um arranque que tenha permitido. Uma nota nunca para um programa. Os
detalhes dizem qual destes motivos manteve o processo a correr.
Um programa da lista incorporada só é poupado onde o sistema guarda os seus programas, como /usr e
/bin, por isso uma cópia chamada sshd noutra pasta é congelada como qualquer outro. Os nomes que
acrescenta em keep-running correspondem onde quer que o programa esteja. Um terminal conta quando
alguém iniciou sessão nele: por SSH, na consola, no tmux ou no screen, através do sudo ou do
su, ou numa janela de terminal. Um multiplexador de terminal só conta para o root e para contas de
pessoas, numeradas a partir de UID_MIN em /etc/login.defs (1000 na maioria dos sistemas), porque
uma conta de serviço também pode iniciar um. Um terminal que um programa abriu para si próprio não
conta, o que impede uma shell remota de se esconder atrás de um. Os terminais abertos pelo servidor
remoto de um editor ou pelo docker exec também não contam, por isso, se o Borg congelar algo que
correu aí, C deixa-o continuar e A permite-o.
O Borg verifica a identidade de um processo, o seu número junto com o momento em que arrancou, imediatamente antes de lhe enviar um sinal, para que um número que outro processo tenha tomado entretanto fique em paz.
O observador como root
Seção intitulada “O observador como root”Sem mais direitos, o Borg sabe apenas dos processos do seu próprio utilizador, olhando para a lista de processos quatro vezes por segundo, e a página diz isso abaixo da lista. Um comando curto pode desaparecer antes da olhada seguinte.
Para saber de cada processo no momento em que arranca, instale a parte que corre como root:
borg service watch installIsto pede a sua palavra-passe uma vez e instala uma unidade separada,
borg-commander-watch.service, que corre borg --watch-root. Essa parte carrega no kernel pequenos
programas do próprio Borg, que leem cada arranque de programa antes de o programa novo correr: o
programa, a linha de comandos tal como foi passada, o processo que o iniciou e o utilizador. Um
comando que termina de imediato é comunicado na mesma, e também a linha de comandos de um processo
que a reescreve depois. A parte root lê /proc para o resto, e para, continua ou termina um
processo quando o Borg pede. Não faz mais nada: a unidade abdica de todas as capacidades de que não
precisa, e a interface do Borg continua a correr como você. Os dois lados falam por um socket na
pasta de estado a que só o dono chega, o Borg aceita uma ligação apenas de um processo que corre
como root, e a parte root liga-se apenas a um socket que pertence ao utilizador para quem foi
instalada. borg service watch uninstall remove-a, e borg service watch status imprime de onde
vêm os eventos e o que foi encontrado. A instalação e o estado avisam enquanto os alertas não
tiverem destino (consulte Alertas fora da máquina).
Os programas precisam do Linux 5.8 ou posterior. Num kernel mais antigo, ou onde a parte root não os
pode carregar, ela ouve os eventos de processo do kernel e lê tudo de /proc, e a página indica-o
por baixo da lista. Depois de atualizar o Borg, execute de novo borg service watch install, para
que a unidade receba os direitos de que a nova versão precise.
Os alertas de qualquer dos lados são os mesmos alertas, no mesmo registo. Um processo de outro utilizador só pode ser congelado pela parte root, por isso retomá-lo ou terminá-lo a partir da página passa pelo observador no serviço. Quando nada o alcança, a página diz que só o dono ou um administrador o pode fazer.
O observador é uma funcionalidade de Linux para já. No macOS a página abre e lê o seu registo, e a origem diz que nada está a observar.
Alertas fora da máquina
Seção intitulada “Alertas fora da máquina”A página Alertas vive na máquina que observa, por isso quem tomar conta dessa máquina pode apagar o
registo. Envie cada alerta para outro lado no momento em que acontece: uma cópia que já chegou fica
fora do seu alcance, e o sinal de vida avisa quando o observador se cala. Adicione [watch.notify]
à configuração no servidor, com qualquer um destes destinos ou com vários. Todos os endereços usam
https://, ou http:// para o próprio servidor:
[watch.notify]name = "web-01" # how messages name this machine, its host name otherwiselevel = "warning" # the least an alert needs to be sent: alert, warning or notice
[watch.notify.telegram]token = "123456:ABC-your-bot-token"chat = "123456789"
[watch.notify.ntfy]url = "https://ntfy.sh/a-long-random-topic"token = "tk_your_token" # where the topic needs one
[watch.notify.webhook]url = "https://example.com/borg"secret = "a long random string"
[watch.notify.heartbeat]url = "https://hc-ping.com/your-check-id"minutes = 5Depois execute borg service watch notify. Envia uma mensagem de teste a cada destino e mostra o
que cada um respondeu.
- Telegram: crie um bot com o @BotFather, que lhe dá o token. Envie uma mensagem ao bot, abra
https://api.telegram.org/bot<token>/getUpdatese tirechat.idda resposta. - ntfy: subscreva na aplicação ntfy um tópico com um nome longo que ninguém adivinhe, ou um tópico no seu próprio servidor ntfy.
- Webhook: o Borg envia cada mensagem para o endereço em JSON. Com
secret, cada pedido levaX-Borg-Signature: t=<time>,v1=<signature>: o HMAC-SHA256, sob o segredo, da hora, de um ponto e do corpo, para que o recetor distinga as mensagens do Borg das forjadas.X-Borg-Eventdiz o que é a mensagem:alert,evidence(o SHA-256 do programa e as correspondências de regras, que seguem um alerta depois de o Borg ler o programa),started,armedoutest. - Sinal de vida: o Borg chama o endereço a cada
minutesminutos enquanto o observador corre e acrescenta/failquando algo está errado: a thread que calcula o hash dos programas parou, um destino não aceita mensagens há 30 minutos, o Borg desistiu de uma, ou o Borg não conseguiu ler a sua caixa de saída. Um serviço como o healthchecks.io avisa-o quando as chamadas param, que é o que acontece quando alguém mata o observador.
Enquanto nenhum destino receber alertas, eles ficam no registo da máquina, e o Borg avisa onde quer
que encontre o observador. A página Alertas mostra Os alertas ficam nesta máquina. por cima dos
detalhes do alerta selecionado, ou na última linha da lista quando esta está maximizada. A mesma
linha aparece quando ativa o observador em Opções → Plugins, em borg service watch install e
borg service watch status, e na saída do serviço quando o observador arranca. Um sinal de vida
sozinho não acaba com o aviso. Diz-lhe que o observador está a correr e não leva alertas, por isso
adicione também Telegram, ntfy ou um webhook.
O aviso fica mais forte quando o Borg está perto de agir. A partir de um dia antes do fim do período de aprendizagem diz O Borg está prestes a congelar processos aqui e ninguém será avisado., e depois de o congelamento começar, O Borg congela processos aqui e ninguém é avisado. O Borg continua a observar, a aprender e a congelar sem um destino para os alertas, por isso configure um antes de o período de aprendizagem acabar numa máquina que não consulta todos os dias.
O serviço envia cada alerta poucos segundos depois de o registar e diz também quando o observador
arranca e quando o congelamento começa. Os alertas de nível nota ficam só na página, a menos que
level seja notice. Uma mensagem que um destino recusa espera em watch-outbox.json, na pasta
de estado, e volta a ser tentada, 5 segundos depois da primeira vez e a cada 30 minutos no máximo.
O Borg guarda até 500 mensagens em espera, menos quando as longas fariam o ficheiro passar de
16 MiB, e tenta cada uma durante 48 horas. A mensagem seguinte diz de quantas desistiu.
Uma mensagem leva no máximo 1000 bytes da linha de comandos, do caminho do programa e do motivo do alerta. Uma mais longa guarda o início e o fim, com reticências entre eles, para que encher o início de um comando não esconda o que ele faz.
Quando o Borg encontra um watch-outbox.json que não consegue ler, muda o nome do ficheiro para
watch-outbox-unreadable.json e começa uma nova caixa de saída. Um posterior recebe um nome
numerado, como watch-outbox-unreadable (2).json. As mensagens que esperavam ficam nesse ficheiro e
nunca são enviadas, por isso o sinal de vida falha uma vez e diz porquê, e a numeração de cada
destino recomeça em 1. Veja o ficheiro e depois apague-o.
Cada destino numera as suas mensagens a partir de 1, e o JSON de cada mensagem leva em previous o
SHA-256 da anterior. Um salto na numeração, ou um previous que não bate certo, quer dizer que uma
mensagem se perdeu ou foi alterada pelo caminho. A numeração é feita no servidor, por isso não
apanha quem controla o servidor.
Os tokens ficam na configuração, que qualquer coisa a correr como o seu utilizador no servidor pode ler. Com eles, alguém pode enviar mensagens que parecem do Borg e continuar a numeração sem saltos, e um bot de Telegram pode apagar o que enviou nas últimas 48 horas. Quem tomar conta do servidor também pode apagar as mensagens que ainda esperam para sair. O que chegou antes disso fica como estava, e um webhook para uma máquina que controla guarda-o tal como chegou. Quando o observador se cala, é o sinal de vida que o avisa.
O que o observador não consegue ver
Seção intitulada “O que o observador não consegue ver”O observador avalia cada programa quando ele arranca, o que deixa algumas coisas fora da sua vista. Conheça-as antes de confiar nele.
- Código que corre dentro de um programa que já está a correr não inicia nada de novo, por isso nenhuma regra olha para ele. Uma aplicação web cujo próprio interpretador foi tomado mantém o nome e o pai de sempre.
- Os processos que já corriam antes de o observador arrancar nunca são examinados, e tudo o que corre durante a semana de aprendizagem conta como normal.
- Sem o observador como root, o Borg vê apenas os seus próprios processos, e um comando que termina
em menos de um quarto de segundo pode desaparecer antes de o Borg olhar. Os serviços que correm
como outro utilizador, como
www-dataoupostgres, precisam do observador como root. Quando o observador como root deixa de correr, o Borg volta a observar os seus próprios processos até que ele corra de novo. - Antes do Linux 5.8, ou onde a parte root não consegue carregar os seus programas, o Borg lê cada
processo novo em
/procdepois de o kernel o comunicar. Um comando que termina de imediato pode já ter desaparecido, e um processo pode mudar antes a sua linha de comandos. - Alguns kernels não enviam eventos de processos, como em certas máquinas virtuais e ambientes de contentores. O Borg a correr como root e o observador como root veem então todos os processos quatro vezes por segundo, e um comando curto pode terminar antes de olharem.
- Uma rajada de processos novos pode encher a fila entre o kernel e o Borg, e o kernel descarta então eventos, por isso alguns arranques nunca são examinados.
- Um comando que terminou antes de o Borg conseguir ler
/proctraz apenas o que os programas leram: o seu programa, a linha de comandos, o processo pai e o utilizador. O seu terminal, os fluxos padrão e as variáveis de pré-carregamento terminaram com ele, por isso as regras sobre eles não podem disparar. Programa apagado enquanto corre só dispara com ele quando o seu ficheiro já não existia ao arrancar, como num programa executado a partir da memória. - Os programas guardam os primeiros 4 KiB de uma linha de comandos, e o Borg vai buscar uma mais
longa a
/procenquanto o processo ainda lá está. Encontram a linha de comandos e o ficheiro do programa através da informação de tipos que o kernel publica em/sys/kernel/btf/vmlinux. Num kernel compilado sem ela, a linha de comandos também vem de/proc. Um comando que terminou antes é então identificado pelo caminho com que foi iniciado, que pode ser relativo à sua pasta de trabalho ou passar por uma ligação simbólica, por isso Programa numa pasta temporária pode não o apanhar. - Tudo o que corre como o utilizador do observador pode parar o observador, alterar os seus
ficheiros na pasta de estado ou deixar continuar um processo congelado com
kill -CONT. Congelar dá-lhe tempo para ver, e o dono do processo ainda o pode desfazer. - Um processo num terminal em que alguém iniciou sessão nunca é congelado, mesmo que a sessão tenha usado uma palavra-passe ou chave roubada. As regras continuam a disparar e a escrever alertas.
- A Exploração da máquina conta os comandos de um programa no espaço de uma hora. Quem espera mais entre comandos, ou corre cada um a partir de um programa diferente, fica abaixo dela.
- Um processo que se desliga do seu pai antes de o Borg congelar o pai continua a correr.
- Sem
[watch.notify], os alertas só chegam até si quando abre a página. Com ele, quem tomar conta da máquina nos segundos depois de um alerta ainda pode travar a mensagem antes de ela sair, e aí é o silêncio do sinal de vida que o avisa.
Este guia acompanha o ramo main · Borg 0.11.0 · 1f6bce6
A versão mais recente pode ainda não incluir tudo o que aqui se descreve. Notas de versão
Traduzido a partir do guia em inglês. As correções são bem-vindas. Os comandos e os atalhos de teclado não são traduzidos.