Tuesday, May 22, 2012

A wide view of the Intel Digital Random Number Generator (DRNG)

Let's focus on two important lessons security history has taught us over the years:
  • Cryptography relies heavily on random numbers
  • Implementing cryptography in the right way is not easy
To point out and stress these concepts, I would like to recall a significant episode... Do you remember Debian/OpenSSL Fiasco in 2008? Briefly, due to some modifications to the code, as a side effect, the only "random" value that was used in the PRNG was the current process ID.

This resulted in the PRNG having only 32,767 different possible seed values (i.e. the default maximum process ID in Linux systems), that means... a lot of people using the same keys to perform sensitive operations! Or... in other words, as a famous quote by Robert Coveyou says: "random number generation is too important to be left to chance".

So, wouldn't it be nice if we could rely on a high quality standard implementation, that is also performing, reliable under worst case assumptions and secure against software attacks? Yes, of course. Is it possible? Well, lucky day... yes, it is!

The news is quite recent and comes from Intel, who developed a Digital Random Number Generator (DRNG) following the Cascade Construction RNG model (however this isn't Intel's first attempt to provide RNG). 

The input is taken from an entropy source in order to supply an entropy pool. This pool is then used to provide nondeterministic random numbers that repeatedly seed a Cryptographically Secure PRNG (CSPRNG). Finally, the CSPRNG generates cryptographically secure random numbers.

Intel's DRNG is implemented in hardware on the processor itself, so the entropy source is built-in and is, indeed, a reliable source of high-quality entropy.

The implementation consists of three logical components that correspond to the ones described above, except for the entropy pool that is replaced by a conditioner to improve the performances.

Here is how it is structured: 

  • The entropy source uses thermal noise over the silicon in order to generate streams of random bits, which are then fed to an AES-CBC-MAC based conditioner.  
  • The conditioner combines pairs of blocks of 256 bit from the entropy source and produces one block of 256 bit that will seed the AES-CTR based Deterministic Random Bit Generator (DRBG), that is the hardware CSPRNG.  
  • The DRBG provides a wider number of random bytes available from the hardware module: it generates long streams of bytes from the seed, thus improving the final number of random bytes being produced.

Note that the employment of block ciphers in this contest is not a novelty and it is a common approach in PRNG construction, as modern block ciphers are designed to perform good pseudo-random permutations.
Also, the hardware approach adopted by Intel gives additional advantages as the self-contained hardware module is isolated from software attacks on its internal state. 
How does a user interface to DRNG? A new Intel 64 instruction is introduced: RDRAND. Intel documentation provides all the necessary details to its usage, and also to determine whether the underlying platform supports the instruction (this can be done using the CPUID instruction).
Basically, RDRAND can be invoked to obtain a 16-, 32-, or 64-bit random integer value. For example, "RDRAND eax" stores a 32-bit random number in eax.
After calling it, the carry flag will either be 1 if a random value was available at the time the RDRAND instruction was executed, or 0 if it wasn't.
It seems that Intel is spending a lot of effort in providing crypto dedicated instructions (remember the AES instructions set?) and I hope this trend will bring us many other ones. I think that it will take some years to see this implementation spreading around and become popular, but I also think this may be the solution to many practical problems in everyday cryptography: good work, Intel!

Sunday, May 13, 2012

A look at object confusion vulnerability (CVE-2012-0779) in Adobe Flash

Recently I noticed an interesting blog entry in contagiodump: it was about a new attack using CVE-2012-0779, that involves a MS Word file named "World Uyghur Congress Invitation.doc". It got me curious, so I started analysing it.

To investigate this file I used FileInsight, it is a simple hex editor that supports OLE format. I searched in the object inside the ObjectPool field and found some useful information.

In particular, you can find this object in the CompObj stream:
and a CLSID in the OCXDATA stream:
Also, in the last screenshot you can notice a JavaScript code listing an url that points to a Flash file:
I searched for this data and discovered that ScriptBridge is the name for AE24FDAE-03C6-11D1-8B76-0080C744F389, and found a nice article, explaining that this CLSID allows the navigation to an url without requiring any user interaction. This is really a powerful feature for malicious purposes!
Now let's focus on "essais.swf". This is a CWS file (a compressed SWF file), but we don't care about this detail as opening it with Trillix will unpack it by default.
This file is encoded by DoSwf:
We need to unpack the DoSwf layer in order get to the exploit code, but Trillix fails at decompiling the ActionScript of the packed Flash file. So i searched for other similar Flash files related to this attack, and found "exp.swf" from the jsunpack website.
This time Trillix is able to show us the decompiled ActionScript code of the packer:
Here we go, this code shows a xor encryption! Searching for a decryption script I found this one, but it doesn't work as it is.

So, I rearranged the code to make it work with this sample. I only had to use the "decrypt" function properly, and fix the following lines:
byte block_size = (byte) (buffer.get() - 1);
byte key = (byte) (buffer.get() - 1);
int offset = buffer.getInt() - 2;
int length = buffer.getInt() - 2;
Once decrypted and decompressed, the result will be a file containing three concatenated Flash files. The first and third Flash files are from the DoSWF and only contain some metadata and license information. The original malicious Flash file is the second one, and you can find it here (thanks to contagiodump for the link).

This is our final exploit! If we give a look at the code we will find: a shellcode (line 23); a heapspray (line 133); some other stuff including cookies usage, a Rtmp connection and some control on the Windows version.

I'm unable to determine where the vulnerability is: maybe the exploit works only on certain software conditions, or maybe the Rtmp connection is involved in some way, or there's some other missing detail... I don't know! I think that I haven't got enough information to fully understand what happens, but at least here it's an idea of how the attack is structured: more complicated than usual .doc based attacks!

One final detail about the .doc file: as usual a exe file is appended at the end of the OLE, this one is a PE encrypted with a byte-per-byte xor using 0x70 as key (bytes that are 0 or 0x70 are not encrypted).

Saturday, May 5, 2012

Analysis of a Microsoft Windows Kernel "Win32k.sys" Local Denial of Service Vulnerability

A couple of days ago, a Microsoft Windows Kernel "Win32k.sys" Local Denial of Service Vulnerability (BID: 53343has been published on the exploit-db website: follow this link to get the poc code.
As I wanted to investigate this vulnerability, I compiled the code in Visual Studio and built the executable.
Then I ran it on a dedicated virtual machine, and…

Yeah… I got the dreaded Blue Screen Of Death! So… it worked :P

This screen gives us useful information; we can read: "PAGE_FAULT_IN_NONPAGED_AREA" and then "STOP: 0x00000050 (0xFF7C98CC, 0x00000000, 0x805D33A5, 0x00000000)".

Now, if we read the documentation we get "Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA". But, what does that mean?  Well, in the Windows Kernel, the memory is divided into two kinds: paged memory and nonpaged memory.
Basically the difference is that the former can be swapped to the disk while the latter can't. So, the error means that the kernel referenced an invalid memory location within the area reserved to the nonpaged memory.

The parameters of the Bug Check stand respectively for: memory address being referenced ("0xFF7C98CC"); read operation/write operation (0 in this case indicates that read operation mode is selected); address that referenced memory (0x805D33A5, the line of code where the crash happened); reserved (that is not set).

I opened ntkrnlpa.exe with IDA, I loaded the debug symbols and searched for the address that caused the crash, getting this:

PAGE:004FC3A5                 cmp     word ptr [ecx], 23h

This means that ecx cointans an invalid pointer.
Also, IDA tells us that we are inside the function:

PAGE:004FC370 ; int __stdcall RtlpGetIntegerAtom(ULONG CrashPointer,int)
Then, analyzing the code of the function:
PAGE:004FC372                 push    ebp
PAGE:004FC373                 mov     ebp, esp
PAGE:004FC375                 push    ecx
PAGE:004FC376                 push    ecx
PAGE:004FC377                 mov     ecx, [ebp+CrashPointer]
PAGE:004FC37A                 test    ecx, 0FFFF0000h
PAGE:004FC380                 jnz     short Crash_Dead
PAGE:004FC3A5 Crash_Dead:
PAGE:004FC3A5                 cmp     word ptr [ecx], 23h

we see that the invalid pointer is the first parameter of the function, and it is accessed without being properly validated.
Besides, we can see that the memory location being accessed is the same that is passed from the user mode POC code:

UINT c[]={ 

Thus we know that the pointer from user mode is never validated or modified in any way.

From the cross-references we see that the previous function is called by these two functions:


Both these functions don't validate the pointer either. In particular we can see it from the code of the second one:

PAGE:004FC692                 push    18h
PAGE:004FC694                 push    offset dword_4031A0
PAGE:004FC699                 call    __SEH_prolog
PAGE:004FC69E                 push    [ebp+arg_0]
PAGE:004FC6A1                 call    _RtlpLockAtomTable@4;
PAGE:004FC6A6                 test    al, al
PAGE:004FC6A8                 jnz     short loc_4FC6B4
PAGE:004FC6AA                 mov     eax, 0C000000Dh
PAGE:004FC6AF                 jmp     loc_4FC76C
PAGE:004FC6B4                 xor     edi, edi
PAGE:004FC6B6                 mov     [ebp+ms_exc.disabled], edi
PAGE:004FC6B9                 lea     eax, [ebp+var_20]
PAGE:004FC6BC                 push    eax    ; int
PAGE:004FC6BD                 mov     esi, [ebp+PointerCrash]
PAGE:004FC6C0                 push    esi   ; CrashPointer
PAGE:004FC6C1                 call    _RtlpGetIntegerAtom@8 ; 

This function is the one used in the exploit.

Again, from the cross-references we got that this function is called by NtFindAtom, which instead does valid proper validation:

PAGE:00535B81                 mov     ecx, [ebp+CopyOfCrashPointer]
PAGE:00535B87                 lea     eax, [ecx+ebx]
PAGE:00535B8A                 cmp     eax, ecx
PAGE:00535B8C                 jb      short Exception
PAGE:00535B8E                 cmp     eax, _MmUserProbeAddress
PAGE:00535B94                 jbe     short CodeOk
PAGE:00535B96                 call    _ExRaiseAccessViolation@0 ;

NtFindAtom is a dead end for us, so we switch the analysis on win32k.sys.

From the source code we see the code making a call to a function named NtUserCreateWindowEx. In particular, this code is a home made syscall to a Kernel API in win32k.sys:

       mov eax,0x1157
       mov edx,7FFE0300h
       call  dword ptr[edx]

Thus loading win32k.sys in IDA, and searching for this API, we find the function:

.text:BF8344E2 ; int __cdecl xxxUserCreateWindowEx(char,int,SIZE_T NumberOfBytes,int pData,int,int,int,int,int,int,int,int,int,int,int)

This function executes a little bit of code until it gets to the following lines:

.text:BF833E54                 mov     eax, [ebp+DataBlock]
.text:BF833E57                 test    eax, 0FFFF0000h
.text:BF833E5C                 jz      short Skip
.text:BF833E5E                 push    dword ptr [eax+8]
.text:BF833E61                 call    _UserFindAtom@4 ;

DataBlock corresponds to the buffer of data which is stored in the variable "c" in the source code.

The code takes a DWORD at the offset + 8 from such a buffer, and this DWORD is exactly 0xff7c98cc… that is... the vulnerable pointer!
We get into UserFindAtom, and we finally find the missing link:
.text:BF80DA19                 mov     edi, edi
.text:BF80DA1B                 push    ebp
.text:BF80DA1C                 mov     ebp, esp
.text:BF80DA1E                 push    ecx
.text:BF80DA1F                 and     [ebp+NtStatus], 0
.text:BF80DA23                 lea     eax, [ebp+NtStatus]
.text:BF80DA26                 push    eax
.text:BF80DA27                 push    [ebp+CrashPointer]
.text:BF80DA2A                 push    _UserAtomTableHandle
.text:BF80DA30                 call    ds:__imp__RtlLookupAtomInAtomTable@12 
this is where win32k.sys transfers control to the vulnerable function RtlLookupAtomInAtomTable in ntkrnlpa.exe passing the non-validated pointer.
This pointer was set in the exploit code to be 0xff7c98cc, which is a memory address that falls within the kernelspace region, and the problem is that nowhere in this series of calls this pointer is validated to make sure it is accessible.
  usermode app
 UserFindAtom                win32k.sys

    V                        ntkrnlpa.exe

This vulnerability does not seem to be exploitable for code execution, it looks like the security impact is a Denial Of Service.
However, we have seen that there are two functions potentially vulnerable:

there are several calls from win32k.sys to them (I found 8 to UserFindAtom and 30 to UserAddAtom). Remember, these two functions won't validate the pointer they take in input, so it is the caller's responsibility to validate it.
I had a quick look at all the other functions that call these two, and at a first glance they seem to perform proper validation.
Thus I am not going to spend too much time on them, but if anyone wants and finds anything, please let me know!
P.S. As it is, the exploit won't work on 64 bit OSes (I tested Windows 7 Professional and Windows 8 Consumer Preview). This may be due to the pointers being 64bit sized, for one thing (or maybe win32k.sys syscall interface is not the same, I haven't checked).