The Wayback Machine - https://web.archive.org/web/20201013192417/https://github.com/xinali/articles/issues/36
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adobe Reader CVE-2010-2883分析 #36

Open
xinali opened this issue Mar 26, 2019 · 1 comment
Open

Adobe Reader CVE-2010-2883分析 #36

xinali opened this issue Mar 26, 2019 · 1 comment

Comments

@xinali
Copy link
Owner

@xinali xinali commented Mar 26, 2019

CVE-2010-2883分析

这个漏洞分析的很迷茫,很蛋疼。漏洞原因用了一天也就熟悉了,但是为了找到从stacat开始到触发shellcode,用了接近半个月的时间。想了各种各样的方法也没有解决到底是怎么触发的。

环境

根据exploitdb

windows xp sp3
Windows Debugger Version 6.11.0001.404 X86

分析

根据exploit-db问题的根源出在CoolType.dll在解析SING Table时造成溢出,
简单的来看一下CoolType.dllSING的解析伪码,理解一下原理

char __cdecl sub_803DCF9(int a1, _DWORD *a2, int a3, int a4)
{
  int v4; // edi
  bool v5; // zf
  int v6; // eax
  size_t v7; // eax
  int v8; // eax
  int v9; // eax
  int v10; // eax
  int v12; // eax
  int *v13; // ecx
  char v14; // [esp+10h] [ebp-58h]
  int v15; // [esp+30h] [ebp-38h]
  int v16; // [esp+38h] [ebp-30h]
  int v17; // [esp+3Ch] [ebp-2Ch]
  int v18; // [esp+40h] [ebp-28h]
  int v19; // [esp+44h] [ebp-24h]
  int v20; // [esp+48h] [ebp-20h]
  int v21; // [esp+4Ch] [ebp-1Ch]
  int v22; // [esp+50h] [ebp-18h]
  char v23; // [esp+57h] [ebp-11h]
  int v24; // [esp+64h] [ebp-4h]
  char v25; // [esp+68h] [ebp+0h]

  v4 = a1;
  v18 = a1;
  v16 = a4;
  sub_804172C();
  v5 = *(_DWORD *)(a1 + 8) == 3;
  v24 = 0;
  if ( !v5 )
  {
    v21 = 0;
    v22 = 0;
    v5 = *(_DWORD *)(a1 + 12) == 1;
    LOBYTE(v24) = 1;
    if ( v5 )
    {
      v23 = 0;
      sub_80217D7(&v21, a1, "name");
      if ( v21 )
        goto LABEL_52;
      sub_8021B06(&v19, a1, "SING"); // <--- 解析SING
      v6 = v19;
      LOBYTE(v24) = 2;
      if ( v19 )
      {
        if ( !(*(_DWORD *)v19 & 0xFFFF) || (*(_DWORD *)v19 & 0xFFFF) == 0x100 )
        {
          v25 = 0;
          strcat(&v25, (const char *)(v19 + 16)); // 问题函数
          sub_8001243(a2, (int)&v25);
          v6 = v19;
        }
        v23 = 1;
      }
    ...
  return 1;
}

v19的数据附加到v25末尾,很明显,如果v19没有做长度校验就很容易造成溢出。

pdf样本分析

具体SING字体相关的说明可以看一下adobe文档

现在来具体分析msf.pdf看看是如何造成溢出的,利用pdfstreamdumper提取出数据,010查看一下字体文件

1552988687765

在具体分析一下SING Table数据

1552988803334

根据github上的解析库afdko可以找到SING Table的具体定义

1552989003690

根据定义,可以发现uniqueName的偏移位置为16字节

typedef struct
{
    Card16 tableVersionMajor;           // +0 偏移
    Card16 tableVersionMinor;			// +2
    Card16 glyphletVersion;				// +4
    Card16 permissions;					// +6
    Card16 mainGID;						// +8
    Card16 unitsPerEm;					// +10
    Int16 vertAdvance;					// +12
    Int16 vertOrigin;					// +14
    Card8 uniqueName[SING_UNIQUENAMELEN]; // +16 
    Card8 METAMD5[SING_MD5LEN];
    Card8 nameLength;
    Card8 *baseGlyphName; /* name array */
} SINGTbl;

exploitdb说是uniqueName造成的溢出,我们在0803DD9F下断点,对照一下数据

.text:0803DD9F                 add     eax, 10h
.text:0803DDA2                 push    eax             ; char *
.text:0803DDA3                 lea     eax, [ebp+108h+var_108] // 即lea eax, [ebp]
.text:0803DDA6                 push    eax             ; char *
.text:0803DDA7                 mov     [ebp+108h+var_108], 0
.text:0803DDAB                 call    strcat

可以发现eax指向的就是SING Table

1552989254940

偏移16字节处正好是uniqueName,根据msdn

1552998441835

没有经过验证strcat会直接溢出[ebp],再来看一下ida反汇编代码

if ( !(*(_DWORD *)v19 & 0xFFFF) || (*(_DWORD *)v19 & 0xFFFF) == 0x100 )
{
    v25 = 0;
    strcat(&v25, (const char *)(v19 + 16));
    sub_8001243(a2, (int)&v25);
    v6 = v19;
}

对应的汇编代码

1553611248092

超过0x104肯定会出错,具体出错的位置,我始终无法跟踪到!其实这里从9.4.0的修复版本中也能看到

1553612940139

其中sub_813391E,长度肯定不会超过0x104



char *__cdecl sub_813391E(char *a1, char *a2, int a3)  // 修复中添加的函数
{
  size_t v3; // eax
  char *result; // eax

  v3 = strlen(a1);
  if ( a3 > v3 )
    result = strncat(&a1[v3], a2, a3 - v3 - 1);
  else
    result = a1;
  return result;
}

不过可以根据这个确定一下溢出长度

1553611571171

即使不知道具体的出错位置,+8的位置是将来跳转的位置,这个是可以确定的。

其实出错的原因,我能想到的无非就是两种

  1. SEH handler

    测试过SEH handler,在我有限的知识体系里,应该先调用ntdll!KiUserExceptionDispatcher在这里下断点,但是却没有断到

    1553611907374

  2. 虚函数指针

    这里在函数sub_8016BDE中的sub_801BB21看到了,调试了一下,但也不对

    int __cdecl sub_801BB21(int (__stdcall ***a1)(int, int, int, int, int, int), int a2, int a3, int a4, int a5, int a6, int a7)
    {
      int (__stdcall **v7)(int, int, int, int, int, int); // eax  <=====
      int result; // eax
    
      v7 = *a1;
      ++dword_823A6A0;
      result = (*v7)(a2, a3, a4, a5, a6, a7);
      if ( !(_BYTE)result )
        --dword_823A6A0;
      return result;
    }

    以上两种方法都尝试了,其中也尝试过用windbg previewTTD调试,但是遇到了这个问题,最终都没有确定具体的原因,很伤。

    再来说一下shellcode,首先需要利用icucnv36模块,因为其在各个版本中的地址是一样的,可以将+8的位置溢出到该模块,从而绕过DEP,但是有一点需要注意,icucnv36模块中没有常规的直接绕过DEP的函数,可以利用其中的

    CreateFileA -> CreateFileMapping -> MapViewOfFile -> memcpy

    这种方法其实在我日常分析恶意代码中比较常见。具体怎么利用就不细说了,网上都有。

    到这里,该漏洞就分析完了

参考

SING 结构定义

Brief Analysis On Adobe Reader SING Table Parsing Vulnerability (CVE-2010-2883)

泉哥的书

@0n3t04ll
Copy link

@0n3t04ll 0n3t04ll commented Apr 28, 2020

這兩天分析了這個漏洞,關於出錯位置在我的電腦上是(接續 sub_801BB21):
result = (*v7)(a2, a3, a4, a5, a6, a7); // 拿 **a1 也就是 0x808b116 當 function pointer

808b116:
0808B2E3 mov eax, [edi+3Ch] ; 從 strcat 就維持相同的值的 edi + 0x3c == 0x12e6d0
0808B308 call dword ptr [eax] ; *(0x12e6d0)

12e6d0 是被 overflow 過去的區域最後的部分,到這邊成功 control flow hijack

關於 12e6d0 是啥?為啥存放 function pointer 就沒什麼頭緒了,不過應該可以確定不是 seh 也不是 return addres

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants
You can’t perform that action at this time.