GHOST : CVE-2015-0235
之前没接触过CVE,但是巅峰极客碰到一题居然利用到了CVE里的漏洞,而且只公布了POC,找不到exp(其实就算有估计也不会用……)。现在复现一下。
之前国赛决赛也出现了自己实现了http服务的题目。不知道越来越贴近实战是不是一个趋势。(二进制真就虽然人少但是卷得狠啊)
漏洞描述
glibc
的__nss_hostname_digits_dots
存在缓冲区溢出漏洞(堆溢出),可以通过gethostbyname *()
函数触发。先介绍一下这个函数,它的功能是将主机名称转换为ipv4地址,但是如果输入本就是ip,则不会通过DNS解析,而是将会不加任何合法性检验地被直接写入tmp.buffer,一同写入的还包括解析的主机信息。所以就很容易超过tmp.buffer的长度,造成溢出。
出题人说0是最容易造成溢出的。
- 通过gethostbyname()函数或gethostbyname2()函数,将可能产生一个堆上的缓冲区溢出
- 经由gethostbyname_r()或gethostbyname2_r(),则会触发调用者提供的缓冲区溢出
- 漏洞产生时至多sizeof(char* )个字节可被覆盖。但是payload中只有数字( ‘0 ‘…’ 9’) ,点( “.”) ,和一个终止空字符(‘\0’ ) 可用。
- 影响范围:2.2 <= glibc <=2.17
分析
gethostbyname()
先通过__nss_hostname_digits_dots()
判断参数是否为IP,如果是IP就直接结束;如果是域名则调用__gethostbyname_r()
进行解析。漏洞发生在__nss_hostname_digits_dots()
中。
- 漏洞函数:nss/digits_dots.c :__nss_hostname_digits_dots(name, resbuf, buffer, …)
- 这个函数负责处理name为IP地址的情况, 当name为域名时只是进行一些复制工作
- name指向要解析的字符串
- resbuf指向存放解析结果的hostennt结构体
- buffer则为解析时所分配的空间, resbuf中的指针指向buffer分配的空间
而且判断很随意只要name[0]是int,hex或者’:’就认为是ip地址。
在计算hostent结构体所需大小时忘记了h_alias_ptr
,然后又直接通过strcpy()
把hostname复制过去造成了一个机器字长的溢出。
strcpy()在溢出这一块老演员了属于是
赛题
巅峰极客 ghost
1 | [*] '/home/giantbranch/Desktop/ghost/pwn' |
InputName()未对idx是否已经存在做检验,len也没有限制。然后直接调用gethostbyname_r()。函数会以此分配 NameArr[idx], HostArr[idx], BufferArr[idx] ,所以堆块的布局都是按照N|H|B
这个顺序
已知存在堆溢出,那就可以通过覆盖size位实现chunk overlap。
LEAK
- 假如有
N0 | B0|H0 | N1 | B1 | H1
- 利用
__nss_hostname_digits_dots()
在写入B0
时溢出H0
的chunk size为0x3031 - 然后通过布局在
H0+0x3030
的位置放上flat(0, 0x21, 0, 0)伪造H0的nextchunkfree(H0)
即可打出chunk overlap, 此时获得了一个B0
,H0
,N1
,B1
,H1
组成的UB chunk - 然后通过切割UB, 使得UB的fd bk指针写入到
H1
内部, 如下图 - 然后show(3)即可泄露地址
FASTBIN ATTACK
- 在
H1
后面通过布局0x70的chunk, 然后free掉, 进入Fastbin[0x70] - 然后继续切割chunk, 修改fastbin chunk的fd为__malloc_hook-0x23, 利用0x7F伪造size
- 然后修改__malloc_hook为OGG
EXP
1 | #! /usr/bin/python |