Wednesday, December 17, 2008

NULL pointer exploitation

Today Sun finally released a fix for a kernel bug I reported to them back in 2007 (TKADV2008-015). The vulnerability is a NULL pointer dereference that can be reliably exploited under x86 platforms (32 and 64bit).

This movie demonstrates the exploitability of the vulnerability. The exploit first escapes from a restricted non-global Solaris zone back into the global zone, drops all restrictions and then gains root privileges.

# mdb -k unix.4 vmcore.4
Loading modules: [ unix krtld genunix specfs dtrace cpu.AuthenticAMD.15 uppc
pcplusmp ufs ip sctp usba fcp fctl nca lofs audiosup zfs random sppp crypto md 
cpc fcip logindmux ptm nfs ]

> $c
0x44434241(c, dad0ebc0) 
ip_sioctl_tunparam+0xfc(0, d46c0200, d6d352b0, d6849380, fecc6e80, d6d352b0)
ip_process_ioctl+0x2a9(0, d6d352b0, d6849380, fecc6e80)
ip_wput_nondata+0x248(0, d6d352b0, d6849380, 0)
ip_output+0x376()
ip_wput+0x14(d6d352b0, d6849380)
putnext+0x1b7(d6d352b0, d6849380)
ar_wput+0x131(d6d31430, d6849380)
putnext+0x1b7(d6d31430, d6849380)
strdoioctl+0x4f1(d6218508, d55d6d10, 0, 100003, 1, d60225b0)
strioctl+0x3b1(d6d64a80, 40586993, 8061020, 100003, 1, d60225b0)
spec_ioctl+0x48(d6d64a80, 40586993, 8061020, 100003, d60225b0, d55d6f78)
fop_ioctl+0x24(d6d64a80, 40586993, 8061020, 100003, d60225b0, d55d6f78)
ioctl+0x199()
sys_sysenter+0x100()

> $r
%cs = 0x0158            %eax = 0x44434241   
%ds = 0xd4d80160        %ebx = 0x000007d0
%ss = 0x000c            %ecx = 0x000007d0
%es = 0x0160            %edx = 0xd561c000
%fs = 0x0000            %esi = 0x00000000
%gs = 0x01b0            %edi = 0x00000000

%eip = 0x44434241  
%ebp = 0xd55d6a8c
%esp = 0xd55d6a48

Sunday, December 14, 2008

Stack Buffer Overflow in MPlayer

I just released an advisory (TKADV2008-014) describing the details of a stack buffer overflow vulnerability I found in the current versions of MPlayer. See the diff of the SVN trunk.

Thursday, December 04, 2008

Tricky Integer Arithmetic

Even that it is known for quite a while that arithmetic errors can lead to integer overflow vulnerabilities (in C) these security issues still tend to confuse a lot of C programmers. A good example is the latest vulnerability I found in the VLC media player: an integer overflow vulnerability that leads to an exploitable heap overflow (see TKADV2008-013 for a detailed description).

The vulnerability itself is quite straight forward:

[...]
891 static void ReadRealIndex( demux_t *p_demux )
892 {
...
900      uint32_t      i_index_count;
...
920 [1]  i_index_count = GetDWBE( &buffer[10] );
...
931 [2]  p_sys->p_index = 
932            (rm_index_t *)malloc( sizeof( rm_index_t ) * (i_index_count+1) );
...
938 [3]  for( i=0; i < i_index_count; i++ )
939      {
940         if( stream_Read( p_demux->s, buffer, 14 ) < 14 )
941             return ;
942
943 [7]     if( GetWBE( &buffer[0] ) != 0 )
944         {
945            msg_Dbg( p_demux, "Real Index: invaild version of index entry %d ",
946                               GetWBE( &buffer[0] ) );
947            return;
948         }
949
950 [4]     p_sys->p_index[i].time_offset = GetDWBE( &buffer[2] );
951 [5]     p_sys->p_index[i].file_offset = GetDWBE( &buffer[6] );
952 [6]     p_sys->p_index[i].frame_index = GetDWBE( &buffer[10] );
[...]

[1] User supplied data from the RealMedia file gets copied into "i_index_count".

[2] The value of "i_index_count" is used to calculate the size of a heap buffer. If the value of "i_index_count" is big enough (e.g. 0x15555555) an integer overflow occurs while calculating the size of the heap buffer. As a consequence it is possible to allocate a small heap buffer by supplying a big value for "i_index_count".

[3] The value of "i_index_count" is used as a counter in this for() loop.

[4] User controlled data from the RealMedia file gets copied into the previously allocated heap buffer (see [2]). As "i" is used as an array index and the for() loop is executed until "i < i_index_count" it is possible to overflow the heap buffer with user controlled data from the RealMedia file. [5] See [4] [6] See [4] As there is also an exit condition that can be triggered to stop the overflow (see [7]) at any given point this leads to a fully controllable heap overflow that can be exploited by a (remote) attacker to execute arbitrary code in the context of VLC. The VideoLAN team "fixed" the vulnerability with the following patch (original link):
diff --git a/modules/demux/real.c b/modules/demux/real.c
index 7574739..ddfb64d 100644
--- a/modules/demux/real.c
+++ b/modules/demux/real.c
@@ -932,16 +932,13 @@ static void ReadRealIndex( demux_t *p_demux )
msg_Dbg( p_demux, "Real Index: Does next index exist? %d ",
GetDWBE( &buffer[16] )  );

-    p_sys->p_index =
-      (rm_index_t *)malloc( sizeof( rm_index_t ) * (i_index_count+1) );
+    p_sys->p_index = calloc( i_index_count + 1, sizeof( rm_index_t ) );
if( p_sys->p_index == NULL )
{
msg_Err( p_demux, "Memory allocation error" ); 
return;
}

-    memset( p_sys->p_index, 0, sizeof(rm_index_t) * (i_index_count+1) );
-
for( i=0; i < i_index_count; i++ )
{
if( stream_Read( p_demux->s, buffer, 14 ) < 14 )
The main difference is that the VLC maintainers exchanged malloc() with calloc(). The idea itself is not bad: calloc() was "hardened" on different platforms so that integer overflows due to multiplication within calloc() should be catched. But in this case the integer overflow still happens as the first argument to calloc() is calculated with the addition "i_index_count + 1". A user supplied "i_index_count" of UINT_MAX (0xffffffff) will cause an integer overflow within the first parameter of calloc() and therefore only allocate a 0 byte buffer. Please notice that calloc(0, sizeof(rm_index_t)) will not return a NULL pointer but a pointer into the legal heap on at least platforms like Windows and Linux. Later on the "i_index_count" value is used as a counter in the for() loop. This still leads to an exploitable heap overflow. Well, I reported this issue back to the VLC maintainers resulting in the following "second patch" (original link):
diff --git a/modules/demux/real.c b/modules/demux/real.c
index ddfb64d..cfadef2 100644
--- a/modules/demux/real.c
+++ b/modules/demux/real.c
@@ -925,14 +925,14 @@ static void ReadRealIndex( demux_t *p_demux )

msg_Dbg( p_demux, "Real Index : num : %d ", i_index_count );

-    if( i_index_count == 0 )
+    if( i_index_count > ( 0xffffffff / sizeof( rm_index_t ) ) )
return;

if( GetDWBE( &buffer[16] ) > 0 )
msg_Dbg( p_demux, "Real Index: Does next index exist? %d ",
GetDWBE( &buffer[16] )  );

-    p_sys->p_index = calloc( i_index_count + 1, sizeof( rm_index_t ) );
+    p_sys->p_index = malloc( ( i_index_count + 1 ) * sizeof( rm_index_t ) );
if( p_sys->p_index == NULL )
{
msg_Err( p_demux, "Memory allocation error" ); 
@@ -954,12 +954,13 @@ static void ReadRealIndex( demux_t *p_demux )
p_sys->p_index[i].time_offset = GetDWBE( &buffer[2] );
p_sys->p_index[i].file_offset = GetDWBE( &buffer[6] );
p_sys->p_index[i].frame_index = GetDWBE( &buffer[10] );
-        msg_Dbg( p_demux, "Real Index: time %d file %d frame %d ",
-                        p_sys->p_index[i].time_offset,
-                        p_sys->p_index[i].file_offset,
-                        p_sys->p_index[i].frame_index );
-
+        msg_Dbg( p_demux,
+                 "Real Index: time %"PRIu32" file %"PRIu32" frame %"PRIu32,
+                 p_sys->p_index[i].time_offset,
+                 p_sys->p_index[i].file_offset,
+                 p_sys->p_index[i].frame_index );
}
+    memset( p_sys->p_index + i_index_count, 0, sizeof( rm_index_t ) );
}
In this patch the malloc() function is used again instead of calloc(). But what is more interesting is the security check that was introduced with this second patch: if( i_index_count > ( 0xffffffff / sizeof( rm_index_t ) ) ). It is now checked if ( 0xffffffff / sizeof( rm_index_t ) ) is smaller than the user supplied value of i_index_count. If so, the heap buffer will not be allocated and the vulnerability can't be reached anymore. The result of the division ( 0xffffffff / sizeof( rm_index_t ) ) is 0x15555555. Now what happens if i_index_count has a value of 0x15555555? Well, the security check can be successfully bypassed and the integer overflow happens again in the calculation of the size argument of malloc(): p_sys->p_index = malloc( ( i_index_count + 1 ) * sizeof( rm_index_t ). I also reported that back to the VLC maintainers. As always, the VLC maintainers reacted promptly and provided another patch to fix the issue. It looks like the following (original link):
diff --git a/modules/demux/real.c b/modules/demux/real.c
index ef3a816..fa5f1ee 100644
--- a/modules/demux/real.c
+++ b/modules/demux/real.c
@@ -921,7 +921,7 @@ static void ReadRealIndex( demux_t *p_demux )

msg_Dbg( p_demux, "Real Index : num : %d ", i_index_count );

-    if( i_index_count > ( 0xffffffff / sizeof( rm_index_t ) ) )
+    if( i_index_count >= ( 0xffffffff / sizeof( rm_index_t ) ) )
return;

if( GetDWBE( &buffer[16] ) > 0 )

Is the vulnerability now *really* fixed with this patch? As I said, integer arithmetic can be quite tricky :>

Sunday, November 30, 2008

Oops ... I did it again ;)

I found another exploitable security vulnerability in VLC media player. This time it's an integer overflow that leads to a fully controllable heap overflow.

Thursday, November 06, 2008

More VLC vulnerabilities

Yesterday, the VideoLAN team released a new version of their VLC media player. The new version fixes two stack overflow vulnerabilities I found in the RealText (TKADV2008-011) and CUE (TKADV2008-012) demuxers of VLC.

This movie shows the exploitability of TKADV2008-011.

Monday, October 20, 2008

Back to the 90s - The VLC Case

Today I released a security advisory (TKDV2008-010) describing the details of a stack overflow that affects the quite popular VLC media player. The vulnerability can be trivially exploited by a (remote) attacker to execute arbitrary code in the context of VLC media player under all supported plattforms including Microsoft Vista. I can hear you say: "Vista? Na, that's not possible! I'm quite sure the security features 'shipped' with Vista (DEP/NX, ASLR, Stack Cookies/Canaries, etc.) prevent you from reliably exploiting such a stack overflow!". Well, these security features would indeed make it very hard (or nearly impossible) to reliably exploit this stack overflow under Vista. But none of them are used by VLC.


The mentioned security features are compile-time options of Microsoft Visual C++ 2005 SP1 and later:

/GS for Stack Cookies/Canaries
/DynamicBase for ASLR
/NXCompat for DEP/NX
/SafeSEH for Exception Handler Protection
Only software that is compiled/linked with these options provides the mentioned security features. The Windows releases of VLC media player are build using the cygwin environment not Visual C++. Excerpt from the VLC build instructions:
[...]
Building VLC from the source code
=================================
[...]
- natively on Windows, using cygwin (www.cygwin.com) with or without the POSIX emulation layer. This is the preferred way to compile vlc if you want to do it on Windows.
[...]
UNSUPPORTED METHODS
-------------------
[...]
- natively on Windows, using Microsoft Visual Studio. This will not work.
[...]

Don't get me wrong, VLC is a very usefull media player that does a superb job in playing all these different kinds of media formats. But as it currently does not take advantage of the mentioned compile-time and run-time defenses of Microsoft Vista it reminds my of the 90s: stack overflow + payload on stack + call esp == reliable (remote) code execution. Someone should really make VLC build with Visual C++ so that all these security features are turned on under Vista ... any volunteers ;)

Sunday, September 21, 2008

Vulnerability rediscovery, XSS and a WebEx bug

Every security researcher who is hunting for bugs hates this particular situation: a vulnerability that you have found and reported to the vendor gets rediscovered and publicly disclosed by someone else. This just happened to me again but this time I decided to also disclose an advisory for the vulnerability.

The vulnerability I'm talking about affects an activex component of WebEx (CVE-2008-2737). See my advisory for a detailed technical description.

I found the vulnerability in april 2008 and Elazar Broad rediscovered it in june 2008. He also informed WebEx/Cisco about the vulnerability but then publicly disclosed it the full disclosure way. In his advisory he states: "When I reported this issue to the vendor, they had stated that they were aware of it, but would not say whether it was the result of an internal audit or an independent researcher". Well, that independent researcher was me ...

Now to the vulnerability: it is a classical stack overflow that can be reliably exploited to execute arbitrary code in the browser of the victim. As WebEx is *the* web conferencing tool there should be a lot of vulnerable browsers out there.

One interesting thing regarding the vulnerability is that while this control is marked as safe for scripting, it has been designed so that it can only be run from the "webex.com" domain. In practice this requirement can be bypassed through the use of any Cross Site Scripting (XSS) vulnerabilities in the WebEx domain. Well, at least in this scenario reflected (non-persistent) XSS turns out to be a *real* security threat ;)

Wednesday, September 17, 2008

Finally fixed ...

The vulnerability described in TKADV2008-008 can be exploited to get reliable code execution in kernel mode under all Windows versions supported by G DATA. See this fancy poc flash movie. The movie is from 2007 as G DATA needed 294 days (!) to provide a fixed version of their products.

The vulnerability is only fixed in the *new* G DATA 2009 products. As far as I know G DATA will *not* provide a fix for AntiVirus, InternetSecurity or TotalCare 2008.

Tuesday, September 09, 2008

Linux Kernel and silent fixes

The Linux Kernel 2.6.26.4 provides a patch called "sctp: fix potential panics in the SCTP-AUTH API" that fixes some NULL pointer dereferences and an information disclosure vulnerability I found in the SCTP-AUTH API.

The NULL pointer dereferences can be used to cause a kernel panic (denial of service) as an unprivileged user but seem not to be exploitable to execute code in the kernel context.

The information disclosure vulnerability - which is btw. not mentioned at all in the patch nore in the kernel changelogs - can be reliably exploited to read arbitrary (kernel) memory as an unprivileged user.

It's quite disturbing to see that security vulnerabilites are indeed silently fixed by some linux kernel developers / maintainers.

Tuesday, August 12, 2008

Reliable code execution with TKADV2008-006

The CA HIPS kernel driver vulnerability described in TKADV2008-006 can be exploited using the common kernel pool (heap) write4 primitive. It is therefore possible to get reliable code execution in kernel mode under all supported plattforms (Windows 2000, XP and 2003).

DRIVER_CORRUPTED_EXPOOL (c5)
An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is caused by drivers that have corrupted the system pool. Run the driver verifier against any new (or suspect) drivers, and if that doesn't turn up the culprit, then use gflags to enable special pool.

Arguments:
Arg1: 41414141, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000001, value 0 = read operation, 1 = write operation
Arg4: 80543a03, address which referenced memory

[...]

FAULTING_IP:
nt!ExDeferredFreePool+fd
80543a03 8913 mov dword ptr [ebx],edx

DEFAULT_BUCKET_ID: DRIVER_FAULT

PROCESS_NAME: poc_xp.exe

TRAP_FRAME: f5c7faa0 -- (.trap 0xfffffffff5c7faa0)
ErrCode = 00000002
eax=0012df50 ebx=41414141 ecx=0012e050 edx=42424242 esi=81e44938 edi=000001ff eip=80543a03 esp=f5c7fb14 ebp=f5c7fb54 iopl=0 nv up ei ng nz ac pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010297
nt!ExDeferredFreePool+0xfd:
80543a03 8913 mov dword ptr [ebx],edx ds:0023:41414141=????????
Resetting default scope

LAST_CONTROL_TRANSFER: from 804f79d7 to 80526fc8

STACK_TEXT:
[...] 00000003 f5c7f9b0 00000000 nt!RtlpBreakWithStatusInstruction
[...] 00000003 41414141 80543a03 nt!KiBugCheckDebugBreak+0x19
[...] 0000000a 41414141 00000002 nt!KeBugCheck2+0x574
[...] 0000000a 41414141 00000002 nt!KiTrap0E+0x233
[...] 0012df58 00000000 0012ef70 nt!ExDeferredFreePool+0xfd
[...] 0012ef70 00000000 0012ef70 nt!ExFreePoolWithTag+0x489
[...] 0012ef70 81b81770 f6c87a01 nt!IoFreeMdl+0x6e
WARNING: Stack unwind information not available. Following frames may be wrong.
[...] 00000000 00000000 00000000 kmxfw+0x2b90

Thursday, August 07, 2008

A crude way to detect VMware

Yesterday the kernel maintainers fixed an information disclosure vulnerability I found in the Linux kernel a few days ago (see TKADV2008-2005). One interesting thing about the vulnerability is that it can be used to detect if a system is running as a guest inside VMware.

The vulnerability itself allows an unprivileged user to access and read arbitrary memory addresses including memory pages owned by the kernel. As I did some tests to check if the vulnerability is indeed exploitable I encountered a weird VMware problem: every time a special kernel memory range is accessed, VMware crashes reproducible.

That means that every similiar kernel bug that allows to read arbitrary kernel memory can be used to crash and therefore detect VMware as an unprivileged user.

With superuser privileges it is of course possible to reproduce the VMware crash without the need of a kernel vulnerability. All you have to do is write and load a kernel module that sweeps over the kernel memory space.