Tuesday, 21 May 2013

Using WebServices Proxy Wrapper to replace Checkmarx’s CWE Guidance with TeamMentor’s Articles

After Creating a WebServices Proxy Wrapper for Checkmarx’s CxWebService its time to replace the existing guidance with TeamMentor’s articles.

We start with a folder containing the CxWebService.asmx


and an App_Code folder with CxPortalWebService.cs (original C# WSDL) and TM_Proxy_for_CxPortalWebService.cs (proxy that invokes the CxPortalWebService.cs methods)


In order to help up to manage the change (and to help deployment), let’s create a git repository here:


click ok the warning screen that there are files in this folder, and the OK shown below:


next  commit the current files:


and create a new branch:


Next I opened VisualStudio 2010 and opened this folder as a WebSite:


… added a new Class file to hold the TeamMentor logic:


I also created a separate project (and solution) to hold the UnitTests:


where I added a number of Nuget dependencies to help development and debugging of the unit tests (NUnit, FluentSharp.CoreLib, FluentSharp.BCL,  FluentSharp.REPL), and added the App_Data files as ‘links’


And with this set-up I can write unit tests like this:


which when executed:


will generate this request (to the real server):


Note that since we can add ‘extra code’ in between the requests, we can do something like this:


which will change the data ‘from the proxy to the real one’ (note the changed value of sessionId)


We can also modify the data ‘returned from the real web service’


which in this case will make our test fail (since it was expected an false value in the IsSuccesfull field

Back to our unit test writing ...

Here is a unit test that checks that we can login ok as admin:


Here is a unit test that checks that the GetQueryDescription is working ok


Using Negative CWE Ids to represent QueryId

One of the problems that we have in mapping CWE data to TeamMentor articles is that there are lots of cases where there is not a 1 to 1 mapping between both sets of guidance. For example TeamMentor has language specific articles, where CWE Guidance tends to be generic.

Another scenario is the fact that TeamMentor clients might have customized versions of those Articles, providing Application Specific guidance.

The good news is that Checkmarx rules are already written by technology, which means that we can use the finding’s queryID to map to an TM article.

The bad news is that when the Cx multiple GUIs (web interface, Client app and IDE plug-ins) fetch guidance for a particular finding, they use the CWE ID and not the QueryID.

As mentioned before I was looking for a way to make this change without requiring any code change of the main Checkmarx code base or files, and with the CxWebService proxy I was able to achieve exactly that.

What I’ve done was to add a special filter to the GetQueryCollectionForLanguageGetResults and GetQueryDescription WebService methods

They all have the same pattern of creating an instance of CxTeamMentor object:


and calling the respective filter method


with the GetQueryDescription filter also receiving the cweId


The  TMFilterFor_CxQueryCollectionResponse and TMFilterFor_CxWSResponseResultCollection filters are responsible for assigning the CWE value to the negative of QueryID




The the TMFilterFor_CxWSResponseQueryDescription is responsible for handling the response, which is this first case, is just making a small change to the description value (if the CWE value is negative)


To see this in action, I here is the CxClient app trying to load the description of a Java Command Injection vulnerability (which has the QueryID of 587)


and here is a .NET Command Injection (which has the QueryID of 423)


This means that we need to map the Query ID 587 (Java Command Injection) to the https://teammentor.net/article/00000000-0000-0000-0000-000000859bca article


and the QueryId 423 (.NET Command Injection) to the https://www.teammentor.net/article/00000000-0000-0000-0000-0000007a1206


Adding test mappings

To try this out lets start with a simple mappings class:


which is used on the TMFilterFor_CxWSResponseQueryDescription:


And now its working :)

Here is the .Net guidance for the .NET Code Injection query/Vulnerability


And  here is the Java guidance for the Java version of the Code Injection query/vulnerability



Source used in Post

1) CxTeamMentor file (at the time of this blog post)
   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;



   6: public class CxTeamMentor_Mappings

   7: {

   8:     public static Dictionary<int, string> Tm_QueryId_Mappings  { get; set; }

   9:     public static string                  HtmlRedirectTemplate { get; set; }  


  11:     static CxTeamMentor_Mappings()

  12:     {

  13:         LoadData();

  14:     }


  16:     public static void LoadData()

  17:     {

  18:         HtmlRedirectTemplate = "<html><head><meta http-equiv=\"refresh\" content=\"0;"+

  19:                                " url=http://teammentor.net/article/{0} \"></head></html>";


  21:         Tm_QueryId_Mappings = new Dictionary<int, string>

  22:             {

  23:                 {-587, "00000000-0000-0000-0000-000000859bca"},

  24:                 {-423, "00000000-0000-0000-0000-0000000b0d98"}

  25:             };

  26:     }

  27: }


  29: public class CxTeamMentor

  30: {


  32:     public void TMFilterFor_CxQueryCollectionResponse(CxQueryCollectionResponse cxQueryCollectionResponse)

  33:     {

  34:         var queries = from queryGroup in cxQueryCollectionResponse.QueryGroups

  35:                       from query in queryGroup.Queries

  36:                       select query;

  37:         foreach (var query in queries)

  38:         {

  39:             query.Cwe = -query.QueryId;             // set the Cwe value to the negative of the QueryId

  40:             query.Name += "_TM";                    // Temp query name minor change

  41:         }

  42:     }

  43:     public void TMFilterFor_CxWSResponseResultCollection(CxWSResponseResultCollection cxWsResponseResultCollection)

  44:     {

  45:         var results = cxWsResponseResultCollection.ResultCollection.Results;

  46:         foreach (var result in results)

  47:         {

  48:             result.CWE = -result.QueryId;           // set the Cwe value to the negative of the QueryId

  49:             result.QueryName += "_TM";              // Temp query name minor change

  50:         }

  51:     }


  53:     public void TMFilterFor_CxWSResponseQueryDescription(int cweId, CxWSResponseQueryDescription cxWsResponseQueryDescription)

  54:     {

  55:         if (cxWsResponseQueryDescription.IsSuccesfull)

  56:         {

  57:             if (cweId < 0)

  58:             {

  59:                 if (CxTeamMentor_Mappings.Tm_QueryId_Mappings.ContainsKey(cweId))

  60:                 {                    

  61:                     cxWsResponseQueryDescription.QueryDescription =

  62:                         String.Format(CxTeamMentor_Mappings.HtmlRedirectTemplate, 

  63:                                       CxTeamMentor_Mappings.Tm_QueryId_Mappings[cweId]);

  64:                 }

  65:                 else

  66:                     cxWsResponseQueryDescription.QueryDescription =

  67:                         String.Format("The TeamMentor article with Id {0} could not be found", cweId);

  68:             }

  69:         }

  70:     }


  72: }