
Una CPU minimale in-memory per la creazione agnostica di protocolli al volo
Harald è una piccola CPU ad alto livello in memoria, in grado di elaborare un insieme di istruzioni per generare protocolli a livello applicativo da utilizzare su un dato protocollo di rete (TCP/UDP).
Harald consumerà un flusso di OPCODE e applicherà diverse trasformazioni al payload affinché sia adatto al protocollo a livello applicativo definito.
[!TIP] Perché Harald? Potresti conoscere Harald Gormsson, re di Danimarca, per il suo soprannome: Blátǫnn, o come lo pronunciamo oggi, Bluetooth. La tecnologia prese il nome dal soprannome di Harald poiché egli collegò i regni danese e vichingo all'epoca. Quindi sto chiamando questo progetto con il suo nome di battesimo.
Harald si comporta come una CPU. Segue un insieme di OPCODE che definiscono azioni. Un PROTOCOLLO. Harald elaborerà le operazioni necessarie per creare il protocollo richiesto al volo.
Una volta fornito il PROTOCOLLO, Harald itererà sul PAYLOAD da inviare attraversando l'intero PROTOCOLLO una volta per ogni frammento. Ovvero: se il payload dovesse essere suddiviso in più frammenti, Harald utilizzerà lo stesso protocollo per ogni frammento, eseguendo ogni azione definita nel protocollo sul frammento di payload corrente.
Harald mantiene una serie di registri da utilizzare dal protocollo per memorizzare valori. Questi registri possono essere usati per eseguire molteplici operazioni, come addizione, sottrazione, codifica e decodifica... ecc.
Harald alloca dinamicamente un array di risultati dove il protocollo può memorizzare le risposte a ogni richiesta effettuata durante l'invio di un frammento di payload.

Harald supporta una varietà di Opcode da fornire come protocollo. Harald eseguirà un insieme di operazioni ad alto livello al ricevimento di un dato Opcode. Ogni Opcode si aspetta un insieme predefinito di argomenti con una lunghezza predefinita.
| OPCODE::Nº | Descrizione | ARGS::Size |
|---|---|---|
| H_F_APPEND::0x01 | Aggiunge i successivi N Byte alla fine del payload | Size::4, NBytes::N |
| H_F_PREPEND::0x02 | Antepone i successivi N Byte alla fine del payload | Size::4, NBytes::N |
| H_F_SPLIT::0x03 | Suddivide il Payload in frammenti della dimensione data | Size::4 |
| H_F_PAYLOAD_INJECT::0x04 | Inietta il frammento di Payload nel Payload Finale | - |
| H_F_SOCK_INIT::0x05 | Inizializza la connessione socket | IsIPAddress:1, SSL_Enabled::1, TCP/UDP::1, [(HostLen::4,HostName:N)/IPAddress::4], Port::2 |
| H_F_SEND::0x06 | Invia il Payload Finale costruito | - |
| H_F_RECV::0x07 | Riceve fino a N Byte | Size::4 |
| H_F_CLOSE::0x08 | Chiude il socket e pulisce | - |
| H_F_INJECT::0x09 | Inietta il registro richiesto nel Payload Finale | Reg::1 |
| H_F_ENCODE_STR::0x0A | Codifica un campo del Payload nella sua rappresentazione stringa | IsReg::1, [(Payload::1, Field::1)/Reg::1], Format::1 |
| H_F_DECODE_STR::0xA0 | Decodifica il contenuto di un registro nella sua rappresentazione numerica | Reg::1 |
| H_F_ENCODE_STRB64::0x0B | Codifica un campo del Payload nella sua rappresentazione B64string | Payload::1, Field::1 |
| H_F_COMPUTE_FRAG_LENGTH::0x0D | Calcola la lunghezza del prossimo frammento da inviare | - |
| H_F_SEARCH::0x0E | Cerca un dato pattern di byte di una data dimensione N in un dato registro | Reg::1, Size::4, NBytes::N |
| H_F_SEEK::0x0F | Sposta il cursore in un dato payload di un dato numero di byte | Payload::1, Offset::4 |
| H_F_PUSH::0x10 | Inserisce un numero di byte o il contenuto di un registro in un altro registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_ADD::0x12 | Somma due registri o un numero a un registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
Il seguente flusso di Opcode genererà i dati richiesti da inviare affinché una comunicazione sia interpretata come HTTP. Inizierà, modificherà il payload per farlo sembrare traffico HTTP, lo invierà su una connessione SSL/TLS e chiuderà la connessione alla fine.
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
Il seguente esempio segue le stesse procedure del precedente. Tuttavia, invece di inviare semplicemente il payload come corpo, il Protocollo istruirà Harald a impostare alcune intestazioni e strutturare il corpo in modo che possa comunicare con l'API di GitHub per pubblicare commenti nell'issue di un repository privato.
Questo tipo di comunicazione può aiutare un attaccante a creare un canale di comunicazione con il server C2 usando un dominio fidato, come *.github.com. Questo stesso esempio potrebbe essere estrapolato per usare risorse AWS (come code SQS sotto sqs..amazonaws.com), risorse Azure (come blob sotto <storage_account_name>.blob.core.windows.net) e così via.
Questo esempio è un buon riferimento per quelle comunicazioni che richiedono 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
Avrai bisogno di un compilatore per compilarlo. Come GCC, Clang, o CL di Microsoft. Inoltre, ci sono alcune dipendenze da librerie:
Installa LibSSL e pkg-config:
sudo apt install libssl-dev pkg-config
Installa OpenSSL tramite brew o compilalo e configuralo da solo.
brew install openssl
Ottieni OpenSSL da uno dei loro distributori collegati o compilalo e configuralo da solo.
Il repository contiene un Makefile per compilare la libreria e alcuni binari di test.
Per compilare la libreria Harald, esegui:
make lib
Questo creerà una libreria condivisa libharald.so, libharald.dll, o
libharald.dylib a seconda della tua piattaforma.
Per compilare i binari di test, esegui:
make test
Questo creerà due binari: test_harald e test_harald_gh (con le loro
rispettive estensioni, in base alla tua piattaforma).
Per testare le funzionalità di Harald, esegui i server forniti socket_server_test.py e https_server_test.py. Questi creeranno rispettivamente un socket e un server HTTPS da utilizzare per i binari di test.
Nota: Potresti dover impostare il tuo
LD_LIBRARY_PATHalla cartella corrente:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_harald
Ti sarà richiesto di creare un certificato SSL/TLS per la comunicazione HTTPS (autofirmato va bene). Puoi crearne uno usando OpenSSL con il seguente comando:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Una volta che i server sono attivi e funzionanti, esegui il binario test_harald:
./test_harald
Il binario dovrebbe connettersi ai server forniti e inviare i payload di dati predefiniti come specificato nel protocollo.
Per testare le funzionalità dell'API di GitHub, alcune preparazioni devono essere effettuate
prima di eseguire il binario test_harald_gh.
Crea un repository e un'issue.
Il file test_harald_gh.c contiene un semplice esempio di come
usare Harald per interagire con l'API di GitHub per creare commenti nelle issue. Richiede
che tu abbia un token di accesso per GitHub, che può essere ottenuto dalle impostazioni del tuo
account GitHub sotto Developer settings -> Personal access tokens ->
Fine-grained tokens. Si raccomanda di limitare il token per ottenere accesso
solo al repository appena creato e ai permessi Read access to metadata e
Read and Write access to issues and pull requests.
Per funzionare correttamente, ti sarà richiesto di modificare i valori segnaposto per:
YOUR_GH_USER: Il tuo nome utente GitHub.ISSUE_NUMBER: Il numero dell'issue sul repository con cui vuoi interagire
(es., "1" per la prima issue in un repo).YOUR_GH_REPO: Il nome del repository con cui vuoi interagire
(es., "harald").YOUR_GH_PAT: Il tuo token di accesso GitHub.Una volta fatto, assicurati di aggiornare la dimensione del payload inviato per adattarla alle tue esigenze!
In test_harald_gh.c#L9, il 4° parametro dell'
opcode H_F_APPEND rappresenta la dimensione del payload. Dovrai aggiornare
questo valore di conseguenza quando modifichi la struttura del payload.
Compila i binari di test ed esegui questo:
./test_harald_gh
Questo creerà un commento nell'issue fornita.
Il codice sorgente contenuto in questo repository può essere utilizzato per eludere il filtraggio di rete e ridurre il rischio di rilevamento da parte di apparati di sicurezza. Prima di utilizzare questo codice sorgente, assicurati che il tuo utilizzo sia conforme a tutte le leggi applicabili nella tua giurisdizione.
| H_F_SUBSTRACT::0x13 | Sottrae due registri o un numero a un registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_READ::0x14 | Legge da un dato registro fino alla lunghezza memorizzata in un altro registro | FromReg::1, SizeReg::1 |
| H_F_STORE::0x15 | Memorizza un valore di registro nello Storage di Harald | Reg::1 |