Como proteger aplicativos Python contra injeção de script malicioso





Os aplicativos Python usam muitos scripts. Isso é o que os cibercriminosos usam para colocar um "porco" em nós - onde menos esperamos ver.



Uma das vantagens do Python é a facilidade de uso: para rodar um script, basta salvá-lo em um .pyarquivo e executar o comando python (, python my_file.py). Também é fácil quebrar nosso arquivo, como módulos my_app.pye my_lib.pycontinuar a conectar os módulos para usar o design import...from: import my_lib from my_app.py.



No entanto, essa simplicidade e leveza têm uma desvantagem: quanto mais fácil for para você executar o código em locais diferentes, mais oportunidades para um invasor interferir.



Coloque o código Python em um lugar seguro



O modelo de segurança Python é baseado em três princípios:



  1. , sys.path , .
  2. , (main), sys.path.
  3. python , -c -m.


Suponha que você queira executar um aplicativo Python que foi instalado "corretamente" em sua máquina. Nesse caso, o único local (além da pasta com o Python instalado) que será adicionado automaticamente ao seu sys.path por padrão é a pasta com o script principal ou arquivo executável.



Por exemplo, se pipestiver dentro /usr/bine você executar /usr/bin/pip, sys.pathapenas será adicionado /usr/bin. Apenas o root pode gravar arquivos em / usr / bin, portanto, este local é considerado seguro.



No entanto, o acordo nos obrigar a fazê-lo: /path/to/python -m pip. Isso evita problemas $PATHe conflitos com a documentação do Windows.



Em geral, tudo ficará bem de qualquer maneira, se apenas você tiver autoridade para adicionar e editar arquivos nos diretórios dos quais o Python obtém módulos para importação.



Pasta de downloads - local vulnerável



Existem muitas maneiras de forçar os navegadores (e às vezes outro software) a colocar arquivos com nomes arbitrários na pasta Downloads sem o conhecimento do usuário. Esta vulnerabilidade é explorada por um ataque denominado DLL Spoofing. No nosso caso, falaremos sobre scripts Python, mas a ideia é a mesma.



Os navegadores tornaram-se mais sérios sobre isso e estão gradualmente tentando garantir que os sites visitados pelo usuário não possam colocar arquivos secretamente em sua pasta Downloads.



No entanto, este problema será muito difícil de resolver completamente: por exemplo, ainda está disponível uma opção Content-Disposition HTTP header’s filename*que permite aos sites escolher um diretório para colocar os arquivos carregados.



Como funciona o ataque



Você executar a instalação: python -m pip. Você está baixando um pacote Python de um site totalmente confiável que, por algum motivo, no entanto, oferece downloads diretos em vez de PyPI. Talvez seja algum tipo de versão interna, talvez seja um lançamento preliminar - sem diferença. Então vai para você totally-legit-package.whl:



~$ cd Downloads
~/Downloads$ python -m pip install ./totally-legit-package.whl


Parece estar bem, mas duas semanas atrás, em um site completamente diferente que você visitou, algum XSS JavaScript baixou pip.py com malware em sua pasta Downloads sem o seu conhecimento.



Estrondo!



Batida!



~$ mkdir attacker_dir
~$ cd attacker_dir
~/attacker_dir$ echo 'print("lol ur pwnt")' > pip.py
~/attacker_dir$ python -m pip install requests
lol ur pwnt


Comportamento estranho PYTHONPATH



Alguns parágrafos acima, escrevi:



o único local (diferente da pasta Python instalada) que será adicionado automaticamente ao seu sys.path por padrão é o script principal ou a pasta executável.


Então, o que "default" faz aqui? Que outros locais você pode adicionar?



Em princípio, $PYTHONPATHqualquer coisa pode ser escrita em uma variável de ambiente . Mas você não escreveria sua localização atual $PYTHONPATH, não é?



Infelizmente, há uma situação em que você pode fazer isso acidentalmente.

Vamos esboçar um aplicativo Python "vulnerável" para ilustração:



# tool.py
try:
    import optional_extra
except ImportError:
    print("extra not found, that's fine")


Vamos criar 2 diretórios: install_dire attacker_dir. Vamos fazer fail in install_dir, então executar cd attacker_dire colocar nosso código malicioso lá pelo nome tool.py:



# optional_extra.py
print("lol ur pwnt")


Tudo o que resta é executá-lo:



~/attacker_dir$ python ../install_dir/tool.py
extra not found, that's fine


Até agora, tudo está indo bem.



Mas agora veremos um erro comum. Muitas pessoas recomendam adicionar $PYTHONPATHmais um item :



export PYTHONPATH="/new/useful/stuff:$PYTHONPATH";


À primeira vista, isso faz sentido: se você adicionar o projeto X $PYTHONPATH, talvez, de acordo com o projeto Y, algo foi adicionado lá também, ou talvez não; em qualquer caso, você não gostaria de substituir as alterações associadas a outros projetos. Isso é especialmente importante quando você está escrevendo documentação que muitas pessoas usarão.



E agora estamos diante de um comportamento "estranho" $PYTHONPATH. Se $PYTHONPATHestava vazio ou não instalado antes do primeiro lançamento , uma linha vazia aparecerá nele, que será reconhecida como o diretório atual. Vamos verificar isso:



~/attacker_dir$ export PYTHONPATH="/a/perfectly/safe/place:$PYTHONPATH";
~/attacker_dir$ python ../install_dir/tool.py
lol ur pwnt


Para maior segurança, vamos $PYTHONPATHesvaziá- lo e tentar novamente:



~/attacker_dir$ export PYTHONPATH="";
~/attacker_dir$ python ../install_dir/tool.py
lol ur pwnt


Exatamente, não é nada seguro!



E mais uma coisa : acontece que as situações em que uma variável está $PYTHONPATHvazia e uma variável $PYTHONPATHnão está definida são duas histórias diferentes:



os.environ.get("PYTHONPATH") == ""</code>  <code>os.environ.get("PYTHONPATH") == None.


Se você quiser ter certeza de limpar $PYTHONPATH, use o comando unset:



~/attacker_dir$ python ../install_dir/tool.py
extra not found, that's fine


Em geral, escrever em uma variável $PYTHONPATHera a maneira mais comum de configurar o ambiente para executar aplicativos Python. Felizmente, ele saiu de moda com o advento dos ambientes virtuais e do virtualenv. Se você tem uma configuração antiga que grava algo $PYTHONPATH, mas pode fazer sem ela, agora é a hora de excluí-la.



Se por algum motivo você não puder fazer isso, use um hack da vida :



export PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}new_entry_1"
export PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}new_entry_2"


Em bash e zsh, isso dará esta saída:



$ echo "${PYTHONPATH}"
new_entry_1:new_entry_2


Bem, agora não há dois pontos extras e entradas vazias.



Finalmente, se você ainda estiver trabalhando com $PYTHONPATH, use caminhos absolutos. É sempre!



O problema é muito mais sério



Existem várias opções para o desenvolvimento perigoso de eventos associados ao lançamento de arquivos Python da pasta Downloads:



  • Executar python ~/Downloads/anything.py(mesmo que anything.pyseja seguro). Sua pasta de Downloads será adicionada a sys.path.
  • Uma vez iniciada, a jupyter notebook ~/Downloads/anything.ipynbpasta Downloads também será adicionada sys.path.


Portanto, é melhor remover os arquivos .py e .ipynb desta pasta antes de executar.



A execução cd Downloadse o lançamento subsequente python -ccom instruções importdentro ou o lançamento interativo pythoncom importação subsequente não resolve completamente o problema se os arquivos importados estiverem na pasta Downloads.



Infelizmente, este ~/Downloads/não é o único local que pode conter arquivos maliciosos. Por exemplo, se você estiver administrando um servidor para o qual os usuários podem fazer upload de arquivos, certifique-se de que ninguém nem nada possa iniciar cd public_uploadsantes de executar o comando python.



Nesse caso, pode valer a pena considerar que o código que lida com o upload de arquivos é anexado aos seus nomes .uploaded. Isso ajudará a evitar a execução de script não planejada .py.



Cuidados



Se você tiver aplicativos escritos em Python que deseja usar enquanto estiver na pasta Downloads, crie uma regra para inserir o caminho para o script ( / path / to / venv / bin / pip), não o módulo ( / path / to / venv / bin / python -m pip).



Em geral, apenas evite usar Downloads como seu diretório de trabalho atual e mova todos os scripts que deseja usar para um local mais adequado antes de iniciar.



É importante entender de onde Python obtém o código de onde será executado. Permitir que alguém execute pelo menos uma linha do script Python esquerdo é equivalente a dar controle total do seu computador!



Por necessidade



Lendo esse artigo com "dicas e truques para a vida" sobre segurança, é muito fácil assumir que o autor é muito inteligente, sabe um monte de pequenas coisas que outras pessoas deveriam saber e pensar constantemente sobre isso. Mas, na verdade, isso não é totalmente verdade. Eu vou explicar.



Ao longo dos anos, observei com frequência invejável como os usuários não entendiam de onde o Python está baixando o código. Por exemplo, as pessoas colocam seu primeiro programa usando Twisted em um arquivo chamado twisted.py. Mas, neste caso, a importação da biblioteca é simplesmente impossível!



Os cibercriminosos se alegram muito mais se forem capazes de atacar com sucesso administradores de sistema ou desenvolvedores. Se você hackear um usuário, obterá os dados desse usuário. Mas se você hackear um administrador ou desenvolvedor e fizer isso direito, poderá obter acesso a milhares de usuários cujos sistemas estão sob o controle do administrador, ou até mesmo milhões de usuários que usam software de desenvolvedor.



Portanto, “apenas tenha cuidado o tempo todo” não é uma receita confiável. Os profissionais de TI responsáveis ​​por produtos com um grande número de usuários realmente precisam ser mais cuidadosos. No mínimo, eles devem ser informados sobre as peculiaridades do trabalho de certas ferramentas de desenvolvimento.



Bug ou recurso ...



Nada do que descrevi acima é realmente um "bug" ou "vulnerabilidade" real. Não acho que os desenvolvedores Python ou Jupyter fizeram algo por engano. O sistema funciona da maneira que foi projetado e isso provavelmente pode ser explicado. Pessoalmente, não tenho ideia de como algo pode ser alterado nele sem restringir o poder do Python, pelo qual o valorizamos tanto.



Uma das minhas invenções favoritas é o SawStop, um sistema de segurança exclusivo para serras de mesa. Ele permite que você pare a rotação da lâmina da serra em 5 milissegundos - ao entrar em contato com o corpo humano. Antes da invenção deste sistema, as serras de mesa eram ferramentas extremamente perigosas, mas desempenhavam uma importante função de produção. Muitas coisas muito úteis e importantes foram feitas nas serras de mesa. No entanto, também é verdade que as serras de mesa foram responsáveis ​​por uma parte desproporcional dos acidentes em marcenarias. SawStop agora economiza muitos dedos todos os anos.



Portanto, ao detalhar as complexidades do script Python, também espero pensar um pouco sobre alguns engenheiros de segurança. O SawStop pode executar código arbitrário para intérpretes interativos? Que solução poderia evitar alguns dos problemas acima?



Fiquem amigos seguros.






Publicidade



VDSina oferece servidores seguros em Linux ou Windows - escolha um dos SO pré-instalados ou instale a partir de sua imagem.






All Articles