Sunday, December 27, 2009

New version of checksec.sh

Modern Linux distributions offer some mitigation techniques to make it harder to exploit software vulnerabilities reliably. Mitigations such as RELRO, NoExecute (NX), Stack Canaries, Address Space Layout Randomization (ASLR) and Position Independent Executables (PIE) have made reliably exploiting any vulnerabilities that do exist far more challenging. The checksec.sh script is designed to test what standard Linux OS security features are being used.

While other mitigations do exist (e.g. grsecurity.net) these are not tested.

What's new with version 1.1:

* New '--proc-libs' option. This option instructs checksec.sh to test the loaded libraries of a process. 

* Additional information on ASLR results (--proc, --proc-all, --proc-libs)
  Thanks to Anthony G. Basile of the Tin Hat project for the hint.
  
* Additional CPU NX check (--proc, --proc-all, --proc-libs)
I tested the new version on Ubuntu 9.10, openSUSE 11.2 and Fedora 12.

You can download the new version 1.1 of checksec.sh here.

Example of additional information on ASLR and NX results:



Example of the new '--proc-libs' option:


Thursday, November 05, 2009

I joined the Twitterverse

Of course, you should follow me on twitter here ;)

Wednesday, September 09, 2009

The Ringtone Massacre

If you are an iPhone or iPod user then get the latest update of iPhone OS released today. This new version fixes a heap buffer overflow I found in CoreAudio of iPhone OS (see TKADV2009-007). The bug may be exploited by maliciously crafted AAC or MP3 files. This includes ringtones on the iPhone.

I'm sure you are only listening to AAC/MP3's you got from trusted sources, right? :>

Saturday, May 16, 2009

!exploitable vs. TKADV2009-006 vs. Static Analysis Tools

The following is the result of Microsoft's !exploitable Windbg extension while analyzing the libsndfile bug I released today (TKADV2009-006).

(3a8.62c): Access violation - code c0000005 (!!! second chance !!!)
eax=00000000 ebx=0000ffff ecx=000029f1 edx=00000003 esi=02158008 edi=02166000
eip=7c34126b esp=04dbfa8c ebp=04dbfac0 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000207
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for 
C:\Programme\Winamp\NSCRT.dll - 
NSCRT!memset+0x49:
7c34126b f3ab            rep stos dword ptr es:[edi]

0:015> !load winext\msec.dll
0:015> !exploitable -v
HostMachine\HostUser
Executing Processor Architecture is x86
Debuggee is in User Mode
Debuggee is a live user mode debugging session on the local machine
Event Type: Exception
Exception Faulting Address: 0x2166000
Second Chance Exception Type: STATUS_ACCESS_VIOLATION (0xC0000005)
Exception Sub-Type: Write Access Violation

Exception Hash (Major/Minor): 0x21214e2e.0x67415f20

Stack Trace:
NSCRT!memset+0x49
libsndfile!Ordinal9+0x290c2
libsndfile!Ordinal9+0x1994f
libsndfile!Ordinal9+0x19eb9
libsndfile!sf_readf_double+0xd5f
libsndfile!sf_open+0x89
in_wave+0x1276
kernel32!GetModuleFileNameA+0x1ba
Instruction Address: 0x7c34126b

Description: User Mode Write AV
Short Description: WriteAV
Exploitability Classification: EXPLOITABLE
Recommended Bug Title: Exploitable - User Mode Write AV starting at 
NSCRT!memset+0x49 (Hash=0x21214e2e.0x67415f20)

User mode write access violations that are not near NULL are exploitable.
Erik, the libsndfile maintainer, also published an interesting blog entry regarding the security measures he took to secure libsndfile. Amongst others he checked his code base with static analysis tools. Unfortunately the bug described in TKADV2009-006 (as well as others) were missed. What a surprise :)

Saturday, April 04, 2009

TKADV2009-005

Today I released an advisory (TKADV2009-005) describing an integer overflow vulnerability in the Quicktime demuxer of xine-lib.

Debug session of the bug

tk@tk-desktop:~$ gdb -q xine

Adjusting the debugger environment:
(gdb) set disassembly-flavor intel

(gdb) directory /home/tk/Desktop/xine-lib-1.1.16.2/src/demuxers/
Source directories searched: /home/tk/Desktop/xine-lib-1.1.16.2/src/demuxers:$cdir:$cwd

(gdb) symbol-file /usr/lib/debug/usr/lib/xine/plugins/1.24/xineplug_decode_qt.so
Load new symbol table from "/usr/lib/debug/usr/lib/xine/plugins/1.24/xineplug_decode_qt.so"? (y or n) y
Reading symbols from /usr/lib/debug/usr/lib/xine/plugins/1.24/xineplug_decode_qt.so...done.

Set a breakpoint after calloc():
(gdb) break demux_qt.c:1550
No source file named demux_qt.c.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (demux_qt.c:1550) pending.

Now let xine play our poc movie file:
(gdb) r Desktop/xine-lib_QuickTime_Bug/poc2.mov 
Starting program: /usr/bin/xine Desktop/xine-lib_QuickTime_Bug/poc2.mov
[Thread debugging using libthread_db enabled]
[New Thread 0xb78646d0 (LWP 11878)]
Dies ist xine (X11 gui) - Ein freier Video-Player v0.99.6cvs.
(c) 2000-2007 Das xine Team.
[New Thread 0xb76edb90 (LWP 11881)]
[New Thread 0xb6eecb90 (LWP 11882)]
[New Thread 0xb5d60b90 (LWP 11883)]
[New Thread 0xb513bb90 (LWP 11884)]
[New Thread 0xb48b8b90 (LWP 11885)]
[New Thread 0xb3eb6b90 (LWP 11886)]
[New Thread 0xb32ccb90 (LWP 11887)]
[New Thread 0xb28feb90 (LWP 11888)]
[New Thread 0xb1cf2b90 (LWP 11889)]
[New Thread 0xb14f1b90 (LWP 11890)]
[New Thread 0xb0cf0b90 (LWP 11891)]
[New Thread 0xb0106b90 (LWP 11892)]
[New Thread 0xaf905b90 (LWP 11893)]
[New Thread 0xaed1bb90 (LWP 11894)]
[New Thread 0xadcf3b90 (LWP 11895)]
[New Thread 0xad4f2b90 (LWP 11896)]
[Switching to Thread 0xb78646d0 (LWP 11878)]

Breakpoint 1, parse_moov_atom (info=0x8ec1978, moov_atom=0x8ec19e8 "", bandwidth=1544000)
at demux_qt.c:1550
warning: Source file is more recent than executable.
1550       if (!trak->time_to_sample_table) {

(gdb) x/1i $eip
0xaccdefc8 <parse_moov_atom+1528>: test   eax,eax

EAX points to the overflow heap buffer allocated by calloc():
(gdb) i r eax
eax            0x8e48d18 149196056

Content of the heap (before the overflow):
(gdb) x/8x 0x8e48d18
0x8e48d18: 0x00000000 0x00000000 0x00000000 0x00000000
0x8e48d28: 0x00000000 0x00000029 0x00000000 0xade1bcae

Breakpoint after the first written bytes:
(gdb) break 1563
Breakpoint 2 at 0xaccdf052: file demux_qt.c, line 1563.

(gdb) c
Continuing.

Breakpoint 2, parse_moov_atom (info=0x8ec1928, moov_atom=0x8ec1998 "???]}??O?j??q?\212_?\022\177;J?w??h~/?o?]\204\032?_??`??\a????L?\234G?", bandwidth=0x178f40) at demux_qt.c:1565
1565       trak->time_to_sample_table[j].count = 0; /* terminate with zero */

The heap buffer is indeed overflowed with user controlled data from the Quicktime movie file:
(gdb) x/8x 0x8e48d18
0x8e48d18: 0x41414141 0x42424242 0x43434343 0x44444444
0x8e48d28: 0x45454545 0x46464646 0x47474747 0x48484848

(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.

Saturday, February 28, 2009

checksec

In my last blog post I described a script called "checkrelro.sh" that can be used to check if ELF executables or processes support the RELRO mitigation technique. I extended that script to also support other memory corruption mitigation techniques. The extended version is now called "checksec.sh" and is able to check Linux ELF executables and running processes if they support the following mitigation techniques: RELRO, Stack Canaries, NX, PIE and ASLR (for more information see Ubuntu, SUSE/Novell, Red Hat).

Example 1 - Check a single executable (Ubuntu 8.10):



Example 2 - Check all executables in a directory (Ubuntu 8.10):



Example 3 - Check a single process by name (Ubuntu 8.10):



Example 4 - Check all running processes (Ubuntu 8.10):



I successfully tested checksec under Ubuntu 8.10 and openSUSE 11.1.

Get checksec.sh here.   UPDATE (27.12.2009): A newer version of checksec.sh is available here. See also this link.

Saturday, February 21, 2009

RELRO - A (not so well known) Memory Corruption Mitigation Technique

After a discussion with Sebastian Krahmer about RELRO I did a little writeup on this memory corruption mitigation technique for my own purpose. I also decided to post it here just in case someone else might find this information valuable.
RELRO is a generic mitigation technique to harden the data sections of an ELF binary/process. There are two different "operation modes" of RELRO:

Partial RELRO
  • compiler command line: gcc -Wl,-z,relro
  • the ELF sections are reordered so that the ELF internal data sections (.got, .dtors, etc.) precede the program's data sections (.data and .bss)
  • non-PLT GOT is read-only
  • GOT is still writeable
Full RELRO
  • compiler command line: gcc -Wl,-z,relro,-z,now
  • supports all the features of partial RELRO
  • bonus: the entire GOT is also (re)mapped as read-only
Interim conclusion: In case of a bss or data overflow bug partial and full RELRO protect the ELF internal data sections from being overwritten (as the ELF sections are reordered). Only full RELRO mitigates the well known technique of modifying a GOT entry to get control over the program execution flow.

Testcases

The checkrelro.sh script can be used to test if an ELF binary or a process supports RELRO.

Recent Linux distris have partial RELRO enabled by default (e.g. Ubuntu 8.10 and openSUSE 11.1). There is therefore no difference between "gcc testcase.c" and "gcc -Wl,-z,relro testcase.c" on these platforms.

Testcase 1 (Ubuntu 8.10): Partial RELRO

File: testcase.c
#include <stdio.h>

int
main (int argc, char *argv[])
{
  size_t *p = (size_t *)strtol (argv[1], NULL, 16);

  p[0] = 0x41414141;
  printf ("RELRO: %p\n", p);

  return 0;
}

This test program tries to write the value 0x41414141 at a given memory address.

Compiling "testcase" with partial RELRO:
$ gcc -g -o testcase testcase.c

Test binary:
$ ./checkrelro.sh --file testcase
testcase - partial RELRO

Get GOT entry of printf(3):
$ readelf -r ./testcase | grep printf
0804a00c  00000407 R_386_JUMP_SLOT   00000000   printf

Try to modify the GOT address:
$ gdb -q ./testcase
(gdb) r 0x0804a00c
Starting program: /home/tk/Desktop/testcase 0x0804a00c

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
If only partial RELRO is used, it is still possible to modify arbitrary GOT entries to gain control of the execution flow of a process.

Testcase 2 (Ubuntu 8.10): Full RELRO

Compiling "testcase" with full RELRO:
$ gcc -g -Wl,-z,relro,-z,now -o testcase testcase.c

Test binary:
$ ./checkrelro.sh --file testcase 
testcase - full RELRO

Get GOT entry of printf(3):
$ readelf -r ./testcase | grep printf
08049ff8  00000407 R_386_JUMP_SLOT   00000000   printf

Try to modify the GOT address:
$ gdb -q ./testcase
(gdb) r 0x08049ff8
Starting program: /home/tk/Desktop/testcase 0x08049ff8

Program received signal SIGSEGV, Segmentation fault.
0x0804842b in main (argc=Cannot access memory at address 0x0
) at testcase.c:8
8               p[0] = 0x41414141;

If full RELRO is enabled, the attempt to overwrite a GOT address leads to an error as the GOT section is mapped read-only.

How is RELRO used in recent Linux distris?

The checkrelro.sh script is also able to enumerate all processes running on a system and test each one of them if they have RELRO enabled.

Testcase 3 (Ubuntu 8.10): Inspect all running processes
$ sudo ./checkrelro.sh --proc-all
init (1) - full RELRO
vmware-guestd (15296) - no RELRO
gedit (15771) - partial RELRO
sshd (16181) - partial RELRO
sshd (16193) - partial RELRO
bash (16196) - no RELRO
notification-da (16626) - partial RELRO
udevd (2542) - partial RELRO
getty (4382) - partial RELRO
getty (4383) - partial RELRO
getty (4390) - partial RELRO
getty (4393) - partial RELRO
getty (4395) - partial RELRO
acpid (4563) - partial RELRO
syslogd (4677) - partial RELRO
dd (4729) - partial RELRO
klogd (4731) - partial RELRO
dbus-daemon (4754) - partial RELRO
avahi-daemon (4776) - partial RELRO
avahi-daemon (4777) - partial RELRO
sshd (4806) - partial RELRO
cupsd (4849) - partial RELRO
hald (4913) - partial RELRO
console-kit-dae (4916) - partial RELRO
hald-runner (4979) - partial RELRO
hald-addon-inpu (4999) - partial RELRO
hald-addon-stor (5004) - partial RELRO
hald-addon-acpi (5009) - partial RELRO
bluetoothd (5055) - partial RELRO
NetworkManager (5110) - partial RELRO
wpa_supplicant (5115) - partial RELRO
nm-system-setti (5118) - partial RELRO
gdm (5148) - partial RELRO
gdm (5151) - partial RELRO
Xorg (5155) - partial RELRO
system-tools-ba (5171) - partial RELRO
atd (5206) - partial RELRO
cron (5234) - partial RELRO
dhclient (5236) - partial RELRO
getty (5333) - partial RELRO
gnome-keyring-d (5425) - partial RELRO
x-session-manag (5436) - partial RELRO
dbus-launch (5554) - partial RELRO
dbus-daemon (5555) - partial RELRO
pulseaudio (5558) - partial RELRO
gconf-helper (5561) - partial RELRO
gconfd-2 (5563) - partial RELRO
seahorse-agent (5569) - partial RELRO
gnome-keyring-d (5574) - partial RELRO
gnome-settings- (5575) - partial RELRO
metacity (5577) - partial RELRO
gvfsd (5599) - partial RELRO
gnome-panel (5600) - partial RELRO
nautilus (5603) - partial RELRO
bonobo-activati (5606) - partial RELRO
gvfs-fuse-daemo (5610) - partial RELRO
gnome-screensav (5630) - partial RELRO
gvfs-hal-volume (5634) - partial RELRO
gvfs-gphoto2-vo (5636) - partial RELRO
trashapplet (5640) - partial RELRO
gvfsd-trash (5643) - partial RELRO
gvfsd-burn (5646) - partial RELRO
fast-user-switc (5650) - partial RELRO
mixer_applet2 (5653) - partial RELRO
nm-applet (5655) - partial RELRO
evolution-alarm (5658) - partial RELRO
trackerd (5659) - partial RELRO
update-notifier (5662) - partial RELRO
tracker-applet (5663) - partial RELRO
bluetooth-apple (5664) - partial RELRO
python (5666) - partial RELRO
gnome-power-man (5669) - partial RELRO
gnome-terminal (5733) - partial RELRO
gnome-pty-helpe (5735) - partial RELRO

# of Processes: 74
No RELRO      : 2
Partial RELRO : 71
Full RELRO    : 1

Testcase 4 (openSUSE 11.1): Inspect all running processes
tk@linux-0skt:~> sudo ./checkrelro.sh --proc-all
init (1) - partial RELRO
acpid (1599) - partial RELRO
klogd (1621) - partial RELRO
syslog-ng (1635) - partial RELRO
dbus-daemon (1645) - partial RELRO
hald (1734) - partial RELRO
console-kit-dae (1746) - partial RELRO
hald-runner (1818) - partial RELRO
hald-addon-inpu (1880) - partial RELRO
hald-addon-stor (1929) - partial RELRO
rpcbind (1930) - partial RELRO
hald-addon-stor (1931) - partial RELRO
hald-addon-acpi (1933) - partial RELRO
kdm (1966) - partial RELRO
X (1982) - partial RELRO
auditd (2173) - partial RELRO
audispd (2175) - partial RELRO
avahi-daemon (2194) - partial RELRO
kdm (2227) - partial RELRO
nscd (2286) - full RELRO
NetworkManager (2290) - partial RELRO
cupsd (2291) - partial RELRO
modem-manager (2293) - partial RELRO
dbus-launch (2294) - partial RELRO
dbus-daemon (2297) - partial RELRO
wpa_supplicant (2299) - partial RELRO
nm-system-setti (2302) - partial RELRO
master (2377) - partial RELRO
pickup (2391) - partial RELRO
qmgr (2392) - partial RELRO
cron (2404) - partial RELRO
dhclient (2475) - partial RELRO
vmware-guestd (2484) - partial RELRO
sshd (2485) - partial RELRO
startpar (2488) - partial RELRO
mingetty (2607) - partial RELRO
mingetty (2609) - partial RELRO
mingetty (2611) - partial RELRO
mingetty (2613) - partial RELRO
mingetty (2615) - partial RELRO
mingetty (2622) - partial RELRO
startkde (2658) - partial RELRO
dbus-launch (3025) - partial RELRO
dbus-daemon (3029) - partial RELRO
kdeinit4 (3048) - partial RELRO
klauncher (3052) - partial RELRO
kded4 (3085) - partial RELRO
kwrapper4 (3289) - partial RELRO
ksmserver (3290) - partial RELRO
kwin (3292) - partial RELRO
plasma (3299) - partial RELRO
knotify4 (3300) - partial RELRO
krunner (3305) - partial RELRO
nepomukserver (3307) - partial RELRO
nepomukservices (3309) - partial RELRO
nepomukservices (3310) - partial RELRO
nepomukservices (3311) - partial RELRO
kaccess (3315) - partial RELRO
kmix (3325) - partial RELRO
amarok (3327) - partial RELRO
policykit-kde (3331) - partial RELRO
pulseaudio (3334) - partial RELRO
klipper (3336) - partial RELRO
kupdateapplet (3340) - partial RELRO
knetworkmanager (3341) - partial RELRO
kdeinit (3346) - partial RELRO
dcopserver (3349) - partial RELRO
klauncher (3351) - partial RELRO
kded (3354) - partial RELRO
kio_file (3379) - partial RELRO
konsole (3421) - partial RELRO
bash (3423) - partial RELRO
sshd (3436) - partial RELRO
sshd (3439) - partial RELRO
bash (3440) - partial RELRO
krunner_lock (4565) - partial RELRO
kblankscrn.kss (4567) - partial RELRO
udevd (529) - partial RELRO

# of Processes: 78
No RELRO      : 0
Partial RELRO : 77
Full RELRO    : 1

Conclusion

In case of a bss or data overflow bug both partial and full RELRO protect the ELF internal data sections from being overwritten.

With full RELRO a working mitigation technique to successfully prevent the modification of GOT entries is available. But as the above testcases have shown, this mitigation technique is not used as default on current Linux distris. The only argument why full RELRO isn't widely used is that the startup of processes is slowed down as the linker has to perform all relocations at startup time.

In consequence the good old GOT overwrite technique can still be used today to get reliable control of the execution flow of a process while exploiting "write n bytes anywhere in memory" bugs like the one in FFmpeg. To gain reliable code execution from that point if ASLR and NX are also enabled is another story :)

There is another interesting writeup available that describes a generic way to implement a similar mitigation technique for ELF objects even if the platform doesn't support RELRO.

Sunday, February 15, 2009

TKADV2009-004 vs. xine-lib

Tomas Hoger from the Red Hat Security Response Team notified me that the 4xm demuxer of xine-lib seems to have the same origin with FFmpeg's version, and is therefore affected by a variant of the bug I described in TKADV2009-004.

xine-lib-1.1.16.1/src/demuxers/demux_4xm.c:

...
192 [1]   const uint32_t current_track = _X_LE_32(&header[i + 8]);
193       if (current_track + 1 > fourxm->track_count) {
194 [2]     fourxm->track_count = current_track + 1;
195 [3]     fourxm->tracks = realloc(fourxm->tracks,
196           fourxm->track_count * sizeof(audio_track_t));
197         if (!fourxm->tracks) {
198           free(header);
199           return 0;
200         }
201       }
...
Unlike FFmpeg, "current_track" is unsigned in xine-lib (see [1]), therefore the exploitation vector described in TKADV2009-004 does not seem directly applicable. However, xine-lib's version of the 4xm demuxer is missing an integer overflow check prior to the allocation of the "fourxm->tracks" buffer (see [2] and [3]).

Tomas also identified a way to exploit this variant of TKADV2009-004: If the first track number is e.g. 0x10000000, a small "fourxm->tracks" array gets allocated in [3]. Subsequent tracks with numbers lower than 0x10000000 will not trigger the array reallocation in [3], but will cause an OOB write.

The bug is fixed in version 1.1.16.2 of xine-lib.

Thanks to Tomas for notification and filing the bug.

Wednesday, January 28, 2009

Exploitable Userland NULL Pointer Dereference

Today I released a security advisory (TKADV2009-004) that describes the details of a very interesting vulnerability I found in FFmpeg. FFmpeg is a software solution to record, convert and stream audio and video. The FFmpeg libraries are used by a lot of popular software projects like VLC, Mplayer, Perian and Xine.

As I said, this vulnerability is quite interesting as it is another example for an exploitable NULL pointer dereference in an userland application.

The vulnerability

The initial vulnerability is a type conversion bug while converting an user controlled unsigned int value to a signed int.

..
fourxm->track_count = 0;
..
current_track = AV_RL32(&header[i + 8]);
..
The AV_RL32() macro in the above code snippet reads an unsigned int value from the media file and stores the value in the signed int variable "current_track".

Later on "current_track" is checked against another value. If "current_track" is greater than this value a heap buffer pointed to by "fourxm->tracks" gets (re)allocated.
..
fourxm->tracks = NULL;  <-- [4]
..
if (current_track + 1 > fourxm->track_count) {
  fourxm->track_count = current_track + 1;  <-- [1]
  if((unsigned)fourxm->track_count >= UINT_MAX /  <-- [3]
        sizeof(AudioTrack))
    return -1;
  fourxm->tracks = av_realloc(fourxm->tracks,
  fourxm->track_count * sizeof(AudioTrack));  <-- [2]
  if (!fourxm->tracks) {
    av_free(header);
    return AVERROR(ENOMEM);
  }
}
..
If "current_track" is greater than "fourxm->track_count" the user controlled value of "current_track" is stored into "fourxm->track_count" (see [1]). The value of "fourxm->track_count" is then used to calculate the size of the heap buffer (see [2]). To avoid an integer overflow, the size of "fourxm->track_count" is checked before the allocation takes place (see [3]).

Now what happens if we supply a value >= 0x80000000 for "current_track"? Well, as there is an unchecked type conversion between unsigned and signed, "current_track" will become negative. If "current_track" is negative, the if statement shown above will always return false and the heap buffer will never be allocated. This results in "fourxm->tracks" still pointing to NULL (see [4]).

Directly after the if statement the following write operations are performed:
..
fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]);
fourxm->tracks[current_track].channels = AV_RL32(&header[i + 36]);
fourxm->tracks[current_track].sample_rate = AV_RL32(&header[i+40]);
fourxm->tracks[current_track].bits = AV_RL32(&header[i + 44]);
..
As "fourxm->tracks" is pointing to NULL these write operations are leading to four classical NULL pointer dereferences. But as NULL is dereferenced by the user controlled value of "current_track" it is possible to write user controlled data to a wide range of memory locations.

Result:
NULL[current_track].offset = user_controlled_data;

As there are four write operations, four memory locations can be overwritten with arbitrary data.
Short summary:
  1. "fourxm->tracks" is initialized with NULL 
  2. The type conversion bug allows us to avoid the allocation of "fourxm->tracks" 
  3. "fourxm->tracks" still points to NULL 
  4. The resulting NULL pointer is then dereferenced by the user controlled value of "current_track" and four 32bit values of user controlled data are assigned to the dereferenced location(s). 
  5. It is therefore possible to overwrite four user controlled memory locations with four user controlled data bytes each.
As I said, that's a beautiful bug.

Exploitability

In my advisory I wrote: "A malicious party may exploit this issue to execute arbitrary code by overwriting a sensitive memory location (such as a GOT/IAT entry, a return address, buffer length or boolean variable)". To see if this nice bug is indeed exploitable I chose the following two test cases:
  • VLC 0.9.8a under Windows XP SP3
  • Mplayer under openSUSE 11.1
As VLC and Mplayer are both using the FFmpeg libraries they are vulnerable to this bug.

Result: Reliable EIP control confirmed under both test cases

Here is the result for VLC under Windows XP SP3:



Here is the result for Mplayer under openSUSE 11.1:
tk@linux-0skt:~/Documents/ffmpeg-checkout-2009-01-02> gdb mplayer
GNU gdb (GDB; openSUSE 11.1) 6.8.50.20081120-cvs
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-suse-linux".
For bug reporting instructions, please see:
<http://bugs.opensuse.org/>...
(no debugging symbols found)

(gdb) run ex_eip_control_mplayer.avi
Starting program: /usr/bin/mplayer ex_eip_control_mplayer.avi
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[Thread debugging using libthread_db enabled]
(no debugging symbols found)
[...]
MPlayer dev-SVN-r27637-4.3-openSUSE Linux 11.1 (i686)-Packman (C) 2000-2008 MPlayer Team
CPU: Intel(R) Core(TM)2 Duo CPU     T7500  @ 2.20GHz (Family: 6, Model: 15, Stepping: 11)
CPUflags:  MMX: 1 MMX2: 1 3DNow: 0 3DNow2: 0 SSE: 1 SSE2: 1
Compiled with runtime CPU detection.
Can't open joystick device /dev/input/js0: No such file or directory
Can't init input joystick
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing ex_eip_control_mplayer.avi.
libavformat file format detected.

Program received signal SIGSEGV, Segmentation fault.
0x55555555 in ?? ()

(gdb) bt
#0  0x55555555 in ?? ()
#1  0x77777777 in ?? ()
Cannot access memory at address 0x6666666a

(gdb) i r
eax            0x0      0
ecx            0x8d4cce0        148163808
edx            0x160    352
ebx            0x806e13f6       -2140269578
esp            0xbfffcfbc       0xbfffcfbc
ebp            0x8998f38        0x8998f38
esi            0x160    352
edi            0x8d59db0        148217264
eip            0x55555555       0x55555555
eflags         0x10297  [ CF PF AF SF IF RF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     5
As a bonus I developed a full working exploit (executes calc.exe) using VLC in version 0.9.8a as an injection vector.

Here is the result under Windows XP SP3.
Roundup:
  1. This is a very nice bug ;) 
  2. Reliable EIP control confirmed while using Mplayer as injection vector under openSUSE 11.1 and VLC 0.9.8a under Windows XP SP3 
  3. Reliable code execution confirmed while using VLC 0.9.8a as injection vector under Windows XP SP3

Thursday, January 22, 2009

GStreamer bugs

I just released a security advisory (TKADV2009-003) describing the details of some heap buffer overflows and an array index out of bounds vulnerability I found in the GStreamer multimedia framework.

The following screenshot shows the result of a poc for the array index out of bounds vulnerability that can be exploited to write the value 0x00000001 to (nearly) any location in memory. I used Songbird as an injection vector as this music player (like many others) is using the GStreamer framework.

Note: EAX holds the user controlled value

Wednesday, January 14, 2009

Commercial usage of ScoopyNG

Atempo Time Navigator is now officially using the VMware detection tricks of ScoopyNG. Thanks to Atempo for asking for permission instead of just using it without confirmation. I'm wondering what other software products are using ScoopyNG. Let me know if you know one.

Sunday, January 11, 2009

Some statistics

In my experience, open source projects are much faster in fixing security bugs than commercial vendors.

Current example:

Commercial product: Sun Solaris TKADV2009-001
Patch development time 115 days

Open source project:
Amarok TKADV2009-002
Patch development time 7 days

The fact itself is not surprising as open source projects are normally not as tightly bound to business processes like commercial vendors. Nevertheless, the time difference is quite impressive.

Since a while I keep record of the "patch development time" in each of my security advisories. This is the time a vendor or open source project needed to provide a fix or patch for the vulnerability.

Here are some patch development time statistics of the vulnerabilities I reported so far:

Average patch development time of open source software projects:
(How long does it take open source projects to patch vulnerabilities?)

Average patch development time: 5.1 days
Total number of vulnerabilities: 8

Average patch development time of commercial software vendors:

(How long does it take commercial software vendors to patch vulnerabilities?)

Average patch development time: 169.9 days
Total number of vulnerabilities: 12

Well, I think these numbers are self-explanatory. I will keep these statistics updated under http://www.trapkit.de/advisories/pdts.php.

vmem_xalloc(): size == 0

The Solaris kernel vulnerability described in TKADV2009-001 can be trivially exploited to crash a Solaris system (all Zones) as an unprivileged user, even if the vulnerability is triggered in a restricted non-global zone.

$ id
uid=101(tk) gid=1(other)

$ zonename
unpriv_zone

$ ppriv -S $$
1157:   -bash
flags = <none>
E: basic
I: basic
P: basic
L: zone

$ ./poc

System crash because of a kernel panic. Debugging information:
> ::msgbuf
[...]
panic[cpu0]/thread=d4764de0:
vmem_xalloc(): size == 0


d418cd94 genunix:vmem_xalloc+2d8 (fec66738, 0, 1000, )
d418cdd0 genunix:vmem_alloc+135 (fec66738, 0, 1)
d418cdfc unix:segkmem_xalloc+2d (fec66738, 0, 0, 1, )
d418ce28 unix:segkmem_alloc_vn+b7 (fec66738, 0, 1, fec)
d418ce40 unix:segkmem_alloc+16 (fec66738, 0, 1)
d418ce8c genunix:vmem_xalloc+3b4 (da004690, fffffffc,)
d418cec8 genunix:vmem_alloc+135 (da004690, fffffffc,)
d418cee4 genunix:kmem_alloc+32 (fffffffc, 1)
d418cf30 kaio:aiosuspend+a6 (0, 3fffffff, 0, 0, )
d418cf64 kaio:kaio+162 (d418cf8c, d418cf78)
d418cf84 genunix:syscall_ap+4d (8, 0, 3fffffff, 0, )

Well, is it indeed necessary to panic the whole system if a memory size of 0 is requested?

Monday, January 05, 2009

Don't trust (media) file extensions

In reaction to the vulnerabilities I recently found in various popular media players I get a lot of mails with a lot of questions. There're two questions that keep repeating themselves:

"The vulnerability is completely theoretical. I have never heard of the [place your favorite name here] media format before, so why should I open such an obscure media file?"
"Am I secure if I don't open [place your favorite name here] media files anymore?"
Both questions are answered quite easily: How would you find out the media file format? By the file extension? DON'T trust media file extensions!

Let's take for example the VLC vulnerability that occurs while processing TiVo media files. I'm sure most of you (including me ;) have never heard of this format before or even used it. The regular file extension for TiVo files is ".ty". But what hinders an evil attacker from renaming the file from "fun.ty" to "fun.avi" or "fun.mov" or "fun.mkv" or whatever he likes? The file will still be opened and processed as a TiVo file by the media player as file extensions are *not* used to recognize the media format.

This is true for all media players under all platforms (that I know).

(Purpose of this blog entry: From now on I can simply provide a link to this entry as an answer for the above questions ;)