CVE-2013-0077 堆溢出分析

    找了好久才發現這個環境比較容易搭建分析...html

  • 環境
    • 系統---Win XP SP3
    • 漏洞程序:QQPlayer 3.7.892.400
    • 出錯DLL:quartz.dll 6.5.2600.5512
    • 調試工具:x32db+gflag.exe
  • 過程
    • 首先gflag設置QQPlayer.exe的堆調試屬性,"gflag.exe -i QQPlayer.exe +hpa",此處添加堆頁檢查堆複製中的溢出。
    • 啓動QQPlayer.exe,而後將x32dbg附加到QQPlayer進程上調試,使得被調試程序的堆分配機制正常執行,再將poc.m2p文件拖入QQPlayer中,由此x32dbg捕獲到錯誤(EXCEPTION_ACCESS_VIOLATION),並停在rep movsd指令處。
    • 此時查看到當前出錯指令位於quartz.dll中,用IDA Pro分析quartz.dll分析,得以下結果。
    • signed int __stdcall sub_7D0706CC(int src_addr, unsigned int count, int a3)
      {
        signed int result; // eax@2
        int v4; // eax@3
        unsigned __int8 v5; // al@3
        unsigned int v6; // ebx@7
        int v7; // ecx@7
        int v8; // ST00_4@7
        unsigned int v9; // eax@7
        signed int v10; // eax@10
      
        if ( *(_BYTE *)(src_addr + 10) & 0x20 )
        {
          v4 = (*(_BYTE *)(src_addr + 6) + ((*(_BYTE *)(src_addr + 5) + (*(_BYTE *)(src_addr + 4) << 8)) << 8)) & 0xFFF;
          *(_DWORD *)a3 = (*(_BYTE *)(src_addr + 6)
                         + ((*(_BYTE *)(src_addr + 5) + ((unsigned int)*(_BYTE *)(src_addr + 4) << 8)) << 8)) >> 12;
          *(_DWORD *)(a3 + 4) = v4;
          v5 = *(_BYTE *)(src_addr + 7);
          if ( (*(_BYTE *)(src_addr + 7) & 0xFu) > 8 )
            v5 &= 0xF7u;
          if ( v5 & 0xF0 && v5 & 0xF )
          {
            v6 = v5;
            v7 = v5 & 0xF;
            *(_QWORD *)(a3 + 16) = dword_7D0707F8[v7];
            v8 = *(_DWORD *)(a3 + 16);
            *(_DWORD *)(a3 + 24) = dword_7D070838[v7];
            *(_DWORD *)(a3 + 28) = MulDiv(v8, 9, 1000);
            v9 = (*(_BYTE *)(src_addr + 10) + ((*(_BYTE *)(src_addr + 9) + ((unsigned int)*(_BYTE *)(src_addr + 8) << 8)) << 8)) >> 6;
            *(_DWORD *)(a3 + 32) = v9;
            if ( v9 == 0x3FFFF )
              *(_DWORD *)(a3 + 32) = 0;
            else
              *(_DWORD *)(a3 + 32) = 400 * v9;
            *(_DWORD *)(a3 + 40) = 2000;
            *(_DWORD *)(a3 + 36) = dword_7D070860[v6 >> 4];
            v10 = (((unsigned int)*(_BYTE *)(src_addr + 11) >> 3) | 32 * (*(_BYTE *)(src_addr + 10) & 0x1F)) << 11;
            *(_DWORD *)(a3 + 8) = v10;
            if ( *(_BYTE *)(src_addr + 11) & 4 )
            {
              if ( v10 > 40960 )
                *(_DWORD *)(a3 + 8) = 40960;
            }
            *(_DWORD *)(a3 + 48) = count;
         //此處qmemcpy爲出錯指令,將src_addr處的內容複製count字節到堆中,覺得count未檢查,致使溢出
         //查看到此處src_addr的起始內容爲0x000001B3
            qmemcpy((void *)(a3 + 52), (const void *)src_addr, count);
            result = 1;
          }
          else
          {
            result = 0;
          }
        }
        else
        {
          result = 0;
        }
        return result;
      }

      返回到x32dbg中調試到此函數上,發現src_addr處起始內容爲0x000001B3,count爲0x000000C3。數據結構

    • 在poc.m2p文件中查找到「0x000001B3」,而且在「0x000001B3」偏移0xC3處後,內容爲「0x00000100」,此時咱們並不知道這個十六進制序列有什麼特殊含義,暫且看作一個開端標誌。以後Google MPEG-2數據結構發現「0x000001B3」爲Video Sequence的起始標誌,「0x00000100」爲Picture Header的起始標誌,因此此函數的功能就是將Video Sequence到Picture Header之間的內容複製到堆中,由於堆中空間不夠,而致使的溢出錯誤。ide

    • 最後咱們探究一下溢出的精確長度複製前的堆起始地址爲0x027A6F64,出錯時爲0x027A7000,0x027A7000-0x027A6F64=0x9C,因此此處分配的堆空間大小爲0x9C字節,而咱們實際複製的內容有0xC3字節,超出全部空間,致使溢出錯誤。函數

  • 總結:此處的堆溢出與棧溢出其實基本相近,都是由於複製數目未檢查而致使的溢出,只是位於不一樣屬性地址空間上的不一樣溢出而已,因地址空間所具備的特性而不一樣;x32dbg等調試器對於堆調試很不友好,沒有windbg對堆的調試支持強,是一個後續須要解決的問題,同時此時找到了堆的溢出錯誤,但是要想達到exp,還有很長一段路...
  • 待續:期待續篇EXP...
相關文章
相關標籤/搜索