
The Perl Jam: Exploiting a 20 Year-old Vulnerability [pdf] - lifthrasiir
http://events.ccc.de/congress/2014/Fahrplan/system/attachments/2542/original/the-perl-jam-netanel-rubin-31c3.pdf
======
ceronman
When he explains how Perl handles an array passed as an argument to a
function:

    
    
        my @list = ('b', 'c');
        test('a', @list, 'd');
    

Which ends up flatting the @list array into the argument list and printing _'
a', 'b', 'c'_, most Perl programmers defend the language saying that the
author just doesn't understand Perl, and that's how things are done in the
language since forever. The response is basically a RTFM.

If you really wanted to send the whole list as single argument to the
function, you should have sent an array reference, like this:

    
    
        test('a', \@list, 'd');
    

Perl programmers say that if you took a minute to understand the language, you
should have known this. However, what they don't realize is that Perl gives
you ambiguous hints about this all the time. For example, the built in _push_
function doesn't seem to follow this logic:

    
    
        push(@list, "item2", "item2");
    

This function knows perfectly that the list is a single argument and the other
ones are the items to push into the list. You don't have to pass a reference
to the array to make it work.

The _push_ function works like this because it uses an obscure feature called
function prototypes. Which is rarely mentioned in any tutorial.

When a Perl newbie sees the push function, it's more than reasonable to think
that passing arrays as function arguments will work as in any other language.
When they find what really happens, it can be very frustrating, specially
because Perl won't give you any error whatsoever. This is one of the reasons
why Perl is so difficult to learn.

~~~
collyw
As an ex Perl guy (well I still use it sometimes), I find append and extend an
endless source of confusion in Python. Especially as strings do the opposite
of what I expect, and get treated as character arrays with extend (or was it
append).

I like the way that in Perl you have to explicitly reference the array, as
this leaves no ambiguity about what is happening. I guess its just what I am
used to.

~~~
haypo
"As an ex Perl guy (well I still use it sometimes), I find append and extend
an endless source of confusion in Python. Especially as strings do the
opposite of what I expect, and get treated as character arrays with extend (or
was it append)."

list.extend(data) works like "for item in data: list.append(item)"

strings (str) do not behave differently than a list or a set. Try .append() on
a list or a set, you get the same behaviour.

Maybe your confusion comes from the fact that strings are immutable in Python,
and a list is not a string.

You may like bytearray() in Python 2 (bytearray.append raises an error if you
pass a string longer than 1 character), but there is not mutable type for
Unicode strings.

~~~
collyw
Yes but I would expect my strings to behave as a scalar variable, not a list
or set.

I prefer the Perl way of having one function push, and specifically
referencing the list if you want it stored that way. That has caused me far
less confusion in Perl than the Python way of doing things.

------
laumars
I love how he is building his own SQL string and then blaming Perl's
DBI->quote for any vulnerabilities that arise. Anyone who writes SQL like that
is writing bad code from the offset (regardless of the programming language
nor it's DB/web frameworks). Parametrised queries and ORMs exist to prevent
the kind of SQL injection attacks he's demonstrating and Perl's various DBD
modules already support parametrised queries (in fact most Perl DBI guides
will walk you through using them!).

This is pretty much "working with databases 101" and if he can't get even that
much right then he should not be stood in front of people lecturing about the
evils of any language nor it's framework.

Sadly though, these days proper security research is less important than
looking cool in front of a small crowd. After all, who needs to have any
knowledge about your subject if you can curse a little and display a few
slides of some tired old internet memes. :/﻿

~~~
OMGWTF
I think

    
    
        $sth = $dbh->prepare("SELECT document FROM table WHERE tag=? AND security_level=?");
        $sth->execute(foo(), $user_level);
    

breaks as well, if foo() unexpectedly returns a list.

~~~
sarciszewski
Breaks as in "SQL injection is possible" or breaks as in "invalid number of
parameters"?

~~~
OMGWTF
If the list contains 2 elements, it will overwrite the second parameter, so
the total number of arguments is still the same.

~~~
laumars
Ah yes, but that's a slightly different feature to the one demonstrated by the
author
([https://www.youtube.com/watch?feature=player_detailpage&v=gw...](https://www.youtube.com/watch?feature=player_detailpage&v=gweDBQ-9LuQ#t=1012)).
However that's not to say that the vulnerability you raised isn't also a
serious one developers need to be mindful of.

------
sarciszewski
I love how, at the very end of the talk, when someone asked the speaker if he
knew of any other languages that had this problem, and the speaker didn't
know, someone decided to shout out "PHP!"

There is something that PHP developers should be made aware of, but it isn't
something as weird as Perl's list behavior.

Test script:

    
    
        <?php
        header("Content-Type: text/plain;charset=UTF-8");
        var_dump($_GET);
    

If you access /test.php?a=1&a=2 you will be greeted with:

    
    
        array(1) {
          ["a"]=>
          string(1) "2"
        }
    

You can reason amongst yourselves about whether 1 or 2 is more desirable, but
it's only one parameter. So the Perl list trickery is not applicable. Now
visit /test.php?a[]=1&a[]=2

    
    
        array(1) {
          ["a"]=>
          array(2) {
            [0]=>
            string(1) "1"
            [1]=>
            string(1) "2"
          }
        }
    

If you're expecting a string in a GET/POST parameter, make sure you're not
receiving an array. This is a HTTP feature, not a bug, but it can sometimes
break code if you're not expecting it. (Break as in error messages)

So, no, PHP is _not_ an example of a language with a similar vulnerability.

~~~
eCa
The vulnerability in the talk is not in Perl. It is in the CGI module.

~~~
sarciszewski
The vulnerability is a Perl language feature that gets misused by the CGI
module and subsequently by application code.

------
lxst
You can watch the talk here:
[https://www.youtube.com/watch?v=gweDBQ-9LuQ](https://www.youtube.com/watch?v=gweDBQ-9LuQ)

~~~
gondo
is it just me, or does he think that swearing makes him look cool?

~~~
brakl
I'd be fine with the swearing if it'd be backed up by some knowledge and
experience, but that smug attitude is just incredibly irritating when coupled
with such level of ignorance. First decide what are you going to bash. Some
libraries, some applications, the entire programming environment ? Using
induction from DBI->quote/CGI and a few old apps to bash the entire Perl
ecosystem is just boringly stupid. It is fine and useful to patch those old
apps, but to give an arrogant lecture as if all programmers use the same
broken approaches in 2014 is just ignorant.

It is extensively documented to prefer placeholders when working with DBI,
that is, if you even use DBI directly and not via an OO mapper. CGI as an
approach is entirely deprecated on all languages/platforms not just Perl. List
expansion ? It _is_ a feature, use it or leave it. You have the option to use
references. If you prefer Python, just use Python. It's like bashing C for
having pointers. So, what else ? Try PHP with those examples. Find some Ruby
apps prone to sql injection. Bash some NodeJS libraries. If Perl is dead
already, be a rockstar bashing the new stuff, why even bother with the ghosts
? I think it is because deep down all Pythonistas know that Perl is a far
superior platform and they all carry a deep ancestral envy. Otherwise they'd
just be happy with their choice already. :)

------
xorcist
This guy just comes off as very smug about a language he apparently has no
idea what he's doing in.

Bascially all the WAT?s are because Perl's lists are very different from
Python's. If he had spent five minutes reading the very first chapters of
Programming Perl he would make much less fool of himself. He explicitly asks
to flatten the lists, so there shouldn't be much surprise that Perl obliges.

That said, the security issues he pointed out are real ones. Be very careful
in you are programming CGI (in _any_ language)!

------
tedunangst
This link may be helpful if ccc.de is fairing poorly.

[http://webcache.googleusercontent.com/search?q=cache:7Ps4U1P...](http://webcache.googleusercontent.com/search?q=cache:7Ps4U1Pt_oQJ:events.ccc.de/congress/2014/Fahrplan/system/attachments/2542/original/the-
perl-jam-netanel-rubin-31c3.pdf+&cd=1&hl=en&ct=clnk&gl=ru)

------
D3ve1inE
Hi guys, Netanel Rubin here.

First of, I'm not a Pythonist. Python has nothing to do with the faults of
Perl - Perl does.

Perl was a great language back at the 90's and early 2000 - it doesn't now.
That is mainly because of the 'write-only' code style and many not-that-
intuitive behaviors other languages practice better. It is true that my talk
was based on bad programming practices, but that's the practices actually used
in the wild - in Bugzilla, TWiki, MovableType, and I haven't even started
talking about what cPanel developers did. So, if 99% of programmers doesn't
use the language properly, who's fault is that? A company needs to provide its
costumers with a working, intuitive product. So is a programming language. If
so many people doesn't know how to use it properly, I'm sorry, but it's the
language fault.

Another thing pointed out is prepare(). Yes, you can use it, no SQLIs there.
BUT, this has nothing to do with the point. The point is that list expansion
behavior in function calls is a problem most programmers weren't aware of.
These are some code sections used at Bugzilla 4.4.6 (fully patched as of
30/12/2014) at different places:
$attachment->_check_content_type($cgi->param('content_type'));
$cgi->uploadInfo($cgi->param('data'))->{'Content-Type'};
IsValidQueryType($cgi->param('query_type'))

And it also has 2 different quote() occurrences:
$dbh->quote($cgi->param('requester')); $dbh->quote($cgi->param('requestee'));

Now, I'm not saying all of those leads to a vulnerability, but as you can see
there's a very visible trend here.

Did all of those programmers and maintainers never read the tutorial for the
language? Or did the language documentation confused them to the point they
simply weren't aware of this behavior?

From a personal perspective of one that did try to figure out what's going on
with lists I can definitely say that this behavior is documents - At several
places, very differently. As a simple example go back to my slides and look at
the CGI documentation screen shot. VERY confusing, and honestly, just false.

As for the attitude, I do apologize for everyone offended by the young
douchebag that attacked your language. But, as recent vulnerabilities showed
us, without a proper show no one's gonna notice you and your point, important
as it may be. So, yes, I added a couple of funny images and built a momentum
for a punch line, but otherwise this talk wouldn't have got the buzz it's
getting right now and programmers would've still be blind to this behaviors,
as sad as it may be.

For an ending note, I do believe Perl has done it course, especially for
large, maintained systems such as Bugzilla and cPanel. It may be the end of an
era, but who said this is such a bad thing?

Thank you for your comments (positive or negative) and for reading this.

~~~
leejo
Excellent, you're here so i (we) can address a couple of the points in your
talk.

1) DBI is not a core module, nor to my knowledge has it ever been.

2) I'm the current _maintainer_ of CGI.pm - i am _not_ the author. This is an
important point because the module is 20 years old, and like any software of
significant size/age/importance it has been through several different hands
(over 30 according to the git log, which only goes back to 1998 so is missing
3 years).

It would be great if i could just release a version of CGI.pm that removes the
list context behaviour of ->param but that would massively break back
compatibility for hundreds, if not thousands, of users. Not all of these users
have the knowledge or resources to fix their code, which is why for the time
being CGI.pm will warn when ->param is called in list context. This _has_
actually broken some software (anyone that has set warnings to be fatal), but
this was the least harmful way i could get out to users who maybe blind to the
issue that there is indeed an issue.

And yes, as many have already stated this was an unfortunate consequence of
the list context behaviour of CGI.pm. Knowing the difference between
scalar/list context in perl is a classic gotcha. This behaviour lurked in code
going back years - the examples you cite would all fall into the "legacy code"
category. You're making the classic mistake of someone who doesn't know perl:
looking at code from over a decade ago and thinking this represents modern
perl. It doesn't.

A couple of other examples of critical bugs that were revealed in 2014:
shellshock and heartbleed. Should we dismiss bash, C, etc, as terrible
languages because of these? No. People make mistakes, don't RTFM,
misunderstand language features, and bugs can exist in legacy code for years
and years. Usually critical bugs.

You could have made an excellent talk from the work you did in exposing the
bug(s) you found. You failed. Learn from this.

~~~
tikums
> A couple of other examples of critical bugs that were revealed in 2014:
> shellshock and heartbleed. Should we dismiss bash, C, etc, as terrible
> languages because of these?

Yes.

