双重释放漏洞(来自<<漏洞战争>>一书)

基本:

1.原理

double free 是UAF的一种, 相对其他类型漏洞比较少见. 主要是由对同一个堆内存块进行二次释放导致的. 利用好可以执行任意代码

2.最简单的double free 导致的bug 示例

#include<stdio.h>
#include<malloc.h>
#include <windows.h>
void main()
{
void *p1,*p2,*p3;
p1=malloc(100);
printf("heap p1:%p ",p1);
p2=malloc(100);
printf("heap p2:%p ",p2);
p3=malloc(100);
printf("heap p3:%p ",p3);

printf("free p1 ");
free(p1);
printf("free p3 ");
free(p3);
printf("free p2 ");
free(p2);

printf("double free p1 ");
free(p1);

getchar();
}

CVE-2010-3974-Microsoft Windows 传真封面编辑器双重释放漏洞

附加到windbg后直接打开poc.cov文件发生异常后:

0:005> g
ModLoad: 6e4f0000 6e504000 C:Windowssystem32FontSub.dll
(efc.f84): C++ EH exception - code e06d7363 (first chance)
Critical error detected c0000374
(efc.f84): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=772d07ed edx=0012f38d esi=00460000 edi=023f40a8
eip=7737280d esp=0012f5e0 ebp=0012f658 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!RtlReportCriticalFailure+0x29:
7737280d cc int 3

然后查看栈回溯:

从符号名可以发现应该是在做一些内存释放,资源销毁的动作,而且是在调用free函数后进入异常流程, 说明很可能是个双重释放漏洞

此外根据free, RtlFreeHeap函数的参数,可知绿色的即为要被释放的地址

0:000> kb
ChildEBP RetAddr Args to Child 
0012f658 7737376b c0000374 7738cdc8 0012f69c ntdll!RtlReportCriticalFailure+0x29
0012f668 7737384b 00000002 7786b978 00460000 ntdll!RtlpReportHeapFailure+0x21
0012f69c 77373ab4 00000003 00460000 023f40a8 ntdll!RtlpLogHeapFailure+0xa1
0012f6f4 77337ad7 00460000 023f40a8 00000000 ntdll!RtlpAnalyzeHeapFailure+0x25b
0012f7e8 77302d68 023f40a8 023f40b0 023f40b0 ntdll!RtlpFreeHeap+0xc6
0012f808 76fc98cd 00460000 00000000 023f40b0 ntdll!RtlFreeHeap+0x142
0012f854 005ef43a 023f40b0 023f40b0 0012f880 msvcrt!free+0xcd
0012f864 005eab0c 00000001 00468b50 0046eea0 FXSCOVER!CDrawRoundRect::`scalar deleting destructor'+0x1a
0012f880 005eb1d4 00000000 0046eea0 6ab98515 FXSCOVER!CDrawDoc::Remove+0x96
0012f88c 6ab98515 0046eea0 6ab984df 0046eea0 FXSCOVER!CDrawDoc::DeleteContents+0xc
0012f894 6ab984df 0046eea0 0046eea0 0012f8d8 MFC42u!CDocument::OnNewDocument+0x15
0012f8a4 005ea812 0046eea0 6ab983e8 628d08b0 MFC42u!COleDocument::OnNewDocument+0xe
0012f8ac 6ab983e8 628d08b0 00468b50 00468bcc FXSCOVER!CDrawDoc::OnNewDocument+0xa
0012f8d8 6ab98598 00000000 00000001 628d0900 MFC42u!CSingleDocTemplate::OpenDocumentFile+0x103

未完待续................

CVE-2014-0502-Adobe Flash Player 双重释放漏洞

1.根据<<漏洞战争>>中可知,先使用fpexs反汇编cc.swf文件,得到flash的as语言代码,

分析代码可以知道:它会获取系统版本来定制rop指令, 是很值得学习的

2.其次,分析代码得出该文件通过下载一张图片文件,而shellcode藏在该图片中,然后从图片中解析出恶意代码

3.通过scdbg这一神器分析shellcode

下载scdbg后通过scdbg.exe -f shellcode文件 可以获得scdbg的返回信息, 即恶意代码将干的事情

4.基于rop指令进行漏洞分析

个人认为 触发有漏洞的指令时将被利用者利用,然后劫持程序的执行流程,而为了绕过dep,一开始就将运行rop指令, 因此定位漏洞指令时可以选择合适rop指令

进行下断, 书中对第2条指令进行下断,因为第一个rop指令经常被执行,不利于定位漏洞指令,因为不知道是正常执行该条指令还是执行了rop. 所以应选择

只被rop调用的指令(逐个试就行). 很值得学习的定位漏洞指令的方法. 因此下断后运行查看栈回溯:

0:016> kb
ChildEBP RetAddr Args to Child
0783fa20 05c51d4c 00000000 00000000 00000000 msvcrt!type_info::operator==+0x3b
WARNING: Stack unwind information not available. Following frames may be wrong.
0783fa4c 05c535ac 00000000 06d86410 06dca1c0 Flash32_12_0_0_44+0xf1d4c
0783fad0 05e2be71 06dca1c0 05e2bf41 06dca1c0 Flash32_12_0_0_44+0xf35ac
0783fad8 05e2bf41 06dca1c0 05c4e62b 00000000 Flash32_12_0_0_44!DllUnregisterServer+0xf2a4c
0783fae0 05c4e62b 00000000 07556000 00000000 Flash32_12_0_0_44!DllUnregisterServer+0xf2b1c
0783faf4 05cab98b 7c809832 07556000 07556000 Flash32_12_0_0_44+0xee62b

然后:

0:000> ub Flash32_12_0_0_44+0xf1d4c
Flash32_12_0_0_44+0xf1d3b:
05c51d3b 10d9 adc cl,bl
05c51d3d ee out dx,al
05c51d3e 53 push ebx
05c51d3f 51 push ecx
05c51d40 51 push ecx
05c51d41 dd1c24 fstp qword ptr [esp]
05c51d44 ff7508 push dword ptr [ebp+8]
05c51d47 e821f9ffff call Flash32_12_0_0_44+0xf166d (05c5166d)

重启程序重新附加下断:

bp  Flash32_12_0_0_44+0xf166d

bp 77bf18d3 (第2条rop指令地址)

继续运行7次后才断在rop指令

在重启程序附加下断, 继续运行第6次时跟进Flash32_12_0_0_44+0xf166d 函数

查看此处反汇编:很明显eax是虚表指针,ecx=esi=对象地址

05c616ea 8b06 mov eax,dword ptr [esi]
05c616ec 53 push ebx
05c616ed ff7608 push dword ptr [esi+8]
05c616f0 c6451401 mov byte ptr [ebp+14h],1
05c616f4 51 push ecx
05c616f5 8bce mov ecx,esi
05c616f7 8bfc mov edi,esp
05c616f9 ff5008 call dword ptr [eax+8] ds:0023:0678137c=05e50c9a

查看eax

0:016> dd eax
06781374 05e3bf39 05c63548 05e50c9a 05e3d2c3
06781384 05e3bf55 05e3c222 05e3c36c 05d49cd0
06781394 05e3c5a3 05e3be79 706f7270 79747265
067813a4 656d614e 00000000 00000000 05e3cc82
067813b4 05decdce 05ba3568 0618e630 0618f360
067813c4 0618ef80 0618f080 0618f180 0618f000
067813d4 0618f0e0 0618f130 0618e5a0 0618e400
067813e4 0618e470 0618e2c0 0618e4d0 0618f1d0

查看ecx ,红色的是eax值,也就是虚表指针
0:016> dd ecx
06dda1c0 06781374 00000000 0715c000 075baf38
06dda1d0 00000016 00000017 06d952c0 00000006
06dda1e0 00000007 00000000 00000000 00000000
06dda1f0 00000000 00000000 00000000 06dd1480
06dda200 0000006a 0000006b 06dd32f0 00000082
06dda210 00000083 00000000 00000000 00000000
06dda220 06db94a0 00000058 00000059 06d9a7a0
06dda230 00000070 00000071 00000000 00000000

然后对绿色的部分查看字符串(因为绿色的更像存储了数据的地址): 

0:016> da 0715c000
0715c000 "@Ar."

0:016> da 075baf38
075baf38 "/1.1.8.1/record/cc.swf"

0:016> da 06d952c0
06d952c0 "record"

0:016> da 06dd1480
06dd1480 "C:/Documents and Settings/Admini"
06dd14a0 "strator/Application Data/Macrome"
06dd14c0 "dia/Flash Player/1.1.8.1/cc.swf/"
06dd14e0 "record.sol"

0:016> da 06dd32f0
06dd32f0 "C:/Documents and Settings/Admini"
06dd3310 "strator/Application Data/Macrome"
06dd3330 "dia/Flash Player/#SharedObjects/"
06dd3350 "TJF64K6G/1.1.8.1/cc.swf/record.s"
06dd3370 "ol"

06dd3370 "ol"
0:016> da 06db94a0
06db94a0 "C:/Documents and Settings/Admini"
06db94c0 "strator/Application Data/Macrome"
06db94e0 "dia/Flash Player/1.1.8.1"

...........

根据这些字符串可以猜测该对象是swf文件中创建的record对象

对这个call下断点:继续运行后又断在此处,在查看esi的值:

0:016> bp Flash32_12_0_0_44+0xf16f9
0:016> g
Breakpoint 1 hit
eax=06eda290 ebx=00000000 ecx=06eda1c0 edx=00000320 esi=06eda1c0 edi=0748f9f8
eip=05d616f9 esp=0748f9f8 ebp=0748fa20 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Flash32_12_0_0_44+0xf16f9:
05d616f9 ff5008 call dword ptr [eax+8] ds:0023:06eda298=77bf18d3
0:016> dd esi
06eda1c0 06eda290 00000000 0725c000 00000000
06eda1d0 00000000 00000000 00000000 00000000
06eda1e0 00000000 00000000 00000000 00000000
06eda1f0 00000000 00000000 00000000 00000000
06eda200 00000000 00000000 00000000 00000000
06eda210 00000000 00000000 00000000 00000000
06eda220 00000000 00000000 00000000 00000000
06eda230 00000000 00000000 00000000 00000000

发现原来绿色的部分以归为0.

在查看栈回溯:

0:016> k
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0748fa20 05d61d4c Flash32_12_0_0_44+0xf16f9
0748fa4c 05d635ac Flash32_12_0_0_44+0xf1d4c
0748fad0 05f3be71 Flash32_12_0_0_44+0xf35ac
0748fad8 05f3bf41 Flash32_12_0_0_44!DllUnregisterServer+0xf2a4c
0748fae0 05d5e62b Flash32_12_0_0_44!DllUnregisterServer+0xf2b1c
0748faf4 05dbb98b Flash32_12_0_0_44+0xee62b
0748fb0c 05ca55b6 Flash32_12_0_0_44+0x14b98b
0748fb44 05e653e4 Flash32_12_0_0_44+0x355b6
0748fb58 05e666a7 Flash32_12_0_0_44!DllUnregisterServer+0x1bfbf
0748fb60 05e666df Flash32_12_0_0_44!DllUnregisterServer+0x1d282
0748fb68 05ca6519 Flash32_12_0_0_44!DllUnregisterServer+0x1d2ba
0748ff90 0628db36 Flash32_12_0_0_44+0x36519
0748ffa0 062d2fcc Flash32_12_0_0_44!IAEModule_IAEKernel_UnloadModule+0xdda96
0748ffb4 7c80b713 Flash32_12_0_0_44!IAEModule_IAEKernel_UnloadModule+0x122f2c

发现DllUnregisterServer这个函数,书中讲该函数主要用于卸载ocx控件,里面包含各类对象的析构函数或者释放对象的操作

重新启动程序附加,对Flash32_12_0_0_44!DllUnregisterServer+0xf2a4c -5 下断, 断下后查看esi(this指针的值).

0:019> dd esi
06fda1c0 06981374 00000000 0735c000 078ccf38
06fda1d0 00000016 00000017 06f952b8 00000006
06fda1e0 00000007 00000000 00000000 00000000
06fda1f0 00000000 00000000 00000000 06fd1480
06fda200 0000006a 0000006b 06fd32f0 00000082
06fda210 00000083 00000000 00000000 00000000
06fda220 06fb94a0 00000058 00000059 06f9a7a0
06fda230 00000070 00000071 00000000 00000000

继续运行直到发生异常时之间会在Flash32_12_0_0_44!DllUnregisterServer+0xf2a4c -5 该处断下2次

一次是在第5次继续运行时,第2次在第6次继续运行时, 在继续运行即第7次继续运行就会发生异常.

说明2次对同一个对象进行释放. 在之中自然很可能存在双重释放漏洞.

原文地址:https://www.cnblogs.com/freesec/p/6421878.html