SToFU Systems · Investigação do incidente · 20 de outubro de 2026
Índice
- Tudo começou com um pedido de desenvolvimento
- Descarga e inspeção dos ficheiros
- Como o hook post-checkout do Git podia ser executado
- O que faz o descarregador do hook do Git
- Havia uma aplicação escondida no arquivo?
- O que devolveu o servidor de descarga
- Poderia tratar-se de um utilitário legítimo?
- Analisar um repositório Git desconhecido
- Depois da análise do arquivo
- Correspondência e ficheiros de prova
Tudo começou com um pedido de desenvolvimento
A primeira mensagem chegou através do nosso site a 15 de outubro de 2026. O remetente pretendia ajuda para desenvolver uma plataforma de deteção de fraude financeira. O sistema proposto atribuiria pontuações de risco às transações e utilizaria análise comportamental, incluindo ainda, entre outros requisitos, verificação por blockchain e produção de relatórios.
A 19 de outubro, recebemos a ligação para descarregar o arquivo. O e-mail que a acompanhava indicava o ramo conf para a arquitetura e o ramo NDA para o acordo. Repetia o pedido para analisar e assinar o acordo de confidencialidade.
Please review the project materials and review and sign the NDA in the NDA branch.
Seguir essas instruções levaria a pessoa responsável pela análise desde a extração do arquivo até à mudança de ramo no Git. O e-mail apresentava ambas as operações como parte da leitura da documentação. Não mencionava a execução de um programa descarregado.
O e-mail com o arquivo do projeto e as instruções para abrir o ramo NDA. Os dados identificativos estão cobertos com retângulos cinzentos.
Descarga e inspeção dos ficheiros
A ligação conduzia a uma página normal de partilha de ficheiros do Dropbox. Descarregámos AI-Fraud-Detection_Blockchain.tar.gz para um ambiente de análise isolado e conservámos o arquivo original como referência. O URL de partilha específico não é divulgado aqui.
Listámos o conteúdo do arquivo e lemos diretamente os objetos Git fornecidos. Isto permitiu-nos recuperar os documentos dos três ramos sem extrair um ramo para a árvore de trabalho nem executar o código fornecido. Nas árvores dos ramos, encontrámos 15 ficheiros Markdown e um documento Word.
| Ramo | Ficheiros | O que encontrámos |
|---|---|---|
master |
8 ficheiros Markdown | Um README, uma visão geral do projeto, requisitos do produto e casos de utilização de negócio. Outros documentos abordavam desempenho, segurança, testes e operações. |
conf |
7 ficheiros Markdown | Orientações para uma proposta de desenvolvimento, arquitetura e integração de blockchain, requisitos de contratos inteligentes, conceção de dados e API, um motor de risco baseado em IA e marcos de entrega. |
NDA |
1 ficheiro DOCX | Um acordo de confidencialidade com um bloco de assinatura e campos de modelo por preencher. |
O produto proposto combinava análise de transações, regras de deteção de fraude e pontuações de aprendizagem automática com verificação por blockchain. A combinação de tecnologias sugerida utilizava Node.js e TypeScript com Express, PostgreSQL, bibliotecas Python de aprendizagem automática e Ethereum. O documento de entrega estabelecia seis marcos ao longo de 24 semanas. Encontrámos documentos de planeamento em todas as árvores fornecidas, sem implementação da aplicação, modelo treinado ou código-fonte de contratos inteligentes para analisar.
Alguns detalhes mereciam uma segunda análise. Os exemplos de API continham as cadeias literais <built-in function id> e <built-in function hash> nos caminhos dos endpoints. O acordo de confidencialidade ainda continha campos de modelo por preencher. Estas incoerências levantavam questões sobre o cuidado com que o material tinha sido preparado.
O ficheiro executável .git/hooks/post-checkout foi uma descoberta mais grave. Os seus comentários descreviam um utilitário de atualização de navegador ou extensão, sem ligação aparente à análise deste projeto. A leitura do script revelou instruções para descarregar um programa externo e iniciá-lo em segundo plano. O pedido do e-mail para mudar de ramo podia conduzir a pessoa responsável pela análise a esse percurso de execução enquanto tentava ler o acordo de confidencialidade.
Mantivemos o repositório inativo e examinámos o hook como texto. Os metadados relevantes do arquivo e o comportamento do script são apresentados abaixo.
Como o hook post-checkout do Git podia ser executado
O ficheiro AI-Fraud-Detection_Blockchain.tar.gz tem 779 429 bytes. As suas 100 entradas TAR incluem 60 ficheiros regulares. Um diretório .git completo chegou juntamente com os documentos.
O diretório de hooks continha os ficheiros .sample habituais e um executável chamado post-checkout.
AI-Fraud-Detection_Blockchain/.git/hooks/post-checkout
Não tem o sufixo .sample. O seu modo TAR é 0777, que inclui permissões de execução, e o seu tamanho é de 2 774 bytes.
O Git invoca post-checkout depois de atualizar a árvore de trabalho através de operações como checkout ou switch, desde que o ambiente permita a execução do hook. A documentação do Git descreve o acionamento.
Porque importa o diretório .git incluído no arquivo
Um git clone normal não copia os hooks locais do lado do cliente do repositório de origem, como explica o Pro Git. Esta entrega incluía o diretório .git existente dentro de um arquivo, pelo que o hook local veio com ele.
O caminho, o modo e o tamanho do hook lidos diretamente do TAR original. Não utilizámos o diretório recebido como repositório Git.
Inspecionámos diretamente o contentor e os objetos Git, sem executar checkout ou switch no repositório recebido.
O que faz o descarregador do hook do Git
Os comentários no script de shell descrevem um utilitário de atualização de navegador ou extensão. Não encontrámos nenhum requisito para esse utilitário nos documentos do projeto. O script é texto simples, sem ofuscação.
O limiar de tamanho não utilizado
O script define THRESHOLD como 100 e pede ao Git uma lista dos nomes dos ficheiros alterados. Inicializa TRIGGER a zero.
THRESHOLD=100
FILES=$(git diff --name-only "$OLD_HEAD" "$NEW_HEAD")
TRIGGER=0
Dentro do ciclo, calcula SIZE. Não existe qualquer comparação com THRESHOLD nem atribuição que altere TRIGGER. O bloco de descarga é executado quando TRIGGER é zero.
if [ "$TRIGGER" -eq 0 ]; then
No percurso normal deste script, a condição é verdadeira mesmo quando a lista de ficheiros alterados está vazia. O limiar não restringe a descarga.
Números de linha originais preservados. TRIGGER permanece a zero. THRESHOLD é declarado, mas nunca utilizado numa comparação.
Descargas separadas para Linux, macOS e Windows
O valor devolvido por uname -s determina o caminho de descarga e o nome do ficheiro local.
| Sistema detetado | Caminho no servidor | Nome do ficheiro local |
|---|---|---|
| Linux | /api/l |
run-command.sh |
| Darwin / macOS | /api/m |
run-command.sh |
| MINGW, MSYS, CYGWIN, Windows_NT | /api/w |
run-command.cmd |
| Sistema não reconhecido | /api/l |
run-command.sh |
Os URL partilham um único host, aqui substituído por <DOWNLOAD_DOMAIN>. Conservámos o hook sem ocultações em privado. Os ramos condicionais abrangem Linux, macOS e Windows, com uma alternativa Linux para um sistema não reconhecido. Não testámos a execução nesses sistemas.
Descarga do ficheiro e tentativa de execução
O hook guarda o ficheiro em ${TMPDIR:-/tmp} utilizando curl, ou wget se curl não estiver disponível. Não existe qualquer verificação de assinatura ou de hash esperado antes das instruções de execução que se seguem.
chmod +x "$CMD_FILE"
"$CMD_FILE" > /dev/null 2>&1 &
O símbolo & final inicia o comando em segundo plano. Tanto a saída padrão como o erro padrão são redirecionados para /dev/null.
Depois da tentativa de execução, o hook escreve azuku em .git-checker no diretório temporário. Nunca verifica a existência desse marcador antes de voltar a descarregar. Também não espera pelo sucesso do processo em segundo plano antes de escrever o ficheiro. Por isso, o marcador poderia existir após uma tentativa de execução sem sucesso.
As instruções originais de descarga, chmod, execução em segundo plano e escrita do marcador. O programa da segunda fase não está presente neste excerto.
Um comentário perto do fim indica que se deve remover o diretório temporário de descarga. Não existe nenhum comando de remoção por baixo.
Havia uma aplicação escondida no arquivo?
A descarga pela rede levantou outra questão. Já existiria uma aplicação no arquivo, talvez no histórico do Git ou no acordo de confidencialidade? Examinámos os limites dos contentores e, em seguida, descodificámos todos os objetos Git fornecidos e inspecionámos o conteúdo do DOCX.
Os limites do arquivo
Registámos o SHA-256 do arquivo original antes de inspecionar o seu conteúdo.
6f44ff4e461828dd1fe6ede75ca8d9d4b579c2ac223463629e9a7537b9df5040
A descompressão do gzip como dados produziu um fluxo TAR de 890 880 bytes. O fluxo gzip terminava corretamente, sem bytes não utilizados a seguir. Os últimos 5 120 bytes após a última entrada TAR eram preenchimento com zeros.
Em seguida, examinámos os ficheiros e objetos correspondentes a essas entradas dos contentores.
Verificações guardadas do fim do fluxo gzip e do preenchimento TAR. Não foi executado qualquer código da amostra.
Localização do hook no cabeçalho TAR
O cabeçalho da entrada post-checkout começa em 0xCF600, ou 849 408, no TAR descomprimido. Os dados do ficheiro começam em 849 920. Estes deslocamentos referem-se ao fluxo TAR, não ao ficheiro .gz comprimido.
Nesse deslocamento, o cabeçalho começa com o caminho para post-checkout.
TAR / representação hexadecimal
000cf600 41 49 2d 46 72 61 75 64 2d 44 65 74 65 63 74 69 |AI-Fraud-Detecti|
000cf610 6f 6e 5f 42 6c 6f 63 6b 63 68 61 69 6e 2f 2e 67 |on_Blockchain/.g|
000cf620 69 74 2f 68 6f 6f 6b 73 2f 70 6f 73 74 2d 63 68 |it/hooks/post-ch|
000cf630 65 63 6b 6f 75 74 00 00 00 00 00 00 00 00 00 00 |eckout..........|
000cf640 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000cf650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000cf660 00 00 00 00 30 30 30 30 37 37 37 00 30 30 30 31 |....0000777.0001|
000cf670 37 35 30 00 30 30 30 31 37 35 30 00 30 30 30 30 |750.0001750.0000|
000cf680 30 30 30 35 33 32 36 00 31 35 32 35 32 30 30 34 |0005326.15252004|
000cf690 33 30 37 00 30 32 34 30 37 35 00 20 30 00 00 00 |307.024075. 0...|
000cf6a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Num cabeçalho TAR, mode ocupa os bytes [100:108] e size ocupa [124:136]. Os campos descodificados desta entrada são apresentados depois do dump.
| Campo TAR | Bytes em bruto / valor |
|---|---|
| mode | b'0000777\x00' |
| size | b'00000005326\x00' |
| Modo octal | 0777 |
| Tamanho decimal | 2774 bytes |
| Soma de verificação armazenada / calculada | 10301 / 10301 |
O tamanho octal corresponde a 2 774 bytes. A soma de verificação armazenada no cabeçalho é 10 301. Recalculá-la com o campo da soma de verificação preenchido com espaços dá o mesmo resultado.
O cabeçalho TAR em bruto do hook e os campos descodificados. O seu nome, permissões e tamanho são visíveis nos bytes do contentor.
Também calculámos o hash do hook extraído desta entrada.
854b3b88b06fad9d9ffec36b35be0133b1d502084d4d7cce232eda2b2dd03092
O dump da entrada TAR e o hook anonimizado estão incluídos no artigo. O hash acima identifica o original sem ocultações conservado em privado, não a cópia com ocultações destinada à publicação.
Leitura de objetos Git sem checkout
Existem 24 objetos soltos em .git/objects, cada um armazenado num fluxo zlib. Os dados descomprimidos contêm um cabeçalho Git seguido do corpo do objeto.
<type> <size>\0<body>
Verificámos o comprimento declarado do corpo e calculámos o SHA-1 de toda a sequência descodificada, incluindo o cabeçalho e o byte NUL. O resultado tem de corresponder ao identificador do objeto no nome do ficheiro. Isto verifica a integridade do objeto. Não indica quem o criou.
Para cada objeto, comparámos o comprimento declarado com o comprimento do corpo e verificámos o hash de todos os dados descodificados.
expanded = zlib.decompress(compressed_object)
header, body = expanded.split(b"\0", 1)
kind, declared_size = header.decode("ascii").split()
assert len(body) == int(declared_size)
assert hashlib.sha1(expanded).hexdigest() == object_id
Também verificámos os finais dos fluxos zlib. Os objetos correspondem a 16 blobs, 5 árvores e 3 commits. Percorrer as pontas dos três ramos, os seus commits pais e as suas árvores filhas permite localizar os 24 objetos. Não existem blobs inacessíveis entre os objetos fornecidos.
Git / relações entre commits
master 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f
tree feb0feaf7b8e826b085e90dea5399772d7b91f02
parent (none)
conf 239b9aa2edc8c5e21fddeea5ed0e937496ae013f
tree 048b51f9673f94354251ce16a78e663c71667a4c
parent 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f
NDA a1311875d86bf6f1a6b9f2fee6527abbd1ce647d
tree cc020d922090835ea4ac3a3e418d0213d7a2ad94
parent 239b9aa2edc8c5e21fddeea5ed0e937496ae013f
O inventário completo de objetos inclui os objetos fora da árvore de trabalho atual.
Inventário dos 24 objetos Git
| Identificador do objeto | Tipo | Corpo, em bytes |
|---|---|---|
| 08e2cda2f440c1792c7c35a3499bfd1ade3e9bad | blob | 6497 |
| 22bb86aacf377c17c7ad0d52c5cefeeb93dfa13e | blob | 5123 |
| 2a7091bdd006a2f98a8c795fd7d2a04c8ee53056 | blob | 2610 |
| 39e13459086f36bc7c933d4e7b5d249a22db24bd | blob | 3061 |
| 3f50e45c67dee5aac77147a5418afe551e8871be | blob | 2433 |
| 476dc872c6def747dcdac549b67a8dc80948b7e1 | blob | 3191 |
| 5a51550933b593eb65da458bbdd579f85c082dab | blob | 752100 |
| 5e53fd0880963e1767ad23fb8612b76e31f04003 | blob | 2807 |
| 60a7cbff83445488fd34b12de1814dc56c956963 | blob | 2054 |
| 74d479352822f5cc1d03552f517cfb5b2d7aa6d3 | blob | 2281 |
| 84e694473554c8a7c01f038a1b6ef8d9355405f7 | blob | 2033 |
| bb7b5d8bc28c4a6257f7d87a685c61ba16a3789c | blob | 2425 |
| d83c8e0c416766be34276013944f5b94726e8c8f | blob | 2776 |
| dfd0f171bca257780eb0d9e22ba2eda1db9d4b68 | blob | 8402 |
| e3b57e48010fc25fd12e7f5f25e952aca843e537 | blob | 6316 |
| ed325750862eb6cdc92b216258a00a784312d793 | blob | 3062 |
| 239b9aa2edc8c5e21fddeea5ed0e937496ae013f | commit | 213 |
| 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f | commit | 165 |
| a1311875d86bf6f1a6b9f2fee6527abbd1ce647d | commit | 212 |
| 048b51f9673f94354251ce16a78e663c71667a4c | tree | 438 |
| 2cb70db8d9317603cb5f0fee0029b66581a7162e | tree | 104 |
| 61874365e5498a30c8b61ef63bbb1d28b4cf4e22 | tree | 320 |
| cc020d922090835ea4ac3a3e418d0213d7a2ad94 | tree | 57 |
| feb0feaf7b8e826b085e90dea5399772d7b91f02 | tree | 104 |
Comprimento e SHA-1 verificados sobre a codificação Git original de cada objeto. As 24 verificações foram bem-sucedidas.
Seguir o acordo de confidencialidade desde a sua árvore até aos seus bytes
O ramo NDA aponta para uma árvore que contém um ficheiro, Non-Disclosure-Agreement.docx. Uma entrada de árvore Git armazena o modo e o nome do ficheiro como texto, seguidos de um NUL e de 20 bytes em bruto para o identificador do blob. Analisámos a entrada diretamente a partir do corpo da árvore.
Árvore Git / representação hexadecimal
00000000 31 30 30 36 34 34 20 4e 6f 6e 2d 44 69 73 63 6c |100644 Non-Discl|
00000010 6f 73 75 72 65 2d 41 67 72 65 65 6d 65 6e 74 2e |osure-Agreement.|
00000020 64 6f 63 78 00 5a 51 55 09 33 b5 93 eb 65 da 45 |docx.ZQU.3...e.E|
00000030 8b bd d5 79 f8 5c 08 2d ab |...y.\.-.|
Bytes em bruto da árvore NDA e a referência descodificada ao respetivo blob DOCX.
Essa entrada faz referência ao seguinte blob.
5a51550933b593eb65da458bbdd579f85c082dab
Após a descompressão zlib, o objeto começa com blob 752100\0. Imediatamente a seguir ao cabeçalho estão os bytes 50 4b 03 04, a assinatura PK de um contentor ZIP.
Blob Git / após a descompressão zlib
00000000 62 6c 6f 62 20 37 35 32 31 30 30 00 50 4b 03 04 |blob 752100.PK..|
00000010 0a 00 00 00 00 00 87 4e e2 40 00 00 00 00 00 00 |.......N.@......|
00000020 00 00 00 00 00 00 09 00 00 00 64 6f 63 50 72 6f |..........docPro|
00000030 70 73 2f 50 4b 03 04 14 00 00 00 08 00 87 4e e2 |ps/PK.........N.|
00000040 40 a5 76 12 16 69 01 00 00 7b 02 00 00 10 00 00 |@.v..i...{......|
00000050 00 64 6f 63 50 72 6f 70 73 2f 61 70 70 2e 78 6d |.docProps/app.xm|
00000060 6c 9d 92 c1 4e c3 30 10 44 ef 48 fc 43 94 7b 62 |l...N.0.D.H.C.{b|
Bytes do objeto comprimido, cabeçalho Git descodificado e início do DOCX. O comprimento e o identificador do objeto foram verificados sobre o objeto completo.
O corpo tem 752 100 bytes. O seu SHA-256 corresponde ao DOCX que guardámos separadamente para análise.
9d85170d2c0aa7a9b90dfc3855715a31d971bba7abb563e9efa1153fdc15634f
Estes objetos permitem seguir o caminho do ramo NDA até aos bytes do documento.
Identificação dos 16 blobs
Quinze blobs são descodificados como documentos de projeto Markdown em UTF-8. O blob restante é o DOCX acima. Nenhum começa com um cabeçalho PE, ELF ou Mach-O.
| Caminho nas árvores | Tamanho, em bytes | Tipo / primeiros bytes |
|---|---|---|
| 04-solution-proposal-guidance.md | 2054 | Texto UTF-8 · 23 20 44 65 76 65 6c 6f 70 6d 65 6e 74 20 43 6f |
| 06-blockchain-architecture.md | 6497 | Texto UTF-8 · 23 20 42 6c 6f 63 6b 63 68 61 69 6e 20 41 72 63 |
| 07-blockchain-integration-specification.md | 2807 | Texto UTF-8 · 23 20 42 6c 6f 63 6b 63 68 61 69 6e 20 49 6e 74 |
| 08-smart-contract-specification.md | 2610 | Texto UTF-8 · 23 20 53 6d 61 72 74 20 43 6f 6e 74 72 61 63 74 |
| 09-data-and-api-architecture.md | 2776 | Texto UTF-8 · 23 20 44 61 74 61 20 26 20 41 50 49 20 41 72 63 |
| 11-ai-fraud-and-risk-engine.md | 3062 | Texto UTF-8 · 23 20 41 49 20 46 72 61 75 64 20 44 65 74 65 63 |
| 14-deliverables-acceptance-and-milestones.md | 6316 | Texto UTF-8 · 23 20 44 65 6c 69 76 65 72 61 62 6c 65 73 2c 20 |
| Detailed/03-business-and-use-cases.md | 3061 | Texto UTF-8 · 23 20 42 75 73 69 6e 65 73 73 20 52 65 71 75 69 |
| Detailed/05-non-functional-requirements.md | 2033 | Texto UTF-8 · 23 20 4e 6f 6e 2d 46 75 6e 63 74 69 6f 6e 61 6c |
| Detailed/10-security-and-privacy-requirements.md | 2433 | Texto UTF-8 · 23 20 53 65 63 75 72 69 74 79 20 26 20 50 72 69 |
| Detailed/12-testing-and-quality-requirements.md | 2425 | Texto UTF-8 · 23 20 54 65 73 74 69 6e 67 20 26 20 51 75 61 6c |
| Detailed/13-deployment-monitoring-and-operations.md | 2281 | Texto UTF-8 · 23 20 44 65 70 6c 6f 79 6d 65 6e 74 2c 20 4d 6f |
| Intro/01-project-overview.md | 8402 | Texto UTF-8 · 23 20 50 72 6f 6a 65 63 74 20 4f 76 65 72 76 69 |
| Intro/02-product-requirements.md | 3191 | Texto UTF-8 · 23 20 50 72 6f 64 75 63 74 20 52 65 71 75 69 72 |
| Non-Disclosure-Agreement.docx | 752100 | DOCX/ZIP · 50 4b 03 04 0a 00 00 00 00 00 87 4e e2 40 00 00 |
| README.md | 5123 | Texto UTF-8 · 23 20 41 49 20 46 72 61 75 64 20 44 65 74 65 63 |
Os 16 blobs fornecidos foram classificados. As árvores contêm documentos do projeto, sem que tenha sido encontrada uma implementação do produto.
Lemos os corpos de texto, além de verificar as suas assinaturas. O DOCX era o único blob não textual e precisava de uma inspeção separada do contentor.
Abertura do DOCX como ZIP
O documento contém 25 entradas ZIP, constituídas por 17 partes de ficheiro e 8 diretórios. Lemos cada parte de ficheiro e verificámos o seu CRC.
| Parte do DOCX | Tamanho, em bytes | CRC32 |
|---|---|---|
| [Content_Types].xml | 1482 | ec936159 |
| _rels/.rels | 737 | 1f222201 |
| customXml/_rels/item1.xml.rels | 296 | 7a393f74 |
| customXml/item1.xml | 400 | 4ed0e3fe |
| customXml/itemProps1.xml | 327 | 457b4363 |
| docProps/app.xml | 635 | 161276a5 |
| docProps/core.xml | 595 | d5626da7 |
| docProps/custom.xml | 722 | 8d44908d |
| word/_rels/document.xml.rels | 1086 | 22475620 |
| word/_rels/settings.xml.rels | 398 | e5802c0c |
| word/document.xml | 91835 | 4df71596 |
| word/fontTable.xml | 4234 | 2796cccd |
| word/media/image1.png | 712863 | 09063019 |
| word/media/image2.png | 10193 | 3aea21cf |
| word/settings.xml | 4116 | 34faa9ef |
| word/styles.xml | 30020 | b4e9edbd |
| word/theme/theme1.xml | 6329 | ed5975e1 |
Nomes, comprimentos e valores CRC32 das partes do DOCX. Inspecionámos os dados ZIP e XML sem abrir o documento no Office.
Não existe vbaProject.bin nem anexo OLE na lista de partes. Dois ficheiros PNG contêm um logótipo e uma imagem de assinatura. Também inspecionámos as relações XML e encontrámos uma referência a um caminho de modelo de documento de escritório local na máquina do autor do documento. Não resolvemos a referência nem carregámos o modelo.
A imagem da assinatura e os campos de autor do Git não nos dão uma forma fiável de identificar o remetente. Ambos podem ser copiados ou substituídos.
Não encontrámos nenhuma aplicação separada nem implementação do produto no conteúdo fornecido. O hook obtém o programa seguinte através da rede. A nossa inspeção dos contentores não exclui todas as técnicas possíveis de exploração ou esteganografia.
O que devolveu o servidor de descarga
Obtivemos os três URL exatos como dados, sem executar as respostas nem seguir redirecionamentos. A 19 de outubro, entre as 17:29:27 e as 17:29:28 UTC, cada um devolveu HTTP 200. Os três corpos continham a mesma mensagem de 21 bytes.
Permanently suspended
As três observações guardadas dos endpoints. Não fizemos mais pedidos aos URL do descarregador durante a preparação deste artigo.
Não temos bytes da segunda fase para analisar por engenharia inversa. Também não sabemos o que esses endpoints devolviam anteriormente, a outro visitante ou sob condições de pedido diferentes. A mensagem de suspensão não nos dá uma explicação verificada para o motivo da suspensão do serviço.
O hook tenta descarregar e executar um ficheiro externo. Alegações sobre roubo de palavras-passe, tokens, código-fonte ou carteiras exigiriam provas que não temos.
Poderia tratar-se de um utilitário legítimo?
Um atualizador interno poderia acabar num arquivo por engano. Os hooks do Git, os processos em segundo plano e curl têm utilizações legítimas.
Neste envio, o e-mail pedia-nos explicitamente que visitássemos outro ramo. Fazê-lo podia invocar o descarregador fornecido, embora o motivo indicado para a mudança de ramo fosse ler um acordo. O e-mail não mencionava a execução. Também não encontrámos qualquer ligação entre um atualizador de navegador e o sistema proposto, e a verificação de tamanho do script estava incompleta.
Tratámos o envio como uma tentativa de ataque através da entrega de código e impedimos a execução do hook. Reconsiderar essa avaliação exigiria o código-fonte dos ficheiros descarregados e uma explicação verificável de por que motivo um prestador de serviços precisava de os executar para analisar o acordo de confidencialidade.
Não estabelecemos a identidade do operador. O endereço do remetente, os metadados dos commits e os nomes no documento são insuficientes para atribuir a operação.
Diagrama de análise das etapas de execução descritas pelo hook fornecido.
Analisar um repositório Git desconhecido
Um programador que seguisse o e-mail podia chegar ao acionamento da execução enquanto ainda lia informações sobre o projeto. Não era necessário compilar nem iniciar a aplicação proposta.
Se analisar envios de clientes numa máquina com chaves SSH de produção ou tokens da cloud, um script inesperado pode ter acesso a esses recursos. Um ambiente descartável precisa de manter essas credenciais fora do alcance. As sessões do navegador na máquina de análise merecem a mesma consideração.
A análise deve incluir o diretório .git fornecido e qualquer automatização do IDE antes de um engenheiro começar a utilizar os seus comandos habituais. Os scripts de instalação também precisam de escrutínio. Nos registos do host, procuraríamos o Git ou uma shell a descarregar um ficheiro para um diretório temporário e a executá-lo em seguida. Um processo curl, por si só, diz-nos muito menos.
Preservar o e-mail e o arquivo originais permite a uma pessoa que os analise mais tarde verificar o que foi entregue. Os hashes e os eventos do host ajudam a estabelecer o que aconteceu na máquina. A ausência de um marcador não permite estabelecer que um programa nunca foi executado.
Descarregar ou extrair o arquivo pode executar este hook?
A descarga e a extração normais não invocam, por si só, o hook post-checkout do Git. Nesta amostra, o acionamento documentado é a atualização da árvore de trabalho pelo Git através de checkout ou switch, quando a execução de hooks é permitida. Inspecionámos diretamente os objetos fornecidos sem invocar essas operações.
Depois da análise do arquivo
Esperávamos que a troca de mensagens seguinte fosse sobre arquitetura e datas de entrega. Em vez disso, enviámos uma resposta sobre o hook e preservámos o material para análise posterior. Continuamos sem poder dizer o que o programa remoto fazia ou quem o operava. O hook deu-nos razões suficientes para interromper o fluxo de trabalho do Git solicitado.
Há mais de cinco anos que a SToFU Systems e as nossas soluções ajudam empresas a proteger os seus sistemas, incluindo contra ataques distribuídos através de correspondência comercial e materiais de desenvolvimento. As nossas auditorias de segurança examinam de que forma o código e os acessos podem ser utilizados indevidamente. Também disponibilizamos engenharia inversa quando uma equipa precisa de compreender software desconhecido.
Se um repositório ou binário suscitar dúvidas, fale com a nossa equipa sobre uma análise técnica antes de o colocar no seu ambiente de desenvolvimento habitual.
Correspondência e ficheiros de prova
As quatro mensagens abaixo utilizam marcadores de substituição para nomes de pessoas, endereços, identidades de terceiros e ligações identificativas. A restante redação de cada nova mensagem é preservada. As citações repetidas são omitidas porque cada e-mail aparece separadamente. O IP do serviço do formulário web e os endereços de destinatários alheios ao caso também são ocultados.
1. O primeiro pedido através do nosso site
Email / dados identificativos substituídos
Date: Thu, 15 Oct 2026 12:55:21 +0000
From: SToFU Site Form <TEAM_EMAIL>
To: <TEAM_EMAIL>
Subject: SToFU Systems - Contact by <SENDER_NAME> <SENDER_EMAIL>
Reply-To: <SENDER_NAME> <SENDER_EMAIL>
Time: 2026-10-15T12:55:21+00:00
IP: [redacted]
Page: /contact
Name: <SENDER_NAME>
Email: <SENDER_EMAIL>
Attachments: none
Message:
We are currently developing an AI-powered FinTech fraud detection platform designed to help financial organizations identify suspicious transactions, assess potential risks in real time, and strengthen their fraud prevention and investigation processes.
The planned platform will incorporate AI/ML-based fraud detection, transaction risk scoring, behavioral analysis, configurable fraud-detection rules, blockchain-based verification, automated alerts, investigation support, and reporting and analytics.
We are looking to connect with an experienced technology partner with expertise in blockchain, financial technology, AI/ML, and scalable web platform development to help us bring this product to life.
We would welcome the opportunity to discuss your team’s capabilities, experience, and potential role in the project. The specific scope of your team’s involvement, technical responsibilities, and collaboration model can be determined through our discussion, based on your expertise and recommendations.
If this opportunity aligns with your team’s capabilities and interests, I’d be happy to share the project overview and technical roadmap for an initial review.
---
O primeiro pedido através do nosso site. Vista anonimizada para publicação do e-mail preservado.
SHA-256 do EML privado sem ocultações: bf7d0f3a59b84f509ca436e0750640e844e9731ce363a42a99d5be60cdf8597e
2. A nossa resposta a solicitar os materiais
Email / dados identificativos substituídos
Date: Sat, 17 Oct 2026 19:46:28 -0000
From: <TEAM_MEMBER_NAME> <TEAM_EMAIL>
To: <SENDER_NAME> <SENDER_EMAIL>
Subject: Re: Your AI fraud detection platform
Cc: [redacted: third-party addresses]
Hi <SENDER_NAME>,
Thank you for getting in touch through our website. I'm <TEAM_MEMBER_NAME>, <TEAM_MEMBER_ROLE> of SToFU Systems (<COMPANY_WEBSITE>). You can find me on <PROFESSIONAL_NETWORK> here:
<PROFILE_URL>
Your fraud detection platform sounds like a great project. Helping financial teams spot suspicious transactions and investigate them more effectively is a worthwhile problem to solve, and we'd be very happy to help you bring it to life.
We'd be glad to help with the architecture, development, security, and ongoing maintenance. We'll do everything we can to get the platform launched and keep it running reliably as it grows.
If you plan to seek investment, we can also help prepare the technical side for those conversations, including a working product or demo, clear architecture and documentation, and a practical development roadmap.
Please send over the project overview and technical roadmap you mentioned. It would be helpful to understand what you've already built and what you'd like to tackle first.
I'd be happy to arrange a call to discuss the project and how we could work together. What day and time would suit you? Please include your time zone so we can find a slot that works for both teams.
Thank you again for reaching out, and have a great day!
Best regards,
<TEAM_MEMBER_NAME>
<TEAM_MEMBER_ROLE>
SToFU Systems
<COMPANY_WEBSITE>
A nossa resposta a solicitar os materiais. Vista anonimizada para publicação do e-mail preservado.
SHA-256 do EML privado sem ocultações: 1e5330dd82e02911254722744a3202e9b761c8c1d2950be937cd5d539c1bcad9
3. O e-mail do arquivo que indicava os ramos NDA / conf
Email / dados identificativos substituídos
Date: Mon, 19 Oct 2026 09:03:41 +0000
From: <SENDER_EMAIL>
To: <TEAM_EMAIL>
Subject: Re: Your AI fraud detection platform
Hi <TEAM_MEMBER_NAME>,
Thank you for your interest in our AI-powered FinTech fraud detection platform.
I’ve also reviewed your <PROFESSIONAL_NETWORK> profile, and I’m confident that you and your team can make a valuable contribution to our project.
I’m happy to share the project materials for your review.
We’ve prepared the project overview, technical roadmap, and NDA, which provide the key information needed to understand the project, its objectives, and the proposed technical direction.
The platform focuses on AI-driven fraud detection, transaction risk assessment, behavioral analysis, fraud prevention, blockchain-based verification, automated alerts, investigation support, and financial risk analytics.
This is the Link:
<FILE_SHARE_URL>
Please review the project materials and review and sign the NDA in the NDA branch.
The NDA is required because the project materials contain confidential business, technical, architectural, and product information.
So, please send me the signed NDA as soon as possible.
In particular, we would appreciate your initial technical assessment of the proposed system architecture and timeline. The detailed documentation and specifications related to these areas are available in the conf branch.
After your review, we would like to arrange a meeting to discuss your technical observations, recommendations, questions, development approach, and potential partnership opportunities in more detail.
Once you have completed your review, please let me know your preferred meeting date and time and provide the signed NDA.
Please feel free to take the time you need to review the materials thoroughly. I look forward to receiving your feedback and speaking with you about the project.
Kind regards,
<SENDER_NAME>
O e-mail do arquivo que indicava os ramos NDA / conf. Vista anonimizada para publicação do e-mail preservado.
SHA-256 do EML privado sem ocultações: f7007ed3053d3ba2ef71ea01c74ec0c4aebfd48417f757ecec8d9d7d5884bf33
4. A nossa resposta após descobrir o hook
Email / dados identificativos substituídos
Date: Mon, 19 Oct 2026 19:37:58 +0200
From: SToFU Systems <TEAM_EMAIL>
To: <SENDER_NAME> <SENDER_EMAIL>
Subject: Re: Your AI fraud detection platform
Hi <SENDER_NAME>,
We reviewed the materials you sent. Unfortunately, we found no application source code or working implementation, only planning documents and an NDA.
Execution of the supplied Git post-checkout hook was disabled during our review. The hook downloads and runs platform-specific files from <DOWNLOAD_DOMAIN>, hides their output, and writes a local marker. Our security policies do not allow the execution of untrusted third-party hooks.
Thank you for your time and for the elaborate attempt to deliver malicious code.
We have traced the technical delivery chain and preserved the archive, hook, download responses, correspondence, and author names and email addresses recorded in the repository. The relevant evidence will be passed to the competent law enforcement authorities in the applicable jurisdictions.
SToFU Systems
A nossa resposta após descobrir o hook. Vista anonimizada para publicação do e-mail preservado.
SHA-256 do EML privado sem ocultações: 31df91adb2eb52be2171836d3e26610328a0a1a1273dbf7d56efe4354bb62e19
- Hook anonimizado, as 101 linhas
- Cabeçalho TAR e início dos dados do ficheiro
- Os 24 objetos Git
- Blob DOCX antes e depois de zlib
- Dump da árvore NDA
- Os 16 blobs e os seus primeiros bytes
- Todas as partes do DOCX
- Limites de gzip e TAR
- Inspeção ao nível dos bytes em formato legível por máquina
- Observações guardadas dos três endpoints
- Fontes e hashes das figuras
- Proveniência da correspondência
Vista anonimizada do hook completo
Os 101 números de linha do código-fonte foram preservados. Os dados identificativos estão cobertos com retângulos cinzentos.
Os originais sem ocultações são conservados em privado. Os ficheiros de prova públicos utilizam marcadores de substituição e as capturas de ecrã utilizam retângulos cinzentos opacos. Os hashes identificados como originais correspondem à fonte privada, não a uma cópia editada para publicação. As figuras são capturas de ecrã de vistas locais das provas, com o texto identificativo removido antes da renderização. Não foi executado qualquer código recebido.















