AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 448443
Accepted
Tim
Tim
Asked: 2018-06-08 06:28:21 +0800 CST2018-06-08 06:28:21 +0800 CST 2018-06-08 06:28:21 +0800 CST

"execute qualquer comando que passará dados não confiáveis ​​para comandos que interpretam argumentos como comandos"

  • 772

Do manual do findutils:

Por exemplo, construções como esses dois comandos

# risky
find -exec sh -c "something {}" \;
find -execdir sh -c "something {}" \;

são muito perigosos. A razão para isso é que o '{}' é expandido para um nome de arquivo que pode conter um ponto e vírgula ou outros caracteres especiais para o shell. Se, por exemplo, alguém criar o arquivo /tmp/foo; rm -rf $HOME, os dois comandos acima poderão excluir o diretório inicial de alguém.

Portanto, por esse motivo, não execute nenhum comando que passará dados não confiáveis ​​(como os nomes dos arquivos) para comandos que interpretam argumentos como comandos a serem interpretados posteriormente (por exemplo, 'sh').

No caso do shell, existe uma solução inteligente para esse problema:

# safer
find -exec sh -c 'something "$@"' sh {} \;
find -execdir sh -c 'something "$@"' sh {} \;

Essa abordagem não garante evitar todos os problemas, mas é muito mais segura do que substituir os dados escolhidos pelo invasor no texto de um comando shell.

  1. A causa do problema é find -exec sh -c "something {}" \;que a substituição de {}não está entre aspas e, portanto, não é tratada como uma única string?
  2. Na solução find -exec sh -c 'something "$@"' sh {} \;,

    • first {}é substituído, mas como {}não está entre aspas, também não "$@"tem o mesmo problema que o comando original? Por exemplo, "$@"será expandido para "/tmp/foo;", "rm", "-rf"e "$HOME"?

    • por que {}não é escapado ou citado?

  3. Você poderia dar outros exemplos (ainda com sh -c, ou sem ele se aplicável; com ou sem findo que pode não ser necessário) onde o mesmo tipo de problema e solução se aplicam, e que são exemplos mínimos para que possamos focar no problema e na solução com pouca distração possível? Veja Maneiras de fornecer argumentos para um comando executado por `bash -c`

Obrigado.

shell
  • 4 4 respostas
  • 2516 Views

4 respostas

  • Voted
  1. Best Answer
    Stephen Kitt
    2018-06-08T06:58:19+08:002018-06-08T06:58:19+08:00

    Isso não está realmente relacionado à citação, mas ao processamento de argumentos.

    Considere o exemplo arriscado:

    find -exec sh -c "something {}" \;
    
    • Isso é analisado pelo shell e dividido em seis palavras: find, -exec, sh, -c, something {}(sem mais aspas), ;. Não há nada para expandir. O shell é executado findcom essas seis palavras como argumentos.

    • Quando findencontra algo para processar, digamos foo; rm -rf $HOME, ele substitui {}por foo; rm -rf $HOME, e executa shcom os argumentos sh, -c, e something foo; rm -rf $HOME.

    • shagora vê -ce, como resultado, analisa something foo; rm -rf $HOME( o primeiro argumento não opcional ) e executa o resultado.

    Agora considere a variante mais segura:

    find -exec sh -c 'something "$@"' sh {} \;
    
    • O shell é executado findcom os argumentos find, -exec, sh, -c, something "$@", sh, {}, ;.

    • Agora, quando findfinds foo; rm -rf $HOME, ele substitui {}novamente e é executado shcom os argumentos sh, -c, something "$@", sh, foo; rm -rf $HOME.

    • shvê -ce analisa something "$@"como o comando a ser executado she foo; rm -rf $HOMEcomo os parâmetros posicionais ( começando de$0 ), expande "$@"para foo; rm -rf $HOME um valor único e é executado somethingcom o argumento único foo; rm -rf $HOME.

    Você pode ver isso usando printf. Crie um novo diretório, insira-o e execute

    touch "hello; echo pwned"
    

    Executando a primeira variante da seguinte forma

    find -exec sh -c "printf \"Argument: %s\n\" {}" \;
    

    produz

    Argument: .
    Argument: ./hello
    pwned
    

    enquanto a segunda variante, executada como

    find -exec sh -c 'printf "Argument: %s\n" "$@"' sh {} \;
    

    produz

    Argument: .
    Argument: ./hello; echo pwned
    
    • 29
  2. Mikel
    2018-06-08T07:39:03+08:002018-06-08T07:39:03+08:00

    Parte 1:

    findapenas usa a substituição de texto.

    Sim, se você fez sem aspas, assim:

    find . -type f -exec sh -c "echo {}" \;
    

    e um invasor foi capaz de criar um arquivo chamado ; echo owned, então ele executaria

    sh -c "echo ; echo owned"
    

    o que resultaria na execução do shell echoentão echo owned.

    Mas se você adicionasse aspas, o invasor poderia simplesmente encerrar suas aspas e colocar o comando malicioso depois, criando um arquivo chamado '; echo owned:

    find . -type f -exec sh -c "echo '{}'" \;
    

    o que resultaria na execução do shell echo '', echo owned.

    (se você trocou as aspas duplas por aspas simples, o invasor também poderá usar o outro tipo de aspas.)


    Parte 2:

    Em find -exec sh -c 'something "$@"' sh {} \;, o {}não é interpretado inicialmente pelo shell, ele é executado diretamente com execve, portanto, adicionar aspas do shell não ajudaria.

    find -exec sh -c 'something "$@"' sh "{}" \;
    

    não tem efeito, pois o shell retira as aspas duplas antes de executar find.

    find -exec sh -c 'something "$@"' sh "'{}'" \;
    

    adiciona aspas que o shell não trata especialmente, então na maioria dos casos significa apenas que o comando não fará o que você deseja.

    Expandir para /tmp/foo;, rm, -rf, $HOMEnão deve ser um problema, porque esses são argumentos para something, e somethingprovavelmente não trata seus argumentos como comandos a serem executados.


    Parte 3:

    Suponho que considerações semelhantes se aplicam a qualquer coisa que receba entrada não confiável e a execute como (parte de) um comando, por exemplo xargse parallel.

    • 3
  3. ilkkachu
    2018-06-08T11:35:53+08:002018-06-08T11:35:53+08:00

    1. A causa do problema é find -exec sh -c "something {}" \;que a substituição de {}não está entre aspas e, portanto, não é tratada como uma única string?

    Em certo sentido, mas citar não pode ajudar aqui . O nome do arquivo que é substituído no lugar de {}pode conter qualquer caractere, incluindo aspas . Qualquer que seja a forma de citação usada, o nome do arquivo pode conter o mesmo e "quebrar" a citação.

    2. ... mas como {}está sem aspas, também não "$@"tem o mesmo problema que o comando original? Por exemplo, "$@"será expandido para "/tmp/foo;", "rm", "-rf", and "$HOME"?

    No. "$@"se expande para os parâmetros posicionais, como palavras separadas, e não os divide mais. Aqui, {}é um argumento para findem si mesmo e findpassa o nome do arquivo atual também como um argumento distinto para sh. Está disponível diretamente como uma variável no script de shell, não é processado como um comando de shell em si.

    ... por que {}não é escapado ou citado?

    Não precisa ser, na maioria das conchas. Se você executar fish, ele precisa ser: fish -c 'echo {}'imprime uma linha vazia. Mas não importa se você as cita, o shell apenas removerá as aspas.

    3. Você poderia dar outros exemplos...

    Sempre que você expande um nome de arquivo (ou outra string não controlada) como está dentro de uma string que é considerada algum tipo de código (*) , existe a possibilidade de execução de comandos arbitrários.

    Por exemplo, isso expande $fdiretamente o código Perl e causará problemas se um nome de arquivo contiver aspas duplas. A citação no nome do arquivo encerrará a citação no código Perl, e o restante do nome do arquivo pode conter qualquer código Perl:

    touch '"; print "HELLO";"'
    for f in ./*; do
        perl -le "print \"size: \" . -s \"$f\""
    done
    

    (O nome do arquivo deve ser um pouco estranho, pois o Perl analisa todo o código antecipadamente, antes de executá-lo. Portanto, teremos que evitar um erro de análise.)

    Enquanto isso passa com segurança por meio de um argumento:

    for f in ./*; do
        perl -le 'print "size: " . -s $ARGV[0]' "$f"
    done
    

    (Não faz sentido executar outro shell diretamente de um shell, mas se você fizer isso, é semelhante ao find -exec sh ...caso)

    (* algum tipo de código inclui SQL, então XKCD obrigatório: https://xkcd.com/327/ mais explicação: https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )

    • 3
  4. Ole Tange
    2018-06-08T23:28:07+08:002018-06-08T23:28:07+08:00

    Sua preocupação é precisamente a razão pela qual o GNU Parallel cita a entrada:

    touch "hello; echo pwned"
    find . -print0 | parallel -0 printf \"Argument: %s\\n\" {}
    

    Isso não será executado echo pwned.

    Ele executará um shell, para que, se você estender seu comando, não tenha uma surpresa repentina:

    # This _could_ be run without spawining a shell
    parallel "grep -E 'a|bc' {}" ::: foo
    # This cannot
    parallel "grep -E 'a|bc' {} | wc" ::: foo
    

    Para mais detalhes sobre o problema de spawning-a-shell, consulte: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell

    • 1

relate perguntas

  • Como funciona este comando? mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 1234 > /tmp/f

  • FreeBSD's sh: funções de lista

  • Existe uma maneira de fazer ls mostrar arquivos ocultos apenas para determinados diretórios?

  • o que grep -v grep faz

  • Como salvar um caminho com ~ em uma variável?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve