Implémenter une tâche
Lorsque Red Kite ne recueille pas une information dont vous avez besoin, écrivez une tâche (job) pour l'obtenir. Les tâches personnalisées sont aussi un bon moyen d'industrialiser les résultats d'un test d'intrusion : si un testeur a trouvé un problème sur un serveur, une tâche peut chercher le même problème sur toutes les ressources pertinentes.
Il existe deux types de tâches :
- les tâches Python, qui utilisent le SDK de Red Kite pour émettre des findings, pour une flexibilité totale;
- les tâches Nuclei, qui exécutent des gabarits Nuclei, pour les vérifications HTTP et réseau.
Créer une tâche
- Allez dans Automatismes > Tâches et cliquez sur Nouvelle tâche personnalisée.
- Choisissez un gabarit de tâche comme point de départ, ou continuez sans gabarit.
- Dans le panneau Configuration, donnez un nom à la tâche et choisissez son type :
codepour une tâche Python, ounucleipour une tâche Nuclei. - Choisissez ses paramètres de pod de tâches, qui définissent le processeur et la mémoire que la tâche peut utiliser, ainsi que son image de conteneur.
- Écrivez la tâche dans l'éditeur de code, puis sauvegardez-la.
Pour adapter une tâche intégrée, utilisez Dupliquer dans son menu et modifiez la copie : les tâches intégrées sont en lecture seule. Consultez Sources de tâches.
Exécuter votre tâche
- Pour la tester, exécutez-la une fois à partir de Automatismes > Lancer. Consultez Lancer une tâche.
- Pour l'exécuter automatiquement, créez un abonnement qui la démarre lorsqu'un finding est émis, ou selon un horaire.
- Pour suivre ses résultats comme des problèmes, créez une intel qui recherche le finding qu'elle émet.
Intrants et sorties d'une tâche
Pour fonctionner correctement, une tâche a des intrants et des sorties. Les intrants sont souvent les informations de la cible, et les sorties sont souvent des journaux et des findings.
Intrants d'une tâche
Les intrants d'une tâche lui sont fournis sous forme de variables d'environnement.
Voici un exemple en Python qui montre comment obtenir la valeur d'une variable d'environnement.
import os
var_content = os.environ['myCustomParameter']
Les données d'entrée peuvent souvent être validées à l'aide du SDK fourni.
Tous les paramètres d'une tâche lui sont fournis sous forme de variables d'environnement. Les noms des paramètres doivent donc respecter un jeu de caractères précis. L'expression régulière suivante sert à valider les caractères des noms de paramètres avant la création de la tâche. Si cette expression régulière n'est pas respectée, la tâche n'est pas créée.
/^[A-Za-z][A-Za-z0-9_]*$/;
De plus, pour éviter les conflits avec les noms de variables courants du système d'exploitation, les variables suivantes ne doivent pas être définies. Si un paramètre porte l'un de ces noms, la tâche n'est pas créée.
| RFLAGS | IFS | MAILPATH | PS1 | CC |
| LANG | MAILRC | PS2 | CDPATH | LC_ALL |
| MAKEFLAGS | PS3 | CFLAGS | LC_COLLATE | MAKESHELL |
| PS4 | CHARSET | LC_CTYPE | MANPATH | PWD |
| COLUMNS | LC_MESSAGES | MBOX | RANDOM | DATEMSK |
| LC_MONETARY | MORE | SECONDS | DEAD | LC_NUMERIC |
| MSGVERB | SHELL | EDITOR | LC_TIME | NLSPATH |
| TERM | ENV | LDFLAGS | NPROC | TERMCAP |
| EXINIT | LEX | OLDPWD | TERMINFO | FC |
| LFLAGS | OPTARG | TMPDIR | FCEDIT | LINENO |
| OPTERR | TZ | FFLAGS | LINES | OPTIND |
| USER | GET | LISTER | PAGER | VISUAL |
| GFLAGS | LOGNAME | PATH | YACC | HISTFILE |
| LPDEST | PPID | YFLAGS | HISTORY | |
| PRINTER | HISTSIZE | MAILCHECK | PROCLANG | HOME |
| MAILER | PROJECTDIR |
Sorties d'une tâche
Les tâches publient leurs findings et leurs journaux à l'aide du SDK de tâches de Red Kite.
Types de tâches
Red Kite prend en charge plusieurs types de tâches. Chaque type a ses avantages et ses inconvénients. Certains sont plus flexibles, d'autres sont plus rapides à implémenter.
Les types de tâches :
Tâche Python
| Type | Langage |
|---|---|
| Code | Python |
Une tâche Python est la façon standard de créer une tâche. Elle vous offre une flexibilité totale, mais vous devez l'implémenter vous-même.
Les tâches Python incluent un SDK intégré pour vous aider à publier correctement des findings et des journaux.
Tâche Nuclei
| Type | Langage |
|---|---|
| Nuclei | Yaml |
Une tâche Nuclei utilise Nuclei, de Project Discovery, pour exécuter des gabarits Nuclei et publier des findings que Red Kite comprend. Elle inclut un analyseur intégré, mais s'il ne répond pas à vos besoins, vous pouvez définir un gestionnaire de findings personnalisé. Ce gestionnaire personnalisé est chargé d'analyser les findings de Nuclei et de publier des findings compatibles avec Red Kite. Il est implémenté en Python. Rassurez-vous : un gabarit, une classe personnalisée et le SDK Python sont disponibles pour vous aider.
Pour démarrer une tâche Nuclei, une cible est toujours requise. Vous pouvez fournir la cible à l'aide des paramètres de tâche suivants :
| Nom | Détails de la valeur |
|---|---|
| targetIp | L'adresse IP de la cible |
| port | Le port de la cible |
| domainName | Le nom de domaine de la cible. Il a priorité sur targetIp lors de la construction de la cible. |
| path | Le chemin qui identifie la racine du site web, par exemple / |
| ssl | True si le site web utilise le chiffrement, false sinon. |
| endpoint | Le point de terminaison de la cible. Par exemple, /target/file.html. |
Ces informations servent à construire la cible Nuclei et à identifier la ressource à laquelle appartiennent les findings. Vous pouvez
fournir des informations partielles pour cibler différentes choses. Par exemple, pour une vérification DNS, seule la valeur domainName
est nécessaire. Pour une vérification web, tous les paramètres précédents sont nécessaires.
Pour démarrer une tâche Nuclei avec l'analyseur par défaut, vous devez configurer celui-ci en fournissant les deux paramètres de tâche suivants :
| Nom | Détails de la valeur |
|---|---|
| stalkerOutputType | domain, host, port ou website. Détermine la ressource à laquelle les données sont liées, en changeant le type des findings publiés. |
| outputFindingName | Le nom de finding souhaité. Il sert à faire correspondre les abonnements. |
Traitement des findings de Nuclei
Le gestionnaire de findings personnalisé analyse chaque ligne JSON produite par Nuclei dans la méthode parse_finding. Pour vous aider à
analyser la sortie de Nuclei, la classe NucleiFinding est fournie. Le gestionnaire publie ensuite tous les findings dans la méthode
publish_findings. Tout ce que retourne la méthode parse_finding est transmis à la méthode publish_findings sous forme de liste. Pour
publier correctement vos findings, consultez la documentation des findings.
Le code du gabarit de gestionnaire de findings personnalisé :
from nuclei_finding import NucleiFinding
from stalker_job_sdk import log_info
class FindingHandler:
"""Custom parser template to get you started. The parse_finding and publish_findings methods are required."""
def __init__(self):
log_info("Initializing the custom handler")
def parse_finding(self, finding_obj: dict, original_string: str, original_path: str):
"""This method returns a NucleiFinding, but it can return any object."""
return NucleiFinding(finding_obj, original_string=original_string, original_path=original_path)
def publish_findings(self, findings: list):
"""This method receives all the findings given by the parse_finding method as a list."""
log_info("TODO: Publish findings")
for finding in findings:
log_info(finding.template_id)
Vous pourriez même passer des paramètres à l'analyseur à partir de l'interface au moyen de variables d'environnement, de la même façon que vous passeriez un paramètre à une tâche basée sur du code.
La classe NucleiFinding analyse le finding fourni dans son constructeur. La plupart du temps, vous ne devriez pas avoir à analyser les
findings vous-même. Si Nuclei fournit une valeur qui correspond à l'une des variables, le constructeur l'analyse.
La classe NucleiFinding et un aperçu de ses données :
class NucleiFinding:
template_id: str = None
name: str = None
tags: 'list[str]' = None
severity: str = None
type: str = None
port: int = None
scheme: str = None
url: str = None
matched_at: str = None
extracted_results: 'list[str]' = None
ip: str = None
domain: str = None
timestamp: str = None
curl_command: str = None
description: str = None
original_string: str = None
matcher_name: str = None