【问题标题】:Is this a safe use of python eval()?这是对 python eval() 的安全使用吗?
【发布时间】:2011-03-18 19:17:06
【问题描述】:

如果攻击者可以控制attacker_controlled_nasty_variable的值,那么这段代码是否存在漏洞?

dic={"one":1,
      "nasty":attacker_controlled_nasty_variable,
     }
store=str(dict)
...
dic=eval(store)

【问题讨论】:

  • 既然攻击者可以编辑你的 Python 源代码,这个问题就很傻了,不是吗?
  • 谁说攻击者在他的本地机器上运行代码?
  • @Tim Pietzcker:如果不在本地机器上运行,攻击者是如何设置讨厌的变量的?
  • @S.Lott SQL 注入、配置文件、网页上的表单 - 很多方法...
  • @S.Lott 然而很多人确实写出了非常糟糕的代码。根据应用程序,您可能希望允许用户拥有他们自己的配置文件,他们可以上传这些配置文件并针对他们的帐户运行,但是如果您不清理您的输入,则会出现漏洞。最重要的是,并非所有项目都由一个人(少数人)整体开发,因此您的代码尽可能好,并且可以弥补您大学的一些不足之处。

标签: python security


【解决方案1】:

使用ast.literal_eval() 代替eval()

【讨论】:

    【解决方案2】:

    是的。它可以替换为具有__repr__() 方法的对象,该方法本身具有有效负载,或者返回传递给eval() 时可能不安全的字符串。

    概念证明:

    class MyClass(object):
      def __repr__(self):
        return 'os.system("format c:")'
    
    bad = [MyClass()]
    print str(bad)
    

    【讨论】:

    • 你能举个例子吗?在他的示例中,我试图想象攻击是如何通过 str() 操作的。
    • class bad_repr(object): def __repr__(self): return 'evil'(如果他的变量只能是字符串,他就不能这样做)使用该类,字符串化的 dict 将看起来像 {'nasty': evil, 'one': 1} - 所以 evil 没有被引用并且可能很漂亮很多python代码。
    • 这个线程中的关键点似乎是潜在的攻击者是否可以设置对象,或者只能设置一个字符串值。
    • @payne,这很重要,因为在上面的代码中,讨厌的输入将是一个字符串,因此不可利用。
    【解决方案3】:

    只要您可以确定attacker_controlled_nasty_variable 绝不是攻击者可以控制__repr__(或__str__)的对象,因为他可以注入python 代码。

    但是,最好使用repr(dic) 而不是str(dic),因为预计只有repr 会返回有效的python 代码。

    另外——正如@payne 所提到的——使用更安全的ast.literal_eval() 而不是eval()

    【讨论】:

      【解决方案4】:

      让我们试试吧:

      >>> attacker_controlled_nasty_variable="`cat /etc/passwd`"
      >>> dic={"one":1,
      ...     "nasty":attacker_controlled_nasty_variable,
      ... }
      >>> store = repr(dic)
      >>> store
      "{'nasty': '`cat /etc/passwd`', 'one': 1}"
      >>> dic=eval(store)
      >>> dic
      {'nasty': '`cat /etc/passwd`', 'one': 1}
      
      >>> attacker_controlled_nasty_variable="'hello',}"
      >>> dic={"one":1,
      ...     "nasty":attacker_controlled_nasty_variable,
      ... }
      >>> repr(dic)
      '{\'nasty\': "\'hello\',}", \'one\': 1}'
      >>> eval(repr(dic))
      {'nasty': "'hello',}", 'one': 1}
      

      您可能想尝试更多案例,但根据经验,__repr__ 似乎正确引用了内容。

      【讨论】:

      • 怎么样:class Bad: def __repr__(self): os.system("do bad stuff) \attacker_controlled_nasty_variable = Bad()?
      • 啊,您确实按照建议尝试了额外的案例!不错。
      猜你喜欢
      • 2023-01-30
      • 2012-12-28
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多