20 nov 2012

Scripts para Meterpreter: Encenciendo el horno

Meterpreter es uno de los payloads más famosos del mundo, denominado por muchos como el rey de los payloads, por todas las funcionalidades que aporta. ¿Podemos aprovecharlo al máximo? ¿Qué es el máximo? ¿Hemos pensado que podemos desarrollar para este payload? Estas preguntas tienen respuesta afirmativa, ya que podemos diseñar e implementar nuestros propios scripts para que Meterpreter los ejecute, ¿Qué necesitamos? Sí, en este caso hay un requisito previo, conocer Ruby. Realmente, a mi me ha picado la curiosidad de aprender Ruby, y de poder desarrollar scripts para este payload, e incluso módulos para el framework. Aprenderemos a desarrollar scripts para Meterpreter!!!

Estas tareas e inquietudes aportan al auditor o usuario de Metasploit la posibilidad de disponer de herramientas inéditas, e incluso de disponer de armas que otros o nadie dispone. Lógicamente, no es una tarea sencilla, debemos tener ideas claras sobre el pentesting y exploiting, dotes de programación en Ruby, entender bien el funcionamiento del framework, paciencia, laboratorio y, lo más importante, ideas sobre que queremos hacer. Podemos tener todas las partes anteriores, que si no tenemos ideas sobre que cosas hacer, no nos servirán de mucho...

Mi primer script para Meterpreter: Hola Mundo

El primer script que desarrollaremos para Meterpreter será el famoso Hola Mundo de todos los programas cuando alguien empieza en el arte de la programación. Entenderemos que los usuarios ya disponer de conocimientos básicos de Ruby, y nos basaremos en detallar que es lo que estamos desarrollando, sin pararnos en exceso en el lenguaje Ruby.

¿Dónde se almacenan los scripts de Meterpreter? Los scripts de Meterpreter son aquellos que son ejecutados por el comando run <script>, cuando se dispone de una sesión de Meterpreter. Estos se encuentran en la siguiente ruta, distribución de BackTrack, /pentest/exploits/framework3/scripts/meterpreter.

Mi código

#Autor: Pablo Gonzalez#Windows Hola Mundo Metasploitopts = Rex::Parser::Arguments.new("-h" => [false, "Help menu."],"-s" => [true, "Mostrar mensaje en Metasploit"])if client.platform !~ /win32|win64/print_line "No compatible"raise Rex::Script::Completedendopts.parse(args) { |opt, idx, val|print_line "val: #{val}"print_line "idx: #{idx}"print_line "opt: #{opt}"case optwhen "-h"print_line "Ayuda de mi script de Meterpreter"print_line "Meterpreter RuLeZ"print_line(opts.usage)raise Rex::Script::Completedwhen "-s"if val != nilprint_line "#{val}"endend}

El código a priori puede parecer confuso, pero vamos a ir destripando y viendo que es sencillo. Hay que entender que este código no hace gran cosa, pero nos dará pie a realizar otros scripts con una mayor funcionalidad.

En primer lugar hablaremos del siguiente fragmento de código:
#Autor: Pablo Gonzalez#Windows Hola Mundo Metasploitopts = Rex::Parser::Arguments.new("-h" => [false, "Help menu."],"-s" => [true, "Mostrar mensaje en Metasploit"])

Los comentarios vienen precedidos por la almohadilla, como en otros lenguajes. El script comienza con declarando una variable opts, la cual referencia a un objeto de tipo Arguments. La clase Arguments viene de Rex y Parser. Para crear una instancia de la clase Arguments se utiliza el constructor New, al que se le pasan un número indefinido de parámetros especiales, en este caso dos. El primer parámetro que se le pasa es "-h" = > [false, "Help menú"], el segundo parámetro  es "-s" => [true, "Mostrar mensaje en Metasploit"]. Los argumentos son separados por comas. Este objeto registra que estos valores son claves para identificar parámetros más adelante.

¿Qué es lo que está ocurriendo realmente? Lo que se está definiendo al objeto de tipo Arguments, es que argumentos se esperan y si recibirán algún tipo de información dichos argumentos. En este ejemplo tenemos que el parámetro -h se corresponde con el menú de ayuda o help menu, mientras que el parámetro -s se corresponde con un posible mensaje que saldrá por pantalla. El primero tiene un campo false, mientras que el segundo tiene el mismo campo a true. ¿Qué es esto? False indica que el parámetro es de tipo SIN VALOR asociado, es decir, no debemos pasarle ningún texto a dicho parámetro para que ejecute su función. Por otro lado el true indica que el parámetro es de tipo CON VALOR asociado, es decir, debemos pasarle un texto a dicho parámetro para que ejecute su función.

opts.parse(args) { |opt, idx, val|print_line "val: #{val}"print_line "idx: #{idx}"print_line "opt: #{opt}"case optwhen "-h"print_line "Ayuda de mi script de Meterpreter"print_line "Meterpreter RuLeZ"print_line(opts.usage)raise Rex::Script::Completedwhen "-s"if val != nilprint_line "#{val}"endend}

El segundo fragmento de código sigue ejecutándose sobre el objeto que acabamos de crear, y se indica a este objeto que cuando se invoque la ejecución del script se realice un parseo de los parámetros de entrada. La línea opts.parse(args) { |opt, idx, val| lo que está indicando es que se parseen los argumentos de entrada en la ejecución del script y además se realice iteraciones, mediante un bucle y se traten las tres variables siguientes opt, idx y val. ¿Qué almacenan dichas variables? opt es la variable que marca que parámetro es el que se está ejecutando, por ejemplo, en nuestro caso disponemos de -h y -s. La variable idx indica el número que ocupa el argumento en la iteración, en otras palabras, marcará 0 para el primer parámetro, pero si este es de tipo con texto asociado, el siguiente será el parámetro 2, ya que el 1 es el texto asociado al parámetro anterior. La variable val contiene el valor del parámetro asociado, es decir, en nuestro el parámetro -s tendrá una variable val con un valor concreto, el cual podrá ser tratado en el parseo de los parámetros de entrada.

Después nos encontramos con el case, este switch identifica el valor que tiene la variable opt en cada iteración y en función de ese valor se irá por una rama u otra del case. En nuestro caso, cuando opt valga -h se ejecutará el menú de ayuda y cuando valga -s se ejecutará la opción de salida por pantalla de un texto.

Como se puede observar la ejecución en una sesión de Meterpreter de nuestro script con el parámetro -h nos muestra el menú que hemos diseñado. Se ha puesto a modo de debugger unas impresiones por pantalla de las variables val, idx y opt. Vemos que las opciones -s y -h difieren en el campo <opt>, que significa que el parámetro -s debe llevar asociado un texto con el que se llevará a cabo una acción.

En el caso de -s, en el case se indica que el valor asociado a esa opción queda recogido en la variable val, por lo que se puede utilizar directamente. Idx en este caso pasará a valer 2 al salir de dicha iteración, quedará reflejado como , ya que el 0 es para opt, y el 1 para val.

if client.platform !~ /win32|win64/print_line "No compatible"raise Rex::Script::Completedend

Por último comentar que este fragmento solo se utiliza por seguridad contra el usuario, para que no ejecute código que no es para un sistema concreto. En nuestro caso indicamos que si la sesión de Meterpreter no se está llevando realizando en un sistema de 32 o 64 bits de Windows, el script no se ejecutará.

Como se ha podido observar, este tipo de desarrollos tan especiales llaman mucho la atención porque permiten realizar cosas muy interesantes y personalizar nuestras propias órdenes sobre sistemas vulnerados con Metasploit. ¿Ya pensáis en hacer un arsenal de scripts personalizados con las cosas, pocas porque hay de todo, que echáis de menos en un Meterpreter?

Próximamente, intentaremos ver como realizar alguna acción en la máquina remota, e intentaremos ir publicando scripts cada vez más interesantes y útiles para los auditores. Como última nota decir que una vez implementado el script este puede dejarse en la ruta /pentest/exploits/framework3/scripts/meterpreter o ejecutar en Meterpreter "run <ruta script.rb>", el cual hemos creado.

5 comentarios: