漏洞简述
因为MS_T120这个channel是内部Channel,MS_T120 Channel被绑定两次(内部绑定一次,然后我们又绑定一次——id不是31)。由于绑定的时候没有限制,所以绑定在两个不同的ID下,因此MS_T120 Channel就有两个引用,假如我们关闭channel,就触发一次free,而我们断开连接系统默认也会free,那就变成了Double Free了(其实Double Free是UAF的特殊情况,因为这个USE是free而已)。
实验环境
win 7 32位 旗舰版
漏洞分析
发送POC
kd> g
*** Fatal System Error: 0x0000000a
(0x00000000,0x00000002,0x00000001,0x840ED940)
Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
Connected to Windows 7 7600 x86 compatible target at (Sun Sep 29 16:59:07.622 2019 (UTC + 8:00)), ptr64 FALSE
Loading Kernel Symbols
...............................................................
................................................................
...............................
Loading User Symbols
................................................................
....................
Loading unloaded module list
.........
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck A, {0, 2, 1, 840ed940}
Probably caused by : termdd.sys ( termdd!_IcaFreeChannel+44 )
Followup: MachineOwner
---------
nt!RtlpBreakWithStatusInstruction:
840b2394 cc int 3
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
IRQL_NOT_LESS_OR_EQUAL (a)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If a kernel debugger is available get the stack backtrace.
Arguments:
Arg1: 00000000, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000001, bitfield :
bit 0 : value 0 = read operation, 1 = write operation
bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status)
Arg4: 840ed940, address which referenced memory
Debugging Details:
------------------
WRITE_ADDRESS: 00000000
CURRENT_IRQL: 2
FAULTING_IP:
nt!ExDeleteResourceLite+87
840ed940 8901 mov dword ptr [ecx],eax
DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT
BUGCHECK_STR: 0xA
PROCESS_NAME: svchost.exe
TRAP_FRAME: 90cc68ac -- (.trap 0xffffffff90cc68ac)
ErrCode = 00000002
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=841b0280 edi=8a998884
eip=840ed940 esp=90cc6920 ebp=90cc6934 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
nt!ExDeleteResourceLite+0x87:
840ed940 8901 mov dword ptr [ecx],eax ds:0023:00000000=????????
Resetting default scope
LAST_CONTROL_TRANSFER: from 84123e71 to 840b2394
STACK_TEXT:
90cc6474 84123e71 00000003 8fa1ca4b 00000065 nt!RtlpBreakWithStatusInstruction
90cc64c4 8412496d 00000003 00000000 840ed940 nt!KiBugCheckDebugBreak+0x1c
90cc688c 8408d7eb 0000000a 00000000 00000002 nt!KeBugCheck2+0x68b
90cc688c 840ed940 0000000a 00000000 00000002 nt!KiTrap0E+0x2cf
90cc6934 90237da2 8a998884 868a7c98 8a998878 nt!ExDeleteResourceLite+0x87
90cc6948 90238060 8a998878 8a998884 868b5670 termdd!_IcaFreeChannel+0x44
90cc6964 9023895f 8a998878 868b5670 00000000 termdd!IcaDereferenceChannel+0x34
90cc69a0 90239354 868b5670 00000005 0000001f termdd!IcaChannelInputInternal+0x3a7
90cc69c8 a60c5dc9 88cc2e24 00000005 0000001f termdd!IcaChannelInput+0x3c
90cc6a00 a60c5e31 a6232008 88cc2e20 88cc2e10 RDPWD!SignalBrokenConnection+0x40
90cc6a18 9023937f a5f73008 00000004 00000000 RDPWD!MCSIcaChannelInput+0x55
90cc6a44 a609d436 88e14884 00000004 00000000 termdd!IcaChannelInput+0x67
90cc726c a609d090 88e14880 88c525a8 840137a0 tssecsrv!CDefaultDataManager::Disconnect+0x3c
90cc72a4 a609ca16 90cc72b4 88e14870 a60a0118 tssecsrv!CFilter::FilterIncomingData+0x222
90cc72d0 9023c772 88c525a8 00000000 868a1cb4 tssecsrv!ScrRawInput+0x60
90cc72f4 a60936a9 868195c4 00000000 868a1cb4 termdd!IcaRawInput+0x5a
90cc7b30 9023b56d 868a1b68 8911f330 8844dc58 tdtcp!TdInputThread+0x34d
90cc7b4c 9023b67c 89073800 00380173 8911f3a0 termdd!_IcaDriverThread+0x53
90cc7b74 9023c00c 8844dc58 8911f330 868b5670 termdd!_IcaStartInputThread+0x6c
90cc7bb4 90239e91 868b5670 8911f330 8911f3a0 termdd!IcaDeviceControlStack+0x50a
90cc7be4 9023a065 8911f330 8911f3a0 88f3ce68 termdd!IcaDeviceControl+0x59
90cc7bfc 840834bc 87c0cbb0 8911f330 8911f330 termdd!IcaDispatch+0x13f
90cc7c14 84284eee 88f3ce68 8911f330 8911f3a0 nt!IofCallDriver+0x63
90cc7c34 842a1cd1 87c0cbb0 88f3ce68 00000000 nt!IopSynchronousServiceTail+0x1f8
90cc7cd0 842a44ac 87c0cbb0 8911f330 00000000 nt!IopXxxControlFile+0x6aa
90cc7d04 8408a42a 0000096c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
90cc7d04 776b64f4 0000096c 00000000 00000000 nt!KiFastCallEntry+0x12a
031cfc4c 776b4cac 6f5b18a7 0000096c 00000000 ntdll!KiFastSystemCallRet
031cfc50 6f5b18a7 0000096c 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
031cfc8c 6f5b25e9 0000096c 00380173 0037f0e0 ICAAPI!IcaIoControl+0x29
031cfcbc 77811174 80000000 031cfd08 776cb3f5 ICAAPI!IcaInputThreadUserMode+0x37
031cfcc8 776cb3f5 0037f0d8 74694ddb 00000000 kernel32!BaseThreadInitThunk+0xe
031cfd08 776cb3c8 6f5b25b2 0037f0d8 00000000 ntdll!__RtlUserThreadStart+0x70
031cfd20 00000000 6f5b25b2 0037f0d8 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: kb
FOLLOWUP_IP:
termdd!_IcaFreeChannel+44
90237da2 8d4644 lea eax,[esi+44h]
SYMBOL_STACK_INDEX: 5
SYMBOL_NAME: termdd!_IcaFreeChannel+44
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: termdd
IMAGE_NAME: termdd.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 4a5bcadf
FAILURE_BUCKET_ID: 0xA_termdd!_IcaFreeChannel+44
BUCKET_ID: 0xA_termdd!_IcaFreeChannel+44
Followup: MachineOwner
---------
可以看到是termdd!_IcaFreeChannel
调用nt!ExDeleteResourceLite
后崩溃了
在free的时候崩溃,那么很有可能就是double free了
在IcaRebindVirtualChannels
和IcaBindVirtualChannels
中我们都可以看到IcaFindChannelByName
函数,我们看看这个函数,通过这个我们知道channelname是在0x94偏移
int __stdcall IcaFindChannelByName(int a1, int a2, char *a3)
{
int v4; // ebx
_DWORD *v5; // esi
int v6; // edi
if ( a2 != 5 )
return IcaFindChannel(a1, a2, 0);
IcaLockChannelTable(a1 + 272);
v4 = a1 + 80;
v5 = *(_DWORD **)(a1 + 80);
if ( v5 == (_DWORD *)(a1 + 80) )
goto LABEL_14;
do
{
v6 = (int)(v5 - 40);
if ( *(v5 - 4) == 5 && !__stricmp((const char *)(v6 + 0x94), a3) ) //通过这个我们知道channelname是在0x94偏移
break;
v5 = (_DWORD *)*v5;
}
while ( v5 != (_DWORD *)v4 );
if ( v5 != (_DWORD *)v4 )
_InterlockedExchangeAdd((volatile signed __int32 *)(v6 + 8), 1u);
else
LABEL_14:
v6 = 0;
IcaUnlockChannelTable(a1 + 272);
return v6;
}
通过上面栈回溯的这一行,我们可以看到free的地址是8a998878
90cc6948 90238060 8a998878 8a998884 868b5670 termdd!_IcaFreeChannel+0x44
看看channel name是不是MS_T120(0x94这个偏移,系统不同,应该不一样的)
kd> da 8a998878+0x94
8a99890c "MS_T120"
可以看到确实是的,我们现在还不能完全确认是MS_T120 channel的UAF。
要进入步确认我们就需要看看这个MS_T120 channel实在哪里创建,是不是释放了两次
现在free函数已经知道了,那么申请内存的函数呢?
我们看看有哪些函数调用了IcaFindChannelByName
可以看到有一个IcaCreateChannel
函数,很可能就是创建Channel,申请内存的函数,我们跟过去,又发现一个_IcaAllocateChannel
进去看看,看到申请的函数了,就是它了
那我们下两个记录断点(这个需要查看汇编,看看ExAllocatePoolWithTag
的返回值,还有_IcaFreeChannel的参数
)
bu termdd!_IcaAllocateChannel+0x1c ".printf \"AllocateChannel Addresss: 0x%x\n\",@eax;.echo;gc"
bu termdd!_IcaFreeChannel ".printf \"FreeChannel Addresss: 0x%x\n\",@esi;.echo;gc"
再发送poc
发送payload
AllocateChannel Addresss: 0x88eecf38
AllocateChannel Addresss: 0x892b4df0
AllocateChannel Addresss: 0x86a10d08
AllocateChannel Addresss: 0x87c63688
AllocateChannel Addresss: 0x88f6e1a8
AllocateChannel Addresss: 0x892b4818
FreeChannel Addresss: 0x88eecf38
FreeChannel Addresss: 0x88f6e1a8
FreeChannel Addresss: 0x892b4818
FreeChannel Addresss: 0x87c63688
FreeChannel Addresss: 0x86a10d08
FreeChannel Addresss: 0x892b4df0
AllocateChannel Addresss: 0x88f6e1a8
AllocateChannel Addresss: 0x892bfc10
AllocateChannel Addresss: 0x88eecf38
AllocateChannel Addresss: 0x87c63688
AllocateChannel Addresss: 0x892b4df0
AllocateChannel Addresss: 0x86a95c50
FreeChannel Addresss: 0x88f6e1a8
FreeChannel Addresss: 0x88f6e1a8
*** Fatal System Error: 0x0000000a
(0x00000000,0x00000002,0x00000001,0x840ED940)
Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
Connected to Windows 7 7600 x86 compatible target at (Fri Sep 27 15:29:54.017 2019 (UTC + 8:00)), ptr64 FALSE
Loading Kernel Symbols
...............................................................
................................................................
..............................
Loading User Symbols
................................................................
....................
Loading unloaded module list
......
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck A, {0, 2, 1, 840ed940}
Probably caused by : termdd.sys ( termdd!_IcaFreeChannel+44 )
Followup: MachineOwner
---------
nt!RtlpBreakWithStatusInstruction:
840b2394 cc int 3
我们看到,对0x88f6e1a8这个地址free了两次
FreeChannel Addresss: 0x88f6e1a8
FreeChannel Addresss: 0x88f6e1a8
那就完全确认这个是UAF,也可以说是DOUBLE FREE(2 free)
在上面的基础,我们再下一个断点,看看是否同一个channel绑定了两个ID
bu termdd!_IcaBindChannel ".echo _IcaBindChannel ==================;kv;gc"
我已经把垃圾信息过滤了,日志如下:
kd> g
AllocateChannel Addresss: 0x88fd5738
_IcaBindChannel ==================
ChildEBP RetAddr Args to Child
a52c99e0 90238be9 88fd5738 00000005 0000001f termdd!_IcaBindChannel (FPO: [Non-Fpo])
a52c9a04 90238d5e 8b1788e9 00000005 891282a7 termdd!_IcaAllocateChannel+0xf1 (FPO: [Non-Fpo])
a52c9a28 90240177 88f9b6b0 00000005 88b89648 termdd!IcaCreateChannel+0x6c (FPO: [Non-Fpo])
a52c9a58 9023a019 88b89648 88b896b8 869454d0 termdd!IcaCreate+0x13d (FPO: [Non-Fpo])
a52c9a70 840834bc 87c0cbb0 88b89648 8694552c termdd!IcaDispatch+0xf3 (FPO: [Non-Fpo])
a52c9a88 8428762d ba4135ef a52c9c30 00000000 nt!IofCallDriver+0x63
a52c9b60 842681d7 87c0cbb0 a57ff6e0 87bf5858 nt!IopParseDevice+0xed7
a52c9bdc 8428e24d 00000000 a52c9c30 00000040 nt!ObpLookupObjectName+0x4fa
a52c9c38 842865ab 013ae714 867ff6e0 a52c9c01 nt!ObOpenObjectByName+0x159
a52c9cb4 84291eb6 03251114 c0100000 013ae714 nt!IopCreateFile+0x673
a52c9d00 8408a42a 03251114 c0100000 013ae714 nt!NtCreateFile+0x34
a52c9d00 776b64f4 03251114 c0100000 013ae714 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ a52c9d34)
......
......
......
_IcaBindChannel ==================
ChildEBP RetAddr Args to Child
a52c9960 9023949b 88fd5738 00000005 00000003 termdd!_IcaBindChannel (FPO: [Non-Fpo])
a52c9b74 9023bf90 86818670 88f17708 86818670 termdd!IcaBindVirtualChannels+0x101 (FPO: [Non-Fpo])
a52c9bb4 90239e91 86818670 88f17708 88f17778 termdd!IcaDeviceControlStack+0x48e (FPO: [Non-Fpo])
a52c9be4 9023a065 88f17708 88f17778 89187758 termdd!IcaDeviceControl+0x59 (FPO: [Non-Fpo])
a52c9bfc 840834bc 87c0cbb0 88f17708 88f17708 termdd!IcaDispatch+0x13f (FPO: [Non-Fpo])
a52c9c14 84284eee 89187758 88f17708 88f17778 nt!IofCallDriver+0x63
a52c9c34 842a1cd1 87c0cbb0 89187758 00000000 nt!IopSynchronousServiceTail+0x1f8
a52c9cd0 842a44ac 87c0cbb0 88f17708 00000000 nt!IopXxxControlFile+0x6aa
a52c9d04 8408a42a 00000840 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
a52c9d04 776b64f4 00000840 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ a52c9d34)
......
......
......
FreeChannel Addresss: 0x88fd5738
FreeChannel Addresss: 0x88fd5738
我们首先确定0x88fd5738这个地址的channel是不是MS_T120
kd> da 0x88fd5738+0x94
88fd57cc "MS_T120"
再看看termdd!_IcaBindChannel
的栈,针对的都是88fd5738
这个地址,但是我们看第3个参数第一次是0x1f(其实就是十进制的31),而第二次是03,那就明显看到将同一个channel绑定了两个ID,导致有了两个引用,所以修复的时候强制指定为31,不管你绑定多少次,ID都是31
a52c99e0 90238be9 88fd5738 00000005 0000001f termdd!_IcaBindChannel (FPO: [Non-Fpo])
a52c9960 9023949b 88fd5738 00000005 00000003 termdd!_IcaBindChannel (FPO: [Non-Fpo])
最后我们再来看看他们调用栈的不同点
第一个调用栈,可以看到从NtCreateFile到termdd!IcaDispatch再到termdd!IcaCreateChannel,就是系统创建的这个channel,分配这个channel后进行了_IcaBindChannel操作
ChildEBP RetAddr Args to Child
a52c99e0 90238be9 88fd5738 00000005 0000001f termdd!_IcaBindChannel (FPO: [Non-Fpo])
a52c9a04 90238d5e 8b1788e9 00000005 891282a7 termdd!_IcaAllocateChannel+0xf1 (FPO: [Non-Fpo])
a52c9a28 90240177 88f9b6b0 00000005 88b89648 termdd!IcaCreateChannel+0x6c (FPO: [Non-Fpo])
a52c9a58 9023a019 88b89648 88b896b8 869454d0 termdd!IcaCreate+0x13d (FPO: [Non-Fpo])
a52c9a70 840834bc 87c0cbb0 88b89648 8694552c termdd!IcaDispatch+0xf3 (FPO: [Non-Fpo])
a52c9a88 8428762d ba4135ef a52c9c30 00000000 nt!IofCallDriver+0x63
a52c9b60 842681d7 87c0cbb0 a57ff6e0 87bf5858 nt!IopParseDevice+0xed7
a52c9bdc 8428e24d 00000000 a52c9c30 00000040 nt!ObpLookupObjectName+0x4fa
a52c9c38 842865ab 013ae714 867ff6e0 a52c9c01 nt!ObOpenObjectByName+0x159
a52c9cb4 84291eb6 03251114 c0100000 013ae714 nt!IopCreateFile+0x673
a52c9d00 8408a42a 03251114 c0100000 013ae714 nt!NtCreateFile+0x34
a52c9d00 776b64f4 03251114 c0100000 013ae714 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ a52c9d34)
......
......
......
而第二次明显是由我们触发的,termdd!IcaDeviceControl到termdd!IcaBindVirtualChannels
ChildEBP RetAddr Args to Child
a52c9960 9023949b 88fd5738 00000005 00000003 termdd!_IcaBindChannel (FPO: [Non-Fpo])
a52c9b74 9023bf90 86818670 88f17708 86818670 termdd!IcaBindVirtualChannels+0x101 (FPO: [Non-Fpo])
a52c9bb4 90239e91 86818670 88f17708 88f17778 termdd!IcaDeviceControlStack+0x48e (FPO: [Non-Fpo])
a52c9be4 9023a065 88f17708 88f17778 89187758 termdd!IcaDeviceControl+0x59 (FPO: [Non-Fpo])
a52c9bfc 840834bc 87c0cbb0 88f17708 88f17708 termdd!IcaDispatch+0x13f (FPO: [Non-Fpo])
a52c9c14 84284eee 89187758 88f17708 88f17778 nt!IofCallDriver+0x63
a52c9c34 842a1cd1 87c0cbb0 89187758 00000000 nt!IopSynchronousServiceTail+0x1f8
a52c9cd0 842a44ac 87c0cbb0 88f17708 00000000 nt!IopXxxControlFile+0x6aa
a52c9d04 8408a42a 00000840 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
a52c9d04 776b64f4 00000840 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ a52c9d34)
......
......
......
那么到最后我们我们关闭连接,我们绑定的MS_T120 channel free了一次,系统自己再free一次,那就造成了double free了
可以看看最后两次free的调用栈,第一次我们主动释放了ID 为03的channel,第二次是我们关闭了连接导致的释放(ID为31),明显看到第二次的栈上有tssecsrv!CDefaultDataManager::Disconnect
(由于多次调试,下面的跟上面的地址会不一样)
FreeChannel Addresss: 0x88ca9d48
ChildEBP RetAddr Args to Child
8e653a10 90238060 88ca9d48 00000000 891e19a8 termdd!_IcaFreeChannel (FPO: [Non-Fpo])
8e653a2c 90238949 88ca9d48 890a0670 00000000 termdd!IcaDereferenceChannel+0x34 (FPO: [Non-Fpo])
8e653a68 90239354 890a0670 00000005 00000003 termdd!IcaChannelInputInternal+0x391 (FPO: [Non-Fpo])
8e653a90 945be1cf 8a9fb0d4 00000005 00000003 termdd!IcaChannelInput+0x3c (FPO: [Non-Fpo])
8e653ab0 945c1548 8a9fb0d4 00000005 00000003 RDPWD!WDICART_IcaChannelInputEx+0x1d (FPO: [Non-Fpo])
8e654148 945bbe42 a41c3008 8a9e9682 00000014 RDPWD!WDW_OnDataReceived+0x240 (FPO: [Non-Fpo])
8e654174 945bbbfd a41c38f0 a41e7134 00000000 RDPWD!SM_MCSSendDataCallback+0x19a (FPO: [Non-Fpo])
8e6541cc 945bba64 00000027 8e654204 8a9e9674 RDPWD!HandleAllSendDataPDUs+0x115 (FPO: [Non-Fpo])
8e6541e8 945d7958 00000027 8e654204 8a9fb0d0 RDPWD!RecognizeMCSFrame+0x32 (FPO: [Non-Fpo])
8e654214 945be63f a41c3008 8a9e96a2 00000001 RDPWD!MCSIcaRawInputWorker+0x3b4 (FPO: [Non-Fpo])
8e654228 9023c772 a41c3008 00000000 8a9e9674 RDPWD!WDLIB_MCSIcaRawInput+0x13 (FPO: [Non-Fpo])
8e65424c 945af46d 8a95a0c4 00000000 8a9e9674 termdd!IcaRawInput+0x5a (FPO: [Non-Fpo])
8e654264 945aef06 8a9e9674 0000002f 8a95a0c0 tssecsrv!CRawInputDM::PassDataToServer+0x2b (FPO: [Non-Fpo])
8e6542a4 945aea16 8e6542b4 8a95a0b0 945b2118 tssecsrv!CFilter::FilterIncomingData+0x98 (FPO: [Non-Fpo])
8e6542d0 9023c772 88c85050 00000000 8a9e9674 tssecsrv!ScrRawInput+0x60 (FPO: [Non-Fpo])
8e6542f4 945a56a9 8918c284 00000000 8a9e9674 termdd!IcaRawInput+0x5a (FPO: [Non-Fpo])
8e654b30 9023b56d 8a9e9528 88580158 8a981b68 tdtcp!TdInputThread+0x34d (FPO: [Non-Fpo])
8e654b4c 9023b67c 8a9f5878 00380173 885801c8 termdd!_IcaDriverThread+0x53 (FPO: [Non-Fpo])
8e654b74 9023c00c 8a981b68 88580158 890a0670 termdd!_IcaStartInputThread+0x6c (FPO: [Non-Fpo])
8e654bb4 90239e91 890a0670 88580158 885801c8 termdd!IcaDeviceControlStack+0x50a (FPO: [Non-Fpo])
8e654be4 9023a065 88580158 885801c8 890a1360 termdd!IcaDeviceControl+0x59 (FPO: [Non-Fpo])
8e654bfc 840834bc 87c0cbb0 88580158 88580158 termdd!IcaDispatch+0x13f (FPO: [Non-Fpo])
8e654c14 84284eee 890a1360 88580158 885801c8 nt!IofCallDriver+0x63
8e654c34 842a1cd1 87c0cbb0 890a1360 00000000 nt!IopSynchronousServiceTail+0x1f8
8e654cd0 842a44ac 87c0cbb0 88580158 00000000 nt!IopXxxControlFile+0x6aa
8e654d04 8408a42a 000007f4 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
8e654d04 776b64f4 000007f4 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8e654d34)
037af99c 776b4cac 6f5b18a7 000007f4 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
037af9a0 6f5b18a7 000007f4 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc (FPO: [10,0,0])
037af9dc 6f5b25e9 000007f4 00380173 029916f8 ICAAPI!IcaIoControl+0x29 (FPO: [Non-Fpo])
037afa0c 77811174 80000000 037afa58 776cb3f5 ICAAPI!IcaInputThreadUserMode+0x37 (FPO: [Non-Fpo])
037afa18 776cb3f5 029916f0 740f4a8b 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
037afa58 776cb3c8 6f5b25b2 029916f0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
037afa70 00000000 6f5b25b2 029916f0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
FreeChannel Addresss: 0x88ca9d48
ChildEBP RetAddr Args to Child
8e653948 90238060 88ca9d48 88ca9d54 890a0670 termdd!_IcaFreeChannel (FPO: [Non-Fpo])
8e653964 9023895f 88ca9d48 890a0670 00000000 termdd!IcaDereferenceChannel+0x34 (FPO: [Non-Fpo])
8e6539a0 90239354 890a0670 00000005 0000001f termdd!IcaChannelInputInternal+0x3a7 (FPO: [Non-Fpo])
8e6539c8 945d7dc9 8a9fb0d4 00000005 0000001f termdd!IcaChannelInput+0x3c (FPO: [Non-Fpo])
8e653a00 945d7e31 a41e7008 8a9fb0d0 8a9fb0c0 RDPWD!SignalBrokenConnection+0x40 (FPO: [Non-Fpo])
8e653a18 9023937f a41c3008 00000004 00000000 RDPWD!MCSIcaChannelInput+0x55 (FPO: [Non-Fpo])
8e653a44 945af436 8a95a0c4 00000004 00000000 termdd!IcaChannelInput+0x67 (FPO: [Non-Fpo])
8e65426c 945af090 8a95a0c0 88c85050 840137a0 tssecsrv!CDefaultDataManager::Disconnect+0x3c (FPO: [Non-Fpo])
8e6542a4 945aea16 8e6542b4 8a95a0b0 945b2118 tssecsrv!CFilter::FilterIncomingData+0x222 (FPO: [Non-Fpo])
8e6542d0 9023c772 88c85050 00000000 8a9e9674 tssecsrv!ScrRawInput+0x60 (FPO: [Non-Fpo])
8e6542f4 945a56a9 8918c284 00000000 8a9e9674 termdd!IcaRawInput+0x5a (FPO: [Non-Fpo])
8e654b30 9023b56d 8a9e9528 88580158 8a981b68 tdtcp!TdInputThread+0x34d (FPO: [Non-Fpo])
8e654b4c 9023b67c 8a9f5878 00380173 885801c8 termdd!_IcaDriverThread+0x53 (FPO: [Non-Fpo])
8e654b74 9023c00c 8a981b68 88580158 890a0670 termdd!_IcaStartInputThread+0x6c (FPO: [Non-Fpo])
8e654bb4 90239e91 890a0670 88580158 885801c8 termdd!IcaDeviceControlStack+0x50a (FPO: [Non-Fpo])
8e654be4 9023a065 88580158 885801c8 890a1360 termdd!IcaDeviceControl+0x59 (FPO: [Non-Fpo])
8e654bfc 840834bc 87c0cbb0 88580158 88580158 termdd!IcaDispatch+0x13f (FPO: [Non-Fpo])
8e654c14 84284eee 890a1360 88580158 885801c8 nt!IofCallDriver+0x63
8e654c34 842a1cd1 87c0cbb0 890a1360 00000000 nt!IopSynchronousServiceTail+0x1f8
8e654cd0 842a44ac 87c0cbb0 88580158 00000000 nt!IopXxxControlFile+0x6aa
8e654d04 8408a42a 000007f4 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
8e654d04 776b64f4 000007f4 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8e654d34)
037af99c 776b4cac 6f5b18a7 000007f4 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
037af9a0 6f5b18a7 000007f4 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc (FPO: [10,0,0])
037af9dc 6f5b25e9 000007f4 00380173 029916f8 ICAAPI!IcaIoControl+0x29 (FPO: [Non-Fpo])
037afa0c 77811174 80000000 037afa58 776cb3f5 ICAAPI!IcaInputThreadUserMode+0x37 (FPO: [Non-Fpo])
037afa18 776cb3f5 029916f0 740f4a8b 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
037afa58 776cb3c8 6f5b25b2 029916f0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
037afa70 00000000 6f5b25b2 029916f0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
漏洞利用简介
由于是double free,其实就是uaf利用思路,我们在第二次free的时候向上回溯
ChildEBP RetAddr Args to Child
8e653948 90238060 88ca9d48 88ca9d54 890a0670 termdd!_IcaFreeChannel (FPO: [Non-Fpo])
8e653964 9023895f 88ca9d48 890a0670 00000000 termdd!IcaDereferenceChannel+0x34 (FPO: [Non-Fpo])
8e6539a0 90239354 890a0670 00000005 0000001f termdd!IcaChannelInputInternal+0x3a7 (FPO: [Non-Fpo])
发现IcaChannelInputInternal有虚函数调用,可以从这劫持控制流
看汇编也就是这里劫持控制流
要控制channel的数据,必须得在其第一次free了之后占位,我们申请同样大小的内存
我们看到申请的大小是0xc8
那么只要控制channel内存的0x8C偏移,劫持v12虚函数指针
但是我们要劫持到哪呢,没有信息泄露啊
现在exp的一般的做法是内核堆喷射,在Non-paged Pool进行堆喷,win7在这个地址上面是没有DEP的,所以直接喷内核shellcode就好了,而且win7的Non-paged Pool的起始地址比较固定,那还好命中一些
一切就绪就可以劫持控制流了
我们也可以看到堆喷射出的shellcode有很多
kd> s 86000000 L 2000000 60 e8 00 00 00 00 5b e8
8688d030 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
8688d088 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
8688d430 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
8688d488 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
8688d830 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
8688d888 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
8688dc30 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
8688dc88 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
86892030 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
86892088 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
86892430 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
86892488 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
86892830 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
86892888 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
86892c30 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
86892c88 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
868c4030 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
868c4088 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
868c4430 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
868c4488 60 e8 00 00 00 00 5b e8-cb ff ff ff 8b 45 00 83 `.....[......E..
868c4830 60 e8 00 00 00 00 5b e8-23 00 00 00 b9 76 01 00 `.....[.#....v..
参考
https://github.com/n1xbyte/CVE-2019-0708
https://www.malwaretech.com/2019/05/analysis-of-cve-2019-0708-bluekeep.html
https://www.malwaretech.com/2019/09/bluekeep-a-journey-from-dos-to-rce-cve-2019-0708.html
补充资料
CVE-2019-0708 微软远程桌面服务远程代码执行漏洞分析之补丁分析