“你好,Checkmarx!” 如何编写对Checkmarx SAST的请求并查找很酷的漏洞



哈Ha!

在本文中,我想谈谈我们在Checkmarx SAST中创建查询的经验。

初次熟悉此分析器时,您可能会得到的印象是,除了搜索弱加密/哈希算法和大量误报外,它不返回任何其他内容。 但是,如果配置正确,它是一种超级强大的工具,可以查找严重的错误。

我们将了解Checkmarx SAST查询语言的复杂性,并编写2个查询来搜索SQL注入和不安全的直接对象引用。


参赛作品


在长期搜索Checkmarx上的任何指南或文章之后,对我来说很清楚,除了正式文档之外,没有足够的有用信息。 官方文档并没有说一切都变得非常清晰易懂。 例如,我找不到任何最佳做法,如何正确组织覆盖查询,如何编写“傻瓜”查询等。是的,有关于CMx查询语言功能的文档,但这是将这些功能组合成一个查询的方法,该文档未编写。

Checkmarx社区缺少文章和指南,可能与该工具的高昂成本有关,因此受众不多。 或者,也许只有很少的人会费力地进行微调,并直接使用解决方案。

根据我的经验,我发现,更多地使用SAST来满足客户方面与各种要求有关的手续,而不是寻找真正的错误。 结果,通过这种方法,我们充其量只有很少数量的“漏洞”,几乎自动被称为“不可利用”(因为在99.9%的情况下都是这样)。

应当注意,Checkmarx本身正在尝试更新其查询,以使它们开箱即用地提供最佳结果。 但是CMx查询语言查询是针对“一般情况”量身定制的。 令牌的初始搜索基于名称。 例如,CMx SAST假定对数据库的所有查询将如下所示:* createQuery *或* createSQLQuery *。 但是,如果使用内部开发来处理数据库,并且以不同的方式调用查询数据库的方法(例如* driveMyQuery *),那么将跳过所有SQL方法。 例如,我们的客户对SQL DB使用定制的ORM。 在这种情况下,开箱即用的CMx查询将跳过所有SQL注入。

缩写和定义


CMx -Checkmarx SAST。
CMxQL -Checkmarx SAST查询语言
令牌 -具有特定值的字符串是词法分析器工作的结果(也称为令牌化)

测试申请


为了写一篇文章,我画了一些Java代码,一个小的测试应用程序。 此代码是实际系统的一小部分的近似副本。 尽管一般而言,测试应用程序的代码与任何其他HTTP后端代码并没有太大区别。 屏幕截图中将显示测试应用程序代码的关键部分。

测试应用程序具有以下结构


WebRouter类,用于处理传入的HTTP请求;内部处理URL的4种方法:
  • / getTransaction-在输入处接受交易ID 并返回有关其的信息ID将其作为字符串,并将其传递给getTransactionInfo(transactionId) => getTransactionInfo(transactoinId) -使transactionId与SQL查询连接(即获得SQL注入);
  • / getSecureTransaction-在输入处接收交易ID并返回有关其的信息ID将其作为字符串并将其传递给getTransactionInfoSecured() => getTransactionInfoSecured(transactoinId) -首先字符串transactionId转换为Long类型,然后将其连接到SQL查询(在此示例中)如果注射未被利用);
  • / getSettings-接受userIdmailboxId作为输入 -并发布邮箱设置。 不验证邮箱标识是否属于该用户;
  • / getSecureSettings-还接受userIdmailboxId作为输入并显示邮箱设置。 但是,将检查邮箱标识是否属于该用户。


CMx:一般信息和基本定义


在开始开发查询之前


查询开发是在单独的程序CxAuditor中进行的。 在CxAuditor中,您需要扫描所有代码(创建本地项目),我们将为此编写查询。 之后,您可以编写和运行新查询。 使用大型代码库,主扫描可能要花费数小时的时间和千兆字节的内存。 此后,每个请求将不会足够快地执行。 这完全不适合开发。

因此,您可以从项目中获取少量文件,理想情况下,可以在代码中找到一个错误,该错误要早于我们正在编写请求的类型(或将错误手动放置在此处)并仅扫描这组文件。 不必遵守项目的文件结构。 也就是说,如果您具有Java程序包A和B,并且程序包B中的类使用程序包A的类和方法,则可以将所有这些都放在一个目录中,并且CMx仍将理解关系并正确地建立文件之间的调用链(很好,或几乎总是正确的,尽管错误几乎与项目的文件结构无关)。

基本定义


列表


CMx中的主要数据类型。 几乎所有CMxQL函数的结果都是CxList 。 这是许多具有某些属性的元素。 以下将考虑对开发最有用的属性。

结果


CMxQL具有内置的变量结果 。 执行完整个查询后,包含结果变量的集合将显示为结果。

也就是说,任何查询的最终操作都应该是字符串result = WHATEVER ,例如:
result = All.FindByName("anyname"); 

流和代码元素


根据返回值的类型,大多数CMxQL函数分为2个,返回“代码元素”的函数和返回Flow的函数。 在这两种情况下,结果都是CxList 。 但是对于Flow和代码元素,其内容将略有不同。
  • 代码元素 -令牌-例如变量,方法调用,赋值等;
  • -给定令牌之间的关系。


全部和“子”全部


每个CMxQL函数都可以在All集合(它包含整个扫描代码的所有标记,我们已经看到了带有result的示例)上执行,也可以在CxList集合上执行,而CxList集合又是通过查询中某些操作(例如查询)而获得的:
 CxList newList = CxList.New(); 

将创建一个空集合,然后我们可以使用Add()方法填充元素,然后按新集合的元素进行搜索:
 CxList newFind = newList.FindByName("narrowedScope"); 

找到的项目的属性


CxList集的每个元素都有几个属性。 分析写查询的结果时,最有用的是:

  • SourceFile-包含此元素的文件的名称;
  • 源行 -带令牌的行号;
  • 源名称 -令牌的名称。 等同于令牌,即,如果变量名为var1,则源名称= var1;
  • 源类型 -令牌的类型。 例如,如果它是一个字符串,则它将是StringLiteral,如果调用了该方法,则将调用MethodInvokeExpr,等等。
  • 目标文件
  • 目的行;
  • 目的地名称;
  • 目标类型。


如果结果集中的元素为Flow,则Source和Destination将有所不同;反之亦然,如果结果是代码元素,则它们将匹配。

开始创建查询


所有CMxQL功能都可以分为几种类型。 在我看来,这里可以注意到CMxQL文档的主要缺点,扩展坞中的所有功能都是按字母顺序简单描述的,而根据功能(然后仅按字母顺序)构建它们会更加方便。

  • 搜索功能-几乎所有名称为FindBy *GetBy *的 CMxQL函数;
  • 集上运算的功能是加,减,交,元素上的迭代等。
  • 分析函数-这些基本上是* ImpactdBy * * InfluencingOn *函数。


查询的基本原理是这些类型的功能的交替。 首先,使用搜索功能,我们仅通过某些属性选择我们感兴趣的令牌。 使用集合上的运算,我们可以将具有不同令牌属性的不同集合组合成一个集合,反之亦然,从集合中减去另一个集合。 然后,使用分析功能构建代码流,并尝试了解潜在漏洞是否取决于入口点的参数。

开始搜索的位置(通常是整个搜索路径)的选择取决于特定的代码,更确切地说,甚至取决于“文本”。 在某些情况下,从入口点搜索用户查询会很方便,在某些情况下,从“结尾”甚至中间位置开始会更方便。 所有这些都取决于特定的代码,您需要分别访问每个存储库。

示例:搜索SQL注入


搜索计划,在方括号中,我指出了集合的名称(查询中的变量):

  1. 定义例外-可以立即扔出搜索范围的令牌( exclusionList );
  2. 确定消毒/安全检查( 消毒 )的位置;
  3. 在数据库中查找所有具有查询执行的低级位置( runSuperSecureSQLQuery );
  4. 查找被调用方法的所有参数runSuperSecureSQLQueryrunSSSQParams );
  5. 查找数据库中查询执行位置的入口点(父方法及其参数)( entryPointsParameters );
  6. 查找runSSSQParams参数对entryPoints的依赖关系,而仅查找那些没有清理输入清理的地方


结果,我们获得了带有SQL查询的低级方法,其中SQL查询的参数为:

  • 取决于方法的参数;
  • 参数被接受为字符串;
  • 参数连接到请求。

我们不会检查是否可以控制这些参数,因为 我们认为,存在一种将变量映射到查询中的机制,并且存在将数字转换为数字类型的机制,并且字符串连接始终被认为是危险的。 即使现在无法控制该行,它也可能会出现在新版本中。

SQLi:步骤1.定义异常


在例外情况下,您需要添加令牌名称可以与所需名称匹配的类或文件,因为 这些令牌将导致无效的条目。

例如,用于访问数据库的方法称为runSuperSecureSQLquery 。 我们假设内部的runSuperSecureSQLquery方法是安全实现的。 我们的任务是找到使用该方法本身并不安全的地方。 对于SQL注入,用户控制参数的串联位置将不是安全的位置。 安全-将参数映射到ORM结构或(例如)数字参数的地方,这是转换为相应类型的地方。 我们不需要扫描比runSuperSecureSQLquery更“深入”的所有代码,这意味着最好将其排除,以避免无用的查找。

要搜索此类异常,可以使用CMxQL函数很方便:
  • FindByFileName() -将查找特定文件中所有标记的集合;
  • GetByClass() -将在给定名称的类中找到所有标记的集合。


对于测试应用程序,此异常是Session类,其中包含runSuperSecureSQLquery方法的实现。
请求在Session类中排除代码的示例( GetByClass()方法检查传递给输入的哪些标记具有CMx类型的ClassDecl ,并将发出该类的许多标记)

 CxList exclusionList = All.GetByClass(All.FindByName("*Session*")); result = exclusionList; 


或者另一种方法是将代码抛出整个Session.java文件:

 CxList exclusionList = All.FindByFileName("*Session.java"); result = exclusionList; 


名称前的星号很重要,因为文件名包含整个路径。
现在,我们可以在下一步中从搜索范围中减去许多标记。

Session类中搜索令牌的结果:



SQLi:步骤2。确定消毒位置


测试应用程序中有2种API方法(请参阅测试应用程序的简要说明)。 两种API方法之间的区别在于, getTransactionInfo()将SQL查询中的transactionId参数连接起来,而getTransactionInfoSecured()首先 transactionId 转换为Long,然后将其作为字符串传递。 两种方法都嵌入了漏洞(参数级联)。 但是,由于在getTransactionInfoSecured()中强制转换为Long,所以最后一个方法不容易受到注入的影响,因为当我们尝试传递注入(字符串)时,我们会收到Java异常。

在此示例中,我们将对Long的演员表视为卫生站点。 要找到这些令牌:

 CxList sanitization = All.FindByName("*Long*"); result = sanitization; 


结果示例:



结果包括具有YP类型LonggetValueAsLong方法的令牌,这些令牌在内部转换为 Long类型。 您需要仔细检查结果,以确保没有多余的东西。

SQLi:步骤3。在数据库中查找所有具有查询执行的低级位置


以下查询将使用runSuperSecureSQLQuery令牌(用于访问数据库)找到所有位置:

 result = All.FindByName("*runSuperSecureSQLQuery*") 

通过令牌名称runSuperSecureSQLQuery的搜索结果:


而且,对于调用此方法的地方( Billing类),将仅找到方法调用令牌(类型MethodInvokeExpr ),对于方法声明位置( Session类),将找到所有令牌-变量。

我们仅过滤方法调用令牌:

 CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery; 

结果:


结果,我们得到了7个位置,其中4个是对runSuperSecureSQLQuery()方法( BillingUser类)的必需调用。 2-调用Session类内部的runSuperSecureSQLQuery()内部方法,还有一个是add方法,这是某种CMxQL搜索奇数。 只是说我不希望它出现在列表中=)正如我们在步骤1中发现的那样, Session类中的标记对我们来说并不有趣,因此我们将从结果中减去它们:

 CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery - exclusionList; 

我们获得对所需方法的有效调用列表:



注意上一个查询中的FindByType()typeof()函数。 如果要按 CMx类型进行搜索,即按CxList属性“源类型”进行搜索-那么我们使用typeof(源类型) 。 如果要按数据类型进行搜索,则需要像字符串一样传递参数。 例如:

 result = All.FindByType("String"); 

将找到所有类型为String的Java令牌。

SQLi:步骤4。找到名为runSuperSecureSQLQuery的方法的所有参数


为了搜索方法参数,使用CMxQL函数GetParameters()

 CxList runSSSQParams = All.GetParameters(runSuperSecureSQLQuery); result = runSSSQParams; 

结果:



SQLi:步骤5.在数据库中查找查询执行位置的入口点


为此,首先获取父方法的名称,在内部是对runSuperSecureSQLQuery数据库的调用,然后获取其参数。 为了搜索父令牌,使用CMxQL函数GetAncOfType()

 CxList entryPoints = runSuperSecureSQLQuery.GetAncOfType(typeof(MethodDecl)); result = entryPoints; 


在此查询中,对于runSuperSecureSQLQuery集,返回所有类型为MethodDecl的父标记-这是调用堆栈中的先前方法:



为了搜索方法参数,我们还使用GetParameters()

 CxList entryPointsParameters = All.GetParameters(entryPoints).FindByType("String"); 


该查询将返回Java类型为String的entryPoints子集的参数:



SQLi:步骤6。查找runSSSQParams参数对entryPointsParameters的依赖关系,而仅查找那些没有消毒输入的地方


在这一步中,我们使用分析功能。 以下功能用于分析流代码:

  • 影响力dBy()
  • ImpactdByAndNotSanitized()
  • 影响()
  • 影响OnAndNotSanitized()
  • 不影响dBy()
  • 不影响开启()


要根据entryPointsParameters父方法的参数查找runSSSQParams请求参数流,并排除卫生令牌:

 CxList dataInflOnTable = runSSSQParams.InfluencedByAndNotSanitized(entryPointsParameters, sanitization); 


但是,我不确定内部的* AndNotSanitized函数是否起到某种作用,它看起来更像是该方法只是从结果中减去已清理的集合。 也就是说,如果您这样做:

 CxList dataInflOnTable = runSSSQParams.InfluencedBy(entryPointsParameters) - sanitization; 


结果也一样。 虽然也许我仍然没有选择,但是仍然存在差异。

查询结果为我们提供了正确构造的Flow:



通过潜在的SQL注入获得流程。 从屏幕截图可以看出,Checkmarx返回了3 Flow。 屏幕截图中的流程最短,它以一个文件和一种方法开始和结束。 下一个Flow已离开Session类。 注意源/目标。 最后一个是Session类中的另一种方法。 会话内的流程如下所示:



要选择一个Flow,请使用ReduceFlow方法(CxList.ReduceFlowType flowType) ,其中flowType可以是:

  • CxList.ReduceFlowType.ReduceBigFlow-选择最短的Flow
  • CxList.ReduceFlowType.ReduceSmallFlow-选择最长的流


SQLi:查找SQL注入的最终查询


 // 1.   CxList exclusionList = All.GetByClass(All.FindByName("*Session*")); // 2.    CxList sanitization = All.FindByName("*Long*"); // 3.    runSuperSecureSQLQuery() CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); runSuperSecureSQLQuery -= exclusionList; // 4.     runSuperSecureSQLQuery() CxList runSSSQParams = All.GetParameters(runSuperSecureSQLQuery); // 5.   ,     runSuperSecureSQLQuery() CxList entryPoints = runSuperSecureSQLQuery.GetAncOfType(typeof(MethodDecl)); CxList entryPointsParameters = All.GetParameters(entryPoints).FindByType("String"); // 6.       (runSuperSecureSQLQuery)     CxList dataInflOnTable = runSSSQParams.InfluencedByAndNotSanitized(entryPointsParameters, sanitization); // 7.   result = dataInflOnTable.ReduceFlow(CxList.ReduceFlowType.ReduceBigFlow); 


示例2:搜索不安全的直接对象引用


在此请求中,我们将搜索与对象一起工作的所有位置,而无需检查对象的所有者。 在这种情况下,可以对mailboxid使用不同名称的HTTP参数(我们假设这是旧式的),并且验证本身可以在不同的阶段进行:在HTTP入口API点的某个位置,在数据库请求之前的某个位置,有时在中间方法中。

搜索计划
  1. 定义异常( exclusionList );
  2. 确定授权检查的位置( idorSanitizer );
  3. 查找入口点-HTTP请求主要处理的位置( webRemoteMethods );
  4. 只有通过入口点令牌才能找到HTTP参数的提取位置mailboxidmailboxidInit );
  5. 查找从webRemoteMethods到中间件方法的所有调用以及这些调用的参数( middlewareMethods );
  6. 查找依赖于mailboxid( apiPotentialIDOR )的中间件方法;
  7. 查找定义了中间件方法的所有位置( middlewareDecl );
  8. 遍历所有apiPotentialIDOR并仅选择其中没有对mailboxid对象的所有者进行验证的中间件 Decl


IDOR:步骤1.识别异常


在这种情况下,请排除特定文件中的所有令牌:

 CxList exclusionList = All.FindByFileName("*WebMethodContext.java"); result = exclusionList; 

WebMethodContext.java包含诸如getMailboxIdgetUserId之类的方法的实现,以及字符串“ mailboxid”。 由于令牌的名称将与我们搜索漏洞所需的名称一致,因此该文件将发出错误的发现。

IDOR:步骤2。找到授权检查


在测试应用程序中, validateMailbox()方法用于确定请求的对象是否属于用户:

 CxList idorSanitizer = All.FindByName("*validateMailbox*"); result = idorSanitizer; 

结果:



IDOR:步骤3。查找自定义HTTP API请求的入口点


HTTP请求处理程序具有特殊的注释,使它们易于查找。 在我的情况下,这是“ WebRemote”; CMxQL函数FindByCustomAttribute()用于搜索注释。 对于FindByCustomAttribute() ,父标记GetAncOfType()的搜索功能将返回注释下的方法:

 CxList webRemoteMethods = All.FindByCustomAttribute("WebRemote") .GetAncOfType(typeof(MethodDecl)); result = webRemoteMethods; 


请求结果:



IDOR:步骤4。仅使用入口点令牌,找到mailboxid参数的HTTP提取位置


要查找与HTTP Mailboxid参数的处理有关的令牌:

 CxList getMailboxId = All.FindByName("\"mailboxId\"") + All.FindByName("\"mid\"") + All.FindByName("\"boxid\""); result = getMailboxId; 

我们添加了3组带有3条不同的线,因为 根据传说,HTTP参数的名称在系统的不同部分可能有所不同。

该查询将找到将mailboxid / mid / boxid写为字符串(用双引号引起来)的所有位置。 但是此查询将返回很多结果tk。 这样的字符串不仅可以在提取HTTP参数的地方找到。 如果我们继续使用此集合,将会得到大量的错误发现。

因此,我们将仅搜索入口点的令牌( webRemoteMethods )。 要查找所有子令牌,请使用CMBQL函数GetByAncs()

 result = All.GetByAncs(webRemoteMethods); 

该请求将返回属于标注为WebRemote的方法的所有令牌。 在这个阶段,我们已经可以过滤那些检查对象所有者的方法的标记。 因此,我们重写前一个查询以搜索子令牌,以便仅选择WebRemote方法的子令牌,而对对象所有者不进行安全检查。 为此,请使用条件循环:

 //          CxList entry_point_tokens = All.NewCxList(); //      webRemoteMethods foreach (CxList method in webRemoteMethods) { //        CxList method_tokens = All.GetByAncs(method); // ,       ,    owner if (method_tokens.FindByName(idorSanitizer).Count > 0) { //  ,     , ,     } else { //  ,         entry_point_tokens.Add(method_tokens); } } 

现在,我们可以使用HTTP Mailboxid参数进行更准确的选择:

 CxList getMailboxHTTPParams = entry_point_tokens.FindByName("\"mailboxid\"") + entry_point_tokens.FindByName("\"mid\"") + entry_point_tokens.FindByName("\"boxid\""); result = getMailboxHTTPParams; 

但是,我们对检索HTTP参数的位置并不感兴趣,而对最终分配了HTTP参数值的变量不感兴趣。 因为通过变量的标记精确地搜索Flow更为可靠。

CMxQL函数FindByInitialization()将查找给定令牌的变量初始化位置:

 CxList mailboxidInit = entry_point_tokens.FindByInitialization(getMailboxHTTPParams); result = mailboxidInit; 

结果:



IDOR:步骤5。查找从webRemoteMethods到中间件方法的所有调用以及这些调用的参数


所谓中间件,是指代码比HTTP API请求的处理方法更深,即比用户请求的入口点更深。 例如,对于上面的屏幕截图,这些是User类的方法,对user.getSettings()user.getSecureSettings()的调用:

 CxList middlewareMethods = All.FindByShortName("user").GetRightmostMember(); CxList middlewareMethodsParams = entry_point_tokens.GetParameters(middlewareMethods); result = middlewareMethodsParams; 

首先,我们选择名称为user的所有令牌,然后使用GetRightmostMember()选择中间件的调用令牌。 方法调用链中的GetRightmostMember()将返回最右边的一个。 然后,使用GetParameters()导出找到的方法的参数。

结果:



IDOR:步骤6。查找依赖于mailboxid的中间件方法


流量分析使用* ImpactdBy ** InfluncingOn *方法 。 它们之间的区别在名称上很明显。

例如:

 All.InfluencedBy(getMailboxHTTPParams) 

将遍历集合All并找到所有依赖于getMailboxHTTPParams的令牌。

可以用另一种方式写同样的东西:

 getMailboxHTTPParams.InfluencingOn(All) 


要搜索取决于mailboxidInit的令牌:

 CxList apiPotentialIDOR = entry_point_tokens.InfluencedByAndNotSanitized(mailboxidInit, idorSanitizer); result = apiPotentialIDOR; 

结果:



IDOR:步骤7。查找所有位置以定义中间件方法


让我们找到可在处理用户请求的地方使用的所有中间方法的定义。 为此,我们突出显示它们的公共属性,例如,在所有此类方法中,都有一个request ()对象创建,该对象创建为CMx类型的ObjectCreateExpr

 CxList requests = (All - exclusionList).FindByType(typeof(ObjectCreateExpr)).FindByName("*Request*"); CxList middlewareDecl = requests.GetAncOfType(typeof(MethodDecl)); result = middlewareDecl; 


(全部 -exclusionList -您可以对集合进行此减法,然后从结果中调用所需的CMxQL函数。 现在, 请求包含名称为“ 请求”的所有令牌以及与对象创建相对应的类型。

接下来,使用熟悉的GetAncOfType(),找到类型为MethodDecl的父标记。

结果:



IDOR:步骤8。遍历所有apiPotentialIDOR,并仅选择其中没有对mailboxid对象的所有者进行验证的中间件Decl


在请求的最后部分,我们将确定直接从入口点方法中调用哪些中间件方法,而不检查谁的信箱ID属于谁。 然后结合Flow以更方便地分析结果。

我们尚未使用的新功能:
GetCxListByPath() -需要此函数来迭代Flow,如果不使用它,则CMx将压缩Code Element中的Flow(在第一个流节点中)
级联*() -将多个流合并为一个所需的许多函数
FindByParameters() -通过特定参数标记查找方法
GetName() -将返回带有令牌名称的字符串,如果CxList中有多个元素,则它将返回第一个。 该方法仅在迭代集合的元素时使用。

请求的最后一部分:

 //    CxList vulns = All.NewCxList(); //   Flow  apiPotentialIDOR foreach(CxList cxFlow in apiPotentialIDOR.GetCxListByPath()) { //    Flow CxList endNode = cxFlow.GetStartAndEndNodes(CxList.GetStartEndNodesType.EndNodesOnly); //       flow (mailboxid) CxList method_call = entry_point_tokens.FindByParameters(endNode); //     CxList method_decl = middlewareDecl.FindByShortName(method_call.GetName()); //     if (method_decl.Count > 0) { //       CxList _all = (All - exclusionList).GetByAncs(method_decl); //       if (_all.FindByName(idorSanitizer).Count > 0) { //  ,       cxLog.WriteDebugMessage("find sanitized in method: " + method_call.GetName()); //  ,   Flow     vulns } else { //     Flow       vulns.Add(cxFlow.ConcatenatePath(method_call).ConcatenatePath(method_decl)); cxLog.WriteDebugMessage("find NOT sanitized in method: " + method_call.GetName()); } } } 


结果:



我们使用CocatenatePath,以便在分析所有位置时可以方便地浏览代码。此方法将一个代码元素附加到流。

IDOR:对IDOR的最终搜索


 // 1.   CxList exclusionList = All.FindByFileName("*WebMethodContext.java"); // 2.     CxList idorSanitizer = All.FindByName("*validateMailbox*"); // 3.    –    HTTP  CxList webRemoteMethods = All.FindByCustomAttribute("WebRemote").GetAncOfType(typeof(MethodDecl)); // 4.         HTTP  mailboxid //     CxList entry_point_tokens = All.NewCxList(); foreach (CxList method in webRemoteMethods) { CxList method_tokens = All.GetByAncs(method); if (method_tokens.FindByName(idorSanitizer).Count > 0) { } else { entry_point_tokens.Add(method_tokens); } } //    HTTP    -  CxList getMailboxHTTPParams = entry_point_tokens.FindByName("\"mailboxId\"") + entry_point_tokens.FindByName("\"mid\"") + entry_point_tokens.FindByName("\"boxid\""); CxList mailboxidInit = entry_point_tokens.FindByInitialization(getMailboxHTTPParams); // 5.      middleware     CxList middlewareMethods = All.FindByShortName("user").GetRightmostMember(); CxList middlewareMethodsParams = entry_point_tokens.GetParameters(middlewareMethods); // 6.  middleware ,     mailboxid CxList apiPotentialIDOR = entry_point_tokens.InfluencedByAndNotSanitized(mailboxidInit, idorSanitizer); // 7.      middleware      CxList requests = (All - exclusionList).FindByType(typeof(ObjectCreateExpr)).FindByName("*Request*"); CxList middlewareDecl = requests.GetAncOfType(typeof(MethodDecl)); // 8.    apiPotentialIDOR     middlewareDecl,      CxList vulns = All.NewCxList(); foreach(CxList cxFlow in apiPotentialIDOR.GetCxListByPath()) { CxList endNode = cxFlow.GetStartAndEndNodes(CxList.GetStartEndNodesType.EndNodesOnly); CxList method_call = entry_point_tokens.FindByParameters(endNode); CxList method_decl = middlewareDecl.FindByShortName(method_call.GetName()); if (method_decl.Count > 0) { CxList _all = (All - exclusionList).GetByAncs(method_decl); if (_all.FindByName(idorSanitizer).Count > 0) { cxLog.WriteDebugMessage("find sanitized in method: " + method_call.GetName()); } else { vulns.Add(cxFlow.ConcatenatePath(method_call).ConcatenatePath(method_decl)); cxLog.WriteDebugMessage("find NOT sanitized in method: " + method_call.GetName()); } } } result = vulns; 


结论


Checkmarx可以轻松地将代码解析为令牌,同时确定其类型。此外,静态分析器还可以很好地搜索令牌,例如,找到当前令牌的父令牌,查找变量的初始化,查找方法的参数等。Flow在构建方面几乎同样出色(但有时仍然会遗漏)。所有这些使得可以像处理任何数据库一样使用该代码,不同之处在于该代码的结构不是预定义的,您必须自己“自定义”它。

为了大大减少误报的数量,请注意以下几点:
  • , ( ).
  • , ( ). , «Privacy Violation», , , Web UI. , .. UI . TLS XSS .
  • - , (, ). , XXE , , - , .
  • false positive, , CMxQL FindBy/GetBy. , ( SQL).
  • false positives, , , , , CMx, . , LDAP , . c LDAP- , , .


how-to «hello world» , Checkmarx.

Source: https://habr.com/ru/post/zh-CN477742/


All Articles