资讯详情

CVE-2016-0165 分析&利用POC

CVE-2016-0165

1. 漏洞简介

1.1.漏洞描述

发生在 图形驱动文件 R G N M E M O B J : : v C r e a t e \textcolor{orange}{RGNMEMOBJ::vCreate} RGNMEMOBJ::vCreate内存越界写漏洞是由函数中的整形溢出引起的,攻击者可以利用这个漏洞来提高当地权限。

1.2.影响版本

windows_10:-:*:*:*:*:*:*:* windows_10:1511:*:*:*:*:*:*:* windows_7:*:sp1:*:*:*:*:*:* windows_8.1:*:*:*:*:*:*:*:* windows_rt_8.1:-:*:*:*:*:*:*:* windows_server_2008:*:sp2:*:*:*:*:*:* windows_server_2008:r2:sp1:*:*:*:*:*:* windows_server_2012:-:*:*:*:*:*:*:* windows_server_2012:r2:*:*:*:*:*:*:* windows_vista:*:sp2:*:*:*:*:*:* 

1.3.危害等级

2.漏洞分析

2.1.补丁分析

这是没有补丁和补丁的补丁 R G N M E M O B J : : v C r e a t e \textcolor{orange}{RGNMEMOBJ::vCreate} RGNMEMOBJ::vCrea/span>te函数对比图

在这里插入图片描述

有点像找不同 ,发现主要有6处不同。

  • 标号①对应的是情况是

这是在分配缓冲区之前增加的两个函数

看到 U L o n g A d d \textcolor{cornflowerblue}{ULongAdd} ULongAdd和 U L o n g L o n g T o U L o n g \textcolor{cornflowerblue}{ULongLongToULong} ULongLongToULong的实现

int __stdcall ULongAdd(unsigned int a1, unsigned int a2, unsigned int *a3)
{ 
        
  if ( a1 + a2 < a1 )  // 判断溢出
  { 
        
    *a3 = -1;
    return 0x80070216;
  }
  else
  { 
        
    *a3 = a1 + a2;
    return 0;
  }
}

HRESULT __stdcall ULongLongToULong(ULONGLONG ullOperand, ULONG *pulResult)
{ 
        
  if ( HIDWORD(ullOperand) ) // 取高32位
  { 
        
    *pulResult = -1;
    return 0x80070216;
  }
  else
  { 
        
    *pulResult = ullOperand; // 仅当高32位为 0x00000000时才允许转成ULONG类型的数据
    return 0;
  }
}

可以推测没打补丁之前这个地方会存在整型溢出漏洞。后续会进行内存分配,然后写入数据。现在看到没打补丁之前的情况:

void __thiscall RGNMEMOBJ::vCreate(RGNMEMOBJ *this, struct EPATHOBJ *a2, char a3, struct _RECTL *a4)
{ 
        
 ...
  v4 = a2;
  if ( !*((_DWORD *)a2 + 2) )
    return;
  *(_DWORD *)this = 0;
  if ( (*(_BYTE *)a2 & 1) != 0 && !EPATHOBJ::bFlatten(a2) )
    return;
  EPATHOBJ::vCloseAllFigures(a2); // 将起始坐标和终止坐标连接,形成封闭图
  v6 = *((_DWORD *)a2 + 1);	// 获取边数
  ...
  LABEL_13:
  if ( v6 >= 0x14 ) // 边数目大于等于0x14
  { 
        
    if ( 40 * (v6 + 1) )
    { 
        
      PoolWithTag = ExAllocatePoolWithTag(PagedPoolSession, 40 * (v6 + 1), 'ngrG');
      v7 = a4;
      P = PoolWithTag;
    }
      ...
  }
   
  pEdge = (struct EDGE *)P;
  vConstructGET(a2, &v29, pEdge, a4);  // 该函数会向pEdge中写入数据
  ...

}

存在整数溢出的隐患是变量 ,而 来源于 结构指针偏移为 的数据。相关类的部分定义如下

typedef struct _PATHOBJ
{
    FLONG   fl;
    ULONG   cCurves;
} PATHOBJ;

class EPATHOBJ : public _PATHOBJ /* epo */
{
private:
    friend VOID vConstructGET(EPATHOBJ& po, PEDGE pedgeHead, PEDGE pedgeFree,RECTL *pBound);

public:
    PPATH    ppath;

protected:
    ...
}

所以以上变量 表示的则是 E P A T H O B J \textcolor{orange}{EPATHOBJ} EPATHOBJ类中的 成员,接下来考虑如何触发这个整型溢出的 。发现有如下函数会调用到这个易受攻击的函数

R G N M E M O B J : : v C r e a t e ( R G N M E M O B J   ∗ t h i s ,   s t r u c t   E P A T H O B J   ∗ a 2 ,   c h a r   a 3 ,   s t r u c t   _ R E C T L   ∗ a 4 ) \textcolor{cornflowerblue}{RGNMEMOBJ::vCreate(RGNMEMOBJ\ *this,\ struct\ EPATHOBJ\ *a2,\ char\ a3,\ struct\ \_RECTL\ *a4)} RGNMEMOBJ::vCreate(RGNMEMOBJ ∗this, struct EPATHOBJ ∗a2, char a3, struct _RECTL ∗a4)

而其中只有函数 N t G d i P a t h T o R e g i o n ( H D C   h d c ) \textcolor{cornflowerblue}{NtGdiPathToRegion(HDC\ hdc)} NtGdiPathToRegion(HDC hdc)和 有关,所以首先尝试在 调用 P a t h T o R e g i o n \textcolor{cornflowerblue}{PathToRegion} PathToRegion函数来触发漏洞。如何触发漏洞是难点之一,我在分析的时候花的最多的时间也在这上面。主要是之前并没有 绘图的编程经验,而该漏洞的触发需要使用到绘图函数,因此在尝试之前有必要做一些前置知识的了解。

2.2.漏洞触发

2.2.1.前置知识
HRGN PathToRegion(
  [in] HDC hdc
);
  • 功能:将路径转换成区域。

  • [in] hdc:处理包含封闭路径的设备上下文。

  • 返回值:如果函数成功,则返回值标识一个有效区域。如果函数失败,则返回值为零。

  1. 路径的概念

    操作系统中,除了已有的位图,画笔,画刷,字体,调色板和区域之外,还增加了一个新的 对象:路径。路径是可以被填充,画出轮廓或同时被画出轮廓并填充的一个或多个图形。路径的引入,大大地丰富了 的图形功能,使得应用程序可以方便地建立复杂区域,绘制和填充不规则图形。

    1. 路径的使用

      与其它原有的 对象不同的是,类库没有专门用一个 **C++**类来封装路径对象(或许在以后的版本中会得到支持)。有关路径的定义和使用等各种操作都必须通过调用 函数(或 类中对应的成员函数)来实现。

      路径的使用过程大致如下: (1)调用 B e g i n P a t h ( ) \textcolor{cornflowerblue}{BeginPath()} BeginPath()函数开始路径定义; (2)调用 绘图函数来定义路径。可用的函数有:

          ```c
          AngleArc
          Arc
          ArcTo
          Chord
          CloseFigure
          Ellipse
          ExtTextOut
          LineTo
          MoveToEx
          Pie
          PolyBezier
          PolyBezierTo
          PolyDraw
          Polygon
          Polyline
          PolylineTo
          PolyPolygon
          PolyPolyline
          Rectangle
          RoundRect
          TextOut 
          ```
      

      (3)调用 E n d P a t h ( ) \textcolor{cornflowerblue}{EndPath()} EndPath()函数结束路径定义;

      (4)使用路径对象,其中就包含函数 P a t h T o R e g i o n \textcolor{cornflowerblue}{PathToRegion} PathToRegion;

2.2.2.触发分析

这个过程我遇到的困难挺多的,首先我从最简单的画线函数 L i n e T o \textcolor{cornflowerblue}{LineTo} LineTo开始尝试,结果并没有走到整型溢出的漏洞点,而是在下图位置的条件判断中

函数返回真,接着就返回了。我又换了别的绘图函数 E l l i p s e \textcolor{cornflowerblue}{Ellipse} Ellipse、 L i n e T o \textcolor{cornflowerblue}{LineTo} LineTo,结果依然是在上图的 判断中成真。有那么多绘图函数,如果都是这样去试显然是低效的且不保证能成功。这不得不使我去分析

R G N M E M O B J : : b F a s t F i l l W r a p p e r \textcolor{cornflowerblue}{RGNMEMOBJ::bFastFillWrapper} RGNMEMOBJ::bFastFillWrapper函数。

int __thiscall RGNMEMOBJ::bFastFillWrapper(RGNMEMOBJ *this, struct EPATHOBJ *ppo)
{ 
        
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v11 = 0;
  v3 = *((_DWORD *)ppo + 2);
  *(_DWORD *)ppo &= ~8u;
  v9 = this;
  *(_DWORD *)(v3 + 0x38) = *(_DWORD *)(v3 + 0x14);
  if ( EPATHOBJ::bEnum((PATHOBJ *)ppo, &ppd) )  // 枚举路径中的坐标点
  { 
        
    if ( (ppd.flags & 2) == 0 && *((_DWORD *)ppo + 1) <= 0x28u )// 如果结束于非子路径,并且曲线个数不超过40
    { 
        
      count = ppd.count;
      if ( (int)ppd.count > 0x28 )
        count = 0x28;
      memcpy(v8, ppd.pptfx, 8 * count);         // 将路径中的所有坐标数据拷贝到栈中
      while ( 1 )
      { 
        
        ppoa = (PATHOBJ *)EPATHOBJ::bEnum((PATHOBJ *)ppo, &ppd);
        if ( (ppd.flags & 1) != 0 )             // 如果是子路径的开始端,则跳出循环
                                                // 函数返回假
          break;
        v5 = ppd.count;
        memcpy(&v8[count], ppd.pptfx, 8 * ppd.count); // 将路径中的所有坐标数据拷贝到栈中
        count += v5;
        if ( !ppoa )
        { 
        
          v6 = RGNMEMOBJ::bFastFill(v9, ppo, count, v8); 
          goto LABEL_12;
        }
      }
    }
  }
  else
  { 
        
    v6 = 1;
    if ( ppd.count > 1 )
      v6 = RGNMEMOBJ::bFastFill(v9, ppo, ppd.count, ppd.pptfx);
LABEL_12:
    v11 = v6;
  }
  *(_DWORD *)ppo &= ~8u;
  *(_DWORD *)(*((_DWORD *)ppo + 2) + 0x38) = *(_DWORD *)(*((_DWORD *)ppo + 2) + 0x14);
  return v11;
}

我们分析的主要目的是使得该函数返回假。所以我们看到该函数成假的返回路径有 @ l i n e : 5 − > @ l i n e : 12 − > @ l i n e : 43 \textcolor{orange}{@line:5->@line:12->@line:43} @line:5−>@line:12−>@line:43,虽然 @ l i n e : 5 − > @ l i n e : 29 − > @ l i n e : 40 \textcolor{orange}{@line:5->@line:29->@line:40} @line:5−>@line:29−>@line:40这条路径也有可能返回假,但是我们还要去考虑函数

R G N M E M O B J : : b F a s t F i l l \textcolor{cornflowerblue}{RGNMEMOBJ::bFastFill} RGNMEMOBJ::bFastFill,增加了工作量,所以先不予考虑这第二条路径。

我们只要想办法让**@line:10@line:12**的条件不成立即可。根据对 E P A T H O B J : : b E n u m \textcolor{cornflowerblue}{EPATHOBJ::bEnum} EPATHO<

标签: 3ad50c晶体管怎样

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台