From 3b287f84f094b8942d01a547470578f1ed82f121 Mon Sep 17 00:00:00 2001 From: KaraZajac Date: Fri, 22 May 2026 16:49:15 -0400 Subject: [PATCH] copy_fail_family: skip DIRTYFAIL typed prompt under --i-know MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vendored DIRTYFAIL exploits call typed_confirm("DIRTYFAIL"), which reads stdin interactively. SKELETONKEY already gates --exploit/--auto behind --i-know, so the prompt is redundant and deadlocks non-interactive runs like `skeletonkey --auto --i-know`. Add a dirtyfail_assume_yes flag, forwarded from skeletonkey_ctx.authorized by the bridge layer's apply_ctx(). When set, typed_confirm() auto-satisfies its gate and logs that it did so. The YES_BREAK_SSH self-lockout guard is exempt — it protects the operator's own access rather than gating authorization, so it still requires an interactive answer. Standalone DIRTYFAIL builds are unchanged: the flag defaults false. --- modules/copy_fail_family/skeletonkey_modules.c | 6 ++++++ modules/copy_fail_family/src/common.c | 14 ++++++++++++++ modules/copy_fail_family/src/common.h | 8 ++++++++ 3 files changed, 28 insertions(+) diff --git a/modules/copy_fail_family/skeletonkey_modules.c b/modules/copy_fail_family/skeletonkey_modules.c index 32614db..a10931e 100644 --- a/modules/copy_fail_family/skeletonkey_modules.c +++ b/modules/copy_fail_family/skeletonkey_modules.c @@ -33,6 +33,12 @@ static void apply_ctx(const struct skeletonkey_ctx *ctx) dirtyfail_use_color = !ctx->no_color; dirtyfail_active_probes = ctx->active_probe; dirtyfail_json = ctx->json; + /* Forward the --i-know authorization gate. SKELETONKEY already + * blocks --exploit/--auto unless --i-know is passed, so by the time + * a DIRTYFAIL exploit callback runs, authorization is established. + * This lets typed_confirm() skip its (now redundant) interactive + * prompt, which otherwise deadlocks `skeletonkey --auto --i-know`. */ + dirtyfail_assume_yes = ctx->authorized; /* dirtyfail_no_revert is intentionally not driven from ctx — * it's a debug knob; default stays off. */ } diff --git a/modules/copy_fail_family/src/common.c b/modules/copy_fail_family/src/common.c index 7458b21..a625e45 100644 --- a/modules/copy_fail_family/src/common.c +++ b/modules/copy_fail_family/src/common.c @@ -31,6 +31,7 @@ bool dirtyfail_use_color = true; bool dirtyfail_active_probes = false; bool dirtyfail_no_revert = false; bool dirtyfail_json = false; +bool dirtyfail_assume_yes = false; static void vlog(FILE *out, const char *prefix, const char *color, const char *fmt, va_list ap) @@ -226,6 +227,19 @@ size_t build_authenc_keyblob(unsigned char *out, bool typed_confirm(const char *expected) { + /* When the caller has already cleared an explicit authorization gate + * (SKELETONKEY's --i-know, forwarded via dirtyfail_assume_yes), the + * DIRTYFAIL typed prompt is redundant and would deadlock non-interactive + * runs like `skeletonkey --auto --i-know`. Auto-satisfy it. + * + * The SSH self-lockout guard (YES_BREAK_SSH) is deliberately exempt: + * it protects the operator's own access rather than gating + * authorization, so it always requires an interactive answer. */ + if (dirtyfail_assume_yes && strcmp(expected, "YES_BREAK_SSH") != 0) { + log_step("confirmation gate '%s' auto-satisfied (--i-know)", expected); + return true; + } + char buf[128]; printf(" Type \033[1;33m%s\033[0m and press enter to proceed: ", expected); fflush(stdout); diff --git a/modules/copy_fail_family/src/common.h b/modules/copy_fail_family/src/common.h index 53dd477..e51c3cb 100644 --- a/modules/copy_fail_family/src/common.h +++ b/modules/copy_fail_family/src/common.h @@ -86,6 +86,14 @@ extern bool dirtyfail_no_revert; * is redirected to stderr. Set by --json. */ extern bool dirtyfail_json; +/* When true, typed_confirm() auto-satisfies its gate instead of reading + * stdin — the caller has already cleared an explicit authorization gate. + * SKELETONKEY's bridge layer sets this from skeletonkey_ctx.authorized + * (i.e. the --i-know flag) so non-interactive runs like + * `skeletonkey --auto --i-know` don't deadlock on the DIRTYFAIL prompt. + * The YES_BREAK_SSH self-lockout guard is exempt — see typed_confirm(). */ +extern bool dirtyfail_assume_yes; + void log_step (const char *fmt, ...) __attribute__((format(printf, 1, 2))); void log_ok (const char *fmt, ...) __attribute__((format(printf, 1, 2))); void log_bad (const char *fmt, ...) __attribute__((format(printf, 1, 2)));