preroll music
Herald: And I'm gonna introduce Netanel Rubin.
He has been here last year with a talk
that he got some bashing for.
This year he's gonna ensure,
it's not the programmer's fault,
it's the language itself. No?
Well, here we go, well here we go.
Netanel, he is working for
PerimeterX in Tel Aviv,
welcome on stage, your talk!
Netanel: Thank you very much, applause
thank you, thank you!
Last year I stood right on this very stage
and I talked about several of Perl's
less thought out "features".
Now, I got some bashing from the Perl community,
but mainly what happened was,
that the Perl community completely rejected my talk
claiming that the language
is completely fine and great
and all of this stuff are just improvements.
It was clear I had to give another talk.
This is why I'm very proud to present
"Perl Jam 2 – The Camel strikes back"!
applause
Thank you
At the last talk, I showed that "lists" are expressions,
used in… many confusing ways.
I also showed how CGI parameters can create lists,
directly from user input.
But most importantly, I showed
that when these two things combine, shit happens.
Great
But the really interesting part
was the PerlMonks response.
The Perl community…
laughter
The Perl community had a long discussion
at the PerlMonks forum
that started with the words
"Sad news from Germany".
A bit dramatic, but who am I to judge?
So, after a long, long discussion,
they came to the unavoidable conclusion
that my talk was, in fact, a "polemic shit",
and they should all just "piss on it". Wink.
They also realized I'm just a
"script kiddie preaching to other script kiddies",
and not just any script kiddies, the CCC audience is a
"heterogeneous group of chaotic punks
who love to see themselves in the hacker
image of Hollywood media".
applause and whistling from audience
What hacker image?
What are they talking about?
We have no hacker image.
Anyway, it got quite surreal, as in some point
they even critized
the "crude use of propaganda
in the camel images". WAT?
laughing
applause
Propaganda in the camel images. Alright.
Anyway, they completely rejected the entire talk,
even though the technical points were valid.
They rejected it because of
some jokes and camel images.
But still, they got so offended they just threw
lame excuses as to why their language sucks.
Two of these lame excuses were
repeated over and over again.
The first was that I should
read the fucking manual, which is funny
because I thought I was the only one who did…
laughter
…and the second is that
I'm using the old, ancient Perl,
and not the new, modern Perl.
more laughter
Remember these two points carefully
as I'll later break them in the presentation.
But, enough with the intro,
let's start with the new madness.
So, Perl allows declaring variables
without specifying their data type.
Of course, this functionality exists
in many dynamic languages,
and is completely fine and very convenient.
But, as usual, Perl took it
to a whole different level.
Perl went as far as removing
data type declarations from function arguments.
You can see that in this example,
I'm just receiving two different arguments
without knowing what type they are.
Let me be clear about that,
you don't get to choose whether you want
to specify argument data types or not,
you can't specify
what data types you're expecting to get.
So even if I built a function
that only works with strings,
I have no way of forcing that
at the function declaration.
Now that's annoying.
But, the real kicker
is how this feature is used.
Apparently, it is very common to write
two completely different blocks of code,
one that handles scalar types,
like strings or ints,
and one that handles non-scalar types,
like arrays or hashes.
Let me repeat that:
Writing multiple code, for multiple data-types,
in one function, is a Perl standard.
And that's sad. You shouldn't write redundant code
because the language lacks the capability
of letting you decide
which cases you don't want to handle.
By the way, Python doesn't let you
declare your function argument data types too,
but unlike Perl, writing redundant code
to cover that up
is definitely not the standard.
Anyway, sad as this may be,
this Perl convention is not dangerous.
The dangerous part begins
when hashes and arrays
are considered as "secure" data types,
mainly because they can't be created
by user input.
This results in this kind of code,
where if the function argument
is a hash, for example,
it is used un-escaped in dangerous functions.
Hashes, specifically, are considered so secure,
that even if you use "taint mode",
which is some kind of safe mode for Perl,
hash keys are not tainted, meaning
that, even if you use safe mode,
they can be still used in dangerous functions
without any validation,
as opposed to other data types.
Now this kind of code appears a lot
in Perl applications,
and apart from the many bugs
this method can cause,
it also makes your code exploitable.
So we know function arguments are of unknown data type.
And we know developers treat hashes and arrays
as "secure" data types,
inserting their values into dangerous functions.
But this practices isn't something
that was created a long time ago,
and found only on redundant code.
Because of how the language is built,
its supposedly restriction-less type of developing,
even now it is the natural way to code
when you're using Perl.
And that's the real problem:
Perl is like a shotgun,
with one trigger you know about
and a dozen that you don't.
So for now, we know
that if we'll somehow manage
to create these "secure" data types,
with our user input,
we could exploit the code.
So the only question remaining really
is what are we gonna exploit?
And the answer, again,
is Bugzilla.
laughter
Like every other Perl project,
Bugzilla is heavily using functions
that treat scalar and non-scalar
argument types very differently.
This is one of them: the load_from_DB function is responsible
for extracting object specific data
out of the database.
Like I just said, it treats scalars,
and in this case hashes, very differently.
If the function argument is a hash,
it takes one of its values
and inserts it as is, un-escaped,
into an SQL statement.
Again, because hashes
are considered secure,
so there's no point of escaping them.
On the other hand,
if the argument is a scalar,
it converts it into an integer
and only then use it in an SQL statement.
Because scalar values are not secure.
hashes: secure
scalar: not secure
This means that if we could control
the function argument entirely,
including its data type,
we could control the SQL query,
effectively exploiting an SQL injection attack,
by inserting a hash
containing that specific value.
But…
CGI input doesn't allow hashes, right?
The whole Perl security module
is built on that assumption.
The problem is that, like us,
developers are assuming
CGI input is the only input method available.
CGI.
But CGI isn't the only way to go.
Bugzilla developers missed the fact
that their own system
is also featuring an XMLRPC and a JSONRPC,
both supporting input of non-scalar data types
like arrays and hashes!
But I'm not blaming them.
Yes, they forgot that there are more ways
for a user to input than CGI,
but still, they're just the product
of how Perl programming is taught,
filled with false assumptions and inconsistencies.
Expecting anything but this kind
of security problems is just naive.
But back to the vulnerability.
If we'll use one of these RPCs,
sending our input parameter with a malicious hash,
instead of just a regular numeric parameter,
we will be able to exploit the SQL injection!
So, if we'll send this regular request,
using the JSONRPC interface,
the number 1 will be used
as the ID of a bug to extract,
but if we'll send this request,
where instead of an integer we'll supply a hash,
then suddenly we will be able
to inject any SQL we'd like
into that statement, effectively
compromising the entire database.
Now when you look at this request, you realize
that this is not a sophisticated vulnerability.
All I did was just change the input data type
from scalar in this case to a hash,
and that's it, the system is compromised.
It was so heavily built on the assumption
that hashes are secure, that it offered me
almost unlimited access security wise.
The funny thing about that is, that
although it's so simple,
the attack has existed for over 5 years.
That's the year I was born in.
So, we now proved this "unknown-argument-type" feature
is a huge source for problems.
We also know writing different code
to handle different data types
just causes a lot of false assumptions.
But most importantly, treating non-scalar
data types such as hashes as "secure",
just because they supposedly can't be created by the user,
is very, very, BAD. Just ask Bugzilla.
But the shocking part really, is that, again,
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.
The problem is that creating non-scalar data types
is impossible in some cases.
We can't rely that some kind of RPC
will exist in the code
and support different data types,
and we can't create data types
using regular user input… Right?
Well, let's have a look at
how different CGI modules
handle different kind of input.
First, we'll take the most trivial scenario.
A single valued parameter,
something that looks like this request,
where the "foo" parameter
is assigned the string "bar".
In this case, a scalar is created on all three CGI modules,
which doesn't really help us,
but is pretty much what we've expected.
It is secure.
But what happens if instead of
sending a single-valued parameter,
we'll send a multi-valued parameter,
like in this request?
Now things are starting to get complicated.
On CGI.PM, as we already know,
a list is created,
which is very useful for us,
but not what we're after.
Let's have a look at
what the "new" Perl modules are creating.
We'll see that both of them are returning
arrays containing our values.
Arrays! WAT?
I thought you can't create
these kind of data types with regular input,
after all, they're considered safe.
But let's continue.
What happens if instead of sending a regular value,
we'll try and upload a file in that parameter?
Now things are really getting out of hand,
because CGI.PM now returns a file descriptor,
and Catalyst and Mojolicious returns a hash.
WAT?
We just exploited
the most popular Perl project in the world
because they assumed hashes can't be created by the user,
and now we're finding out
that not only we can create hashes,
it is a god-damned feature?!
That's insane!
The whole Perl security standard is built on that assumption
that users can't create non-scalar data-types
and now suddenly these are features?
But let's send a multi-file upload request
as in several files in the same parameter.
Watch closely, because this is where it gets ridiculous.
Now, CGI.PM returns a list of File Descriptors,
Catalyst returns a list of Hashes
and Mojolicious returns an Array of Objects! WAT?!
laughter and applause
Almost any Perl project in the world
uses one of these modules
for parsing CGI input.
Just think how many developers assumed
the exact same thing Bugzilla assumed
and treated hashes and arrays as secure data types.
So if you're using CGI.PM,
instead of the expected scalar value you could be getting
a list, a file descriptor or a list of file descriptors
and if you're using Catalyst
you could receive a scalar, an array, a hash or a list,
which is basically any data type.
So expecting your function… yeah
audience chuckling
So expecting your function arguments
to be of a specific data type is false.
Expecting hashes and arrays to be secure is also false.
Expecting scalar only user input
is a major false.
And to be honest, it seems that in Perl expecting is false!
laughter and applause
You just can't expect anything
even the most basic of things
such as what data type your variable is made of.
You just don't know.
But I felt all of these points will
go un-noticed
without an extreme example of Perl's absurdity.
So I found an extreme example.
One that will clearly show
the ridiculous nature of the language.
And this is it:
All this code does is print an uploaded file's content.
And to show you how basic and simple that code is,
I'll explain each line.
The first line just creates a new CGI instance,
so we could get the file from the user.
The second line checks if a file
has been uploaded in the "file" parameter.
The third line gets the file descriptor from the CGI module,
while the fourth line loops through the file
and the fifth prints it.
That's it. Again: all this code does
is get a file and print it.
clapping
That's it.
A user has uploaded a file to the server
and the server is just returning its content.
It's not saving it anywhere,
it's not moving it anywhere,
it just prints its content.
There should be absolutely
nothing dangerous in this code,
it contains literally five lines.
Yet, it's demo time.
laughter
So trust me, you don't need to see the text,
all you need to see is that
when I'm sending a regular request nothing happens.
When I send it now, nothing happens,
I'm just getting the file content.
We're having fun, you don't see the burp…
Now, nice. Okay.
So…
…L't me just…
…I have no idea where my mouse is, okay.
So…
I'm sending a regular request,
nothing happens, just getting the content.
I know, you can't see the text…
…and…
when I'm sending my malicious request,
something interesting will pop up.
Watch closely! It's gonna be quick.
Ready?
Oh, you haven't seen it, it's on the different screen.
Just a second… oh… duplicate…
(from audience): … magnify it!
Netanel: I'll magnify you!
laughter
Alright, so… watch closely.
Ohh, uuh? What was that?
Let's see it again.
mocking Uuuuuh?!
laughter and applause
Yupp, clearing throat
… just a second.
Nice.
So you're probably asking yourself right now
"What the fuck did I just see?"
laughter
"Was that a terminal screen?"
And the answer is … "Yes"
Yes, it was,
specifically the "ipconfig" command output.
Or in other words: What you just saw
was me exploiting that five lines
with a remote code execution attack.
So now that you saw the magic happens,
I think it's time for some explanations.
The first line, responsible for checking
if a file has been uploaded in the "file" parameter,
doesn't exactly do as it says.
Instead of checking if the "file"
parameter is an uploaded file,
it checks if one of its values is a file descriptor.
Let me clarify that, instead of checking
if the parameter is only a file,
it checks if the parameter is also a file.
laughter
Meaning that uploading a file
and assigning another scalar value to the same parameter
will still work and bypass the check!
WAT?
more laughter and applause
Creative fellows those guys are.
So now we can assign the "file" parameter
both a regular file and a scalar value.
But what happens when we try to get
the "file" parameter value?
In a regular request, it should return
the uploaded file descriptor,
but now that we're adding another value to that parameter,
param() returns a list containing all the values we sent:
the file we've uploaded and our scalar value.
But the "file" variable
can't contain two values, right?
So instead of converting
the returned list into an array
Perl only uses the first element of that list.
So if we'll send our scalar value
before we send our file,
the $file variable will be assigned
our scalar value
instead of the uploaded file descriptor.
Which means, that $file
is now a regular string!
in high pitched voice: WAT?
But what happens to this operator
when we use a string
instead of a file descriptor?
Well, the brackets operator
doesn't work with strings, right?
It works with file descriptors,
why should it work with strings?
Well, that appears true
unless that string is "ARGV".
laughter and applause
That's not a crazy part.
more laughter
In that case the brackets operator, listen closely,
loops through the script arguments,
which in CGI comes directly from the
query string instead the command line,
and it treats them as file paths,
inserting each one into an open() call!
again laughter
WAT?
Yeah, that made sense in some point, I guess.
All of this basically means that now,
instead of displaying
our own uploaded file content,
we can display the content
of any file on the server.
But that's not the end,
as we haven't executed code yet.
To execute code, we have
to look at the open() function.
Again, this is the function being called
with the ARGV values as file paths.
open() is responsible for opening
a file descriptor to a given file.
Unless a "pipe" character is added
to the end of the string,
laughter
and in that case instead of opening the file,
it executes it…
applause rising
…acting as an exec() call!
more applause
So … when we send our exploit,
containing our uploaded file,
the "ARGV" malicious scalar value,
and the ipconfig command followed by a pipe
this is what we get.
WAT?
WAT?
applause
I know, I'm shocked too, but I'm not done yet.
laughter
Truth be told, I didn't write that code.
Remember that PerlMonks told me
that I should read their fucking manual?
more laughter
Guess where that code came from:
the official CGI documentation!
big applause and audience whistling
But, I'm not blaming CGI.PM developers.
Nor am I blaming developers
who copied from CGI.PM examples.
After all, who could have known
that this is what this code will do?
This is how it could be exploited?
There's no exec calls,
the file is not saved anywhere,
and we're only using a "print".
The sole responsible for this mess,
is the Perl language.
Perl is the one silently expanding lists,
Perl is the one mixing up your data types,
Perl is the one executing user input
with no exec calls,
Perl is the problem,
not its developers.
applause rising
And until this god-damned, bizarre,
dangerous language is fixed,
you could only
stop
using
Perl!
Thank you!
more applause
Herald: So I guess
we have some time for questions now.
laughter
Netanel: Maybe
Herald: And I have the funny feeling,
we will have some questions now.
Ok, so we have some microphones here.
Please queue up.
Please do not shout in, because we need
to record it on the stream.
Well, here we go.
And we also have some questions
from the internet, don't we?
Signal Angel: Oh yes, we do!
laughter
Signal: But before we come
to the technical questions,
the IRC wants you to know,
what you did to it:
it felt like there were explosions
and camels everywhere.
Netanel laughing: That's the point
Signal: And incidently they want to know,
if you have a list of those camel pics somewhere?
Netanel: I think Google has it?
more laughter
Just there search camels.
Signal: So for the first question.
Opello(?) wants to know,
if the take-away is, that Perl project authors
so shouldn't trust input
and instead verify types with REF
and always use prepared SQL statements?
Netanel: That's a good question. The take-away should be…
laughter
well, how will I phrase it …
I think I have a slide … somewhere …
more laughter
Oh wait, where's my slide?
Don't worry, have it right here.
But really, trusting user input
is always a bad idea
and most developers know it.
The problem is, that…
well, at least from the code
I saw written in Perl,
and that's a lot of code, trust me
…is that hashes and arrays
are almost always considered secured
as they supposedly can't be
created by user input, as I said.
But, when you're expecting your user input
to be a scalar, a string or even a list
and instead you get a hash from unexpected
directions, you get confused.
And you can't always
live in the fear of not knowing
what data type you're trying to handle.
Well, not trusting scalar data types
is a wise decision, because it's dangerous.
But not trusting your hashes,
as well not trusting your arrays?
What's next? Not trusting your own code?
You just can't expect anything
to really work as it should.
When you're writing Perl,
you are constantly attacked
by all these different directions.
And even the data type direction is a problem now.
I hope that answered the question
beside the slide.
Herald: Well, then we're gonna go over
and start with number one.
Questioner: So thank you for opening our eyes.
Even I use Perl, I would say,
for cooking and yes …
Netanel: I remember you
Q: Sorry?
N: I remember you from the last talk!
Q: No no
N: Oh, you're new? Oh… smirking
Q: I'm new, I'm new…
Q: So… I can't say, I'm not guilty of that,
but I still would say yes,
Perl is a bit like cooking with my mum.
Sometimes I put something into…
the… with the boiling thing…
and sometimes she, sometimes I go away,
sometimes she go away
and the only thing you can do is always taste.
And yes, you're maybe right, Perl is a language
where you never know what comes out,
but it's real cool!
If you get the right response you can use it,
if you use it to write web applications
I would agree.
Web applications, the professional ones
at least, are not for cooking,
but for doing funny things and
have some fun, I think it's a perfect language.
N: I think Perl is a lot of fun.
laughter
I completely agree on that. laughing
Herald: Then we're gonna go over to two.
Question: Was your life ever threatened
while interacting with the Perl community?
laughter
N: Could you please repeat that? I …
Q: Was your life ever threatened
while interacting with the Perl community?
N: Definitely. Definitely,
I'm getting hate mail every day,
living in fear …
H: And over to the three, please.
Q: I think I speak for all of us,
when I thank you for this wonderful talk,
N: Uh, thank you. Thank you really! Thank you.
applause
Q: Brilliantly executed, but… ehm…
you spoke about Perl 5 I think.
N: Yes, you are absolutely right.
Q: As some of you might know, this christmas…
laughter
Q: …so tomorrow Ingo Blechschmidt
is going to give a talk about how Perl 6
will make everything better
and how everyone should start
using Perl 6 and…
N: It also craps rainbows
Q: Yeah, of course…
Q: My personal comment is:
wouldn't it have happened
with a statically typed language?
So I think some nice folks at Haskell
in IRC are waiting for you Perl developers
to please come, join us … Thank you!
N: smirking
Herald and Netanel start speaking simultaneously
H: …sorry, to answer first, where am I… sorry
N: Ah, no..., I am not answering, just...
just a quick note about Perl 6.
This talk is all about Perl 5, alright?
I … Perl 6 came out a couple of days ago and …
...from …at least from what I saw,
Perl 6 is to Perl as…
C++ is to C. It's the same name,
but it's a whole different language.
So yes, this is Perl 5.
Maybe I'll come back next year about Perl 6?
laughter
Who knows?
Herald: I'm looking forward to that already.
applause
Herald pointing to Signal Angel
Signal: Yeah… Joerd(?) wants to know:
of course you talked a lot about CGI.PM
which you know was removed from repository from Perl
even before your talk last year.
So what about it's replacements
from CPAN like CGI::Simple.
Netanel: I don't know, I haven't checked it.
When I decided on which modules to check,
I took CGI.PM because even though it is old,
it is the most popular in the world as of today
and I took Mojolicious and Catalyst because
they were really popular, too.
So I didn't take the newest modules,
I take the most popular modules.
And I think, that's the important
aspect of … deciding.
Herald: And over to one, please.
Questioner: Hi… I'm… part of the Perl community, and…
laughter
N: Hi!
Q: But I just start with Perl – 5
N: Uhh… ehm… uhh… didn't you… nhaa…
laughter
Q: We use Perl for almost every module
that we have at work
and this worked really fine.
N: …yeah…
Q: And I don't know why you're picking Perl as language to attack.
It's a really old language, it's also every language
that we can pick, that has problems.
But it doesn't mean this has to die or
stop using it. So I don't know why…
N: …you're right, you're right.
First of all, you're completely right,
because a language shouldn't die, it should improve.
C got critized and it improved.
PHP got critized and it improved.
Why can't Perl be critized, too?
Why is it like a code, when you say
something bad about Perl, then,
I don't know, a horde of PerlMonks jumps on you?
Why don't improve the language?
Don't use it in your work though,
it's dangerous.
laughter and applause
H: Then we're gonna jump over to five, please.
Q: Hi. I'm not a Perl developer,
but I use a lot of Ruby and Python.
Is this really limited to Perl or
does this apply to more or less
any dynamic language?
N: As I said in one of the first few slides,
some of it also applies to Python.
Specifically the thing
when you can't specify what data types
your function arguments can get.
But, what's unique to Perl is that
writing different code
for different data types in one function
is very, very common.
You can do it in every language, of course!
But it is very common only in Perl!
And that is unique about it,
of course besides the thing
that hashes and arrays are secure.
That's of course Perls only fault.
H: Good, then we're gonna go over to six, please.
Q: Hey! Did you say WAT more
while preparing this talk or while holding it?
N: Uhm. Both. Laughing.
Did I rant? That was the … right?
Q: Did you say it more
while preparing it or while holding it?
N: I'm missing your word, man, can you...
Ahh, wat… WAT! Ohh… Yeah, both!
laughter
H: Ok, do we have another from the internet?
Signal: Does your exploit
also work in tainted mode?
N: No, I believe not. No, it doesn't.
H: And another one...
S: Is there any Perl obfuscated code exploits
like this for Catalyst or Mojolicious?
someone chuckling in audience
N: I've no idea, man, maybe.
I didn't check it of course.
I didn't check every module
for every exploit, I ever want to create, but
on CGI.PM, which is again
the most popular CGI library, it did.
So, maybe the internet
can find more exploits. I know it can.
H: Bring it on. That's it?
N: That's it?
Thank you!
applause
Herald: Thank you very much!
Netanel: Thank you!
postroll music
subtitles created by c3subtitles.de
in the year 2016. Join, and help us!