首页 > 其他 > 详细

CVE_2019-1458

时间:2020-04-25 18:00:24      阅读:334      评论:0      收藏:0      [点我收藏+]

样本分析

  1. 拿到样本后观察到这是个MFC程序,并且在资源段存在加密数据

技术分享图片

  1. 在样本中找到解密这段shellcode的地方后将其dump出来,载入IDA分析

技术分享图片

技术分享图片

  1. 经过分析发现这段shellcode通过内存加载运行了位于其中的dll文件

    技术分享图片

  2. 将其dump出来后经过分析发现其实现了傀儡进程了那一套,替换的进程就是CVE-2019-1458的32位提权exp

    技术分享图片

漏洞分析

  1. exp中首先根据不同系统版本使用不通方法获取了NtUserMessageCall的地址、并初始化了一些内核结构成员的偏移数组

    技术分享图片

    技术分享图片

  2. 随后根据不通系统版本采用了不同的内存占位对象,我测试的环境Win7 x86 sp1是采用的Palette对象,因为在Win7中可以通过GdiSharedHandleTable来泄露GDI对象的内核地址,所以在exp中通过不断地申请一对Palette对象,使两者内核地址之差为0x2000,通过后面分析可知,该样本利用这个有条件的任意写修改了位于内存上方的Palette2的numberOfEntries,然后通过越界写修改位于内存下方的Palette3的ptr_PALETTEENTRY 指针,从而将这个有条件的任意写漏洞转换为了任意地址读写

    signed int sub_401B40()
    {
      unsigned int v0; // edx
      HPALETTE palette1; // ebx
      HPALETTE palette2; // eax
      HPALETTE v3; // edi
      int v4; // edx
      unsigned int v5; // esi
      unsigned int v6; // eax
      bool v7; // cf
      bool v8; // zf
      HPALETTE v9; // eax
      int v10; // edx
      HPALETTE v11; // edi
      unsigned int v12; // eax
    
      v0 = Palettle_array_index;
      while ( v0 < 0xFFD )
      {
        stru_4081C0.palVersion = 0x300;
        stru_4081C0.palNumEntries = palette_number;
        memset(stru_4081C0.palPalEntry, 1, 8192u);
        palette1 = CreatePalette(&stru_4081C0);
        palette2 = CreatePalette(&stru_4081C0);
        v3 = palette2;
        if ( !palette1 || !palette2 )
          break;
        v4 = Palettle_array_index + 2;
        Palettle_array1[v4] = palette1;
        Palettle_array2[v4] = palette2;
        Palettle_array_index = v4;
        v5 = GetGdiKernelAddress(palette1);
        v6 = GetGdiKernelAddress(v3);
        v7 = v5 < v6;
        v8 = v5 == v6;
        if ( v5 >= v6 )
          goto LABEL_9;
        if ( v6 - v5 == 0x2000 )          // 保证两个Palettle对象地址足够接近
        {
          handle_Palettle_1 = palette1;
          kernelAddress_Palettle_1 = v5;
          handle_Palettle_2 = v3;
          kernelAddress_Palettle_2 = v6;
    LABEL_12:
          v9 = CreatePalette(&stru_4081C0);
          v10 = Palettle_array_index;
          v11 = v9;
          dword_4041A0[Palettle_array_index] = v9;
          Palettle_array_index = v10 + 1;
          v12 = GetGdiKernelAddress(v9);
          if ( v12 > kernelAddress_Palettle_2 && v12 - kernelAddress_Palettle_2 == 0x2000 )
          {
            kernelAddress_Palettle_3 = v12;
            handle_Palettle_3 = v11;
            sub_4017F0();
            return 1;
          }
          if ( v12 < kernelAddress_Palettle_1 && kernelAddress_Palettle_1 - v12 == 0x2000 )
          {
            handle_Palettle_3 = handle_Palettle_2;
            kernelAddress_Palettle_3 = kernelAddress_Palettle_2;
            handle_Palettle_2 = handle_Palettle_1;
            handle_Palettle_1 = v11;
            kernelAddress_Palettle_2 = kernelAddress_Palettle_1;
            kernelAddress_Palettle_1 = v12;
            sub_4017F0();
            return 1;
          }
        }
        else
        {
          v7 = v5 < v6;
          v8 = v5 == v6;
    LABEL_9:
          if ( !v7 && !v8 && v5 - v6 == 0x2000 )
          {
            handle_Palettle_2 = palette1;
            kernelAddress_Palettle_2 = v5;
            handle_Palettle_1 = v3;
            kernelAddress_Palettle_1 = v6;
            goto LABEL_12;
          }
        }
      }
    
  3. 随后创建了一个MySwitchWnd窗口并调用NtUserMessageCall,通过在IDA中分析win32k!NtUserMessageCall后发现NtUserMessageCall只是个分发函数,其最终的处理函数由其参数Msg和dwType决定,通过windbg中调试发现在Msg = 0x1 dwType = 0xE0时,最终的调用流向了win32k!xxxWrapSwitchWndProc

    技术分享图片

    技术分享图片

  4. 通过windbg动态调试发现gpsi->mpFnid_serverCBWndProc[6]为0,而exp中创建的窗口的Class中将cbwndExtra设置为4,且新创建的窗口cbwndExtra的内容为0,因此通过此次NtUserMessageCall调用绕过了一下三个检查成功将hwnd->fnid设置为0x2A0

    技术分享图片

  5. 接着将实现回到exp中,发现其通过SetWindowLongWhwnd->cbwndExtra设置为Palette内核地址-0x40的值,随后创建了#32771窗口,这个窗口类在msdn中解释为用于任务切换窗口,至于创建这个窗口的作用,就是将gpsi->mpFnid_serverCBWndProc[6]设置为0xB4用于绕过后面的检查,然后通过SetKeyboardState将ALT键的状态设置为press,最后再次调用了NtUserMessageCall

    技术分享图片

  6. 在第二次调用NtUserMessageCallMsg = 0x14并且此时hwnd->fnid = 0x2A0,因此调用在xxxSwitchWndProc中流向了xxxPaintSwitchWindow

    技术分享图片

  7. xxxPaintSwitchWindow中调用Getpswi检查了a1->cbwndExtra + 0xB0 != gpsi->mpFnid_serverCBWndProc[6],由于在前面样本中已经创建了#32771窗口来将gpsi->mpFnid_serverCBWndProc[6]初始化为0xB4,因此Getpswi在检查通过后返回了hwnd->cbwndExtra的值,在简单的检查了当前ALT键是否被按下后调用了_GetClientRect漏洞函数。现在我们知道v1 = a1->cbwndExtra = kernelAddress_Palettle_2 - 0x40,因此_GetClientRect第二个参数v1 + 0x48之后其实是指向了 kernelAddress_Palettle_2 + 8

    技术分享图片

  8. _GetClientRect中我们观察到了有对第二个参数(也就是kernelAddress_Palettle_2 + 8)赋值的操作,并且在windbg中观察到lprc[3]就是kernelAddress_Palettle->numberOfEntries的地址,其被赋值为a1->rcClient.bottom,这个值是由我们创建窗口的大小和位置决定的,exp中这个值为0x7000。因此通过被扩大的kernelAddress_Palettle->numberOfEntries来达到越界修改的效果

    技术分享图片

  9. kernelAddress_Palettle->numberOfEntries被增大为0x7000后,就可以通过GetPaletteEntriessetPaletteEntries构造读写原语

    技术分享图片

    技术分享图片

  10. 构造好读写原语后,exp中采用了读取system token并替换指定进程token的方式进行了提权

    技术分享图片

参考链接

https://github.com/piotrflorczyk/cve-2019-1458_POC

CVE_2019-1458

原文:https://www.cnblogs.com/DreamoneOnly/p/12774145.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!