
Kit modular de resposta a incidentes para coletar dados forenses de endpoints macOS potencialmente infectados, capturando artefatos de navegador, mecanismos de persistência, processos e configurações de rede.
Este conjunto de scripts foi projetado para coletar uma variedade de dados de um endpoint considerado infectado, para facilitar o processo de resposta a incidentes. Esses dados não devem ser considerados uma coleta forense completa, mas capturam muitas informações forenses úteis.
Se você deseja dados forenses verdadeiros, realmente deve capturar um dump completo de memória e imagear todo o disco. Isso está fora do escopo deste kit.
O script deve ser executado em um sistema ativo, não em uma imagem ou outro repositório de dados forenses. Ele não exige estritamente permissões de root para ser executado, mas não conseguirá coletar grande parte dos dados pretendidos sem elas.
Os dados serão coletados de duas formas. A primeira é na forma de arquivos de resumo, contendo saída de comandos de shell, dados extraídos de bancos de dados e similares. Por exemplo, o módulo browser gerará um arquivo browser_extensions.txt com um resumo de todas as extensões de navegador instaladas para Safari, Chrome e Firefox.
A segunda são arquivos completos coletados do sistema de arquivos. Eles são armazenados em uma subpasta artifacts dentro da pasta de coleta.
O script é muito simples de executar. Ele aceita apenas um parâmetro, que é obrigatório, para passar um script de configuração em formato JSON:
./pict.py -c /path/to/config.json
O script de configuração descreve o que o script coletará e como. Deve ser algo assim:
{
"collection_dest" : "~/Desktop/",
"all_users" : true,
"collectors" : {
"browser" : "BrowserExtCollector",
"persist" : "PersistenceCollector",
"suspicious" : "SuspiciousBehaviorCollector",
"browserhist" : "BrowserHistoryCollector",
"bash_config" : "BashConfigCollector",
"bash_hist" : "BashHistoryCollector",
"processes" : "ProcessCollector",
"network_config" : "NetworkConfigCollector",
"profiles" : "ProfileCollector",
"certs" : "TrustedCertCollector"
},
"settings" : {
"keepLSData" : true,
"zipIt" : true
},
"moduleSettings" : {
"browser" : {
"collectArtifacts" : true
}
},
"unused" : {
"installs" : "InstallationCollector"
}
}
Isso especifica o caminho para armazenar os dados coletados. Pode ser um caminho absoluto ou um caminho relativo à pasta home do usuário (começando com til). O caminho padrão, se não especificado, é /Users/Shared.
Os dados serão coletados em uma pasta criada neste local. Essa pasta terá um nome no formato PICT-computername-YYYY-MM-DD, onde o nome do computador é o nome da máquina especificado em Preferências do Sistema > Compartilhamento e a data é a data da coleta.
Se verdadeiro, coleta dados de todos os usuários da máquina sempre que possível. Se falso, coleta dados apenas do usuário que está executando o script. Se não especificado, esse valor padrão é verdadeiro.
PICT é modular e pode ser facilmente expandido ou reduzido em escopo, simplesmente alterando quais módulos do Coletor são usados.
Os dados collectors são um dicionário onde a chave é o nome do módulo a ser carregado (o nome do arquivo Python sem a extensão .py) e o valor é o nome da subclasse do Coletor encontrada nesse módulo. Você pode adicionar entradas adicionais para módulos personalizados (veja Writing your own modules), ou pode remover entradas para impedir que esses módulos sejam executados. Uma maneira fácil de remover módulos, sem ter que pesquisar os nomes exatos mais tarde se quiser adicioná-los novamente, é movê-los para um dicionário de nível superior chamado unused.
Este dicionário fornece configurações globais.
keepLSData especifica se o arquivo lsregister.txt - que pode ser bastante grande - deve ser mantido. (Este arquivo é gerado automaticamente e é usado para construir a saída por alguns outros módulos. Ele contém uma riqueza de informações úteis, mas pode ter mais de 100 MB. Se você não precisar de todos esses dados, ou não quiser lidar com tantos dados, defina isso como falso e ele será excluído quando a coleta terminar.)
zipIt especifica se deve gerar automaticamente um arquivo zip com o conteúdo da pasta de coleta. Observe que o processo de compactar e descompactar os dados alterará alguns atributos, como a propriedade do arquivo.
Este dicionário especifica configurações específicas do módulo. Nem todos os módulos têm suas próprias configurações, mas se um módulo permitir suas próprias configurações, você pode fornecê-las aqui. No exemplo acima, você pode ver uma configuração booleana chamada collectArtifacts sendo usada com o módulo browser.
Também existem configurações globais de módulo que são mantidas pela classe Coletor, e que podem ser definidas individualmente para cada módulo.
collectArtifacts especifica se deve coletar os artefatos de arquivo que normalmente seriam coletados pelo módulo. Se falso, todos os artefatos serão omitidos para esse módulo. Isso pode ser necessário em casos onde o espaço de armazenamento é uma consideração e os artefatos coletados são grandes, ou em casos onde os artefatos coletados podem representar um problema de privacidade para o usuário cujo sistema está sendo analisado.
Os módulos devem consistir em um arquivo contendo uma classe que é subclasse de Coletor (definido em collectors/collector.py), e devem ser colocados na pasta collectors. Um novo módulo Coletor pode ser facilmente criado duplicando o arquivo collectors/template.py e personalizando-o para seu próprio uso.
def __init__(self, collectionPath, allUsers)Este método pode ser sobrescrito se necessário, mas o super Collector.init() deve ser chamado nesse caso, preferencialmente antes que seu código personalizado seja executado. Isso dá ao objeto a chance de configurar suas propriedades antes que seu código tente usá-las.
def printStartInfo(self)Este é um método muito simples que será chamado quando a coleta deste módulo começar. Sua intenção é imprimir uma mensagem no stdout para dar ao usuário uma noção do progresso, fornecendo feedback sobre o que está acontecendo.
def applySettings(self, settingsDict)Isso dá ao módulo a chance de aplicar quaisquer configurações personalizadas. Cada módulo pode ter suas próprias configurações definidas, mas o settingsDict também deve ser passado para o super, para que a classe Coletor possa lidar com quaisquer configurações que ela define.
def collect(self)Este método é o núcleo do módulo. Ele é chamado quando é hora do módulo iniciar a coleta. Ele pode escrever quantos arquivos precisar, mas deve confinar essa atividade a arquivos dentro do caminho self.collectionPath, e deve usar nomes de arquivos que não estejam já em uso por outros módulos.
Se você deseja coletar artefatos, não tente fazer isso por conta própria. Simplesmente adicione caminhos ao array self.pathsToCollect, e a classe Coletor cuidará de copiá-los para os subcaminhos apropriados na pasta artifacts, e manterá os metadados (permissões, atributos estendidos, flags, etc.) nos artefatos.
Quando o método terminar, certifique-se de chamar o super (Collector.collect(self)) para dar à classe Coletor a chance de lidar com suas responsabilidades, como coletar artefatos.
Seu método collect pode usar quaisquer dados coletados nos arquivos basic_info.txt ou lsregister.txt encontrados em self.collectionPath. Eles são coletados no início pelo script pict.py, e podem ser assumidos como disponíveis para uso por qualquer outro módulo. No entanto, você não deve confiar na saída de outros módulos, pois não há garantia de que os arquivos estarão disponíveis quando seu módulo for executado. Os módulos podem não ser executados na ordem em que aparecem em seu JSON de configuração, já que dicionários Python são não ordenados.
Agradecimentos a Greg Neagle por FoundationPlist.py, que resolveu muitos problemas com a leitura de plists binários, plists contendo tipos de dados de data, etc.