Notícias
Inicialmente apelidada de 'Evilquest' e mais tarde 'Thiefquest'. malware exibe vários comportamentos, incluindo criptografia de arquivos, exfiltração de dados e registro de chaves
De particular interesse, do ponto de vista da pesquisa, é a rotina de criptografia personalizada. Uma inspeção superficial do código de malware sugere que ele não está relacionado à criptografia de chave pública. Pelo menos parte dela usa uma tabela normalmente associada ao RC2. O possível uso de RC2 e sementes baseadas em tempo para criptografia de arquivos me levou a examinar mais profundamente o código, o que me permitiu entender como interromper a rotina de criptografia do malware. Como resultado, nossa equipe criou um decodificador para uso público.
Descobrindo a rotina de criptografia
Como mencionado em outros relatórios [4], a função responsável pela criptografia de arquivos é rotulada internamente como carve_target .
Antes de criptografar o arquivo, a função verifica se o arquivo já está criptografado comparando os últimos 4 bytes do arquivo com um valor DWORD codificado.
Se o teste falhar, a criptografia do arquivo começa gerando uma chave de 128 bytes e chamando a função tpcrypt , que basicamente acaba chamando generate_xkey . Essa função é a parte de expansão da chave seguida por tp_encrypt , que pega a chave expandida e a usa para criptografar os dados.
Depois disso, a chave será codificada, usando o tempo como uma semente. Um valor DWORD será gerado e utilizado.
A rotina de codificação é simplesmente um loop XOR baseado em ROL:
Neste ponto, podemos ver que algo interessante acontece, e não tenho certeza se é intencional pelo desenvolvedor ou não. A chave gerada é de 128 bytes, como mencionamos anteriormente.
Os cálculos usados para codificar a chave acabam realizando o loop 4 vezes mais, produzindo 132 bytes.
Isso significa que a chave de texto não criptografado usada para codificar a chave de criptografia de arquivos acaba sendo anexada à chave de criptografia de arquivos codificados. Examinar um arquivo completamente criptografado mostra que um bloco de dados foi anexado a ele.
Revertendo a criptografia de arquivos
Felizmente, não precisamos reverter isso, pois o ator deixou a função de descriptografia, uncarve_target , no código. Essa função usa dois parâmetros: um local do arquivo e um valor inicial que será usado para decodificar a chave do arquivo integrado.
Após verificar se o arquivo é um arquivo criptografado, examinando os últimos 4 bytes, a função começa a ler uma estrutura de dados no final do arquivo.
Após a execução do código, podemos reconstruir estaticamente uma versão da aparência dessa estrutura:
estrutura
{
encob blob [size + 12 ]
long long size
int int marker
}
struct enc
{
val
longo longo int val2 // 3º parâmetro para eip_key
longo longo val3 // 1º param para eip_key
char encoded_blob [ 4 - val% 4 + val] // para 0x80, isto é 132
}
A chave do arquivo codificado será descriptografada e verificada usando os dois valores da estrutura e o outro valor inicial transmitido para uncarve_target . A chave do arquivo será descriptografada por eip_decrypt , que é a rotina de descriptografia de criptografia no local.
A função eip_key utilizará os dois valores DWORD e o argumento seed para gerar a chave XOR para decodificar a chave do arquivo.
Em seguida, o arquivo é definido no início e, em seguida, um arquivo temporário é aberto para gravação.
O arquivo é então lido em um buffer alocado e a chave e os dados do arquivo codificado são passados para tpdcrypt .
Como antes, temos uma expansão de chave seguida desta vez por uma chamada para tp_decrypt .
Uma olhada na função de expansão de teclas mostra uma referência a uma tabela codificada que corresponde ao código RC2 que pode ser encontrado online.
estrutura de importação
sys de importação
rol = val lambda, r_bits, max_bits = 32 : \
(val << r_bits% max_bits) & ( 2 ** max_bits -1 ) | \ ((val & ( 2 ** max_bits -1 )) >> (max_bits- (r_bits% max_bits))))
data = open (sys.argv [ 1 ], 'rb' ) .read ()
teste = dados [ -4 :]
se teste! = '\ xbe \ xba \ xbe \ xdd' :
print ( "versão desconhecida" )
sys.exit ( -1 )
append_length = struct .unpack_from ( '<I' , dados [ -12 :]) [ 0 ]
append_struct = data [- (comprimento do anexo + 12 ):]
keySize = struct .unpack_from ( '<I' , append_struct) [ 0 ]
se keySize! = 0x80 :
print ( "Chave estranha?" )
sys.exit ( -1 )
dados_codificados = append_struct [ 20 : 20 + 132 ]
xorkey = struct .unpack_from ( '<I' , dados_codificados [ -4 :]) [ 0 ]
decodificação def ( blob, chave ):
out = ""
para i no intervalo ( len (blob ) / 4):
temp = struct .unpack_from ( '<I' , blob [i * 4 :]) [ 0 ]
temp ^ = chave
chave = rol (chave, 1 )
a + = struct .Pack ( '<I' , TEMP)
retornar para fora [: 0x80 ]
temp = decodificar (dados_codificados, xorkey)
impressão (temp)
Tentar descriptografar o RC2, no entanto, parece funcionar apenas parcialmente no momento, usando rotinas RC2 nas bibliotecas Python e Golang. Serão necessárias análises adicionais para verificar o que é diferente.
No entanto, para descriptografar os arquivos das vítimas, precisamos apenas pegar a chave do arquivo e chamar a função tp_decrypt que está localizada dentro do próprio malware. Fazer o dump do assembly para esta função e construí-lo em um objeto compartilhado a ser executado usando a chave de arquivo recuperada parece funcionar corretamente.
Usando esse método, o SentinelLabs criou um decodificador público que está disponível aqui (esta ferramenta é lançada sob a licença de software do MIT).
Amostra
SHA-1 : 178b29ba691eea7f366a40771635dd57d8e8f7e8
SHA-256 : f409b059205d9a7700d45022dad179f889f18c58c7a284673975271f6af41794
Referências
1: https://twitter.com/dineshdina04/status/1277668001538433025
2: https://www.bleepingcomputer.com/news/security/thiefquest-ransomware-is-a-file-stealing-mac-wiper-in-disguise /
3: https://blog.malwarebytes.com/mac/2020/06/new-mac-ransomware-spreading-through-piracy/
4: https://objective-see.com/blog/blog_0x59.html
Fonte: SentinalLabes