本题为一道经典的控制堆块的题目,对于这类题目通常的方法是将控制堆块申请出来当做用户堆块来使用,向其写入特定数据来篡改其中的函数指针。

阅读全文 »

总结:

通过这道题的学习与收获有:

1、atol函数放入的数据应该是打包之前的,而非是打包之后的数据

2、exit函数执行流程,exit函数的调用流程exit函数—>run_exit_handlers函数—>_dl_fini函数—> rtld_lock_unlock_recursive指针 如果我们能够将最后的指针所指向的内容修改为one_gadget,那么即可获取shell。这个劫持exit_hook的可取之处在于,程序正常结束的话,最后都会调用这个exit函数

3、学会了重新绑定程序所对应的libc动态库(patch libc和ld)

4、用这个方法可以在开了PIE的程序中下断点。gdb.attach(p, ‘b * $rebase(0xd63)\nc’)

5、one_gadget加上参数-l2可以搜索更多的one_gadget。

6、即使相同的libc库,在小版本不同的情况下,某些内容的偏移也是不一样的。

阅读全文 »

由于本人比较菜,同时学pwn的时间不是太久,因此iscc的很多堆还没有能力去做,只把比赛的栈题给做完了 赛后又做了一下unlink那道题。其他堆题目前还没有复现。(有一个格式化字符串太简单了,我就不写wp了)

阅读全文 »

写在前面:

在之前做这道题的时候SWPUCTF_2019_p1KkHeap,就受到了tcache dup+tcache poisoning来爆破申请tcache_perthread_struct结构体的启发,结果在做这道题的时候就遇见了这种手法。由于还需要打io_leak再次爆破半个字节,因此这种手法成功的概率只有1/256。

阅读全文 »

总结:

通过本题的学习,知道了malloc consolidate函数可以让fast bin的堆块进行合并,然后放到unsorted bin,同时将下一个堆块的prev inuse位置空。通过这一点给了我们利用unlink的机会,如果在2.23下我们可以利用UAF,那么即使没有溢出,也可以利用malloc consolidate让下一个堆块的prev inuse置空,最后在被合并的堆块里伪造一个fake chunk即可触发unlink。

阅读全文 »

总结

通过本题的学习与总结有:

  1. 之前一直以为ret2libc必须得返回到原本的输入函数处,再次输入一次getshell。但有时候我们重新返回到原本的输入函数可能会出现一些问题,因此我们可以打一个栈迁移+rop执行read。就是先覆盖rbp为bss段上的地址,然后执行puts函数泄露libc,接着执行read函数往bss段上输入数据,最后执行leave ret完成栈迁移从而将执行流劫持到bss段上

  2. 插入到栈里的canary是从TLS结构体中的stack_guard成员变量赋值过来的(而函数返回时,会将栈里的canary与TLS中的stack_guard做对比)。主线程中的TLS通常位于mmap映射出来的地址空间里,而位置也比较随机,覆盖的可能性不大;子线程中的TLS则位于线程栈的顶部(高地址处),而这个子线程栈通常也是mmap映射出来的一段内存,这就给了我们栈溢出控制子线程中的TLS机会

  3. TLS(Thread Local Storage) 线程局部存储。本身是一种机制,简单来说就是多个线程访问同一个全局变量或者静态变量可能会发生冲突,而这个机制类似于让每个线程都备份了一份全局变量或者静态变量,当前线程只能修改自己这份全局变量或者静态变量并不会影响其他线程的全局变量以及静态变量。

  4. 在glibc实现中,TLS被指向一个segment register fs(x86-64上),它的结构tcbhead_t定义如下:

    typedef struct
    {
    void *tcb; /* Pointer to the TCB. Not necessarily the
    thread descriptor used by libpthread. */
    dtv_t *dtv;
    void *self; /* Pointer to the thread descriptor. */
    int multiple_threads;
    int gscope_flag;
    uintptr_t sysinfo;
    uintptr_t stack_guard;
    uintptr_t pointer_guard;
    ...
    } tcbhead_t;

    而上面的stack_guard也就是放到栈里的canary,而在程序里看见的这行代码

    xor rdx, fs:28h中的fs寄存器也就指向了TLS这个结构体,而偏移0x28的位置正好是stack_guard,canary是来自于内核生成的一个随机数。

  5. 最后要说一下这个子线程栈和父线程内存的关系。每个线程都会有自己单独的栈区,而子线程的栈区通常都是调用了mmap映射了一段内存。在父进程里我们依然可以看到这片内存

    阅读全文 »

总结&&启发:

总结:

通过这道对于tcache机制有了一定的认识。

tcache_perthread_struct结构体是用来管理tcache链表的,它的源码如下:

typedef struct tcache_entry
{
struct tcache_entry *next;
} tcache_entry;
typedef struct tcache_perthread_struct
{
char counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
# define TCACHE_MAX_BINS 64

这个结构体中有两个成员变量,一个是64字节的counts数组。该数组的每个元素都各自对应了64个tcache链表其中一条上chunk的数量(最大为7)。另一个成员变量是一个结构体指针数组,该数组的大小为64*8字节,该数组存放的是每条tcache链表的头指针。

阅读全文 »

总结:

通过这道题的学习与收获有:

1、本题的核心是劫持__free_hook。利用memcpy溢出,更改free状态堆块的fd指针,将其改写完__free_hook的地址,然后申请回来,写入system地址,最终free掉存有/bin/sh的堆块获取shell。

2、学会了新技能——使用IDA新建结构体,同时分析了IDA中的宏,通过对这个宏取字节的分析又加深了对指针的理解
3、使用sprintf的格式化字符串漏洞泄露数据时,要考虑到format在第二个参数的影响,最后的距离栈顶的偏移只加5(并不考虑rdi寄存器)

4、做的第一道堆题,体会到了在堆块中布局来获取shell的思想。

阅读全文 »

总结

通过这道题的学习与总结有:

这道题考察的依然是利用UAF打unlink。unlink攻击的核心是可以伪造fake_chunk以及控制fake_chunk下面的堆块的chunk头。虽然无法直接溢出,但是我们可以做一个double free,然后打fastbin attack将chunk头申请出来(在低地址堆块中写入size,保证chunk头可以从fastbin上出来),接着就可以打unlink了。

阅读全文 »