
Bonjour, Habr!
Dans l'article, je veux parler de notre expérience dans la création de mes requêtes dans Checkmarx SAST.
Lorsque vous vous familiarisez avec cet analyseur pour la première fois, vous pouvez avoir l'impression qu'en plus de rechercher des algorithmes de chiffrement / hachage faibles et un tas de faux positifs, il ne renvoie rien d'autre. Mais lorsqu'il est correctement configuré, c'est un outil super puissant qui peut rechercher des bugs graves.
Nous allons comprendre les subtilités du langage de requête Checkmarx SAST et écrire 2 requêtes pour rechercher des injections SQL et des références d'objet direct non sécurisées.
Entrée
Après une longue recherche de guides ou d'articles sur Checkmarx, il est devenu clair pour moi qu'en dehors de la documentation officielle, il n'y avait pas assez d'informations utiles. Et la documentation officielle ne dit pas que tout devient très clair et compréhensible. Par exemple, je n'ai trouvé aucune meilleure pratique, comment organiser correctement les requêtes de remplacement, comment écrire une requête «pour les nuls», etc. Oui, il existe une documentation sur les fonctions du langage de requête CMx, mais voici comment combiner ces fonctions en une seule requête, la documentation n'est pas écrite.
Peut-être que le manque d'articles et de guides de la communauté Checkmarx est associé au coût élevé de l'outil et, par conséquent, à un public restreint. Ou peut-être que peu de gens s'embarrassent du réglage fin et utilisent la solution telle quelle, prête à l'emploi.
D'après mon expérience, je constate davantage que SAST est davantage utilisé pour se conformer aux formalités liées aux diverses exigences des clients que pour rechercher de vrais bugs. Avec cette approche, nous avons donc, au mieux, un nombre relativement faible de «vulnérabilités» que l'on appelle presque automatiquement «non exploitables» (car elles sont dans 99,9% des cas).
Il convient de noter que Checkmarx essaie lui-même de mettre à jour ses requêtes afin de donner le meilleur résultat prêt à l'emploi. Mais les requêtes CMx Query Language sont adaptées au «cas général». La recherche initiale de jetons est basée sur le nom. Par exemple, CMx SAST suppose que toutes les requêtes vers la base de données ressembleront à ceci: * createQuery * ou * createSQLQuery *. Mais si le développement interne est utilisé pour travailler avec la base de données et que la méthode d'interrogation de la base de données est appelée différemment, par exemple * driveMyQuery *, toutes les méthodes SQL seront ignorées. Par exemple, notre client utilise ORM personnalisé pour SQL DB. Dans ce cas, les requêtes CMx prêtes à l'emploi ont ignoré toutes les injections SQL.
Abréviations et définitions
CMx - Checkmarx SAST.
CMxQL -
Langage de requête Checkmarx SAST
Token - une chaîne avec une certaine valeur est le résultat du travail de l'analyseur lexical (qui est aussi appelé tokenisation)
Application de test
Pour écrire un article, j'ai esquissé du code Java, une petite application de test. Ce code est une copie approximative d'une petite partie du système réel. Bien qu'en général le code de l'application de test ne soit pas très différent de tout autre code backend HTTP. Les sections clés du code de l'application de test seront visibles sur les captures d'écran.
L'application de test a la structure suivante
Classe
WebRouter pour le traitement des requêtes HTTP entrantes; 4 méthodes de traitement des URL à l'intérieur:
- / getTransaction - accepte l' ID de transaction à l'entrée et renvoie les informations dessus, id le prend comme chaîne et le transmet à getTransactionInfo (transactionId) => getTransactionInfo (transactoinId) - fait que transactionId concatène à la requête SQL (c'est-à-dire que l'injection SQL est obtenue);
- / getSecureTransaction - accepte l' ID de transaction en entrée et renvoie les informations dessus, id le prend comme chaîne et le transmet getTransactionInfoSecured () => getTransactionInfoSecured (transactoinId) - convertit d' abord la chaîne transactionId en type Long, puis la concatène à la requête SQL (dans ce cas où l'injection n'est pas exploitée);
- / getSettings - accepte userId et mailboxId comme entrée - et émet les paramètres de boîte aux lettres. Ne vérifie pas que l' ID de boîte aux lettres appartient à l'utilisateur;
- / getSecureSettings - accepte également userId et mailboxId à l'entrée et affiche les paramètres de boîte aux lettres. MAIS vérifie que l' ID de boîte aux lettres appartient à l'utilisateur.
CMx: informations générales et définitions de base
Avant de commencer à développer des requêtes
Le développement des requêtes est effectué dans un programme distinct CxAuditor. Dans CxAuditor, vous devez analyser tout le code (créer un projet local), pour lequel nous écrirons des requêtes. Après cela, vous pouvez écrire et exécuter de nouvelles requêtes. Avec une grande base de code, l'analyse principale peut prendre des heures et des gigaoctets de mémoire. Après cela, chaque demande ne sera pas exécutée assez rapidement. Ceci est totalement inadapté au développement.
Par conséquent, vous pouvez prendre un petit ensemble de fichiers du projet, idéalement avec un bogue trouvé dans le code avant le type sous lequel nous écrivons une demande (ou y mettre le bogue avec vos mains) et analyser uniquement cet ensemble de fichiers. Il n'est pas nécessaire de respecter la structure de fichiers du projet. Autrement dit, si vous avez le package Java A et B, et que les classes du package B utilisent les classes et les méthodes du package A, vous pouvez mettre tout cela dans un seul répertoire, et CMx comprendra toujours les relations et construira correctement les chaînes d'appels entre les fichiers (enfin, ou presque toujours correct, bien que les erreurs soient à peine liées à la structure des fichiers du projet).
Définitions de base
Cxlist
Le type de données principal dans CMx. Le résultat de presque toutes les fonctions CMxQL sera
CxList . C'est beaucoup d'éléments avec certaines propriétés. Les propriétés les plus utiles pour le développement seront examinées ci-dessous.
résultat
CMxQL a un
résultat variable intégré. L'ensemble qui contient la variable de
résultat , après l'exécution de la requête entière, sera affiché comme résultat.
Autrement dit, l'opération finale de toute requête doit être la chaîne
result = WHATEVER , par exemple:
result = All.FindByName("anyname");
élément de flux et de code
La plupart des fonctions CMxQL par type de valeurs retournées sont divisées en 2, celles qui renvoient des "éléments de code" et celles qui renvoient Flow. Dans les deux cas, le résultat est une
CxList . Mais son contenu sera légèrement différent pour les éléments Flow et code.
- Élément de code - jeton - par exemple, une variable, un appel de méthode, une affectation, etc.
- Flow - la relation entre les jetons donnés.
Tous et «sous» tous
Chaque fonction CMxQL peut être exécutée soit sur l'ensemble
All (il contient tous les jetons de tout le code analysé, nous avons déjà vu un exemple avec
résultat ) ou sur l'ensemble
CxList , qui à son tour a été obtenu à la suite de certaines opérations de la requête, par exemple, la requête:
CxList newList = CxList.New();
va créer un ensemble vide, que nous pouvons ensuite remplir avec des éléments en utilisant la méthode
Add () , puis rechercher déjà par les éléments du nouvel ensemble:
CxList newFind = newList.FindByName("narrowedScope");
Propriétés des objets trouvés
Chaque élément de l'ensemble CxList possède plusieurs propriétés. Lors de l'analyse des résultats de l'écriture de requêtes, les plus utiles sont:
- SourceFile - le nom du fichier qui contient cet élément;
- Ligne source - numéro de ligne avec jeton;
- Nom de la source - le nom du jeton. Équivalent au jeton, c'est-à-dire si la variable est appelée var1, alors Nom de la source = var1;
- Type de source - le type de jeton. Par exemple, s'il s'agit d'une chaîne, ce sera StringLiteral, si la méthode est appelée, puis MethodInvokeExpr et bien d'autres;
- Fichier de destination
- Ligne de destination;
- Nom de destination;
- Type de destination.
La source et la destination seront différentes si les éléments de l'ensemble de résultats sont Flow, et vice versa, ils correspondront si le résultat est des éléments de code.
Commencez à créer des requêtes
Toutes les fonctions CMxQL peuvent être divisées en plusieurs types. Ici, à mon avis, on peut noter le principal inconvénient de la documentation CMxQL, toutes les fonctions du dock sont décrites simplement par ordre alphabétique, alors qu'il serait beaucoup plus pratique de les structurer selon la fonctionnalité et seulement ensuite par ordre alphabétique.
- Fonctions de recherche - presque toutes les fonctions CMxQL avec le nom FindBy * et GetBy * ;
- Les fonctions des opérations sur les ensembles sont l'addition, la soustraction, l'intersection, l'itération sur les éléments, etc.
- Fonctions d'analyse - Il s'agit essentiellement des fonctions * InfluencedBy * * InfluencingOn * .
Le principe de base des requêtes est l'alternance de ces types de fonctions. Tout d'abord, en utilisant les fonctions de recherche, nous sélectionnons uniquement les jetons qui nous intéressent par certaines propriétés. En utilisant des opérations sur des ensembles, nous pouvons combiner différents ensembles avec différentes propriétés de jeton en un seul, ou vice versa, soustraire l'autre d'un. Ensuite, en utilisant les fonctions d'analyse, nous construisons le flux de code et essayons de comprendre si les vulnérabilités potentielles dépendent des paramètres aux points d'entrée.
Le choix de l'endroit à partir duquel commencer la recherche, et en général du chemin de recherche entier, dépend du code spécifique, et plus précisément, même du «texte». Dans certains cas, il est pratique de rechercher des requêtes utilisateur à partir du point d'entrée, dans certains cas, il est plus pratique de commencer par la «fin» ou même par le milieu. Tout dépend du code spécifique et vous devez approcher individuellement chaque référentiel.
Exemple: recherche d'injection SQL
Plan de recherche, entre parenthèses, j'ai indiqué le nom des ensembles (variables dans la requête):
- Définissez les exceptions - jetons qui peuvent être immédiatement retirés des étendues de recherche ( exclusionList );
- Déterminer l'emplacement des contrôles de désinfection / sécurité ( désinfection );
- Trouver tous les emplacements de bas niveau avec exécution de requête dans la base de données ( runSuperSecureSQLQuery );
- Trouver tous les paramètres des méthodes appelées runSuperSecureSQLQuery ( runSSSQParams );
- Trouver des points d'entrée (méthodes parentes et leurs paramètres) pour les lieux d'exécution des requêtes dans la base de données ( entryPointsParameters );
- Trouvez les dépendances des paramètres runSSSQParams sur entryPoints , tandis que seuls les endroits où il n'y a pas de nettoyage de la purification d' entrée.
En conséquence, nous obtenons des méthodes de bas niveau avec des requêtes SQL, où les paramètres de la requête SQL:
- dépendent des paramètres de la méthode;
- les paramètres sont acceptés sous forme de chaînes;
- les paramètres sont concaténés à la demande.
Nous ne vérifierons pas si nous pouvons contrôler ces paramètres, car nous pensons qu'il existe un mécanisme pour mapper des variables dans une requête et qu'il existe un transtypage en type numérique pour les nombres, et la concaténation de chaînes est toujours considérée comme dangereuse. Même s'il n'y a aucun contrôle sur la ligne maintenant, elle pourrait bien apparaître dans la nouvelle version.
SQLi: étape 1. Définition des exceptions
Dans les exceptions, vous devez ajouter les classes ou fichiers dans lesquels les noms de jeton peuvent correspondre à ceux que vous recherchez, car ces jetons entraîneront des entrées non valides.
Par exemple, une méthode d'accès à une base de données est appelée
runSuperSecureSQLquery . Nous supposons que la méthode
runSuperSecureSQLquery à l' intérieur est implémentée en toute sécurité. Et notre tâche est de trouver des endroits où il n'est pas sûr d'utiliser la méthode elle-même. Pour l'injection SQL, les lieux de concaténation des paramètres contrôlés par l'utilisateur ne seront pas des endroits sûrs. Et des emplacements sûrs pour mapper des paramètres dans la structure ORM ou, par exemple, pour des paramètres numériques, il s'agit d'une conversion vers le type correspondant. Nous n'avons pas besoin d'analyser tout le code qui se trouve «plus profondément» que
runSuperSecureSQLquery , ce qui signifie qu'il est préférable de l'exclure afin d'éviter les découvertes inutiles.
Pour rechercher de telles exceptions, il est pratique d'utiliser les fonctions CMxQL:
- FindByFileName () - trouvera l'ensemble de tous les jetons dans un fichier particulier;
- GetByClass () - trouvera l'ensemble de tous les jetons de la classe avec le nom donné.
Pour une application de test, cette exception est la classe
Session , qui contient l'implémentation de la méthode
runSuperSecureSQLquery .
Un exemple de demande d'exclusion de code dans la classe
Session (la méthode
GetByClass () vérifiera lequel des jetons transmis à l'entrée a un type
CMx de
ClassDecl et émettra beaucoup de jetons de cette classe)
CxList exclusionList = All.GetByClass(All.FindByName("*Session*")); result = exclusionList;
Ou une autre façon consiste à jeter du code dans le fichier
Session.java entier:
CxList exclusionList = All.FindByFileName("*Session.java"); result = exclusionList;
L'astérisque devant le nom est important, car le nom de fichier inclut le chemin d'accès complet.
Nous avons maintenant de nombreux jetons qui peuvent être soustraits dans les prochaines étapes de l'étendue de recherche.
Résultat de la recherche de jetons dans la classe
Session :

SQLi: étape 2. Détermination des lieux de désinfection
Il existe 2 méthodes API dans l'application de test (voir une brève description de l'application de test). La différence entre les deux méthodes API est que
getTransactionInfo () concatène le paramètre transactionId dans la requête SQL, et
getTransactionInfoSecured () convertit d' abord transactionId en Long, puis le transmet sous forme de chaîne. La vulnérabilité (concaténation des paramètres) est intégrée dans les deux méthodes. Mais grâce à la
conversion en Long dans
getTransactionInfoSecured () , la dernière méthode n'est pas vulnérable à l'injection, car lorsque nous essayons de passer une injection (chaîne), nous obtenons une exception Java.
Dans cet exemple, nous considérerons le plâtre de Long comme le site d'assainissement. Pour trouver ces jetons:
CxList sanitization = All.FindByName("*Long*"); result = sanitization;
Exemple de résultat:

Le résultat comprenait des jetons avec les méthodes de type YP
Long et
getValueAsLong , qui
convertissent en interne
la valeur en type
Long . Vous devez examiner attentivement le résultat pour vous assurer qu'il n'y a rien de plus.
SQLi: étape 3. Rechercher tous les emplacements de bas niveau avec exécution de requête dans la base de données
La requête suivante trouvera tous les emplacements à l'aide du jeton runSuperSecureSQLQuery (utilisé pour accéder à la base de données):
result = All.FindByName("*runSuperSecureSQLQuery*")
Résultat de la recherche par nom de jeton runSuperSecureSQLQuery:

De plus, pour les endroits où cette méthode est appelée (classe de
facturation ), seuls les jetons d'invocation de méthode (type
MethodInvokeExpr ) seront trouvés, et pour le lieu de déclaration de méthode (classe
Session ), tous les jetons seront trouvés - variables.
Nous filtrons uniquement les jetons d'appel de méthode:
CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery;
Résultat:

En conséquence, nous avons obtenu 7 places, dont 4 les appels requis à la méthode
runSuperSecureSQLQuery () (classes de
facturation et d'
utilisateur ). 2 - appels à la méthode interne runSuperSecureSQLQuery () à l'intérieur de la classe
Session , et une de plus est la méthode
add , qui est plutôt une sorte de bizarrerie de recherche CMxQL. Disons simplement que je ne m'attendais pas à ce qu'il soit dans la liste =) Les jetons de la classe
Session , comme nous l'avons découvert à l'étape 1, ne sont pas intéressants pour nous, nous allons donc simplement les soustraire du résultat:
CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery - exclusionList;
Nous obtenons une liste valide d'appels à la méthode requise:

Notez les fonctions
FindByType () et
typeof () dans la requête précédente. Si nous voulons rechercher par type CMx, c'est-à-dire par la propriété
CxList «Source Type» - alors nous utilisons
typeof (Source Type) . Si nous voulons faire une recherche par type de données, nous devons passer le paramètre comme une chaîne. Par exemple:
result = All.FindByType("String");
trouvera tous les jetons java de type String.
SQLi: étape 4. Trouver tous les paramètres des méthodes appelées runSuperSecureSQLQuery
Pour rechercher des paramètres de méthode, la fonction
CMxQL GetParameters () est utilisée :
CxList runSSSQParams = All.GetParameters(runSuperSecureSQLQuery); result = runSSSQParams;
Résultat:

SQLi: étape 5. Rechercher des points d'entrée pour les emplacements d'exécution des requêtes dans la base de données
Pour ce faire, nous obtenons d'abord les noms des méthodes parentes, à l'intérieur desquelles se trouvent les appels à la base de données
runSuperSecureSQLQuery , puis nous obtenons leurs paramètres. Pour rechercher des jetons parents, la fonction
CMxQL GetAncOfType () est utilisée :
CxList entryPoints = runSuperSecureSQLQuery.GetAncOfType(typeof(MethodDecl)); result = entryPoints;
Dans cette requête, pour l'ensemble runSuperSecureSQLQuery, renvoyez tous les jetons parents de type MethodDecl - il s'agit de la méthode précédente dans la pile des appels:

Pour rechercher des paramètres de méthode, nous utilisons également
GetParameters () :
CxList entryPointsParameters = All.GetParameters(entryPoints).FindByType("String");
La requête renverra les paramètres d'un sous-ensemble de
entryPoints avec le type Java String:

SQLi: étape 6. Recherchez les dépendances des paramètres runSSSQParams sur entryPointsParameters, alors que seuls les endroits où il n'y a pas d'entrée d'entrée de nettoyage
Dans cette étape, nous utilisons les fonctions d'analyse. Les fonctions suivantes sont utilisées pour analyser le code Flow:
- InfluencedBy ()
- InfluencedByAndNotSanitized ()
- InfluencingOn ()
- InfluencingOnAndNotSanitized ()
- NotInfluencedBy ()
- NotInfluencingOn ()
Pour rechercher les paramètres de demande de flux
runSSSQParams en fonction des paramètres de la méthode parent
entryPointsParameters et exclure les jetons d'assainissement:
CxList dataInflOnTable = runSSSQParams.InfluencedByAndNotSanitized(entryPointsParameters, sanitization);
Cependant, je ne sais pas si les fonctions
* AndNotSanitized à l'intérieur font de la magie, et il semble plus que la méthode soustrait simplement l'ensemble aseptisé de son résultat. Autrement dit, si vous le faites:
CxList dataInflOnTable = runSSSQParams.InfluencedBy(entryPointsParameters) - sanitization;
il se passe la même chose. Même si je n'ai peut-être pas trouvé d'option alors qu'il y a encore des différences.
Le résultat de la requête nous donne un flux correctement construit:

Got Flow avec injection SQL potentielle. Comme le montre la capture d'écran, Checkmarx a renvoyé 3 Flow. Le flux dans la capture d'écran est le plus court, il commence et se termine dans un fichier et une méthode. Le flux suivant part déjà dans la classe Session. Faites attention à la source / destination. Et la dernière est une autre méthode de la classe Session. Le flux à l'intérieur de la
session ressemblera à ceci:

Pour sélectionner un flux, la méthode
ReduceFlow (CxList.ReduceFlowType flowType) est utilisée , où flowType peut être:
- CxList.ReduceFlowType.ReduceBigFlow - sélectionnez le flux le plus court
- CxList.ReduceFlowType.ReduceSmallFlow - sélectionnez le flux le plus long
SQLi: requête finale pour trouver une injection SQL
Exemple 2: recherche de références d'objet direct non sécurisées
Dans cette demande, nous rechercherons tous les endroits où le travail avec les objets a lieu sans vérifier le propriétaire de l'objet. Dans ce cas, différents noms de paramètres HTTP pour l'identifiant de boîte aux lettres peuvent être utilisés (nous supposons qu'il s'agit de Legacy), et la vérification elle-même peut avoir lieu à différentes étapes: quelque part juste au point API d'entrée HTTP, quelque part avant la demande à la base de données, et parfois dans les méthodes intermédiaires.
Plan de recherche
- Définissez les exceptions ( exclusionList );
- Identifier les lieux de contrôle des autorisations ( idorSanitizer );
- Trouver des points d'entrée - lieux pour le traitement principal des requêtes HTTP ( webRemoteMethods );
- Uniquement par des jetons de point d'entrée pour trouver l'emplacement d'extraction du paramètre HTTP mailboxid ( mailboxidInit );
- Trouver tous les appels de webRemoteMethods vers les méthodes middleware et les paramètres de ces appels ( middlewareMethods );
- Trouvez des méthodes de middleware qui dépendent de l'identifiant de boîte aux lettres ( apiPotentialIDOR );
- Trouver tous les endroits où les méthodes middleware sont définies ( middlewareDecl );
- Parcourez tous les apiPotentialIDOR et sélectionnez uniquement les middlewareDecl dans lesquels il n'y a pas de vérification du propriétaire de l'objet boîte aux lettres .
IDOR: Étape 1. Identifier les exceptions
Dans ce cas, excluez tous les jetons d'un fichier spécifique:
CxList exclusionList = All.FindByFileName("*WebMethodContext.java"); result = exclusionList;
WebMethodContext.java contient une implémentation de méthodes telles que
getMailboxId et
getUserId , ainsi que la chaîne "mailboxid". Étant donné que le nom des jetons coïncidera avec ceux dont nous avons besoin pour rechercher les vulnérabilités, ce fichier émettra de fausses constatations.
IDOR: Étape 2. Recherchez les contrôles d'autorisation
Dans l'application de test, la méthode
validateMailbox () est utilisée pour déterminer si l'objet demandé appartient à l'utilisateur:
CxList idorSanitizer = All.FindByName("*validateMailbox*"); result = idorSanitizer;
Résultat:

IDOR: étape 3. Rechercher des points d'entrée pour les requêtes API HTTP personnalisées
Les gestionnaires de requêtes HTTP ont une annotation spéciale qui les rend faciles à trouver. Dans mon cas, il s'agit de «WebRemote», la fonction
CMxQL FindByCustomAttribute () est utilisée pour rechercher des annotations. Pour
FindByCustomAttribute () , la fonction de recherche du jeton parent
GetAncOfType () renverra la méthode sous l'annotation:
CxList webRemoteMethods = All.FindByCustomAttribute("WebRemote") .GetAncOfType(typeof(MethodDecl)); result = webRemoteMethods;
Résultat de la demande:

IDOR: étape 4. À l'aide des jetons de point d'entrée uniquement, recherchez les emplacements d'extraction HTTP pour le paramètre mailboxid
Pour rechercher des jetons liés au traitement du paramètre HTTP mailboxid:
CxList getMailboxId = All.FindByName("\"mailboxId\"") + All.FindByName("\"mid\"") + All.FindByName("\"boxid\""); result = getMailboxId;
nous avons ajouté 3 sets avec 3 lignes différentes, car selon la légende, le nom du paramètre HTTP peut différer selon les différentes parties du système.
La requête trouvera tous les endroits où la
boîte aux lettres / mid / boxid est écrite sous forme de chaîne (entre guillemets). Mais cette requête renverra beaucoup de trouvailles, tk. une telle chaîne peut être trouvée non seulement aux endroits où les paramètres HTTP sont extraits. Si nous continuons à travailler avec cet ensemble, nous obtiendrons un grand nombre de fausses découvertes.
Par conséquent, nous ne rechercherons que des jetons de points d'entrée (
webRemoteMethods ). Pour trouver tous les jetons enfants, la fonction
CMBQL GetByAncs () est utilisée :
result = All.GetByAncs(webRemoteMethods);
La demande renverra tous les jetons appartenant aux méthodes annotées en tant que
WebRemote . Déjà à ce stade, nous pouvons filtrer les jetons des méthodes dans lesquelles le propriétaire de l'objet est vérifié. Par conséquent, nous réécrivons la requête précédente pour rechercher des jetons enfants de manière à sélectionner uniquement les jetons enfants des méthodes
WebRemote , où il n'y a pas de contrôle de sécurité pour le propriétaire de l'objet. Pour ce faire, utilisez une boucle avec la condition:
Nous pouvons maintenant effectuer une sélection plus précise à l'aide des paramètres HTTP
mailboxid :
CxList getMailboxHTTPParams = entry_point_tokens.FindByName("\"mailboxid\"") + entry_point_tokens.FindByName("\"mid\"") + entry_point_tokens.FindByName("\"boxid\""); result = getMailboxHTTPParams;
Mais nous ne nous intéressons pas aux endroits où les paramètres HTTP sont obtenus, mais aux variables auxquelles sont finalement attribuées les valeurs des paramètres HTTP. Puisqu'il est plus fiable de rechercher Flow précisément avec des jetons de variables.
La fonction
CMxQL FindByInitialization () trouvera les lieux d'initialisation des variables pour les jetons donnés:
CxList mailboxidInit = entry_point_tokens.FindByInitialization(getMailboxHTTPParams); result = mailboxidInit;
Résultat:

IDOR: étape 5. Recherchez tous les appels de webRemoteMethods vers les méthodes et paramètres middleware de ces appels
Par middleware, j'entends un code qui va plus loin que les méthodes de traitement des requêtes API HTTP, c'est-à-dire plus profondément que les points d'entrée des requêtes des utilisateurs. Par exemple, pour la capture d'écran ci-dessus, il s'agit des méthodes de la classe
User , des appels à
user.getSettings () et
user.getSecureSettings () :
CxList middlewareMethods = All.FindByShortName("user").GetRightmostMember(); CxList middlewareMethodsParams = entry_point_tokens.GetParameters(middlewareMethods); result = middlewareMethodsParams;
Tout d'abord, nous sélectionnons tous les jetons avec le nom d'utilisateur, puis en utilisant
GetRightmostMember (), nous sélectionnons les jetons d'appel pour le middleware.
GetRightmostMember () dans la chaîne d'appels de méthode renverra celui le plus à droite. Ensuite, nous dérivons les paramètres de la méthode trouvée en utilisant
GetParameters () .
Résultat:

IDOR: étape 6. Rechercher des méthodes middleware qui dépendent de l'identifiant de boîte aux lettres
L'analyse de flux utilise les
méthodes * InfluencedBy * et
* InfluncingOn * . La différence entre eux est claire de nom.
Par exemple:
All.InfluencedBy(getMailboxHTTPParams)
passera par l'ensemble Tous et trouvera tous les jetons qui dépendent de
getMailboxHTTPParams .
La même chose peut être écrite d'une autre manière:
getMailboxHTTPParams.InfluencingOn(All)
Pour rechercher des jetons dépendants de
mailboxidInit :
CxList apiPotentialIDOR = entry_point_tokens.InfluencedByAndNotSanitized(mailboxidInit, idorSanitizer); result = apiPotentialIDOR;
Résultat:

IDOR: Étape 7. Trouvez tous les endroits pour définir les méthodes du middleware
Trouvons les définitions de toutes les méthodes intermédiaires qui peuvent être utilisées dans les endroits où les demandes des utilisateurs sont traitées. Pour ce faire, nous mettons en évidence leur propriété commune, par exemple, dans toutes ces méthodes, il y a la création d'un objet
Request () , la création d'un objet est de type
CMx ObjectCreateExpr :
CxList requests = (All - exclusionList).FindByType(typeof(ObjectCreateExpr)).FindByName("*Request*"); CxList middlewareDecl = requests.GetAncOfType(typeof(MethodDecl)); result = middlewareDecl;
(All - exclusionList) - vous pouvez effectuer cette soustraction d'ensembles, puis appeler la fonction CMxQL souhaitée à partir du résultat.
Les requêtes contiennent désormais tous les jetons avec le nom
Request et le type correspondant à la création de l'objet.
Ensuite, en utilisant le
GetAncOfType () familier
, nous trouvons le jeton parent de type
MethodDecl .
Résultat:

IDOR: Étape 8. Parcourez tous les apiPotentialIDOR et sélectionnez uniquement les middlewareDecl dans lesquels il n'y a pas de vérification du propriétaire de l'objet mailboxid
Dans la dernière partie de la demande, nous déterminerons lesquelles des méthodes middleware sont appelées directement à partir des méthodes du point d'entrée et ne vérifions pas à qui appartient l'
ID de boîte aux
lettres . Combinez ensuite Flow pour une analyse plus pratique des résultats.
Nouvelles fonctionnalités que nous n'avons pas encore utilisées:
GetCxListByPath () - cette fonction est nécessaire pour itérer sur Flow, si elle n'est PAS utilisée, CMx compressera le flux dans l'élément de code (dans le premier nœud de flux)
Concaténer * () - un certain nombre de fonctions nécessaires pour combiner plusieurs flux en un seul
FindByParameters () - recherche une méthode par un jeton de paramètre spécifique
GetName () - retournera une chaîne avec le nom du jeton, s'il y a plus d'un élément dans CxList, alors il retournera le premier. La méthode est utilisée uniquement lors de l'itération sur les éléments d'un ensemble.
La dernière partie de la demande:
Résultat:
CocatenatePath , . Code Element Flow
IDOR: IDOR
Conclusion
Checkmarx , . , , , .. Flow ( ). , , «» .
false positive, :
- , ( ).
- , ( ). , «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.