pwnable.kr passcode

思路

  • 首先查看保护,发现看开启了nx保护和canary,代表不可以简单的栈溢出


    checksec.png
  • 从main函数开始看,看到当passcode1==338150和passcode2==13371337的时候就可以成功的调用system("/bin/cat flag"),尝试调用程序


    first try.png
  • 发现输入后passcode失败了,程序出现错误,回看代码,发现在login函数中使用scanf函数时没有加上一个&号,因此并没有去到passcode1和passcode2的地址,因此使用got表覆盖

已知当第一次调用函数后,plt和got会形成一种对应关系,plt表中存有对应的GOT表项的地址,GOT表中存有函数的实际地址,那么以后调用该函数,则不需要重新符号解析即可直接访问plt再到got,直接到函数运行

  • 连续调用welcome和login,观察发现name,passcode1和passcode2共用一个栈底,且name在-0x70,passcode1在-0x10,passcode2在-0xC,name与passcode1相差0x60,即96,而name可以输入100个,意味着我们或许可以去覆盖passcode1的地址


    同一ebp.png
name.png

passcode1.png

passcode2.png
  • 同时scanf函数在第二个参数没有输入&的情况下,会将栈中的四个内存作为地址。因此在输入name时,将最后四个字符修改为got表中printf或者fflush的地址,即passcode1的内容变成地址了,然后在scanf("%d", passcode1)的时候相当于scanf("%d", &printf()),这时我们的再输入改变的将是printf函数在got表中的内容,因此我们将system函数的地址转换为10进制输入,那么下一次调用printf函数时,系统找到got表,执行其中内容时,执行的就是system函数
from pwn import *

context.log_level='debug'

io = process('./passcode')

payload='A'*96 + p32(0x0804a000) + str(0x80485e3)

io.send(payload)
io.interactive()
flag.png

你可能感兴趣的:(pwnable.kr passcode)