Daily Archives: August 6, 2019

Low-level Reversing of BLUEKEEP vulnerability (CVE-2019-0708)

This work was originally done on Windows 7 Ultimate SP1 64-bit. 

The versions of the libraries used in the tutorial are:

  • termdd.sys version 6.1.7601.17514
  • rdpwsx.dll version 6.1.7601.17828
  • rdpwd.sys version 6.1.7601.17830
  • icaapi.dll version 6.1.7600.16385
  • rdpcorekmts.dll version 6.1.7601.17828

 

The Svchost.exe process

In the Windows NT operating system family, svchost.exe ('Service Host) is a system process that serves or hosts multiple Windows services.

It runs on multiple instances, each hosting one or more services. It's indispensable in the execution of so-called shared services processes, where a grouping of services can share processes in order to reduce the use of system resources.

The tasklist /svc command on a console with administrator permission shows us the different svchost processes and their associated services.

Image 1.png

Also in PROCESS EXPLORER you can easily identify which of the SVChosts is the one that handles RDP connections.(Remote Desktop Services)

image2019-7-1_8-54-22.png

 


STEP 1) Initial reversing to find the point where the program starts to parse my data decrypted

The first thing we'll do is try to see where the driver is called from, for that, once we're debugging the remote kernel with Windbg or IDA, we put a breakpoint in the driver dispatch i.e. in the IcaDispatch function of termdd.sys.

image2019-7-1_9-1-57.png

In windbg bar I type

.reload /f

!process 1 0

PROCESS fffffa8006598b30

SessionId: 0 Cid: 0594 Peb: 7fffffd7000 ParentCid: 01d4

DirBase: 108706000 ObjectTable: fffff8a000f119a0 HandleCount: 662.

Image: svchost.exe

The call stack is

WINDBG>k

Child-SP RetAddr Call Site

fffff880`05c14728 fffff800`02b95b35 termdd!IcaDispatch

fffff880`05c14730 fffff800`02b923d8 nt!IopParseDevice+0x5a5

fffff880`05c148c0 fffff800`02b935f6 nt!ObpLookupObjectName+0x588

fffff880`05c149b0 fffff800`02b94efc nt!ObOpenObjectByName+0x306

fffff880`05c14a80 fffff800`02b9fb54 nt!IopCreateFile+0x2bc

fffff880`05c14b20 fffff800`0289b253 nt!NtCreateFile+0x78

fffff880`05c14bb0 00000000`7781186a nt!KiSystemServiceCopyEnd+0x13

00000000`06d0f6c8 000007fe`f95014b2 ntdll!NtCreateFile+0xa

00000000`06d0f6d0 000007fe`f95013f3 ICAAPI!IcaOpen+0xa6

00000000`06d0f790 000007fe`f7dbd2b6 ICAAPI!IcaOpen+0x13

00000000`06d0f7c0 000007fe`f7dc04bd rdpcorekmts!CKMRDPConnection::InitializeInstance+0x1da

00000000`06d0f830 000007fe`f7dbb58a rdpcorekmts!CKMRDPConnection::Listen+0xf9

00000000`06d0f8d0 000007fe`f7dba8ea rdpcorekmts!CKMRDPListener::ListenThreadWorker+0xae

00000000`06d0f910 00000000`7755652d rdpcorekmts!CKMRDPListener::staticListenThread+0x12

00000000`06d0f940 00000000`777ec521 kernel32!BaseThreadInitThunk+0xd

00000000`06d0f970 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

An instance of CKMRDPListener class is created.

This thread is created, the start address of the thread is the method CKMRDPListener::staticListenThread

image2019-7-1_10-17-43.png

the execution continues here

image2019-7-1_10-20-52.png

here

image2019-7-1_10-22-19.png

here

image2019-7-1_10-23-22.png

IcaOpen is called

image2019-7-1_10-24-34.png

image2019-7-1_14-18-49.png

We can see RDX (buffer) and r8d (size of buffer) both are equal to zero in this first call to IcaOpen.

Next the driver termdd is opened using the call to ntCreateFile

image2019-7-1_9-12-46.png

We arrived to IcaDispatch when opening the driver.

image2019-7-1_10-30-44.png

 

Reversing we can see

image2019-7-1_10-49-54.png

image2019-7-1_11-37-10.png

The MajorFunction value is read here 

image2019-7-1_11-40-31.png

image2019-7-1_11-41-16.png

As MajorFuncion equals 0 it takes us to IcaCreate

image2019-7-1_11-43-26.png

image2019-7-1_11-45-17.png

Inside IcaCreate, SystemBuffer is equal to 0

image2019-7-1_12-51-8.png

image2019-7-1_12-49-25.png

image2019-7-1_12-52-42.png

A chunk of size 0x298 and tag ciST is created, and I call it chunk_CONNECTION.

image2019-7-1_13-10-53.png

chunk_CONNECTION is stored in FILE_OBJECT.FsContext

image2019-7-1_13-14-27.png

I rename FsContext to FsContext_chunk_CONNECTION.

image2019-7-1_13-16-44.png

IcaDispatch is called for second time

Child-SP RetAddr Call Site
fffff880`05c146a0 fffff880`03c96748 termdd!IcaCreate+0x36
fffff880`05c146f0 fffff800`02b95b35 termdd!IcaDispatch+0x2d4
fffff880`05c14730 fffff800`02b923d8 nt!IopParseDevice+0x5a5
fffff880`05c148c0 fffff800`02b935f6 nt!ObpLookupObjectName+0x588
fffff880`05c149b0 fffff800`02b94efc nt!ObOpenObjectByName+0x306
fffff880`05c14a80 fffff800`02b9fb54 nt!IopCreateFile+0x2bc
fffff880`05c14b20 fffff800`0289b253 nt!NtCreateFile+0x78
fffff880`05c14bb0 00000000`7781186a nt!KiSystemServiceCopyEnd+0x13
00000000`06d0f618 000007fe`f95014b2 ntdll!NtCreateFile+0xa
00000000`06d0f620 000007fe`f95018c9 ICAAPI!IcaOpen+0xa6
00000000`06d0f6e0 000007fe`f95017e8 ICAAPI!IcaStackOpen+0xa4
00000000`06d0f710 000007fe`f7dbc015 ICAAPI!IcaStackOpen+0x83
00000000`06d0f760 000007fe`f7dbd2f9 rdpcorekmts!CStack::CStack+0x189
00000000`06d0f7c0 000007fe`f7dc04bd rdpcorekmts!CKMRDPConnection::InitializeInstance+0x21d
00000000`06d0f830 000007fe`f7dbb58a rdpcorekmts!CKMRDPConnection::Listen+0xf9
00000000`06d0f8d0 000007fe`f7dba8ea rdpcorekmts!CKMRDPListener::ListenThreadWorker+0xae
00000000`06d0f910 00000000`7755652d rdpcorekmts!CKMRDPListener::staticListenThread+0x12
00000000`06d0f940 00000000`777ec521 kernel32!BaseThreadInitThunk+0xd
00000000`06d0f970 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

We had seen that the previous call to the driver had been generated here

image2019-7-1_13-36-4.png


When that call ends an instance of the class Cstack is created 

image2019-7-1_13-37-32.png

And the class constructor is called.

image2019-7-1_13-38-2.png


this matches the current call stack

fffff880`05c146a0 fffff880`03c96748 termdd!IcaCreate+0x36
fffff880`05c146f0 fffff800`02b95b35 termdd!IcaDispatch+0x2d4
fffff880`05c14730 fffff800`02b923d8 nt!IopParseDevice+0x5a5
fffff880`05c148c0 fffff800`02b935f6 nt!ObpLookupObjectName+0x588
fffff880`05c149b0 fffff800`02b94efc nt!ObOpenObjectByName+0x306
fffff880`05c14a80 fffff800`02b9fb54 nt!IopCreateFile+0x2bc
fffff880`05c14b20 fffff800`0289b253 nt!NtCreateFile+0x78
fffff880`05c14bb0 00000000`7781186a nt!KiSystemServiceCopyEnd+0x13
00000000`06d0f618 000007fe`f95014b2 ntdll!NtCreateFile+0xa
00000000`06d0f620 000007fe`f95018c9 ICAAPI!IcaOpen+0xa6
00000000`06d0f6e0 000007fe`f95017e8 ICAAPI!IcaStackOpen+0xa4
00000000`06d0f710 000007fe`f7dbc015 ICAAPI!IcaStackOpen+0x83
00000000`06d0f760 000007fe`f7dbd2f9 rdpcorekmts!CStack::CStack+0x189
00000000`06d0f7c0 000007fe`f7dc04bd rdpcorekmts!CKMRDPConnection::InitializeInstance+0x21d
00000000`06d0f830 000007fe`f7dbb58a rdpcorekmts!CKMRDPConnection::Listen+0xf9
00000000`06d0f8d0 000007fe`f7dba8ea rdpcorekmts!CKMRDPListener::ListenThreadWorker+0xae
00000000`06d0f910 00000000`7755652d rdpcorekmts!CKMRDPListener::staticListenThread+0x12
00000000`06d0f940 00000000`777ec521 kernel32!BaseThreadInitThunk+0xd
00000000`06d0f970 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

 

The highlighted text is the same for both calls, the difference is the red line and the upper lines

00000000`06d0f7c0 000007fe`f7dc04bd rdpcorekmts!CKMRDPConnection::InitializeInstance+0x1da

image2019-7-1_13-41-16.png

The second call returns to  

00000000`06d0f7c0 000007fe`f7dc04bd rdpcorekmts!CKMRDPConnection::InitializeInstance+0x21d

image2019-7-1_13-42-34.png

And this second call continues to

image2019-7-1_13-43-46.png

Next

image2019-7-1_13-45-3.png

Next

image2019-7-1_14-20-48.png

We arrived to _IcaOpen, calling ntCreafile for the second time, but now Buffer is a chunk in user allocated with a size different than zero, its size is 0x36.

image2019-7-1_13-46-58.png

This second call reaches IcaDispath and IcaCreate in similar way to the first call.

 

But now SystemBuffer is different than zero, I suppose that SystemBuffer is created, if the buffer size is different to zero.(in the first call buffer=0 → SystemBuffer=0 now buffer!=0 → SystemBuffer is !=0).


SystemBuffer is stored in _IRP.AssociatedIrp.SystemBuffer here 

image2019-7-2_6-33-41.png

 

in the decompiled code

image2019-7-2_6-49-1.png

Previously IRP is moved to r12

image2019-7-2_6-34-34.png

=

image2019-7-1_13-50-29.png


That address is accessed many times over there, so the only way to stop when it is nonzero is to use a conditional breakpoint. 

image2019-7-2_7-50-54.png

image2019-7-2_8-36-51.png

The first time that RAX is different from zero it stops before the second call to CREATE, and if I continue executing, I reach IcaCreate with that new value of SystemBuffer.

image2019-7-2_7-57-25.png

We arrived at this code, the variable named "contador" is zero, for this reason, we landed in IcaCreateStack.

image2019-7-2_8-18-25.png


In IcaCreateStack a new fragment of size 0xBA8 is allocated, I call it chunk_stack_0xBA8.

image2019-7-2_8-21-24.png

I comment the conditional breakpoint part, to avoid stopping and only keep logging.

image2019-7-2_8-44-4.png

 

I repeat the process to get a new fresh log. 

image2019-7-2_8-43-25.png

Summarizing by just executing this two lines of code to create a connection, and even without sending data, we have access to the driver

The most relevent part of the log when connecting is this.

image2019-7-5_7-41-1.png

IcaCreate was called two times, with MajorFunction = 0x0.
The first call allocates CHUNK_CONNECTION, the second call allocates chunk_stack_0xBA8.

We will begin to reverse the data that it receives, for it would be convenient to be able to use Wireshark to analyze the data, although as the connection is encrypted with SSL, in Wireshark we could only see that the encrypted data which does not help us much.

image2019-7-10_7-17-40.png


The data travels encrypted and thus the Wireshark receives it, but we will try to use it all the same.


For this purpose we need to detect the point where the program begins to parse data already decrypted.

image2019-7-10_7-21-1.png

The driver rdpwd.sys is in charge of starting to parse the data already decrypted.

The important point for us is in the function MCSIcaRawInputWorker, where the program started to parse the decrypted code.

image2019-7-10_7-23-32.png

 

STEP 2) Put some conditional breakpoints in IDA PRO to dump to a file the data decrypted

The idea is place a conditional breakpoint in that point, so that each time the execution passes there, it will save the data it has already decrypted in a file, then use that file and load it in Wireshark.

image2019-7-10_7-40-29.png

This will analyze the module rdpwd.sys and I can find its functions in IDA, debugging from my database of termdd.sys, when it stops at any breakpoint of this driver.

image2019-7-10_7-44-21.png

image2019-7-10_7-44-42.png

I already found the important point: if the module rdpwd.sys changes its location by ASLR, I will have to repeat these steps to relocate the breakpoint correctly.

 

address = 0xFFFFF880034675E8

filename=r"C:\Users\ricardo\Desktop\pepe.txt"

size=0x40
out=open(filename, "wb"
dbgr =True
data = GetManyBytes(address, size, use_dbg=dbgr)
out.write(data)
out.close()

This script saves in a file the bytes pointed by variable "address", the amount saved will be given by the variable "size", and saves it in a file on my desktop, I will adapt it to read the address and size from the registers at the point of breakpoint.

address=cpu.r12
size=cpu.rbp
filename=r"C:\Users\ricardo\Desktop\pepe.txt"
out=open(filename, "ab")
dbgr =True
data = GetManyBytes(address, size, use_dbg=dbgr)
out.write(data)

image2019-7-10_8-21-26.png

This will dump the bytes perfectly to the file.

image2019-7-10_8-16-31.png


I will use this script in the conditional breakpoint.

image2019-7-10_8-25-48.png

This script made a raw dump, but wireshark only imports in this format.

image2019-7-10_8-52-4.png

 

address=cpu.r12
size=cpu.rbp
filename=r"C:\Users\ricardo\Desktop\pepe.txt"
out=open(filename, "ab")
dbgr =True
data = GetManyBytes(address, size, use_dbg=dbgr)

str=""
for i in data:
     str+= "%02x "%ord(i)
out.write(str)

in Windows 7 32 bits version this is the important point where the decrypted code is parsed, and we can use this script to dump to a file.

image2019-7-25_7-4-49.png

Windows 7 32 script

address=cpu.eax

size=cpu.ebx

filename=r"C:\Users\ricardo\Desktop\pepefff.txt"

out=open(filename, "ab")

dbgr =True

data = GetManyBytes(address, size, use_dbg=dbgr)

str=""

for i in data:

     str+= "%02x "%ord(i)

out.write(str)

Windows XP 32 bits script 

address=cpu.eax

size=cpu.edi

filename=r"C:\Users\ricardo\Desktop\pepefff.txt"

out=open(filename, "ab")

dbgr =True

data = GetManyBytes(address, size, use_dbg=dbgr)


str=""

for i in data:

    str+= "%02x "%ord(i)

out.write(str)

This is the similar point in Windows XP.

image2019-7-29_9-7-42.png

image2019-7-29_9-9-50.png

 

STEP 3) Importing to Wireshark

This script will save the bytes in the format that wireshark will understand.

When I I"Import from hex dump", I will use the port "3389/tcp" : "msrdp" 

image2019-7-10_9-39-29.png

We load our dump file and put the destination port as 3389, the source port is not important.

 

I add a rule to decode port 3389 as TPKT

image2019-7-10_10-5-44.png

image2019-7-10_9-43-3.png

That file will be decoded as TPKT in wireshark.

That's the complete script.

image2019-7-10_10-30-53.png


Using that script, the dump file is created, when it is imported as a hexadecimal file in Wireshark, it is displayed perfectly.

image2019-8-7_13-3-46.png

This work can be done also by importing the SSL private key in wireshark, but I like to do it in the most manual way, old school type.

STEP 4) More reversing

We are ready to receive and analyze our first package, but first we must complete and analyze some more tasks that the program performs after what we saw before receiving the first package of our data.

We can see that there are a few more calls before starting to receive data, a couple more calls to the driver.

image2019-7-11_7-40-17.png

The part marked in red is what we have left to analyze from the first connection without sending data.

I will modify the conditional breakpoint to stop at the first MajorFunction = 0xE.

image2019-7-11_7-50-23.png

It will stop when MajorFunction = 0xE

image2019-7-11_7-54-22.png

We arrived at IcaDeviceControl.

image2019-7-11_7-55-47.png

We can see that this call is generated when the program accepts the connection, calling ZwDeviceIoControlFile next.

image2019-7-11_8-16-31.png

We can see that IRP and IO_STACK_LOCATION are maintained with the same value, fileobject has changed.

image2019-7-11_8-34-49.png

We will leave the previous structure called FILE_OBJECT for the previous call, and we will make a copy with the original fields called FILE_OBJECT_2, to be used in this call.

image2019-7-11_8-40-35.png

The previous FILE_OBJECT was an object that was obtained from ObReferenceObjectByHandle.

image2019-7-11_8-51-20.png

The new FILE_OBJECT has the same structure but is a different object, for that reason we create a new structure for this.

image2019-7-11_11-16-45.png

We continue reversing ProbeAndCaptureUserBuffers

image2019-7-11_11-50-29.png

A new chunk with the size (InputBufferLenght + OutputBufferLenght) is created.

image2019-7-11_11-47-15.png

Stores the pointers to the Input and Output buffers chunks.

image2019-7-11_11-51-8.png

We can see that IcaUserProbeAddress is similar to nt! MmUserProbeAddress value

image2019-7-12_6-36-39.png

That's used to verify whether a user-specified address resides within user-mode memory areas, or not.

If the address is lower than IcaUserProbeAddress resides in User mode memory areas, and a second check is performed to ensure than the InputUserBuffer + InputBufferLenght address is bigger than InputUserBuffer address.(size not negative)

image2019-7-12_7-9-41.png

Then the data is copied from the InputUserBuffer to the chunk_Input_Buffer that has just allocated for this purpose.

We can see the data that the program copies from InputUserBuffer, it's not data that we send yet.

image2019-7-12_7-11-34.png

Since the OutputBufferLength is zero, it will not copy from OutputUserBuffer to the chunk_OutputBuffer.

image2019-7-12_7-13-47.png

Clears chunk_OutputBuffer and return.

image2019-7-12_7-17-41.png

Returning from ProbeAndCaptureUserBuffers, we can see that this function copies the input and output buffer of the user mode memory to the new chunks allocated in the kernel memory, for the handling of said data by the driver

image2019-7-12_7-21-55.png

The variable "resource" points to IcaStackDispatchTable.

image2019-7-12_7-37-14.png

I frame the area of the table and create a structure from memory which I call _IcaStackDispatchTable.

image2019-7-12_7-45-56.png

image2019-7-12_7-43-49.png

I entered and started to reverse this function.

image2019-7-12_8-28-20.png

The first time we arrived here, the IOCTL value is 38002b.

image2019-7-12_8-44-11.png

We arrived to a call to _IcaPushStack.

image2019-7-12_9-10-25.png

Inside two allocations are performed, i named them chunk_PUSH_STACK_0x488 and chunk_PUSH_STACK_0xA8

image2019-7-12_11-43-51.png

When IOCTL value 0x38002b is used, we reach _IcaLoadSd 

image2019-7-12_11-57-33.png

 

We can see the complete log of the calls to the driver with different IOCTL only in the connection without sending data yet.

IO_STACK_LOCATION 0xfffffa80061bea90L

IRP 0xfffffa80061be9c0L

chunk_CONNECTION 0xfffffa8006223510L

IO_STACK_LOCATION 0xfffffa80061bea90L

IRP 0xfffffa80061be9c0L

FILE_OBJECT 0xfffffa8004231860L

chunk_stack_0xBA8 0xfffffa80068d63d0L

FILE_OBJECT_2 0xfffffa80063307b0L

IOCTL 0x380047L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38002bL

chunk_PUSH_STACK_0x488 0xfffffa8006922a20L

chunk_PUSH_STACK_0xa8 0xfffffa8005ce0570L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38002bL

chunk_PUSH_STACK_0x488 0xfffffa8005f234e0L

chunk_PUSH_STACK_0xa8 0xfffffa8006875ba0L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38002bL

chunk_PUSH_STACK_0x488 0xfffffa8005daf010L

chunk_PUSH_STACK_0xa8 0xfffffa8006324c40L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38003bL

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x3800c7L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38244fL

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38016fL

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x380173L

FILE_OBJECT_2 0xfffffa8006334c90L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x38004bL

IO_STACK_LOCATION 0xfffffa8004ceb9d0L

IRP 0xfffffa8004ceb900L

FILE_OBJECT 0xfffffa8006334c90L

chunk_channel 0xfffffa8006923240L

guarda RDI DESTINATION 0xfffffa8006923240L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x381403L

FILE_OBJECT_2 0xfffffa8006335ae0L

IOCTL 0x380148L


I will put conditional breakpoints in each different IOCTL, to list the functions where each one ends up.

 

The IOCTLs 0x380047, 0x38003b, 0x3800c7, 0x38244f, 0x38016f, 0x38004b, 0x381403  end in _IcaCallStack

image2019-7-15_8-12-31.png

These IOCTLs also reach _IcaCallSd

image2019-7-15_8-13-6.png

IOCTL 0x380148 does nothing 

IOCTL 0x380173 reaches _IcaDriverThread

image2019-7-15_8-28-38.png

And this last one reaches tdtcp_TdInputThread also.

image2019-7-15_8-30-27.png

This function is used to receive the data sended by the user.

 

STEP 5) Receiving data

If we continue running to the point of data entry breakpoint, we can see in the call stack that it comes from tdtcp! TdInputThread.

image2019-7-15_8-57-57.png

 

The server is ready now, and waiting for our first send.

 

We will analyze the packages and next we will return to the reversing.

STEP 6) Analyzing Packets

Negotiate Request package

03 00 00 13 0e e0 00 00 00 00 00 01 00 08 00 01 00 00 00

Step 6.png

Requested Protocol 

image2019-7-15_10-28-28.png

Negotiation Response package

The Response package was similar only with Type=0x2 RDP Negotiation Response

image2019-7-15_10-37-35.png

Connect Initial Package

The package starts with 

"\x03\x00\xFF\xFF\x02\xf0\x80" #\xFF\xFF are sizes to be calculated and smashed at the end

Header 

03 -> TPKT: TPKT version = 3  00 -> TPKT: Reserved = 0  FF -> TPKT: Packet length - high part  FF -> TPKT: Packet length - low part

X.224

 02 -> X.224: Length indicator = 2  f0 -> X.224: Type = 0xf0 = Data TPDU  80 -> X.224: EOT

PDU

"7f 65" .. -- BER: Application-Defined Type = APPLICATION 101,
"82 FF FF" .. -- BER: Type Length = will be calculated and smashed at the end in the Dos sample will be 0x1b2
"04 01 01" .. -- Connect-Initial::callingDomainSelector
"04 01 01" .. -- Connect-Initial::calledDomainSelector
"01 01 ff" .. -- Connect-Initial::upwardFlag = TRUE


"30 19" .. -- Connect-Initial::targetParameters (25 bytes)
"02 01 22" .. -- DomainParameters::maxChannelIds = 34
"02 01 02" .. -- DomainParameters::maxUserIds = 2
"02 01 00" .. -- DomainParameters::maxTokenIds = 0
"02 01 01" .. -- DomainParameters::numPriorities = 1
"02 01 00" .. -- DomainParameters::minThroughput = 0
"02 01 01" .. -- DomainParameters::maxHeight = 1
"02 02 ff ff" .. -- DomainParameters::maxMCSPDUsize = 65535
"02 01 02" .. -- DomainParameters::protocolVersion = 2


"30 19" .. -- Connect-Initial::minimumParameters (25 bytes)
"02 01 01" .. -- DomainParameters::maxChannelIds = 1
"02 01 01" .. -- DomainParameters::maxUserIds = 1
"02 01 01" .. -- DomainParameters::maxTokenIds = 1
"02 01 01" .. -- DomainParameters::numPriorities = 1
"02 01 00" .. -- DomainParameters::minThroughput = 0
"02 01 01" .. -- DomainParameters::maxHeight = 1
"02 02 04 20" .. -- DomainParameters::maxMCSPDUsize = 1056
"02 01 02" .. -- DomainParameters::protocolVersion = 2


"30 1c" .. -- Connect-Initial::maximumParameters (28 bytes)
"02 02 ff ff" .. -- DomainParameters::maxChannelIds = 65535
"02 02 fc 17" .. -- DomainParameters::maxUserIds = 64535
"02 02 ff ff" .. -- DomainParameters::maxTokenIds = 65535
"02 01 01" .. -- DomainParameters::numPriorities = 1
"02 01 00" .. -- DomainParameters::minThroughput = 0
"02 01 01" .. -- DomainParameters::maxHeight = 1
"02 02 ff ff" .. -- DomainParameters::maxMCSPDUsize = 65535
"02 01 02" .. -- DomainParameters::protocolVersion = 2


"04 82 FF FF" .. -- Connect-Initial::userData (calculated at the end in the DoS example will be 0x151 bytes)

"00 05" .. -- object length = 5 bytes
"00 14 7c 00 01" .. -- object
"81 48" .. -- ConnectData::connectPDU length = 0x48 bytes
"00 08 00 10 00 01 c0 00 44 75 63 61" .. -- PER encoded (ALIGNED variant of BASIC-PER) GCC Conference Create Request PDU

"81 FF" .. -- UserData::value length (calculated at the end in the DoS example will be 0x13a bytes)

#-------------
"01 c0 ea 00" .. -- TS_UD_HEADER::type = CS_CORE (0xc001), length = 0xea bytes
"04 00 08 00" .. -- TS_UD_CS_CORE::version = 0x0008004
"00 05" .. -- TS_UD_CS_CORE::desktopWidth = 1280
"20 03" .. -- TS_UD_CS_CORE::desktopHeight = 1024
"01 ca" .. -- TS_UD_CS_CORE::colorDepth = RNS_UD_COLOR_8BPP (0xca01)
"03 aa" .. -- TS_UD_CS_CORE::SASSequence
"09 04 00 00" .. -- TS_UD_CS_CORE::keyboardLayout = 0x409 = 1033 = English (US)
"28 0a 00 00" .. -- TS_UD_CS_CORE::clientBuild = 2600


"45 00 4d 00 50 00 2d 00 4c 00 41 00 50 00 2d 00 " ..
"30 00 30 00 31 00 34 00 00 00 00 00 00 00 00 00 " .. -- TS_UD_CS_CORE::clientName = EMP-LAP-0014


"04 00 00 00" .. -- TS_UD_CS_CORE::keyboardType
"00 00 00 00" .. -- TS_UD_CS_CORE::keyboardSubtype
"0c 00 00 00" .. -- TS_UD_CS_CORE::keyboardFunctionKey


"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " .. -- TS_UD_CS_CORE::imeFileName = ""


"01 ca" .. -- TS_UD_CS_CORE::postBeta2ColorDepth = RNS_UD_COLOR_8BPP (0xca01)
"01 00" .. -- TS_UD_CS_CORE::clientProductId
"00 00 00 00" .. -- TS_UD_CS_CORE::serialNumber
"18 00" .. -- TS_UD_CS_CORE::highColorDepth = 24 bpp
"07 00" .. -- TS_UD_CS_CORE::supportedColorDepths = 24 bpp

"01 00" .. -- TS_UD_CS_CORE::earlyCapabilityFlags

 

"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " .. -- TS_UD_CS_CORE::clientDigProductId

07 -> TS_UD_CS_CORE::connectionType = 7
00 -> TS_UD_CS_CORE::pad1octet

01 00 00 00 -> TS_UD_CS_CORE::serverSelectedProtocol
#---------------

04 c0 0c 00 -> TS_UD_HEADER::type = CS_CLUSTER (0xc004), length = 12 bytes

"15 00 00 00" .. -- TS_UD_CS_CLUSTER::Flags = 0x15 f (REDIRECTION_SUPPORTED | REDIRECTION_VERSION3)
"00 00 00 00" .. -- TS_UD_CS_CLUSTER::RedirectedSessionID

#------------

"02 c0 0c 00" -- TS_UD_HEADER::type = CS_SECURITY (0xc002), length = 12 bytes
"1b 00 00 00" .. -- TS_UD_CS_SEC::encryptionMethods

"00 00 00 00" .. -- TS_UD_CS_SEC::extEncryptionMethods


"03 c0 38 00" .. -- TS_UD_HEADER::type = CS_NET (0xc003), length = 0x38 bytes

In this package we need to set the user channels, and a MS_T120 channel needs to be included in the list.

Erect Domain Package

domain package1.png

 

image2019-7-15_11-25-10.png

  0x04: type ErectDomainRequest

  0x01:  subHeight length = 1 byte

  0x00 : subHeight = 0

  0x01:  subInterval length = 1 byte

  0x00:  subInterval = 0

 

User Attach Packet package

image2019-7-15_13-17-26.png

image2019-7-15_13-25-21.png

We need to analyze the response.

03 00 00 0b 02 f0 80 2e 00 00 07

image2019-7-15_13-42-33.png

The last byte is the initiator, we need to strip from the response to use in the next packet.

Channel Join request package

Building the package

              xv1 = (chan_num) / 256   

             val = (chan_num) % 256   

             
'\x03\x00\x00\x0c\x02\xf0\x80\x38\x00' + initiator + chr(xv1) + chr(val) 

 

For channel 1003 by example

 

              xv1 = (1003) / 256   = 3 

 

             val = (1003) % 256   = 235

 

             
'\x03\x00\x00\x0c\x02\xf0\x80\x38\x00' + initiator + chr(3) + chr(235) 

 

image2019-7-15_14-26-0.png

 

image2019-7-15_14-31-39.png

 

0x38: channelJoinRequest (14)

image2019-7-16_7-39-52.png

All channel join packages are similar, the only thing that changes are the last two bytes that correspond to the channel number. 

Channel Join Confirm Response package

The response was

03 00 00 0f 02 f0 80 3e 00 00 07 03 eb 03 eb

0x3e:channelJoinConfirm (15)

image2019-7-16_8-1-54.png

result: rt_succesful (0x0)

The packet has the same initiator and channelid values than the request to the same channel.

 

When all the channels response the Join Request, the next package sended is send Data Request.

image2019-7-22_11-46-44.png

Client Info PDU or Send Data Request Package

image2019-7-22_11-48-45.png

The remaining packages are important for the exploitation, so for now we will not show them in this first delivery.

STEP 7) The vulnerability

The program allocate a channel MS_T120 by default, the user can set different channels in the packages.

This is the diff of the function named IcabindVirtualChannels

image2019-8-6_12-3-44.png

This is the patch for the Windows XP version, which its logic is similar for every vulnerable windows version, when the program compares the string MS_T120 with the name of each channel, the pointer is forced to be stored in a fixed position of the table, forcing to use the value 0x1f to calculate the place to save it .

In the vulnerable version, the pointer is stored using the channel number to calculate the position in the channel table, and we will have two pointers stored in different locations, pointing to the same chunk.

If the user set a channel MS_T120 and send crafted data to that channel, the program will allocate a chunk for that, but will store two different pointers to that chunk, after that the program frees the chunk, but the data of the freed chunk is incorrectly accessed, performing a USE AFTER FREE vulnerability.

The chunk is freed here

image2019-8-6_13-50-59.png

Then the chunk is accessed after the free here, EBX will point to the freed chunk.

image2019-8-6_13-51-59.png

If a perfect pool spray is performed, using the correct chunk size, we can control the execution flow, the value of EAX controlled by us, EBX point to our chunk, EAX =[EBX+0x8c] is controlled by us too.

image2019-8-6_13-55-45.png

STEP 8) Pool spray

There is a point in the code that let us allocate our data with size controlled, and the same type of pool.

image2019-8-6_14-2-16.png

We can send bunch of crafted packages to reach this point, if this packages have the right size can fill the freed chunk, with our data.

In order to get the right size is necessary look at the function IcaAllocateChannel.

In Windows 7 32 bits, the size of each chunk of the pool spray should be 0xc8.

image2019-8-6_14-7-12.png

For Windows XP 32 bits that size should be 0x8c.

image2019-8-6_14-8-47.png

 

This pool spray remain in this loop allocating with the right size, and we can fill the freed chunk with our own data to control the code execution in the CALL (IcaChannelInputInternal + 0x118)

Be happy

Ricardo Narvaja

English
Latest from CoreLabs
Attribute this content to a different author: 
Ricardo Narvaja
Big text: 
Article
Resource type: 
Articles

The Twin Journey, Part 2: Evil Twins in a Case In-sensitive Land

In the first of this 3-part blog series, we covered the implications of promoting files to “Evil Twins” where they can be created and remain in the system as different entities once case sensitiveness is enabled.

In this 2nd post we try to abuse applications that do not work well with CS changes, abusing years of “normalization” assumptions.

It is worth noting that the impact of this change will vary depending on the target folder.

Out of the box, Windows provides a tool to change CS information by invoking the underlying API NtSetFileInformation with FILE_CASE_SENSITIVE_INFORMATION flags.

This tool contains several checks at user-mode level to restrict the target folder but, as usual, it can be easily bypassed using different path combinations. It is possible to create a tool or invoke the API from PowerShell to remove these checks.

Let us go over the following scenarios:

  • Changing ROOT drive CS:
    1. fsutil restrictions will be bypassed and most of the console will not work unless you specify full paths (mostly due to environment variables broken on case-sensitiveness).

  • Combinations to bypass this check include:
    • \\?\C:\ (by drive letter with long path)
    • \\.\BootPartition\\  (by partition)
    • \\?\Volume{3fb4edf7-edf1-4083-84f8-7fbca215bfee}\ (volume id)
  • Change “protected folders” CS.
    1. For some folders is not enough to be Administrator, but to have other type of ACL’s instead.
    2. TrustedInstaller has the required permissions to do so and… you just need Admin permissions to change the service path:

If you change Windows folder case sensitiveness by using the same technique, Windows will not boot anymore.

These scenarios introduce new unexpected behaviors in the current applications, like for instance:

  • There is a folder with CS enabled and two directories with the same name, different case.
  • Trying to change CS will fail due to “multiple files/folders with the same name already exists” check.
  • Move to recycle bin on one of the folders.
  • Change CS of the folder.
  • Restore the deleted file.
  • The contents of the deleted file overwrite the one originally kept.

Screenshots

Left: Root drive with case sensitive enabled.

Right: Program Files CS changed thanks to Trusted Installer ACL. If an application is not considering the proper case, next time it tries to execute a binary whose name may be normalized (to uppercase) it can spawn a different app.

Watch the video recorded by our expert Cedric Cochin illustrating this technique:

Protection and Detection with McAfee Products

  • Products that rely on SysCore will protect C:\ from case sensitive changes
  • Endpoint Security Expert Rules
  • Active Response:
    • Create a custom collector to query Case sensitiveness of important folders.
    • Search for fsutil executions (or even History Processes if that collector is part of your Active Response version)
      • “Processes where Processes name equals fsutil.exe”
    • MVISION EDR:
      • Realtime search
        • “Processes where Processes name equals fsutil.exe”
      • Search for fsutil execution in the historical view

Artifacts involved:

  • NT attributes change
  • Fsutil execution
  • Trusted Installer service changes

Outcomes for this technique include:

  • A ransomware could create C:\Windows\SYSTEM32 and cause a BSOD on next restart
  • Change dll being loaded or an event stops application from starting

The post The Twin Journey, Part 2: Evil Twins in a Case In-sensitive Land appeared first on McAfee Blogs.

7 Cybersecurity Practices to Protect Organizations from Future Threats

Image Source: Freepik

Cybersecurity is the process of protecting and defending an enterprise’s use of cyberspace by detecting, preventing and responding to any of the malicious attacks like disabling, disrupting, injecting malware, or anything thing else aimed to harm the organization.

At its center, cybersecurity defends your organization from vicious and threat attacks aimed to disrupt and steal information from your organization. Cybersecurity risks are similar to financial and reputational risks as it could directly affect the organization’s growth, driving the costs up and adversely affecting the revenue.

If you’re a part of an organization, and especially, if your workplace stocks sensitive information of individuals or clients involved, then this is an ideal time to educate yourself regarding cybersecurity and ways to safeguard your organization against cyber attacks and threats with the help of professionals who hold cybersecurity certifications.

  1. Enable Firewall

In football, there’s a famous phrase- “Attack is the first line of defense.” and in the scenario of cybersecurity, the firewall serves the very same purpose. The firewall protects unauthorized access to your system, mail services, and websites. In addition to the external firewall, considering installing internal firewalls for the work network as well as on for your home network, in cases if employees decide to work remotely.

  1. Conduct Cybersecurity Awareness Training

According to a recent survey, 77% of those who took part admitted that they use free public WiFi networks to access work-related documents or have connected their corporate devices to such networks which are most often unsecured. Only 17% of them said that they use a VPN when outside the office.

 

33% of insider threat attacks have caused due to mistakes or irrationality from the employees; these mistakes are preventable. As per the SANS, cybersecurity experts have reported that their knowledge programs have made a tangible impact on the organization’s security.

  1. Back-Up Company Data

It is one of the prioritized security practices among cybersecurity professionals. Backing up your data could be a lifesaver. In the advent of Trojan horses and Ransomware, small mistakes could lead to complete data wipeout.

 

Handling the back-up data is also equally important. Make sure back-ups are thoroughly protected, encrypted, and updated frequently.

  1. Multi-Factor Authentication

MFA (Multi-factor authentication) is considered to be one of the prominent cybersecurity practices among professionals. MFA adds an extra layer of protection to any data that is protected by this means.

 

Even in an unfortunate situation if any malicious attack gets to your sensitive data, it would further require to pass additional authentication layers of security to get to the actual data and cause any harm. Also, these practices are notification enabled, and any susceptible attempt is reported to the user by multiple communication channels.

  1. Bring Your Own Device (BYOD) Policies 

BYOD policies have been around since 2004, and ever since it has managed only to boom among the corporate culture. It is predicted that by 2022, the BYOD market will hit $367B. Also, research data has it that the companies who opt for BYOD, save $350/year for every employee.

Sure, letting the employees use their own devices for work increases their productivity, but it does make the organization’s data susceptible to cyber attacks. With the increasing use of the mobile device, smartwatches, and wearables, and IoT products companies that are serious about BYOD or using cloud storage, in general, should consider the security vulnerability and implement stringent policies to protect their valuable information. MDM (Mobile Device Management) software enables the cybersecurity or the IT team to implement security settings and configurations that let them secure all devices connected to company networks

  1. Manage Passwords

Changing passwords is a pain, and employees often distance themselves from such action unless the HR or the IT team forcefully sit next to them and make them change their passwords.

Password management is a critical part of corporate security, and in today’s BYOD world, it is essential to be extra cautious about data protection. Privileged access accounts are diamond mine for the attackers, and when it comes to the security of these accounts, unauthorized access could doom the growth of the organization.

  1. Document Cybersecurity Policies

Business often operates on verbal bases when it comes to security while ideally, they should be considering documenting every policy and training operations related to cyberspace. Multiple online portals like the Small Business Administration (SBA) & FCC’s Cyberplanner 2.0 Cybersecurity portal provides checklists, online instruction, and information distinct to protect online businesses.

Conclusion

Always remember the fact that one unsafe click could result in complete data wipeout or leak, and education yourselves about the cybersecurity practices that could help your organization prevent itself from threats. Not just to an organization’s security, it is also helpful to any individual who uses the internet. Keeping yourselves afloat regarding such practices is a part of the job as all kinds of engagement is slowly and swiftly happening on the cloud.

 

———————

 

Author Bio:

Gaurav Belani is a senior SEO and content marketing analyst at The 20 Media, a content marketing agency that specializes in data-driven SEO. He has more than seven years of experience in digital marketing and loves to read and write about AI, ML, cybersecurity and other emerging technologies. In his spare time, he enjoys watching movies and listening to music. Connect with him on Twitter @belanigaurav.

 

The post 7 Cybersecurity Practices to Protect Organizations from Future Threats appeared first on CyberDB.

The McAfee Americas Channel Promise

In my 26th year at McAfee, my fourth leading the Americas Channel Organization, I wanted to take a step back and ask my team a few questions:

  • What does being a part of the McAfee Channel team mean to our partners, to our company, and to our channel employees?
  • Why do we do what we do?
  • What value do we bring?

Over the course of eight weeks, I worked with the core Americas Channel management team and a third-party vendor to frame out the McAfee Americas Channel Promise. This exercise forced us to dig deep into our organization and define what matters, articulate the value of our channel, and more. I would like to share what we launched last month at the Americas Channel All Hands event, because I hope it’s something you can attach yourselves to as a McAfee partner.

I AM McAfee Channel

The Americas Channel is a vital growth engine for increasing market share for McAfee.

We Bring

Scale and market presence

Competitive insights

Deeper customer advocacy

Operational and financial stability

Managed services

Advocacy for partners

Our Value Proposition

Together, we will deliver on our customers’ business outcomes. The channel provides McAfee with the ability to scale effectively and efficiently with our McAfee differentiators. The best way to achieve scale is through a robust, purpose-built channel.

We do this through resellers, system integrators, distributors, OEMs (original equipment manufacturers), security consultants, and service providers.

Our channel community enables us to meet the demands of an ever-changing landscape of customer expectations, consumption models, competitive threats, and shifting markets.

Without Our Channel Community, McAfee Would:

Lack alternative consumption and purchasing options for customers

Sacrifice sales and operational capacity

Increase financial risk and exposure

Lose scale and market presence globally

Miss out on competitive insights

Incur additional go-to-market costs

I AM McAfee Channel

To Our Channel Partners

We are your partner and your primary advocate inside McAfee.

To Our Company

We are a growth catalyst that helps deliver on our customers’ value drivers at scale, provide deeper customer relationships, and position McAfee as the cybersecurity market leader.

To Our Channel Employees

We are the place to be within McAfee. We embody our company values in all that we do, and we believe that “Together is power.” We foster strong partnerships with and through our channel partners to increase McAfee’s market share and maintain our position as cybersecurity leader, build deeper customer relationships, and help keep the world safe from cyberthreats.

I AM McAfee Channel, and I hope that if you’re a partner with McAfee, this message resonates with you. I know it does with our team, and we are proud to be a part of this partnership with you. Your feedback is welcome in the comments.

The post The McAfee Americas Channel Promise appeared first on McAfee Blogs.