Mercurial > dropbear
view fuzz/fuzz-common.c @ 1930:299f4f19ba19
Add /usr/sbin and /sbin to default root PATH
When dropbear is used in a very restricted environment (such as in a
initrd), the default user shell is often also very restricted
and doesn't take care of setting the PATH so the user ends up
with the PATH set by dropbear. Unfortunately, dropbear always
sets "/usr/bin:/bin" as default PATH even for the root user
which should have /usr/sbin and /sbin too.
For a concrete instance of this problem, see the "Remote Unlocking"
section in this tutorial: https://paxswill.com/blog/2013/11/04/encrypted-raspberry-pi/
It speaks of a bug in the initramfs script because it's written "blkid"
instead of "/sbin/blkid"... this is just because the scripts from the
initramfs do not expect to have a PATH without the sbin directories and
because dropbear is not setting the PATH appropriately for the root user.
I'm thus suggesting to use the attached patch to fix this misbehaviour (I
did not test it, but it's easy enough). It might seem anecdotic but
multiple Kali users have been bitten by this.
From https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=903403
author | Raphael Hertzog <hertzog@debian.org> |
---|---|
date | Mon, 09 Jul 2018 16:27:53 +0200 |
parents | 19b28d2fbe30 |
children |
line wrap: on
line source
#define FUZZ_NO_REPLACE_STDERR #define FUZZ_NO_REPLACE_GETPW #include "includes.h" #include "includes.h" #include "dbutil.h" #include "runopts.h" #include "crypto_desc.h" #include "session.h" #include "dbrandom.h" #include "bignum.h" #include "atomicio.h" #include "fuzz-wrapfd.h" #include "fuzz.h" struct dropbear_fuzz_options fuzz; static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param); static void load_fixed_hostkeys(void); static void load_fixed_client_key(void); // This runs automatically before main, due to contructor attribute in fuzz.h void fuzz_early_setup(void) { /* Set stderr to point to normal stderr by default */ fuzz.fake_stderr = stderr; } void fuzz_common_setup(void) { disallow_core(); fuzz.fuzzing = 1; fuzz.wrapfds = 1; fuzz.do_jmp = 1; fuzz.input = m_malloc(sizeof(buffer)); _dropbear_log = fuzz_dropbear_log; crypto_init(); fuzz_seed("start", 5); /* let any messages get flushed */ setlinebuf(stdout); #if DEBUG_TRACE if (debug_trace) { fprintf(stderr, "Dropbear fuzzer: -v specified, not disabling stderr output\n"); } else #endif if (getenv("DROPBEAR_KEEP_STDERR")) { fprintf(stderr, "Dropbear fuzzer: DROPBEAR_KEEP_STDERR, not disabling stderr output\n"); } else { fprintf(stderr, "Dropbear fuzzer: Disabling stderr output\n"); fuzz.fake_stderr = fopen("/dev/null", "w"); assert(fuzz.fake_stderr); } } int fuzz_set_input(const uint8_t *Data, size_t Size) { fuzz.input->data = (unsigned char*)Data; fuzz.input->size = Size; fuzz.input->len = Size; fuzz.input->pos = 0; memset(&ses, 0x0, sizeof(ses)); memset(&svr_ses, 0x0, sizeof(svr_ses)); memset(&cli_ses, 0x0, sizeof(cli_ses)); wrapfd_setup(fuzz.input); // printhex("input", fuzz.input->data, fuzz.input->len); fuzz_seed(fuzz.input->data, MIN(fuzz.input->len, 16)); return DROPBEAR_SUCCESS; } #if DEBUG_TRACE static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) { if (debug_trace) { char printbuf[1024]; vsnprintf(printbuf, sizeof(printbuf), format, param); fprintf(stderr, "%s\n", printbuf); } } #else static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) { /* No print */ } #endif /* DEBUG_TRACE */ void fuzz_svr_setup(void) { fuzz_common_setup(); _dropbear_exit = svr_dropbear_exit; char *argv[] = { "dropbear", "-E", }; int argc = sizeof(argv) / sizeof(*argv); svr_getopts(argc, argv); load_fixed_hostkeys(); } void fuzz_svr_hook_preloop() { if (fuzz.svr_postauth) { ses.authstate.authdone = 1; fill_passwd("root"); } } void fuzz_cli_setup(void) { fuzz_common_setup(); _dropbear_exit = cli_dropbear_exit; _dropbear_log = cli_dropbear_log; char *argv[] = { "dbclient", "-y", "localhost", "uptime" }; int argc = sizeof(argv) / sizeof(*argv); cli_getopts(argc, argv); load_fixed_client_key(); /* Avoid password prompt */ setenv(DROPBEAR_PASSWORD_ENV, "password", 1); } #include "fuzz-hostkeys.c" static void load_fixed_client_key(void) { buffer *b = buf_new(3000); sign_key *key; enum signkey_type keytype; key = new_sign_key(); keytype = DROPBEAR_SIGNKEY_ANY; buf_putbytes(b, keyed25519, keyed25519_len); buf_setpos(b, 0); if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed ed25519 hostkey"); } list_append(cli_opts.privkeys, key); buf_free(b); } static void load_fixed_hostkeys(void) { buffer *b = buf_new(3000); enum signkey_type type; TRACE(("load fixed hostkeys")) svr_opts.hostkey = new_sign_key(); buf_setlen(b, 0); buf_putbytes(b, keyr, keyr_len); buf_setpos(b, 0); type = DROPBEAR_SIGNKEY_RSA; if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed rsa hostkey"); } buf_setlen(b, 0); buf_putbytes(b, keyd, keyd_len); buf_setpos(b, 0); type = DROPBEAR_SIGNKEY_DSS; if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed dss hostkey"); } buf_setlen(b, 0); buf_putbytes(b, keye, keye_len); buf_setpos(b, 0); type = DROPBEAR_SIGNKEY_ECDSA_NISTP256; if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed ecdsa hostkey"); } buf_setlen(b, 0); buf_putbytes(b, keyed25519, keyed25519_len); buf_setpos(b, 0); type = DROPBEAR_SIGNKEY_ED25519; if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed ed25519 hostkey"); } buf_free(b); } void fuzz_kex_fakealgos(void) { ses.newkeys->recv.crypt_mode = &dropbear_mode_none; ses.newkeys->recv.algo_mac = &dropbear_nohash; } void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port, char **remote_host, char **remote_port, int UNUSED(host_lookup)) { if (local_host) { *local_host = m_strdup("fuzzlocalhost"); } if (local_port) { *local_port = m_strdup("1234"); } if (remote_host) { *remote_host = m_strdup("fuzzremotehost"); } if (remote_port) { *remote_port = m_strdup("9876"); } } /* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */ void fuzz_fake_send_kexdh_reply(void) { assert(!ses.dh_K); m_mp_alloc_init_multi(&ses.dh_K, NULL); mp_set_ul(ses.dh_K, 12345678uL); finish_kexhashbuf(); } /* fake version of spawn_command() */ int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) { *ret_writefd = wrapfd_new_dummy(); *ret_readfd = wrapfd_new_dummy(); if (ret_errfd) { *ret_errfd = wrapfd_new_dummy(); } if (*ret_writefd == -1 || *ret_readfd == -1 || (ret_errfd && *ret_errfd == -1)) { m_close(*ret_writefd); m_close(*ret_readfd); if (ret_errfd) { m_close(*ret_errfd); } return DROPBEAR_FAILURE; } else { *ret_pid = 999; return DROPBEAR_SUCCESS; } } /* Fake dropbear_listen, always returns failure for now. TODO make it sometimes return success with wrapfd_new_dummy() sockets. Making the listeners fake a new incoming connection will be harder. */ /* Listen on address:port. * Special cases are address of "" listening on everything, * and address of NULL listening on localhost only. * Returns the number of sockets bound on success, or -1 on failure. On * failure, if errstring wasn't NULL, it'll be a newly malloced error * string.*/ int fuzz_dropbear_listen(const char* UNUSED(address), const char* UNUSED(port), int *UNUSED(socks), unsigned int UNUSED(sockcount), char **errstring, int *UNUSED(maxfd)) { if (errstring) { *errstring = m_strdup("fuzzing can't listen (yet)"); } return -1; } int fuzz_run_server(const uint8_t *Data, size_t Size, int skip_kexmaths, int postauth) { static int once = 0; if (!once) { fuzz_svr_setup(); fuzz.skip_kexmaths = skip_kexmaths; once = 1; } fuzz.svr_postauth = postauth; if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) { return 0; } uint32_t wrapseed; genrandom((void*)&wrapseed, sizeof(wrapseed)); wrapfd_setseed(wrapseed); int fakesock = wrapfd_new_fuzzinput(); m_malloc_set_epoch(1); fuzz.do_jmp = 1; if (setjmp(fuzz.jmp) == 0) { svr_session(fakesock, fakesock); m_malloc_free_epoch(1, 0); } else { fuzz.do_jmp = 0; m_malloc_free_epoch(1, 1); TRACE(("dropbear_exit longjmped")) /* dropbear_exit jumped here */ } return 0; } int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) { static int once = 0; if (!once) { fuzz_cli_setup(); fuzz.skip_kexmaths = skip_kexmaths; once = 1; } if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) { return 0; } // Allow to proceed sooner ses.kexstate.donefirstkex = 1; uint32_t wrapseed; genrandom((void*)&wrapseed, sizeof(wrapseed)); wrapfd_setseed(wrapseed); int fakesock = wrapfd_new_fuzzinput(); m_malloc_set_epoch(1); fuzz.do_jmp = 1; if (setjmp(fuzz.jmp) == 0) { cli_session(fakesock, fakesock, NULL, 0); m_malloc_free_epoch(1, 0); } else { fuzz.do_jmp = 0; m_malloc_free_epoch(1, 1); TRACE(("dropbear_exit longjmped")) /* dropbear_exit jumped here */ } return 0; } const void* fuzz_get_algo(const algo_type *algos, const char* name) { const algo_type *t; for (t = algos; t->name; t++) { if (strcmp(t->name, name) == 0) { return t->data; } } assert(0); } void fuzz_dump(const unsigned char* data, size_t len) { if (fuzz.dumping) { TRACE(("dump %zu", len)) assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len); } } static struct passwd pwd_root = { .pw_name = "root", .pw_passwd = "!", .pw_uid = 0, .pw_gid = 0, .pw_dir = "/root", .pw_shell = "/bin/sh", }; static struct passwd pwd_other = { .pw_name = "other", .pw_passwd = "!", .pw_uid = 100, .pw_gid = 100, .pw_dir = "/home/other", .pw_shell = "/bin/sh", }; /* oss-fuzz runs fuzzers under minijail, without /etc/passwd. We provide sufficient values for the fuzzers to run */ struct passwd* fuzz_getpwnam(const char *login) { if (!fuzz.fuzzing) { return getpwnam(login); } if (strcmp(login, pwd_other.pw_name) == 0) { return &pwd_other; } if (strcmp(login, pwd_root.pw_name) == 0) { return &pwd_root; } return NULL; } struct passwd* fuzz_getpwuid(uid_t uid) { if (!fuzz.fuzzing) { return getpwuid(uid); } if (uid == pwd_other.pw_uid) { return &pwd_other; } if (uid == pwd_root.pw_uid) { return &pwd_root; } return NULL; }