CVE-2016-0165 分析&利用POC
时间:2023-01-15 00:30:00
CVE-2016-0165
1. 漏洞简介
1.1.漏洞描述
发生在 Win32k.sys 图形驱动文件 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.危害等级
7.8 | 高危
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中写入数据
...
}
@line:16 存在整数溢出的隐患是变量 v6,而 v6来源于 EPATHOBJ结构指针偏移为 8的数据。相关类的部分定义如下
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:
...
}
所以以上变量 v6表示的则是 E P A T H O B J \textcolor{orange}{EPATHOBJ} EPATHOBJ类中的 ppath成员,接下来考虑如何触发这个整型溢出的 BUG。发现有如下函数会调用到这个易受攻击的函数
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)和 ppath有关,所以首先尝试在 Ring3调用 P a t h T o R e g i o n \textcolor{cornflowerblue}{PathToRegion} PathToRegion函数来触发漏洞。如何触发漏洞是难点之一,我在分析的时候花的最多的时间也在这上面。主要是之前并没有 Win32绘图的编程经验,而该漏洞的触发需要使用到绘图函数,因此在尝试之前有必要做一些前置知识的了解。
2.2.漏洞触发
2.2.1.前置知识
HRGN PathToRegion(
[in] HDC hdc
);
-
功能:将路径转换成区域。
-
[in] hdc
:处理包含封闭路径的设备上下文。 -
返回值:如果函数成功,则返回值标识一个有效区域。如果函数失败,则返回值为零。
路径的概念
在 Win32操作系统中,除了已有的位图,画笔,画刷,字体,调色板和区域之外,还增加了一个新的 GDI对象:路径。路径是可以被填充,画出轮廓或同时被画出轮廓并填充的一个或多个图形。路径的引入,大大地丰富了 Windows的图形功能,使得应用程序可以方便地建立复杂区域,绘制和填充不规则图形。
路径的使用
与其它原有的 GDI对象不同的是,MFC类库没有专门用一个 **C++**类来封装路径对象(或许在以后的版本中会得到支持)。有关路径的定义和使用等各种操作都必须通过调用 API函数(或 CDC类中对应的成员函数)来实现。
路径的使用过程大致如下:
(1)调用 B e g i n P a t h ( ) \textcolor{cornflowerblue}{BeginPath()} BeginPath()函数开始路径定义;
(2)调用 GDI绘图函数来定义路径。可用的函数有:```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,结果依然是在上图的 if判断中成真。有那么多绘图函数,如果都是这样去试显然是低效的且不保证能成功。这不得不使我去分析
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<