← Voltar ao blog

Alternate Data Streams: o segundo atributo $DATA que toda a gente esquece

· 6 min de leitura

Os ADS são a funcionalidade do NTFS que continua a apanhar de surpresa os analistas mais juniores. Um ficheiro pode ter mais do que um atributo $DATA. O atributo sem nome é aquele cuja dimensão é apresentada pelo dir. Tudo o resto, qualquer atributo com dois pontos no identificador, é invisível para as ferramentas a que a maioria das pessoas recorre. Os atacantes sabem disto. A Microsoft sabe disto. O auditor que rever o seu relatório de IR também devia saber.

O mecanismo, em poucas palavras

No registo do MFT, o tipo de atributo 0x80 é $DATA. O cabeçalho transporta um nome opcional. Um único registo pode carregar vários atributos $DATA: um sem nome (o fluxo primário) e qualquer número com nome. A partir do espaço de utilizador, endereça-os com filename:streamname.

echo payload > readme.txt:nope
type readme.txt:nope

O readme.txt tem zero bytes segundo qualquer medição que o Explorador mostre. O fluxo com nome nope contém a carga útil. O mesmo registo do MFT. A mesma entrada no índice do directório-pai. Dois atributos de dados independentes.

Isto não é um bug. É uma decisão de desenho de 1993 que o NTFS herdou do HPFS para permitir que os Services for Macintosh associassem resource forks. Hoje quase ninguém usa ADS para isso. Toda a gente, Microsoft incluída, usa-os para metadados ad-hoc.

Onde o próprio Windows coloca ADS

O Zone.Identifier é o caso famoso. Edge, Chrome, Firefox e Outlook acrescentam-no a tudo o que atravessa uma fronteira de segurança. O conteúdo é um fragmento INI com o URL de origem, o referrer, e uma linha ZoneId=3 que activa as protecções Mark-of-the-Web no Office e no SmartScreen. Se estiver a ler um MFT e um binário em Downloads\ não tiver Zone.Identifier, pergunte porquê. Alguém pode ter corrido Unblock-File ou copiado o ficheiro através de um arquivo que descarta fluxos.

Outros fluxos abençoados pela Microsoft com que se vai cruzar:

  • $KSP em ficheiros de layout de teclado para línguas asiáticas.
  • OECustomProperty e companhia em anexos do Outlook guardados em disco.
  • Dados de reparse Wof em ficheiros comprimidos sob WIMBoot e CompactOS.
  • SmartScreen em executáveis que o Defender já analisou.
  • encryptable em directórios de cache do ConfigMgr.

Estes aparecem constantemente. Aprenda como é a sua linha de base antes de marcar fluxos como suspeitos.

O que os atacantes fazem realmente com ADS

Repetem-se três padrões:

  1. Esconderijo da carga útil, lançador separado. O ficheiro visível é benigno (um documento Word, um PDF, um ficheiro de licença). O fluxo com nome carrega o PE verdadeiro. WMI, wmic process call create ou rundll32 lançam legit.docx:payload.exe directamente. O Defender já analisa fluxos com nome hoje em dia, mas muitos EDR ainda não o fazem quando o fluxo é criado por um processo de confiança.
  2. Esconderijo living-off-the-land. Cargas úteis de PowerShell escritas em ads:script.ps1 e depois executadas com Get-Content -Stream. Surpreendentemente comum em contratos de red team porque sobrevive a uma pesquisa de IOC apenas por caminho.
  3. Persistência em fluxos alternativos de ficheiros de sistema. C:\Windows\System32\drivers\etc\hosts:backdoor é o exemplo de manual. O ficheiro hosts parece intacto, o carimbo temporal pode até ser o original, e a maioria das ferramentas de monitorização de integridade de ficheiros nunca olha para além do fluxo sem nome.

A propriedade comum: não os vê com dir, não os vê no Explorador, e não os vê fazendo hash do ficheiro visível. Vê-os lendo o registo do MFT.

Detectá-los num host ao vivo

dir /R enumera fluxos na cmd. O Get-Item -Stream * do PowerShell faz o mesmo com saída mais limpa. O streams.exe da Sysinternals percorre uma árvore. Os três funcionam bem no volume em que se encontra. Nenhum ajuda se o volume estiver offline ou se não souber que ficheiros verificar.

dir /R C:\Users\bob\Documents\
Get-ChildItem -Recurse | ForEach-Object { Get-Item $_.FullName -Stream * } |
  Where-Object Stream -ne ':$DATA'

Esse segundo one-liner enumera todos os fluxos não-padrão numa árvore. Corra-o numa instalação fresca de Windows e já terá centenas de hits, na sua maioria Zone.Identifier. Filtre para fluxos maiores do que algumas centenas de bytes e o ruído cai rapidamente.

Porque o MFT é a melhor lente

Os comandos no host enumeram ficheiro a ficheiro. Falham aquilo que não pensou em verificar. O MFT não. Todos os atributos $DATA, com nome ou não, são escritos no registo no tipo de atributo 0x80. Percorra a tabela, liste todos os atributos $DATA de cada registo com nomes e tamanhos, e fica com um inventário exaustivo de todos os fluxos no volume numa única passagem.

Algumas coisas que isto lhe dá e que a enumeração ficheiro a ficheiro não dá:

  • Fluxos em ficheiros em directórios onde nunca teria pensado em procurar, incluindo C:\Windows\Temp\ e C:\$Recycle.Bin\.
  • Fluxos em ficheiros eliminados. O registo do MFT sobrevive à eliminação; o ADS continua listado no fluxo de atributos. O fls e o istat do Sleuth Kit mostram-nos; o MFTECmd e o CLI omerbenamram/mft também.
  • Fluxos residentes cujo conteúdo está inline no registo do MFT. Cargas pequenas (loaders de PowerShell, blobs base64, configurações codificadas) cabem frequentemente no slack de um registo de 1.024 bytes. Pode lê-los directamente a partir do extracto do MFT sem nunca tocar na área de dados. Veja resident data para o limite de tamanho.
  • Nomes dos fluxos. O MFT preserva o nome que o atacante escolheu. :payload.exe parece inócuo numa lista de tamanhos de ficheiro; é gritante quando se faz grep ao dump de atributos por exe.

O filtro de triagem que uso na prática

Depois de analisar o MFT com o MFTECmd ou o mft_dump, exporto todos os registos com mais do que um atributo $DATA. Depois removo:

  • Tudo cujo nome do fluxo adicional seja Zone.Identifier e tenha menos de 1 KB.
  • Tudo em \Windows\WinSxS\ (o manifest store, cheio de fluxos legítimos).
  • Tudo num directório de aplicação assinado pelo fornecedor cujo fluxo seja uma miniatura ou chave de metadados conhecida.

O que sobra é o conjunto de trabalho. Numa estação limpa fica habitualmente abaixo de uma centena de registos. Num host onde aconteceu algo interessante, os deltas aparecem imediatamente.

Cruze os sobreviventes com o USN journal para ver quando cada fluxo foi criado ou modificado pela última vez. Um atributo $DATA com nome que apareceu às 02:14 e não foi tocado desde então merece um olhar mais atento. Combine com o Sysmon e os logs de eventos de Security se os tiver: o Sysmon Event ID 15 (FileCreateStreamHash) é o único ID de evento que captura a criação de ADS com o hash do conteúdo do fluxo.

Uma nota sobre o Defender

O Defender moderno analisa ADS por omissão. É genuinamente bom no padrão "atirar um PE conhecido-mau para um fluxo" por força bruta. É menos bom em PowerShell pequeno e ofuscado escondido em fluxos, e nem sempre toca em fluxos em caminhos excluídos. Não assuma que o silêncio do Defender é prova de ausência.

Leituras adicionais

  • Microsoft, File Streams. A mecânica oficial, incluindo a API BackupRead/BackupWrite que copia todos os fluxos.
  • istat e fls do Sleuth Kit para enumeração offline que faz emergir ADS.
  • Documentação da Microsoft sobre Mark of the Web para o que Zone.Identifier realmente faz e como o Office o usa.

Recursos externos