运用QL和LGTM举行变异剖析 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

运用QL和LGTM举行变异剖析

申博_安全防护 申博 70次浏览 已收录 0个评论

在软件开辟中,我们常常看到雷同的代码毛病在项目的生命周期中反复涌现。这些雷同的毛病以至会涌如今多个项目中。偶然,这些毛病同时有多个运动实例,偶然一次只要一个运动实例,然则它们不断地从新涌现。当这些毛病致使平安破绽时,效果可以相当严重。

在本文中,我将诠释怎样运用QL的变异剖析(variant analysis)来处置惩罚这个题目,并演示怎样运用LGTM对你本身的项目举行变异剖析。注重:本文运用的是实在存在的systemd示例。

雷同的毛病反复涌现是一种一般征象吗?

在举行变异剖析之前,我想先举个例子。在有很多有目共睹的案例中,雷同的破绽频频涌现。以Google的Project Zero的Tavis Ormandy发明的破绽为例:

运用QL和LGTM举行变异剖析

我们可以从这篇批评中看到,这不是Tavis在Ghostscript中发明的第一个破绽。Ghostscript是一套建基于Adobe、PostScript及可移植文档花样(PDF)的页面形貌言语等而编译成的免费软件。上图是他正在搜检之前报告的一个破绽的修复顺序,发明其并没有被准确地修复。

如今让我们按着上面的思绪找到issue 1690:

我们看到的又是一条关于先前破绽的解释!

假如我们按着这个思绪继承往下,破绽则会越来越多!

运用QL和LGTM举行变异剖析

一样的毛病在代码库的差别部份一次又一次的反复被发明。每次修复时,都邑发明有新的变异涌现。

这意味着,很多破绽的原始状况都是出不多的,只不过是跟着时候的推移,它们一般以轻微修悛改的情势或变异情势,涌如今各个开辟项目中,给人觉得破绽有很多类,其实不然。

什么是变异剖析?

每当发明平安破绽时,无论是经由历程平安研讨、代码评审、破绽赏金设计照样经由历程其他流程,我们都应当先视察破绽反复的频次,肯定代码库中是不是存在其他类似的破绽,并竖立一个流程机制来防备破绽再次发生。

运用QL和LGTM举行变异剖析

第一步是诊断那里出了题目,以便我们可以找到并修复破绽。然则,如上所述,这一般是不够的,因为大多数破绽并不是以原封不动的情势涌现的。这时候,就须要变异剖析发挥作用了。

变异剖析是猎取现有破绽、查找根本原因以及在代码库中搜刮变异破绽的历程。按着传统观念,这个历程应当是由平安研讨人员而不是开辟人员完成的,但正如我将要在下面诠释的那样,不一定老是如许。重要的是找到一切这些变异并同时修补它们,不然这些破绽可以会在野外被应用。一旦找到一切的变异,末了一步是确保类似的破绽不再涌现。

我们怎样找到变异?

现在运用的最罕见的自动化平安研讨手艺一般包括回归测试、单元测试和隐约测试。这些测试要领可以协助庇护代码库,但这些要领在查找已知破绽的变异对象时,却不是最优的。除了自动化以外,你还可以手动搜检变异代码。但是,关于任何合理大小的项目(或项目的鸠合),手动梳理悉数代码库是完全不可行的。另外,手动历程不会让我们深切相识可以存在的破绽,同时还轻易涌现工资毛病。

开辟人员在尝试庇护代码时面对的另一个题目是,他们一般缺少某些平安学问,或许不相识破绽怎样被应用。而这类专业学问和东西一般只能在专业公司的平安团队的成员中找到,因而开辟人员不得不完全依靠专业公司的平安团队来猎取这些信息,这也造成了对项目的平安状况没法实时有效的掌握。比方,在处置惩罚开源项目时,开辟人员可以没有对悉数代码库的背景举行完全的相识,很轻易无意中引入致使平安破绽的代码。

荣幸的是,有一种可用的资本可以自动完成很多沉重的变异剖析事情,无需手动梳理源代码,就可以同享平安学问和最好实战经验。更重要的是,这类手艺关于开源项目是完全免费的。

先来看看LGTM背地的手艺QL。QL采用了一种全新的要领来剖析代码,该要领会将代码视为数据。起首,将这些代码放入一个特别的关联数据库,剖析代码之间的关联。你可以查询这个数据库,查到这些代码从基础语法形式到数据流的悉数剖析状况,而这些代码的关联关联之前是不可以被自动检测到的。这就许可开辟人员应用QL自动化和扩大变异剖析。基础剖析完成以后,你就可以经由历程再次编写和修正查询,以发明语义上与原始破绽类似的代码形式。征采出来的任何效果都邑被举行分类,并供应应开辟团队来完成修复。除此以外,每一个查询都可以放在一个中心存储库中,以便与组织表里的其他人同享。然后,这些查询将一连运转,以便在新变异可以致使破绽之前捕捉它们。

怎样在LGTM上运用QL ?

假如你运用的是LGTM,那末这意味着你已在运用QL了! LGTM供应了项目源代码最新版本的警报视图,该视图是经由历程对该代码库运转QL的规范查询天生的。这些查询都是开源的,而且不断更新,如许你就可以从客户、内部专家和QL的其他用户的平安团队猎取同享的学问。你还可以运用LGTM的自动代码检察集成来为每一个pull要求运转这些查询,并在兼并之前捕捉题目。除此以外,你还可以将本身的特别查询增加到存储库中,并让LGTM将它们与规范查询一同运转。

让我们看一个例子,看看一个有名的开源项目怎样应用一切这些功用,让LGTM作为变异剖析平台的。

在2018年10月中旬,谷歌的Jann Horn发明了systemd的一个破绽,systemd是很多Linux发行版的中心部份。

研讨发明,当经由历程fgets()举行行支解时,systemd很轻易遭到状况注入进击(state injection attack)。因为systemd是一个开源项目,重要开辟人员须要一种要领来正告开源代码的运用者不要运用fgets()的任何功用。为此,他们在CODING_STYLE文档的末端增加了一段申明。但是……

正如systemd的维护者所指出的,他们的CODING_STYLE文档末端的解释申明不足以阻挠贡献者对fgets()的运用。为了改良这类状况,systemd团队决定在LGTM上的项目中增加一个定制QL查询,以捕捉对fget()的任何运用。

import cpp

predicate dangerousFunction(Function function) {
  exists (string name | name = function.getQualifiedName() |
    name = "fgets")
}

from FunctionCall call, Function target
where call.getTarget() = target
  and dangerousFunction(target)
select call, target.getQualifiedName() + " is potentially dangerous"

该查询会搜检是不是有人对fgets()举行挪用,然后为每一个挪用显现一个LGTM正告,申明这些函数有潜伏的风险。

经由历程编写自定义查询,systemd的开辟人员可以轻松地跟踪代码库中fgets()的一切用法。起首,他们在LGTM的交互查询掌握台中运转查询以搜检效果。然后,他们将查询增加到存储库中,以便LGTM将其与一切规范查询一同运转,从而许可他们延续监控对systemd代码库中fgets()的挪用。在建立此查询后不久,假如我们在个中一个提交中检察src/udev/udev-rules.c,就可以看到这些警报正在启动。

运用QL和LGTM举行变异剖析

经由历程运用LGTM作为一个延续集成东西,在将要求发送到主分支之前自动检察个中的代码,systemd团队可以阻挠其他开辟人员在他们的代码中意外埠从新引入对fgets()的挪用。这就是QL和LGTM真正的代价地点,纵然你没有本身的专用平安工程师团队,你也可以应用它们,为项目供应延续的监控和可扩大的变异剖析。

虽然这个查询异常简朴,但事实证明它对systemd团队异常有协助。运用QL,可以编写更高等的查询来处置惩罚更具挑战性的题目。接下来,我们将更深切地研讨QL,带你从头最先编写你本身的查询,并演示怎样运用它来修正你本身项目的现有查询。

深入分析web.config上传方面的安全问题(上)

引言 这是我撰写的第二篇分析web.config安全问题的文章。早在2014年[1]的时候,我们撰写过一篇这方面的文章,其中介绍了一种运行ASP经典代码的方法,以及如何仅通过上传web.config文件发动存储型XSS攻击。 在这篇文章中,我们将着眼于运行web.config文件本身,以及在把web.config上传到IIS服务器上的应用程序过程中可以派上用场的其他技术。这里的主要目标,是使用web.config文件在服务器上执行代码或命令,以及针对存储型XSS的其他攻击技术。 本文中描述

变异剖析是猎取一个已知题目或破绽样本,并在代码库中找到该破绽的其他实例的历程。接下来,我将展现怎样运用既有的破绽样原本编写和革新QL查询。我们将试图找到的这类破绽是snprintf的潜伏运用破绽,snprintf已成为热点项目中很多CVE的泉源,包括rsyslog (CVE-2018-1000140)和icecast (CVE-2018-18820)。在最先编写查询之前,让我们先相识一下要运用的手艺。

QL

QL言语是一种高等的、面向对象的逻辑言语,它支撑Semmle的一切库和剖析。运用QL,你可以疾速实行变异剖析,以发明之前未知的平安破绽。

Semmle QL附带了大批的库来实行掌握和数据流剖析、污染跟踪(taint tracking)和探究已知的要挟模子。运用QL,你可以在多个代码库上运转开箱即用或自定义查询,以取得准确且相干的平安性剖析,从而使你可以关注最症结的题目。

QL将代码视为数据,许可你编写定制查询来研讨代码,以至辨认最庞杂的语义形式。你可以运用你喜好的IDE的QL插件在当地编写和实行QL查询。你还可以运用LGTM查询掌握台在web浏览器中直接编写QL,并查询个中的平安破绽。

Semmle QL的事情道理

运用QL和LGTM举行变异剖析

QL的事情道理是建立或提取源代码的可查询数据库,然后许可你运转查询来探究代码,或查找已知破绽的变异对象。每次挪用编译器时,Semmle都邑“阻拦”编译器挪用,并运用雷同的参数挪用提取顺序,这使得提取顺序精确地检察编译以构建顺序的雷同源代码。提取顺序网络有关源代码的一切相干信息,比方文件名、AST的示意情势、范例信息、关于预处置惩罚器操纵的信息等,并将其存储在关联数据库中。关于没有编译器的诠释言语,提取顺序经由历程直接在源代码上运转来网络类似的信息。

提取完成后,项目的一切相干信息都包括在一个快照数据库中,然后可以在另一台机械上查询快照数据库。快照中还包括建立数据库时天生的源文件的副本,以便剖析效果可以显现在代码中的准确位置。

查询是用QL言语编写的,一般依靠于一个或多个规范QL库。固然,你也可以编写本身的定制库。它们由QL编译器编译为高效的可实行花样,然后由QL评价顺序在长途事情盘算机上或当地开辟人员盘算机上的快照数据库上运转。

查询效果可以用多种体式格局诠释和显现,包括在IDE插件(如Eclipse的QL)或web仪表板(如LGTM)中显现查询效果。

样本破绽

尽人皆知,sprintf是不平安的,因为它不能防备缓冲区溢出。一个罕见的毛病是顺序员假定snprintf老是返回写入缓冲区的字节数。在开源流媒体服务器Icecast中,有种假定(假如缓冲区的大小不受限定,它老是返回它写入缓冲区的字节数)会致使破绽,它许可进击者编写掩盖服务器客栈内容的HTTP标头文件,并许可长途代码实行。我们将开辟一个查询来发明snprintf的这些不平安运用。

下面是Icecast CVE-2018-18820中易受进击代码的简化版本。此代码用于轮回中,将每一个HTTP标头(cur_header)从用户要求复制到一个新缓冲区(post),并在个中组织要发送到另一个服务器的post要求的主体。此时的变异对象就是post_offset,它会跟踪每次轮回迭代时我们须要写入的位置。

post_offset += snprintf(post + post_offset,
                        sizeof(post) - post_offset,
                        "%s",
                        cur_header);

因为post_offset的值没有举行边境搜检,而且假定snprintf返回它将写入的数据的长度,这将许可用户发送一个将被截断的长HTTP标头。不过这部份长度将许可我们定位post_offset。然后我们可以发送第二个HTTP标头,其内容将被写入被定位的位置。

我们将运用这个已知的破绽样原本编写一个简朴的QL查询,以捕捉另一个代码库中的其他变异对象。查询可以在LGTM的查询掌握台中运转,也可以在IDE中运转。

目的代码库

如今我们已有了一个破绽样本,须要挑选一个代码库来运转变异剖析。本文,我们将在rsyslog上运转查询。

我们如今已晓得rsyslog/librelp有一个破绽的变异对象,不过它在commit 2cfe657中得到了修复,在修复之前和以后对快照运转查询将异常有效,如许我们就可以确认我们是不是准确捕捉了变异对象。

我们将对以下内容举行查询:

· 最新版本的rsyslog;

· 最新版本的rsyslog / librelp;

· rsyslog / librelp的版本5b81b1f(在修复CVE-2018-1000140之前);

· rsyslog / librelp的版本2cfe657(在修复CVE-2018-1000140以后);

一个简朴的查询

我们起首编写一个简朴的查询来查找一切对snprintf的挪用,QL查询由一个select子句构成,该子句指导应当返回的效果。

import cpp

from FunctionCall call
where call.getTarget().getName() = "snprintf"
select call, "potentially dangerous call to snprintf."

查询的第一行导入C/ c++规范QL库,该库定义了FunctionCall之类的观点。我们运用where子句指定一个前提,即我们只对挪用函数的目的的称号即是(没有分派!)snprintf的行感兴趣。不过,getname()操纵可用于任何函数挪用。

末了,我们挑选call(具有FunctionCall范例),返回目的名为snprintf的每一个FunctionCall,并显现解释信息。

优化查询历程

一个罕见的事情流程是从一个简朴的查询最先,比方查找对snprintf的挪用的查询,并依据涌现的任何形式革新查询。

我们的第一个查询找到173个效果,手动搜检这些效果是不现实的。我们可以依据视察效果来优化我们的查询,即只要在花样申明符中运用%s挪用snprintf可以轻易遭到的进击。

import cpp

from FunctionCall call
where call.getTarget().getName() = "snprintf"
  and call.getArgument(2).getValue().regexpMatch("(?s).*%s.*")
select call, "potentially dangerous snprintf."

这个革新后的查询只找到包括花样字符串%s的snprintf挪用。每次优化查询时,我们都邑删除潜伏的误报。如许,如今的查询效果就只要103个效果。

接下来,我们将运用污染跟踪来查找对snprintf的挪用,其返回值将返回它们的大小参数。

import cpp
import semmle.code.cpp.dataflow.TaintTracking

from FunctionCall call
where call.getTarget().getName() = "snprintf"
  and call.getArgument(2).getValue().regexpMatch("(?s).*%s.*")
  and TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(call.getArgument(1)))
select call, "potentially dangerous call to snprintf."

当存在从源节点到会聚节点的数据流途径时,TaintTracking :: localTaint(source,sink)为真。在上面的查询中,我们运用(DataFlow::exprNode(call)作为源,它返回与snprintf挪用对应的数据流图中的节点。Sink是我们运用挪用的第一个参数,它对应snprintf的size参数。

假如研讨一下这个查询天生的效果,就会发明rsyslog中只要一个效果,即易受进击的librelp版本。对rsyslog效果的手动搜检显现它实际上是一个误报:

if (offset + len + 1 >= option_str_len) {
        break;
}
int bytes = snprintf((char*)option_str + offset,
                (option_str_len - offset), "%s&", token);

我们可以进一步革新查询,消除已举行了类似搜检的状况。

import cppimport semmle.code.cpp.dataflow.TaintTrackingimport semmle.code.cpp.controlflow.Guardsfrom FunctionCall callwhere call.getTarget().getName() = "snprintf"
  and call.getArgument(2).getValue().regexpMatch("(?s).*%s.*")
  and TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(call.getArgument(1)))
  // Exclude cases where it seems there is a check in place
  and not exists(GuardCondition guard, Expr operand |
      // Whether or not call is called is controlled by this guard 
      guard.controls(call.getBasicBlock(), _) and
      // operand is one of the values compared in the guard
      guard.(ComparisonOperation).getAnOperand() = operand and
      // the operand is derrived from the return value of the call to snprintf 
      TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(operand))
  )select call

这个经由革新的查询只发生一个效果,经由剖析,是破绽CVE-2018-1000140。在Semmle团队发明这个破绽以后,rsyslog的首席开辟人员修复了这个破绽,从他们的代码库中删除了对snprintf的风险挪用。

原文地点: https://www.4hou.com/web/18266.html


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明运用QL和LGTM举行变异剖析
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址