Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perl 5.8.8 (Tainting) vulnerable to CWE-732 attacks #9632

Open
p5pRT opened this issue Jan 20, 2009 · 8 comments
Open

Perl 5.8.8 (Tainting) vulnerable to CWE-732 attacks #9632

p5pRT opened this issue Jan 20, 2009 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 20, 2009

Migrated from rt.perl.org#62526 (status was 'open')

Searchable as RT62526$

@p5pRT
Copy link
Author

p5pRT commented Jan 20, 2009

From adamk@cpan.org

Created by adamk@cpan.org

CWE-732 is the Common Weakness Enumeration identifier for the class of security bugs where a program does not validate the providence of critical files before loading them.

That is, a program does not check if a critical file MIGHT have been written to by an untrusted actor. This weakness was included in the SANS institute Top 25 security bugs list.

A full description of CWE-732 is available at the following URL.

http​://cwe.mitre.org/data/definitions/732.html

The perl 'require' function appears to be vulnerable to exploits based on CWE-732, suggesting this may be a pervasive weakness in the perl executable.

Worse, perl's tainting implementation does not seem to protect against these exploits.

For example, create a file foo.pm that contains.

print "Vulnerable to CWE-732\n";

Next, chmod the foo.pm file to have world-writable permissions.

chmod 666 foo.pm

Next, create foo.pl that contains.

require './foo.pm';

Finally, execute foo.pl with.

perl -T foo.pl

It's debatable whether or not this should be specifically protected against by -T or if some other action should be needed, I leave discussion of the specifics to P5P.

I also apologise that I only have a 5.8.8 to validate this again, my 5.10 install is only on Windows, where a validation is not as simple as on unix.

Adam K

Perl Info

Flags:
    category=core
    severity=critical

Site configuration information for perl v5.8.8:

Configured by Debian Project at Fri Apr 25 20:33:47 UTC 2008.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
  Platform:
    osname=linux, osvers=2.6.24.4, archname=i486-linux-gnu-thread-multi
    uname='linux ninsei 2.6.24.4 #1 smp preempt fri apr 18 15:36:09 pdt 2008 i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i486-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.8 -Dsitearch=/usr/local/lib/perl/5.8.8 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.8 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include'
    ccversion='', gccversion='4.1.2 20061115 (prerelease) (Debian 4.1.1-21)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.3.6.so, so=so, useshrplib=true, libperl=libperl.so.5.8.8
    gnulibc_version='2.3.6'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.8:
    /etc/perl
    /usr/local/lib/perl/5.8.8
    /usr/local/share/perl/5.8.8
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.8
    /usr/share/perl/5.8
    /usr/local/lib/site_perl
    /usr/local/lib/perl/5.8.4
    /usr/local/share/perl/5.8.4
    .


Environment for perl v5.8.8:
    HOME=/home/adam
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

From @craigberry

On Tue, Jan 20, 2009 at 7​:30 AM, adamk@​cpan.org (via RT)
<perlbug-followup@​perl.org> wrote​:

# New Ticket Created by adamk@​cpan.org
# Please include the string​: [perl #62526]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=62526 >

CWE-732 is the Common Weakness Enumeration identifier for the class of security bugs where a program does not validate the providence of critical files before loading them.

I assume you mean provenance, not providence, though divine intention
sneaking into your code might also be a bit scary :-).

That is, a program does not check if a critical file MIGHT have been written to by an untrusted actor. This weakness was included in the SANS institute Top 25 security bugs list.

A full description of CWE-732 is available at the following URL.

http​://cwe.mitre.org/data/definitions/732.html

Note that most of the recommended mitigating actions are upstream from
what a program does at run-time​: things like system architecture and
administration, installation practices and procedures, and so on. The
only run-time recommendation I can see is setting default permissions.
I don't see anything about validating the origin of files -- did I
miss that?

The perl 'require' function appears to be vulnerable to exploits based on CWE-732, suggesting this may be a pervasive weakness in the perl executable.

Worse, perl's tainting implementation does not seem to protect against these exploits.

For example, create a file foo.pm that contains.

print "Vulnerable to CWE-732\n";

Next, chmod the foo.pm file to have world-writable permissions.

Er, how do you do that in a properly installed Perl without
privileges? Or does this only apply to a user's locally-installed
libraries? As far as core modules go, if someone has the ability to
overwrite them with nefarious versions, then most likely they also
have the ability to remove anything we'd put in to check for the
vulnerability, up to and including inserting a hacked version of the
Perl executable.

chmod 666 foo.pm

Next, create foo.pl that contains.

require './foo.pm';

Finally, execute foo.pl with.

perl -T foo.pl

It's debatable whether or not this should be specifically protected against by -T or if some other action should be needed, I leave discussion of the specifics to P5P.

I don't see how checking for world write access could possibly meet
the test of "a critical file might have been written to by an
untrusted actor." Any such actor with a bit of common sense would
evade such a check by simply removing the world write bit after
replacing the file with an evil version. Almost any run-time check,
tainting or otherwise, could only tell you whether there is still a
danger of something getting mangled in the future.

Possibly some sort of digital signature validation at run-time could
verify the origin of a file -- that would require more thought (and a
lot more expertise) than I can provide at the moment.

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

From @nwc10

On Wed, Jan 21, 2009 at 11​:21​:09AM -0600, Craig A. Berry wrote​:

On Tue, Jan 20, 2009 at 7​:30 AM, adamk@​cpan.org (via RT)
<perlbug-followup@​perl.org> wrote​:

It's debatable whether or not this should be specifically protected against by -T or if some other action should be needed, I leave discussion of the specifics to P5P.

I don't see how checking for world write access could possibly meet
the test of "a critical file might have been written to by an
untrusted actor." Any such actor with a bit of common sense would
evade such a check by simply removing the world write bit after
replacing the file with an evil version. Almost any run-time check,
tainting or otherwise, could only tell you whether there is still a
danger of something getting mangled in the future.

They can't necessarily remove the world write bit. They need to own the file
for that. (Or be root, which is already "game over")

The problem it guards against is any user running code that happens to require
code that is world writable, or down a path where something is world writable,
where the world writeable file (or directory) is owned by some user A, and has
been attacked by unprivileged user B. (For example user B is the user nobody,
that a web server is running as)

You're right that it can't detect the case where the "unknown actor" had
privileges sufficient to cover their trail. But that isn't the only case.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

From @Abigail

On Wed, Jan 21, 2009 at 11​:21​:09AM -0600, Craig A. Berry wrote​:

On Tue, Jan 20, 2009 at 7​:30 AM, adamk@​cpan.org (via RT)
<perlbug-followup@​perl.org> wrote​:

# New Ticket Created by adamk@​cpan.org
# Please include the string​: [perl #62526]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=62526 >

CWE-732 is the Common Weakness Enumeration identifier for the class of security bugs where a program does not validate the providence of critical files before loading them.

I assume you mean provenance, not providence, though divine intention
sneaking into your code might also be a bit scary :-).

That is, a program does not check if a critical file MIGHT have been written to by an untrusted actor. This weakness was included in the SANS institute Top 25 security bugs list.

A full description of CWE-732 is available at the following URL.

http​://cwe.mitre.org/data/definitions/732.html

Note that most of the recommended mitigating actions are upstream from
what a program does at run-time​: things like system architecture and
administration, installation practices and procedures, and so on. The
only run-time recommendation I can see is setting default permissions.
I don't see anything about validating the origin of files -- did I
miss that?

The perl 'require' function appears to be vulnerable to exploits based on CWE-732, suggesting this may be a pervasive weakness in the perl executable.

Worse, perl's tainting implementation does not seem to protect against these exploits.

For example, create a file foo.pm that contains.

print "Vulnerable to CWE-732\n";

Next, chmod the foo.pm file to have world-writable permissions.

Er, how do you do that in a properly installed Perl without
privileges? Or does this only apply to a user's locally-installed
libraries? As far as core modules go, if someone has the ability to
overwrite them with nefarious versions, then most likely they also
have the ability to remove anything we'd put in to check for the
vulnerability, up to and including inserting a hacked version of the
Perl executable.

chmod 666 foo.pm

Next, create foo.pl that contains.

require './foo.pm';

Finally, execute foo.pl with.

perl -T foo.pl

It's debatable whether or not this should be specifically protected against by -T or if some other action should be needed, I leave discussion of the specifics to P5P.

I don't see how checking for world write access could possibly meet
the test of "a critical file might have been written to by an
untrusted actor." Any such actor with a bit of common sense would
evade such a check by simply removing the world write bit after
replacing the file with an evil version. Almost any run-time check,
tainting or otherwise, could only tell you whether there is still a
danger of something getting mangled in the future.

Possibly some sort of digital signature validation at run-time could
verify the origin of a file -- that would require more thought (and a
lot more expertise) than I can provide at the moment.

I wonder whether -T should even check for this. It isn't that the
string 'foo.pm' comes from an untrusted source; it's hardcoded in the
script, which means that the author indeed intended to use 'foo.pm'.

Furthermore, if -T were to be changed that it disallows executing code
from files with the world write bit turned on, how would you untaint it?

Abigail

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

From @moritz

adamk@​cpan.org (via RT) wrote​:

For example, create a file foo.pm that contains.

print "Vulnerable to CWE-732\n";

Next, chmod the foo.pm file to have world-writable permissions.

chmod 666 foo.pm

Next, create foo.pl that contains.

require './foo.pm';

Finally, execute foo.pl with.

perl -T foo.pl

In a similar setting, openssh protects stupid users with too permissive
~/.ssh or ~/.ssh/authorized_keys by ignoring that file if it's writable
by anyone but the user himself.

Whether we want something similar for module loading is basically a
question of paranoia level.

Cheers,
Moritz

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2009

From @gisle

On Jan 21, 2009, at 18​:30 , Nicholas Clark wrote​:

On Wed, Jan 21, 2009 at 11​:21​:09AM -0600, Craig A. Berry wrote​:

On Tue, Jan 20, 2009 at 7​:30 AM, adamk@​cpan.org (via RT)
<perlbug-followup@​perl.org> wrote​:

It's debatable whether or not this should be specifically
protected against by -T or if some other action should be needed,
I leave discussion of the specifics to P5P.

I don't see how checking for world write access could possibly meet
the test of "a critical file might have been written to by an
untrusted actor." Any such actor with a bit of common sense would
evade such a check by simply removing the world write bit after
replacing the file with an evil version. Almost any run-time check,
tainting or otherwise, could only tell you whether there is still a
danger of something getting mangled in the future.

They can't necessarily remove the world write bit. They need to own
the file
for that. (Or be root, which is already "game over")

The problem it guards against is any user running code that happens
to require
code that is world writable, or down a path where something is world
writable,
where the world writeable file (or directory) is owned by some user
A, and has
been attacked by unprivileged user B. (For example user B is the
user nobody,
that a web server is running as)

So, potentially we could change the definition of 'do' under -T so that​:

- do $file​:
  - open($file) or fail
  - resolve $file as an absolute file name and expand all symlinks
in the path
  - for each directory in the path of $file and $file itself​:
  stat
  fail if not owned by the current user or root
  fail if world or group writable
  - open($file) again; fail if we did not open the same file as the
first time
  - read file content
  - evaluate content

- require implemented in terms of do
- use implemented in terms of require

Seems insanely expensive to me and something that would break lots of
code. The question is then if anything less brutal worth it. I don't
think so.

--Gisle

You're right that it can't detect the case where the "unknown actor"
had
privileges sufficient to cover their trail. But that isn't the only
case.

@p5pRT
Copy link
Author

p5pRT commented Jan 22, 2009

From @demerphq

2009/1/21 Gisle Aas <gisle@​activestate.com>​:

On Jan 21, 2009, at 18​:30 , Nicholas Clark wrote​:

On Wed, Jan 21, 2009 at 11​:21​:09AM -0600, Craig A. Berry wrote​:

On Tue, Jan 20, 2009 at 7​:30 AM, adamk@​cpan.org (via RT)
<perlbug-followup@​perl.org> wrote​:

It's debatable whether or not this should be specifically protected
against by -T or if some other action should be needed, I leave discussion
of the specifics to P5P.

I don't see how checking for world write access could possibly meet
the test of "a critical file might have been written to by an
untrusted actor." Any such actor with a bit of common sense would
evade such a check by simply removing the world write bit after
replacing the file with an evil version. Almost any run-time check,
tainting or otherwise, could only tell you whether there is still a
danger of something getting mangled in the future.

They can't necessarily remove the world write bit. They need to own the
file
for that. (Or be root, which is already "game over")

The problem it guards against is any user running code that happens to
require
code that is world writable, or down a path where something is world
writable,
where the world writeable file (or directory) is owned by some user A, and
has
been attacked by unprivileged user B. (For example user B is the user
nobody,
that a web server is running as)

So, potentially we could change the definition of 'do' under -T so that​:

- do $file​:
- open($file) or fail
- resolve $file as an absolute file name and expand all symlinks in the
path
- for each directory in the path of $file and $file itself​:
stat
fail if not owned by the current user or root
fail if world or group writable
- open($file) again; fail if we did not open the same file as the first
time
- read file content
- evaluate content

- require implemented in terms of do
- use implemented in terms of require

Seems insanely expensive to me and something that would break lots of code.
The question is then if anything less brutal worth it. I don't think so.

If we do this I dont think we should do it via -T i think we should do
it via some other mechanism. A new switch or something. Preferably
long

--i-am-amazingly-paranoid-so-i-want-you-to-distrust-world-writable-source-files

would probably do fine. Perhaps we could support --iaapsiwytdwwsf as a
short form.

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants