The Perl Conference Salt Lake City 2018 Banner

Netanel Rubin's Perl Jam circus

I’ve just watched Netanel Rubin’s Perl Jam 2 talk from this year’s Chaos Communication Congress. As he’s due to give the same talk at Black Hat Asia, I thought it would be good to set the record straight concerning his claims about Perl (others have already done so). He makes 3 major claims:

  1. The Perl language is insecure
  2. Bugzilla & CGI.pm are representative of idiomatic Perl
  3. Perl doesn’t improve

I’m going to address each claim in turn and show why it is false. In my view, Perl remains a powerful, general-purpose language well-suited to tasks like building dynamic web applications, processing big data, and managing systems.

Claim 1: The Perl language is insecure

Function declarations cannot specify argument data types

Netanel Rubin, The Perl Jam 2

This isn’t true. Since 2008 Perl has supported subroutine signatures, with type checks using the Method::Signatures module. Since 2006 the Moose object system provided a fully-fledged type system and meta object programming interface (there’s also MooseX::Method::Signatures).

Developers treat hashes and arrays as “secure” data types … this is the Perl standard. You’re not expected to use it, you have to, as you don’t have any other choice. This security mess is a fundamental part of the language.

Netanel Rubin, The Perl Jam 2

Netanel starts by describing taint mode and claims that hashes are so secure, hash keys bypass Perl’s taint check. It’s true that hash keys are never considered tainted. This is documented in perlsec and discussed in depth in Chapter 2 of Mastering Perl. But it’s not because hashes are assumed to be secure, it’s because tainting hash keys involves a huge performance penalty. He never explains his claim as to why arrays are considered secure.

Perl’s ref function is a reliable and secure way to determine the data type of a reference. Arguments passed to functions are always passed as an array of scalars via @_. There is no doubt, no ambiguity. It’s not required security-wise, but if you want to use them you can use function signatures, types and meta-object programming in Perl. They’ve been available for years.

But I felt all of these points will go unnoticed without an extreme example of Perl’s absurdity. So I found an extreme example. One that will clearly show the ridiculousness nature of the language.

Netanel Rubin, The Perl Jam 2

This is the vulnerable code, from an example CGI application:

use strict;
use warnings;
use CGI;

my $cgi = CGI->new;

if ($cgi->upload( 'file' )) {
  my $file = $cgi->param( 'file' );
  while (<$file>) {
    print "$_";
  }
}

The issue with this code is that if $file has the value of ARGV, the diamond operator <$file> will call open on every value in @ARGV. CGI populates @ARGV with the HTTP query parameters which creates the vulnerability. So if the HTTP query parameter is ls|, Perl will execute ls. If the CGI program was running in taint mode, this attack vector would fail. Regardless, it’s a well-understood risk, the PLEAC project’s Perl recommendations from 1999 shows how to properly parse file descriptors in CGI parameters (ex 19.4). O’Reilly’s CGI Programming on the Web by Shishir Gundavaram recommended parsing metacharacters like | from user input, which also prevents this attack. That book was published in 1996.

The piping open behavior is well documented in open, perlipc and perlsec. Chapter 2 of Mastering Perl also covers it. It’s a useful feature when you want to efficiently process a lot of data from an external command: just like a shell pipe, it creates a socket between the Perl program and the external binary, avoiding the need to read the entire output into memory at once.

Netanel also identified a SQL injection vulnerability in Bugzilla. The weakness was caused by a poorly coded function which failed to properly validate input used in a dynamic SQL query. The developers should have used the safer pass-by-parameter DBI prepare and execute functions.

In both cases Perl provided methods for securely parsing untrusted input, but the developers didn’t use them.

Claim 2: Bugzilla & CGI.pm are representative of idiomatic Perl

Like every other Perl project, Bugzilla is heavily using functions that treat scalar and non-scalar argument types very differently.

Netanel Rubin, The Perl Jam 2

Netanel is referring to this code from his talk, which uses the argument type to decide what to do:

sub test {
  $arg1 = @_; # Get an argument

  if (ref $arg1 eq 'HASH')
    print $arg1{'key'};
  else
    print $arg1;
}

Aside from the fact that Netanel’s code contains a big error which means it would never work, the claim that every other Perl project is coded in this way is preposterous. Dist::Zilla is a popular Perl project with over 20,000 lines of code. Can you guess how frequently Dist::Zilla uses the construct Netanel describes? A quick grep of the code shows zero instances. Bugzilla was developed in 1998, it is not an example of Modern Perl.

Regarding CGI.pm, I can’t say it better than the official documentation:

CGI.pm HAS BEEN REMOVED FROM THE PERL CORE

The rationale for this decision is that CGI.pm is no longer considered good practice for developing web applications, including quick prototyping and small web scripts. There are far better, cleaner, quicker, easier, safer, more scalable, more extensible, more modern alternatives available at this point in time.

CGI.pm documentation

Claim 3: Perl doesn’t improve

Things get interesting during the Q&A section of the talk when an audience member says:

We use Perl for almost every module that we have at work, and it works really fine. I don’t know why you are picking Perl as a language to attack. It’s a really old language, and every language you can pick has problems, it doesn’t mean that … you have to stop using it.

Audience Member, The Perl Jam 2

Netanel responds:

C got criticized and it improved. PHP got criticized and it improved. Why can’t Perl be criticized too? … why don’t they improve the language?

Netanel Rubin, The Perl Jam 2

The funny thing is Perl is improving all the time. Every year there is a major release of Perl which brings new features and enhancements to the language (history). Last year’s release included a new operator, the double diamond << >> which disables the piping open behavior shown earlier. CGI.pm was removed from Perl’s core modules list in May 2014. Both of those occurrences predate Netanel’s talk.

Instead of waiting for a major release milestone, the Perl development team can fix critical security issues in a minor release if needed (for example see 5.16.3).

Perl also has a strong toolchain for evaluating Perl code. Perl::Critic is a linter that reviews Perl code against recommended coding practices. There is even a policy to check for potential SQL injection vulnerabilities.

Conclusion

You can’t always live in the fear of not knowing what data type you are trying to handle … not trusting your hashes, not trusting your arrays, what’s next, not trusting your own code?

Netanel Rubin, The Perl Jam 2

As someone who has years of experience writing professional Perl code, and working with Perl programmers, I do not recognize this experience at all. All Netanel has shown is an attack on some example code from a neglected module and a SQL injection bug in a legacy application.

Is the Ruby language to blame for a vulnerability in Ruby-on-Rails? Is PHP insecure because over 950 exploits were found for WordPress? This isn’t a dynamic language issue either; in Static vs. dynamic languages: a literature review author Dan Luu found little evidence that statically typed languages were safer than dynamic ones.

Anytime you fail to adequately parse untrusted input you’re going to have a bad day. Blaming Perl for developers’ bad code is like blaming the Alphabet for being turned into 50 Shades of Grey.


This article was originally posted on PerlTricks.com.

Tags

David Farrell

David is the editor of Perl.com. An organizer of the New York Perl Meetup, he works for ZipRecruiter as a software developer.

Browse their articles

Feedback

Something wrong with this article? Help us out by opening an issue or pull request on GitHub