Railgun es una extensión de Metepreter diseñada específicamente para maquinas comprometidas bajo plataformas windows y permite realizar invocaciones directas a la API de windows así como cargar librerías DDL a la maquina comprometida y ejecutar posteriormente el código contenido en ellas. El uso de Railgun facilita mucho algunas actividades que con Meterpreter por si solo pueden ser un poco complejas o requerir privilegios de administrador, con Railgun muchos de los scripts ejecutados no necesitan que se cuente con privilegios administrativos sobre la maquina comprometida.

Ahora bien, los beneficios de utilizar RailGun saltan a la vista, es posible invocar la API de windows remotamente, lo que conlleva a que se puede acceder directamente a los dispositivos disponibles en la maquina remota, leer y escribir arbitrariamente sectores del disco e inclusive, mapear dispositivos de bloque remoto a local, vale la pena utilizar y aprender esta API, no es así?

NOTA1: Para poder utilizar Railgun correctamente, es necesario ver la API de las funciones que se encuentran las DLL de windows, para mayor información ver: http://msdn.microsoft.com/en-us/library/aa383749

NOTA2: Muchas de las funciones en windows que funcionan con Strings tienen una versión para cadenas regulares y otra versión para cadenas unicode, las primeras terminan con la letra “A” y las segundas con “W” por ejemplo la función CreateFile tiene dos versiones CreateFileA y CreateFileW

Utilizar Railgun es sencillo, sin embargo es necesario conocer las funciones y las DLL incluidas en windows para poder ejecutarlas adecuadamente con sus parámetros correspondientes, desde IRB de meterpreter la sintaxis básica para utilizar Railgun es:

client . railgun . NOMBRE_DDL . FUNCION . {PARAMETROS_FUNCION}

Por otro lado, tambien es posible cargar librerías que no se encuentren incluidas por defecto empleando la funcion add_ddl, por ejemplo:

>>client.railgun.add_dll(‘nombre_dll’)

A continuación se incluyen algunos ejemplos de ejecución de funciones en la maquina remota utilizando RailGun

>> client.railgun.kernel32.GetCurrentProcessId => {«GetLastError»=>0, «return»=>996}

Como se puede apreciar en el ejemplo anterior, la función GetCurrentProcessId se encuentra definida en la librería kernel32.dll de Windows y el resultado de su ejecución cuenta con dos valores, el primero indicando si ha existido algún error en la llamada y el segundo el resultado propiamente dicho, en este caso concreto, el identificador del proceso actual (que indica el proceso en el cual se encuentra ejecutándose meterpreter)

>> client.railgun.kernel32.CopyFileA(«C:\\boot.ini»,»C:\\boot_copy.ini»,FALSE) => {«GetLastError»=>0, «return»=>true}

Se invoca a la funcion “CopyFile” donde el primer parámetro indica el fichero existente, el segundo el fichero que se creará con el contenido del fichero existente y el tercer parámetro quiere decir que si el fichero ya existe (boot_copy.ini) este debe de ser sobre-escrito y no fallar, si el valor fuera TRUE y el fichero ya existe, la función fallará.

>> client.railgun.kernel32.CreateFileA(«C:\\ficherTexto.txt»,»GENERIC_WRITE|GENERIC_READ»,»FILE_SHARE_READ|FILE_SHARE_WRITE»,nil,»CREATE_ALWAYS»,0,0) => {«GetLastError»=>183, «return»=>488}

>>client.railgun.kernel32.GetFileSize(488,nil)

=> {«GetLastError»=>0, «return»=>0}

>> client.railgun.kernel32.WriteFile(488,»Texto claro»,11,4,nil)

=> {«lpNumberOfBytesWritten»=>11, «GetLastError»=>0, «return»=>true}

>> attr = client.railgun.kernel32.GetFileAttributesA(«C:\\ficherTexto.txt»)

=> {«GetLastError»=>0, «return»=>32}

>> printf(«ATTR: %s, IN FILE»,attr[‘return’])

ATTR: 32, IN FILE

>> client.railgun.kernel32.CloseHandle(488)

=> {«GetLastError»=>0, «return»=>true}

En el caso anterior se ha creado un fichero en la maquina remota utilizando la función CreateFileA y posteriormente se realizan una serie de manipulaciones sobre dicho fichero, tales como consultar y acto seguido escribir en él.

La API de windows es muy extensa y es imposible abarcar la cantidad de invocaciones que se puede llevar a cabo desde Railgun, sin embargo se intentará indicar el uso de algunas que son muy útiles

Determinando si el usuario actual tiene privilegios de administrador.

>> status = client.railgun.shell32.IsUserAnAdmin() => {«GetLastError»=>0, «return»=>true}

>>

?> printf («El usuario es admin? %s»,status[‘return’])

El usuario es admin? true

Establecer el modo inactivo en la maquina remota, ponerla a “dormir”

>> client.railgun.kernel32.SetThreadExecutionState(«ES_CONTINUOUS | ES_SYSTEM_REQUIRED»)

=> {«GetLastError»=>0, «return»=>2147483648}

Activar el bloqueo de la estacion de trabajo (WIN + L) similar al comando anterior

>> client.railgun.user32.LockWorkStation() => {«GetLastError»=>0, «return»=>true}

Retornar el nombre del host remoto

>>client.railgun.kernel32.GetComputerNameA(260,260) => {«nSize»=>15, «lpBuffer»=>»JDAANIAL-6825E7», «GetLastError»=>203, «return»=>true}