
Um CPU mínimo em memória para criação de protocolos agnósticos em tempo real
Harald é uma CPU minúscula de alto nível em memória, capaz de processar um conjunto de instruções para gerar protocolos de camada de aplicação a serem usados sobre um determinado protocolo de rede (TCP/UDP).
Harald consumirá um fluxo de OPCODES e aplicará diferentes transformações ao payload para que ele seja adequado ao protocolo de camada de aplicação definido.
[!TIP] Por que Harald? Você pode conhecer Harald Gormsson, rei da Dinamarca, por seu apelido: Blátǫnn, ou como pronunciamos hoje em dia, Bluetooth. A tecnologia foi nomeada em homenagem ao apelido de Harald, pois ele conectou os reinos dinamarquês e viking naquela época. Então estou nomeando isto em homenagem ao seu primeiro nome.
Harald se comporta como uma CPU. Ele segue um conjunto de OPCODES que definem ações. Um PROTOCOLO. Harald processará as operações necessárias para criar o protocolo necessário em tempo real.
Uma vez que o PROTOCOLO é fornecido, Harald irá iterar sobre o PAYLOAD a ser enviado percorrendo todo o PROTOCOLO uma vez para cada fragmento. Ou seja: se o payload tiver que ser dividido em múltiplos fragmentos, Harald usará o mesmo protocolo para cada fragmento, executando cada ação definida no protocolo contra o fragmento de payload atual.
Harald mantém uma série de registradores para serem usados pelo protocolo para armazenar valores. Esses registradores podem ser usados para realizar múltiplas operações, como adição, subtração, codificação e decodificação... etc.
Harald aloca dinamicamente um array de resultados onde o protocolo pode armazenar as respostas para cada requisição realizada ao enviar um fragmento de payload.

Harald suporta uma variedade de Opcodes a serem fornecidos como um protocolo. Harald realizará um conjunto de operações de alto nível ao receber um determinado Opcode. Cada Opcode espera um conjunto predefinido de argumentos com um comprimento predefinido.
| OPCODE::Nº | Descrição | ARGS::Size |
|---|---|---|
| H_F_APPEND::0x01 | Anexa os seguintes N Bytes ao payload final | Size::4, NBytes::N |
| H_F_PREPEND::0x02 | Prefixa os seguintes N Bytes ao payload final | Size::4, NBytes::N |
| H_F_SPLIT::0x03 | Divide o Payload em fragmentos do tamanho fornecido | Size::4 |
| H_F_PAYLOAD_INJECT::0x04 | Injeta o fragmento do Payload no Payload Final | - |
| H_F_SOCK_INIT::0x05 | Inicializa a conexão do socket | IsIPAddress:1, SSL_Enabled::1, TCP/UDP::1, [(HostLen::4,HostName:N)/IPAddress::4], Port::2 |
| H_F_SEND::0x06 | Envia o Payload Final construído | - |
| H_F_RECV::0x07 | Recebe até N Bytes | Size::4 |
| H_F_CLOSE::0x08 | Fecha o socket e limpa | - |
| H_F_INJECT::0x09 | Injeta o registrador solicitado no Payload Final | Reg::1 |
| H_F_ENCODE_STR::0x0A | Codifica um campo do Payload para sua representação em string | IsReg::1, [(Payload::1, Field::1)/Reg::1], Format::1 |
| H_F_DECODE_STR::0xA0 | Decodifica o conteúdo de um registrador para sua representação numérica | Reg::1 |
| H_F_ENCODE_STRB64::0x0B | Codifica um campo do Payload para sua representação em string B64 | Payload::1, Field::1 |
| H_F_COMPUTE_FRAG_LENGTH::0x0D | Calcula o comprimento do próximo fragmento a ser enviado | - |
| H_F_SEARCH::0x0E | Procura por um determinado padrão de bytes de um determinado tamanho N em um determinado registrador | Reg::1, Size::4, NBytes::N |
| H_F_SEEK::0x0F | Move o cursor em um determinado payload por um determinado número de bytes | Payload::1, Offset::4 |
| H_F_PUSH::0x10 | Insere um número de bytes ou o conteúdo de um registrador em outro registrador | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_ADD::0x12 | Soma dois registradores ou um número a um registrador | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
O seguinte fluxo de Opcodes irá gerar os dados necessários a serem enviados para que uma comunicação seja entendida como HTTP. Ele irá iniciar, modificar o payload para parecer tráfego HTTP, enviá-lo por uma conexão SSL/TLS e fechar a conexão no 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
O exemplo a seguir segue os mesmos procedimentos do anterior. No entanto, em vez de apenas enviar o payload como corpo, o Protocolo instruirá Harald a configurar alguns cabeçalhos e estruturar o corpo para que ele possa se comunicar com a API do GitHub para publicar comentários em uma issue de um repositório privado.
Esse tipo de comunicação pode ajudar um atacante a criar um canal de comunicação com o servidor C2 usando um domínio confiável, como *.github.com. Este mesmo exemplo poderia ser extrapolado para usar recursos da AWS (como filas SQS em sqs..amazonaws.com), recursos do Azure (como blobs em <storage_account_name>.blob.core.windows.net) e assim por diante.
Este exemplo é uma boa referência para aquelas comunicações que exigem um 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
Você precisará de um compilador para compilá-lo. Como GCC, Clang, ou o CL da Microsoft. Além disso, há algumas dependências de bibliotecas:
Instale LibSSL e pkg-config:
sudo apt install libssl-dev pkg-config
Instale OpenSSL via brew ou compile e configure você mesmo.
brew install openssl
Obtenha o OpenSSL de qualquer um de seus distribuidores vinculados ou compile e configure você mesmo.
O repositório contém um Makefile para compilar a biblioteca e alguns binários de teste.
Para compilar a biblioteca Harald, execute:
make lib
Isso criará uma biblioteca compartilhada libharald.so, libharald.dll, ou
libharald.dylib dependendo da sua plataforma.
Para compilar os binários de teste, execute:
make test
Isso criará dois binários: test_harald e test_harald_gh (com suas
respectivas extensões, com base na sua plataforma).
Para testar as funcionalidades do Harald, execute os servidores provisionados socket_server_test.py e https_server_test.py. Estes criarão um socket e um servidor HTTPS, respectivamente, para serem usados pelos binários de teste.
Nota: Você pode precisar definir seu
LD_LIBRARY_PATHpara a pasta atual:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_harald
Será necessário criar um certificado SSL/TLS para comunicação HTTPS (autoassinado é suficiente). Você pode criar um usando OpenSSL com o seguinte comando:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Uma vez que os servidores estejam ativos e em execução, execute o binário test_harald:
./test_harald
O binário deve se conectar aos servidores provisionados e enviar os payloads de dados predefinidos conforme especificado no protocolo.
Para testar as funcionalidades da API do GitHub, algumas preparações devem ser feitas
antes de executar o binário test_harald_gh.
Crie um repositório e uma issue.
O arquivo test_harald_gh.c contém um exemplo simples de como
usar Harald para interagir com a API do GitHub para criar comentários em issues. Ele
requer que você tenha um token de acesso para o GitHub, que pode ser obtido nas configurações
da sua conta do GitHub em Developer settings -> Personal access tokens ->
Fine-grained tokens. É recomendado restringir o token para obter acesso apenas
ao repositório recém-criado e às permissões Read access to metadata e
Read and Write access to issues and pull requests.
Para executar corretamente, você precisará modificar os valores de placeholder para:
YOUR_GH_USER: Seu nome de usuário do GitHub.ISSUE_NUMBER: O número da issue no repositório com o qual você deseja interagir
(por exemplo, "1" para a primeira issue em um repositório).YOUR_GH_REPO: O nome do repositório com o qual você deseja interagir
(por exemplo, "harald").YOUR_GH_PAT: Seu token de acesso do GitHub.Uma vez feito, certifique-se de atualizar o tamanho do payload enviado para corresponder às suas necessidades!
Em test_harald_gh.c#L9, o 4º parâmetro do
opcode H_F_APPEND representa o tamanho do payload. Você precisará atualizar
esse valor de acordo quando modificar a estrutura do payload.
Compile os binários de teste e execute este:
./test_harald_gh
Isso criará um comentário na issue fornecida.
O código-fonte contido neste repositório pode ser usado para evadir filtragem de rede e reduzir o risco de detecção por appliances de segurança. Antes de usar este código-fonte, certifique-se de que seu uso está em conformidade com todas as leis aplicáveis em sua jurisdição.
| H_F_SUBSTRACT::0x13 | Subtrai dois registradores ou um número de um registrador | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_READ::0x14 | Lê de um determinado registrador até o comprimento armazenado em outro registrador | FromReg::1, SizeReg::1 |
| H_F_STORE::0x15 | Armazena um valor de registrador no Storage do Harald | Reg::1 |