Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.89k stars 533 forks source link

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

Open p5pRT opened 15 years ago

p5pRT commented 15 years ago

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

Searchable as RT62526$

p5pRT commented 15 years ago

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 commented 15 years ago

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 commented 15 years ago

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

p5pRT commented 15 years ago

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@&#8203;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 commented 15 years ago

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@&#8203;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 commented 15 years ago

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 commented 15 years ago

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@&#8203;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 commented 15 years ago

From @demerphq

2009/1/21 Gisle Aas \gisle@&#8203;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@&#8203;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/"