Quão seguro é o idioma 'ssh… “$ (typeset -f foo); foo ”'?

3

Suponha que alguma função do shell foo esteja definida na sessão atual do shell. Então o comando

typeset -f foo

imprime o código fonte desta função. Isto significa que, pelo menos em princípio, pode-se executar esta função em um host remoto via ssh como mostrado abaixo:

ssh <REMOTE-HOST> "$(typeset -f foo); foo"

(Para os fins desta questão, suponha que todos os comandos e caminhos do sistema de arquivos mencionados por foo estejam disponíveis em <REMOTE-HOST> . Além disso, suponha que bash seja o shell em ambas as extremidades.)

Meu instinto é que o acesso cego a algum código-fonte gerado automaticamente como esse seria extremamente frágil, mas não consegui encontrar um exemplo de uma função foo em que esse idioma falha.

Minha pergunta é: Quão seguro é esse idioma? Se não é seguro, alguém pode me dar um exemplo concreto que ilustra como ele falha? (A questão da segurança inclui o seguinte: o bash garante que tais usos de typeset -f sejam seguros?)

NB: Neste post não estou procurando alternativas; Eu só quero entender as propriedades desse idioma em particular.

EDIT: esclareceu que bash é o shell em ambas as extremidades.

    
por kjo 10.01.2018 / 20:43

1 resposta

4

Não é seguro se o código não for interpretado na mesma localidade em que foi gerado (ou se o nome da localidade for o mesmo, mas a definição dessa localidade difere entre o ssh host do cliente e host do servidor).

Particularmente importante é a codificação de caracteres e associação de caracteres nas categorias blank , alpha e alnum .

Por exemplo, o caractere α (letra minúscula grega alfa) no conjunto de caracteres BIG5 é codificado como 0xa3 0x5c, sendo 0x5c \ em ASCII (e todos os conjuntos de caracteres incluindo BIG5).

Então, se você tiver uma função foo definida nesse conjunto de caracteres como:

foo() {
  echo α
}

typeset -f fará a saída como tal, mas se for interpretado em uma localidade diferente como C, 0xa3 0x5c não será considerada como α , mas como um caractere 0xa3 desconhecido seguido por uma barra invertida. Isso pode ser explorado como com:

$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo \xa3\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token '}'
bash: line 5: '}'

O foo() { echo α\;}; echo gotcha; } tornou-se foo() { echo <0xa3>\; }; echo gotcha; } quando interpretado na localidade diferente.

Outros problemas:

O caractere à em UTF-8 é codificado como 0xc3 0xa0. Em iso8859-1 e vários outros conjuntos de caracteres iso8859 , 0xa0 é o caractere de espaço sem quebra. Em alguns sistemas, esse caractere é incluído na classe de caracteres blank , portanto, honrado pelo bash como um delimitador de tokens em sua sintaxe.

O Solaris é um desses sistemas em que U + 00A0 é considerado em branco:

$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN\'{system("echo gotcha")}\' 1;}' bash -c 'typeset -f foo; echo foo'  | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha

Veja como:

nawk -v x=àBEGIN... 1

foi interpretado como:

nawk -v x=<0xc3> 'BEGIN{system("...")}' 1

Note que se a função foi definida em uma localidade onde 0xa0 não era um espaço em branco ou onde 0xa3 0x5c era alfa, typeset -f ainda produziria o mesmo mesmo se chamado em uma localidade onde é um espaço em branco (produzindo uma saída diferente quando interpretado)

$ LC_ALL=zh_TW.big5 bash -c $'f() { echo \xa3\x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token '('
bash: line 3: '    echo �\$(uname)'

Mais geralmente, a saída de typeset , alias , export -p , set , locale são todos significados para serem adequados para reinputação em uma casca, mas além desses questões locais, várias implementações são conhecidas por terem vários problemas, e eu não ficaria surpreso se ainda houvesse muito mais.

Então, sim, eu concordo que você está certo em considerá-lo perigoso, e é uma boa ideia usá-los apenas no contexto em que você sabe de onde vêm os dados gerados. Por exemplo, no caso de typeset -f foo , use-o apenas em uma função foo que você definiu (e evite usar caracteres não-ASCII nele).

    
por 11.01.2018 / 14:17