
CVE-2017-8570 Exp e análise de amostras de exploração
Causa: Ao abrir um documento do Office, o FLTLDR.EXE é usado para renderizar um arquivo EPS incorporado que contém a vulnerabilidade. O arquivo é escrito em linguagem PostScript e pode ser explorado pelo atacante através da operação "save-restore", sendo essencialmente uma vulnerabilidade de UAF (Use-After-Free). A vulnerabilidade pode ser explorada quando um usuário abre um arquivo contendo uma imagem gráfica malformada ou insere uma imagem gráfica malformada em um arquivo do Office.
Versões afetadas: Microsoft Office 2010 Service Pack 2, Microsoft Office 2013 Service Pack 1, Microsoft Office 2016
POC: GitHub de kcufId
O autor pesquisou por muito tempo na internet, mas não encontrou um pacote de instalação do Office que contivesse o EPSIMP32.FLT. Felizmente, o mestre kcufId forneceu um LoadEps.exe para carregar arquivos EPS, agradecimentos ao mestre kcufId.
O LoadEps.exe primeiro carrega o EPSIMP32.FLT:

Depois chama ImportGr para começar a carregar o arquivo EPS:

Aqui, pressione F7 para seguir e então interrompa com sucesso no ponto de interrupção definido dentro do EPSIMP32.FLT.
Antes de entrar no assunto principal, vamos primeiro explicar a estrutura do objeto PostScript.
// PostScript Object
struct PostScript object
{
dword type;
dword attr;
dword value1;
dword value2; // se for array, aponta para userdict onde o objeto array é armazenado
}ps_obj;
Os diferentes type correspondem aos seguintes valores:
0x0 nulltype
0x3 integertype
0x5 realtype
0x8 booleantype
0x10 operatortype
0x20 marktype
0x40 savetype
0x300 nametype
0x500 stringtype
0x900 filetype
0x30000 arraytype
0x0B0000 packedarraytype
0x70000 packedarraytype
0x110000 dicttype
0x210000 gstatetype
Tomando uma string como exemplo, explicamos sua estrutura de armazenamento. Definindo um ponto de interrupção na função forall, podemos ver como ela processa strings (como localizar a função forall, consulte https://paper.seebug.org/368/).

A imagem 1 corresponde a ps_obj, cujo campo value2 aponta para o item correspondente na lista de índices (imagem 2); o item de índice aponta para uma estrutura de tamanho 0x30, cujo offset 0x24 contém um ponteiro para um ponteiro para uma estrutura de tamanho 0x28 (imagem 5), e o offset 0x2C armazena o tamanho da string (imagem 3); na estrutura da imagem 5, o offset 0x4 armazena o endereço do item correspondente na lista de índices (ou seja, o endereço 0x01DB5E94 da imagem 4), o offset 0x20 aponta para o local final de armazenamento da string (imagem 6), e o offset 0x24 é o tamanho real da memória ocupada — tamanho da string + 1.
Estrutura de tamanho 0x30:
+0x0 dword
+0x4 dword
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword
+0x24 dword pp_struct // ponteiro para ponteiro para estrutura de tamanho 0x28
+0x28 dword
+0x2c dword size // tamanho real da string
Estrutura de tamanho 0x28 (para array, essa estrutura tem tamanho 0x2C, e offset 0x28 aponta para elementos do array, cada elemento sendo um ps_obj):
+0x0 dword
+0x4 dword // armazena o endereço do item correspondente na lista de índices
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword ptr_object // aponta para o local final de armazenamento da string
+0x24 dword size // tamanho real da memória ocupada, tamanho real da string + 1
Primeira ativação da vulnerabilidade:

Primeiro, o estado da VM é salvo na variável l62. Em seguida, para cada caractere na variável l63, é chamado o processo de tratamento l61 —>> l59 —>> l56. l62 restore restaura o estado anterior, liberando assim o espaço de memória alocado pela instrução /l62 save def para a variável l63, tornando-se um ponteiro pendente.

As variáveis l95-l99 determinam o fluxo subsequente e todos têm valor 0 (ou seja, 32 bits):

Segunda ativação da vulnerabilidade: primeiro, aloca um espaço de memória de tamanho 0x27 (que realmente ocupará 0x28) para armazenar l63:

Depois, l62 restore restaura o estado anterior, liberando o espaço de memória alocado para l63, tornando-se um ponteiro pendente. Em seguida, executa l100; o espaço de memória antes ocupado por l63 é agora usado para armazenar a estrutura 0x28 da string l102 (ou seja, l136) (isso explica por que l63 alocou 0x27 de tamanho de memória):

Obtém os valores nos offsets 0x4, 0x20 e 0x24 dessa estrutura:

Finalmente, modifica o conteúdo da string l136 (a imagem mostra apenas parte das modificações):

Essas modificações são cuidadosamente construídas e serão usadas na terceira ativação da vulnerabilidade.
Terceira ativação da vulnerabilidade: aloca um array contendo 0x37 elementos, e ao percorrer até o 0x34º elemento, executa l62 restore:

Após executar restore, a estrutura 0x30 do array é sobrescrita pelo conteúdo da string l193:

Assim, o objeto executado pelo último (0x36) processo forall torna-se a estrutura 0x30 da imagem acima, e obter seu 0x36º elemento leva à string cuidadosamente construída na segunda ativação da vulnerabilidade:

O elemento do array obtido é um array de tamanho 4, cujo primeiro elemento é uma string com endereço inicial 0 e tamanho 0x7FFFFFFF:

Esse array é armazenado na variável l159, e seu primeiro elemento — a string com endereço inicial 0 e tamanho 0x7FFFFFFF — é armazenado na variável l201. A partir daí, é possível obter o valor de qualquer endereço através da variável l201.
Obtendo a base da kernel32.dll:


Assim, a variável l314 armazena a base do EPSIMP32.FLT.

Nota: A sintaxe do comando search é a seguinte:

Encontrando o gadget especificado:


Construindo a estrutura do tipo file:
l199 l201 get_dword
/l487 exch def
l487 l201 get_dword
/l488 exch def
l488 36 my_add l201 get_dword
/l489 exch def
l489 l201 get_dword
/l490 exch def
l490 32 my_add l201 get_dword
/l491 exch def
l199 l491 l201 put_data_to_array
l199 12 my_sub 2304 l201 put_data_to_array

Escrevendo dados construídos no endereço l492 (l491+0x32):
l492 0 l201 put_data_to_array %% 0x00 0
l492 4 my_add l375 l201 put_data_to_array %% 0x04 Endereço de <5E C3>
l492 8 my_add l373 l201 put_data_to_array %% 0x08 Endereço de <94 00 00 00 00 5E C3>
l492 12 my_add l377 l201 put_data_to_array %% 0x0C Endereço de <C2 0C 00>
l492 16 my_add l370 l201 put_data_to_array %% 0x10 Endereço de VirtualProtect()
l492 20 my_add 0 l201 put_data_to_array %% 0x14 0
l492 24 my_add 0 l201 put_data_to_array %% 0x18 0
l492 28 my_add 0 l201 put_data_to_array %% 0x1C 0
l492 32 my_add l368 l201 put_data_to_array %% 0x20 Endereço do Shellcode
l492 36 my_add l368 l201 put_data_to_array %% 0x24 Endereço do Shellcode——lpAddress
l492 40 my_add l349 l201 put_data_to_array %% 0x28 Tamanho do Shellcode——dwSize
l492 44 my_add 64 l201 put_data_to_array %% 0x2C PAGE_EXECUTE_READWRITE——flNewProtect
l492 48 my_add l493 l201 put_data_to_array %% 0x30 lpflOldProtect
Finalmente, ao executar a instrução closefile, salta para o Shellcode:

O script de exploração EPS está localizado no diretório \word\media, visível após descompactar. As amostras de exploração desta vulnerabilidade são basicamente idênticas, exceto pela parte do Shellcode. Portanto, tomamos como exemplo uma amostra da organização Patchword para análise.
Nome do arquivo: Cyber_Secure_Pakistan.docx
MD5: DD89BBB916A2C909630EC78CBB0E13E5
Saltar para o Shellcode, restaurar a pilha:

Alocar memória:

Obter endereços de chamada de função:

Durante a depuração, pode ter sido devido a problemas de ambiente que o endereço da chamada da função CreateToolhelp32Snapshot não foi obtido com sucesso:

Preencher manualmente o endereço e abrir o Word para continuar a análise. Enumerar processos, procurar por WINWORD.exe:

Criar um programa chamado MSBuild.exe no diretório C:\ProgramData\Microsoft\DeviceSync:

Escrever o conteúdo do arquivo, que está armazenado na variável payload_32 do script EPS:


Criar o arquivo vmtools.dll:

Escrever o conteúdo do arquivo, que está armazenado na variável payload_32_f2 do script EPS:


Criar o arquivo VMwareCplLauncher.exe:

Seu conteúdo está armazenado na variável payload_32_f1 do script EPS:

Este arquivo é um arquivo legítimo assinado pela VMware:

Injetar o seguinte conteúdo no explorer.exe:

Sua função é criar o processo VMwareCplLauncher.exe:

O fluxo subsequente é mencionado neste relatório da 360, e este artigo não aborda a parte de análise por enquanto:

Leitores interessados podem ler o relatório para mais detalhes.
Nota: As amostras de exploração desta vulnerabilidade são basicamente semelhantes, a diferença está no payload final do MSBuild.exe, que está armazenado na variável payload_32 do script EPS. Pode ser extraído diretamente e, após preencher o cabeçalho do arquivo DOS, arrastado para o IDA para análise.