<<< Date Index >>>     <<< Thread Index >>>

cdp buffer overflow vulnerability



~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*

Product:      cdp - console cd player
Versions:     All     
Bug:          Buffer overflow
Impact:       Attackers can execute arbitrary code
Risk:         Medium/High
Date:         March 31, 2004
Author:       Shaun Colley
              Email: shaunige yahoo co uk
              WWW: http://www.nettwerked.co.uk

~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*



Introduction
#############

cdp is... "cdp is a program that plays CDs at the
linux console. It has a full-screen ncurses mode, and
a command-line mode suitable for scripts that wish to
play audio CDs. I consider cdp to be the CD equivalent
of mpg123." - Taken from project page:
<http://cdp.sourceforge.net/>.

Despite cdp's usual robustness (and all credit to the
authors), cdp is vulnerable to a stack-based buffer
overflow vulnerability which may allow a potential
attacker to craft a malicious audio CD, social
engineer a user into playing the CD with 'cdp',
triggering a buffer overflow.



Details
########

The buffer overflow occurs in the routine which
displays the information for each track, printTOC(). 
This function prints the track number, track name, and
track time information to the screen when a user plays
a CD with cdp.  Due to lack of bounds checking when
preparing and printing this information, a track with
a songname which exceeds 200 bytes in length will
trigger a buffer overflow.  Below is the offending
code:

--- from cdp.c ---
[...]

char                 buffer[ 200 ], ch;

[...]

printf( "Track Num  Start Time  Length  Name \n" );
    for  ( ind = 0; ind < cdStatus.thiscd.ntracks;
ind++ ) {
        trk = &cdStatus.thiscd.trk[ ind ];
        if  ( trk->songname != NULL ) {
            sprintf( buffer, "%s", trk->songname );
        } else
            buffer[ 0 ] = 0;

[...]
--- end of snippet ---

As can be seen above, an sprintf call is made, copying
trk->songname, if a songname exists, into a buffer
which is only 200 bytes long.  cdp gets the songname
(name of the track) when a call to load() is made,
which calls search_db() during it's execution flow. 
In this function, a songname possibly as long as 502
bytes is copied into a cdinfo type struct pointer
(safely), which is later used by printTOC() (the
vulnerable function) to be copied into 'buffer', which
has only 200 bytes allocated, as seen and explained
above, thus presenting the possibility of a
stack-based buffer overflow, as 'buffer' can often be
overflowed by up to 302 bytes.

An attacker could create a specially crafted audio CD,
and give it to a user, presenting an opportunity for
exploitation of the issue, as very few people check
the authenticity of audio CDs given to them.



Exploitation
#############

Exploitation of this issue would require that an
attacker create a CD which has a track name (songname)
exceeding 200 bytes, specially crafted to overwrite
the instruction pointer (EIP) to redirect the
execution flow elsewhere, causing execution of
arbitrary code.  Once a working exploit audio CD had
been created, an attacker needs to simply pass the CD
to a privileged user, and social engineer them into
believing that the CD contains good music.

I have not developed a proof-of-concept for this
issue, but arbitrary code execution is most definately
possible.



Solution
#########

I contacted the author around 5 days ago, but I
haven't heard any response.  This could be because the
cdp project isn't maintained much anymore.  The latest
release was in January 2000.

I have produced a patch to fix the issue, since the
vendor hasn't contacted me back.  The patch implements
an snprintf() call rather than an sprintf()
invokation, which fixes the vulnerability because
bounds checks are performed.

--- songname.patch ---

--- cdp.c       2004-03-31 15:48:55.000000000 +0100
+++ cdp.1.c     2004-03-31 15:44:35.000000000 +0100
@@ -154,7 +154,7 @@
     for  ( ind = 0; ind < cdStatus.thiscd.ntracks;
ind++ ) {
         trk = &cdStatus.thiscd.trk[ ind ];
         if  ( trk->songname != NULL ) {
-            sprintf( buffer, "%s", trk->songname );
+            snprintf( buffer, strlen(buffer), "%s",
trk->songname );
         } else
             buffer[ 0 ] = 0;


--- eof ---

The patch can also be obtained from
<http://www.nettwerked.co.uk/code/songname.patch>.

The following steps can be taken to fix the problem:

1) Create a file containing the above patch
2) Apply the patch 

bash# patch cdp.c songname.patch

3) Rebuild 'cdp'

bash# make && make install

The issue should now be fixed.


No proper workarounds exist, except for running an
application which guards against stack-based
overflows, such as StackGuard.



Credit
#######

This issue was discovered and researched by Shaun
Colley - <shaunige yahoo co uk>.




Thank you for your time.
Shaun. 


        
        
                
___________________________________________________________
WIN FREE WORLDWIDE FLIGHTS - nominate a cafe in the Yahoo! Mail Internet Cafe 
Awards  www.yahoo.co.uk/internetcafes