Dentro de uma linguagem de programação, eu executo um comando shell simples
cd var; echo > create_a_file_here
com var sendo uma variável que contém uma string de (espero) um diretório para o local onde eu quero criar o arquivo "create_a_file_here". Agora, se alguém vir esta linha de código, é possível explorá-la atribuindo, por exemplo:
var = "; rm -rf /"
As coisas podem ficar bem feias. Uma maneira de evitar o caso acima seria talvez pesquisar na string var vários caracteres especiais como ';' antes de executar o comando shell, mas duvido que isso abranja todas as explorações possíveis.
Alguém sabe uma boa maneira de garantir que "cd var" mude apenas um diretório e nada mais?
shell-script
shell
ES___
fonte
fonte
var
como argumento. Por exemplo, chamandosh
com argumentos-c
,'cd "$1"; echo > create_a_file_here'
,'sh'
,var
obras e não precisa de qualquer alteraçãovar
. O'sh'
argumento é passado como$0
.sh
ou criando sua própria linguagem de programação com uma sintaxe semelhante, mas que se expande emvar
vez de exigir que você escrevacd "$var"
? Ou isso ébash
comshopt -s cdable_vars
? Ah, acho que você quer dizer que outro programa bifurca um shell para executar esses comandos. Então, basta citarvar
, mas certifique-se que não inclui em si um caracter de aspas ...s='"'; echo "$s"
impressões"
.var=untrusted string
no programa pai, tambémvar
é uma variável de ambiente que já está definida ao chamarsh
. Então, você só precisa citá-lo toda vez que o expandir, o que é possível de forma confiável. Ah, vejo que idéia já é parte da resposta de Stéphane> <.Respostas:
Se bem entendi,
var
é uma variável na sua linguagem de programação.E na sua linguagem de programação, você está solicitando que um shell interprete uma string que é a concatenação
"cd "
, o conteúdo dessa variável e"; echo > create_a_file_here"
.Nesse caso, sim, se o conteúdo de
var
não for totalmente controlado, é uma vulnerabilidade de injeção de comando.Você pode tentar citar adequadamente o conteúdo da variável¹ na sintaxe do shell, para garantir que ele seja passado como um único argumento para o
cd
builtin.Outra abordagem seria passar o conteúdo dessa variável de outra maneira. Uma maneira óbvia seria passar isso em uma variável de ambiente. Por exemplo, em C:
Desta vez, o código que você solicita que o shell interprete seja corrigido, ainda precisamos escrevê-lo corretamente na sintaxe do shell (aqui assumida como um shell compatível com POSIX):
-P
paracd
fazer uma simpleschdir()
--
marcar o final das opções para evitar problemas aovar
iniciar com-
(ou+
em algumas conchas)CDPATH
a string vazia no caso de estar no ambienteecho
comando se tivercd
sido bem-sucedido.Há (pelo menos) um problema restante: se
var
houver-
, ele não chdir no diretório chamado,-
mas no diretório anterior (como armazenado em$OLDPWD
) eOLDPWD=- CDPATH= cd -P -- "$DIR"
não é garantido que ele funcione. Então você precisaria de algo como:¹ Observe que apenas fazer um não
é o caminho a seguir, você estaria apenas mudando o problema.system(concat("cd \"", var, "\"; echo..."));
Por exemplo, um
var = "$(rm -rf /)"
ainda seria um problema.A única maneira confiável de citar texto para shells semelhantes a Bourne é usar aspas simples e também cuidar das aspas simples que podem ocorrer na string. Por exemplo, vire
char *var = "ab'cd"
parachar *escaped_var = "'ab'\\''cd'"
. Ou seja, substituir toda'
a'\''
e embrulhe a coisa toda dentro'...'
.Que ainda assume que essa seqüência citada não é usado dentro de acentos graves, e você ainda precisa o
--
,-P
,&&
,CDPATH=
...fonte
Solução simples: não chame o shell do seu programa. Em absoluto.
Seu exemplo aqui é trivial, alterar o diretório e criar arquivos deve ser fácil em qualquer linguagem de programação. Mas mesmo se você precisar executar um comando externo, geralmente não há necessidade de fazê-lo através do shell.
Então, por exemplo, em Python, em vez de executar
os.system("somecmd " + somearg)
, usesubprocess.run(["somecmd", somearg])
. Em C, em vez desystem()
, usefork()
eexec()
(ou encontre uma biblioteca que faça isso).Se você precisar usar o shell, cite os argumentos da linha de comando ou passe-os pelo ambiente, como na resposta de Stéphane . Além disso, se você se preocupar com caracteres especiais, a solução correta é não tentar filtrar (lista negra) caracteres potencialmente perigosos, mas apenas manter os caracteres conhecidos como seguros (lista de permissões).
Permita apenas os personagens cujas funções você conhece, para que haja menos risco de perder alguma coisa. O resultado final pode ser que você decide apenas permitir
[a-zA-Z0-9_]
, mas isso pode ser suficiente para concluir o trabalho. Você também pode querer verificar se o seu local e conjunto de ferramentas não incluem letras acentuadas comoä
eö
em que. Eles provavelmente não são considerados especiais por nenhum shell, mas, novamente, é melhor ter certeza se eles passam ou não.fonte
[a-zA-Z0-9]
não inclui coisas comoà
cuja codificação também pode ser mal interpretada por alguns shells (comobash
) em alguns locais.Dentro de uma linguagem de programação, deve haver maneiras melhores de fazer coisas do que executar comandos shell. Por exemplo, a substituição
cd var
pelo equivalente de sua linguagem de programaçãochdir (var);
deve garantir que qualquer truque com o valor devar
apenas resulte em um erro "Diretório não encontrado" em vez de ações não intencionais e possivelmente maliciosas.Além disso, você pode usar caminhos absolutos em vez de alterar diretórios. Apenas concatene o nome do diretório, a barra e o nome do arquivo que você deseja usar.
Em C, eu poderia fazer algo como:
Certamente sua linguagem de programação pode fazer algo semelhante?
fonte