
Una CPU mínima en memoria para la creación agnóstica de protocolos sobre la marcha
Harald es una pequeña CPU de alto nivel en memoria, capaz de procesar un conjunto de instrucciones para generar protocolos de capa de aplicación que se utilizarán sobre un protocolo de red determinado (TCP/UDP).
Harald consumirá un flujo de OPCODES y aplicará diferentes transformaciones a la carga útil para que sea adecuada para el protocolo de capa de aplicación definido.
[!TIP] ¿Por qué Harald? Puede que conozcas a Harald Gormsson, rey de Dinamarca, por su apodo: Blátǫnn, o como lo pronunciamos hoy en día, Bluetooth. La tecnología recibió el nombre del apodo de Harald, ya que él conectó los reinos danés y vikingo en aquella época. Así que le pongo este nombre por su nombre de pila.
Harald se comporta como una CPU. Sigue un conjunto de OPCODES que definen acciones. Un PROTOCOLO. Harald procesará las operaciones necesarias para crear el protocolo requerido sobre la marcha.
Una vez proporcionado el PROTOCOLO, Harald iterará sobre el PAYLOAD que se enviará recorriendo todo el PROTOCOLO una vez por cada fragmento. Es decir: si la carga útil tuviera que dividirse en varios fragmentos, Harald utilizará el mismo protocolo para cada fragmento, ejecutando cada acción definida en el protocolo contra el fragmento de carga útil actual.
Harald mantiene una serie de registros que el protocolo puede utilizar para almacenar valores. Estos registros pueden usarse para realizar múltiples operaciones, como suma, resta, codificación y decodificación... etc.
Harald asigna dinámicamente un array de resultados donde el protocolo puede almacenar las respuestas a cada petición realizada al enviar un fragmento de carga útil.

Harald admite una variedad de Opcodes que se pueden proporcionar como protocolo. Harald realizará un conjunto de operaciones de alto nivel al recibir un Opcode determinado. Cada Opcode espera un conjunto predefinido de argumentos con una longitud predefinida.
| OPCODE::Nº | Descripción | ARGS::Size |
|---|---|---|
| H_F_APPEND::0x01 | Añade los siguientes N Bytes al final de la carga útil | Size::4, NBytes::N |
| H_F_PREPEND::0x02 | Antepone los siguientes N Bytes al final de la carga útil | Size::4, NBytes::N |
| H_F_SPLIT::0x03 | Divide la carga útil en fragmentos del tamaño indicado | Size::4 |
| H_F_PAYLOAD_INJECT::0x04 | Inyecta el fragmento de carga útil en la carga útil final | - |
| H_F_SOCK_INIT::0x05 | Inicializa la conexión de socket | IsIPAddress:1, SSL_Enabled::1, TCP/UDP::1, [(HostLen::4,HostName:N)/IPAddress::4], Port::2 |
| H_F_SEND::0x06 | Envía la carga útil final construida | - |
| H_F_RECV::0x07 | Recibe hasta N Bytes | Size::4 |
| H_F_CLOSE::0x08 | Cierra el socket y limpia | - |
| H_F_INJECT::0x09 | Inyecta el registro solicitado en la carga útil final | Reg::1 |
| H_F_ENCODE_STR::0x0A | Codifica un campo de la carga útil a su representación como cadena | IsReg::1, [(Payload::1, Field::1)/Reg::1], Format::1 |
| H_F_DECODE_STR::0xA0 | Decodifica el contenido de un registro a su representación numérica | Reg::1 |
| H_F_ENCODE_STRB64::0x0B | Codifica un campo de la carga útil a su representación como cadena B64 | Payload::1, Field::1 |
| H_F_COMPUTE_FRAG_LENGTH::0x0D | Calcula la longitud del siguiente fragmento a enviar | - |
| H_F_SEARCH::0x0E | Busca un patrón de bytes dado de un tamaño N dado en un registro dado | Reg::1, Size::4, NBytes::N |
| H_F_SEEK::0x0F | Mueve el cursor en una carga útil dada un número de bytes dado | Payload::1, Offset::4 |
| H_F_PUSH::0x10 | Inserta un número de bytes o el contenido de un registro en otro registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_ADD::0x12 | Suma dos registros o un número a un registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
El siguiente flujo de Opcodes generará los datos necesarios para enviar en una comunicación que sea entendida como HTTP. Iniciará, modificará la carga útil para que parezca tráfico HTTP, la enviará a través de una conexión SSL/TLS y cerrará la conexión al final.
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
El siguiente ejemplo sigue los mismos procedimientos que el anterior. Sin embargo, en lugar de simplemente enviar la carga útil como cuerpo, el Protocolo indicará a Harald que configure algunas cabeceras y estructure el cuerpo para que pueda comunicarse con la API de GitHub para publicar comentarios en un issue de un repositorio privado.
Este tipo de comunicación puede ayudar a un atacante a crear un canal de comunicación con el servidor C2 usando un dominio de confianza, como *.github.com. Este mismo ejemplo podría extrapolarse para usar recursos de AWS (como colas SQS bajo sqs..amazonaws.com), recursos de Azure (como blobs bajo <storage_account_name>.blob.core.windows.net) y demás.
Este ejemplo es una buena referencia para aquellas comunicaciones que requieren 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
Necesitarás un compilador para compilarlo. Como GCC, Clang o el CL de Microsoft. Además, hay algunas dependencias de librerías:
Instala LibSSL y pkg-config:
sudo apt install libssl-dev pkg-config
Instala OpenSSL mediante brew o compílalo y configúralo tú mismo.
brew install openssl
Obtén OpenSSL de cualquiera de sus distribuidores enlazados o compílalo y configúralo tú mismo.
El repositorio contiene un Makefile para compilar la librería y algunos binarios de prueba.
Para compilar la librería Harald, ejecuta:
make lib
Esto creará una librería compartida libharald.so, libharald.dll o
libharald.dylib según tu plataforma.
Para compilar los binarios de prueba, ejecuta:
make test
Esto creará dos binarios: test_harald y test_harald_gh (con su
extensión respectiva, según tu plataforma).
Para probar las funcionalidades de Harald, ejecuta los servidores provisionados socket_server_test.py y https_server_test.py. Estos crearán un servidor de socket y un servidor HTTPS respectivamente para ser usados por los binarios de prueba.
Nota: Puede que necesites establecer tu
LD_LIBRARY_PATHa la carpeta actual:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_harald
Se te requerirá crear un certificado SSL/TLS para la comunicación HTTPS (autofirmado está bien). Puedes crear uno usando OpenSSL con el siguiente comando:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Una vez que los servidores estén en funcionamiento, ejecuta el binario test_harald:
./test_harald
El binario debería conectarse a los servidores provisionados y enviar las cargas útiles de datos predefinidas según lo especificado en el protocolo.
Para probar las funcionalidades de la API de GitHub, deben realizarse algunas preparaciones
antes de ejecutar el binario test_harald_gh.
Crea un repositorio y un issue.
El archivo test_harald_gh.c contiene un ejemplo simple de cómo
usar Harald para interactuar con la API de GitHub para crear comentarios en issues. Requiere
que tengas un token de acceso para GitHub, que puede obtenerse desde la configuración de tu
cuenta de GitHub en Developer settings -> Personal access tokens ->
Fine-grained tokens. Se recomienda restringir el token para obtener acceso
únicamente al repositorio recién creado y a los permisos Read access to metadata y
Read and Write access to issues and pull requests.
Para ejecutarlo correctamente, se te requerirá modificar los valores de marcador de posición para:
YOUR_GH_USER: Tu nombre de usuario de GitHub.ISSUE_NUMBER: El número de issue en el repositorio con el que quieres interactuar
(por ejemplo, "1" para el primer issue de un repositorio).YOUR_GH_REPO: El nombre del repositorio con el que quieres interactuar
(por ejemplo, "harald").YOUR_GH_PAT: Tu token de acceso de GitHub.Una vez hecho esto, ¡asegúrate de actualizar el tamaño de la carga útil enviada para que coincida con tus necesidades!
En test_harald_gh.c#L9, el cuarto parámetro del
opcode H_F_APPEND representa el tamaño de la carga útil. Deberás actualizar
este valor en consecuencia cuando modifiques la estructura de la carga útil.
Compila los binarios de prueba y ejecuta este:
./test_harald_gh
Esto creará un comentario en el issue proporcionado.
El código fuente contenido en este repositorio puede usarse para evadir el filtrado de red y reducir el riesgo de detección por parte de dispositivos de seguridad. Antes de usar este código fuente, asegúrate de que tu uso cumple con todas las leyes aplicables en tu jurisdicción.
| H_F_SUBSTRACT::0x13 | Resta dos registros o un número a un registro | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_READ::0x14 | Lee de un registro dado hasta la longitud almacenada en otro registro | FromReg::1, SizeReg::1 |
| H_F_STORE::0x15 | Almacena un valor de registro en el Storage de Harald | Reg::1 |