From 961f0e723903011d4f54c2396e44efa91fcc74ce Mon Sep 17 00:00:00 2001 From: pancake Date: Fri, 6 Jan 2023 12:55:15 +0100 Subject: [PATCH] Fix ANSI Escape Sequence Injection vulns via DWARF ##vuln * Reported by @solid-snail via huntrdev * BountyID: 583133af-7ae6-4a21-beef-a4b0182cf82e * Reproducer: dwarf_test_func_patched --- libr/anal/meta.c | 13 ++++++----- libr/bin/dwarf.c | 47 +++++++++++++++++++++++++++++--------- libr/cons/hud.c | 5 ++++- libr/core/cmd_meta.c | 5 +++-- libr/core/cmd_print.c | 2 +- libr/util/str.c | 6 +++-- test/db/cmd/dwarf | 52 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 107 insertions(+), 23 deletions(-) diff --git a/libr/anal/meta.c b/libr/anal/meta.c index 5f2a3201390ff..6afeeeef7e423 100644 --- a/libr/anal/meta.c +++ b/libr/anal/meta.c @@ -111,12 +111,13 @@ static bool meta_set(RAnal *a, RAnalMetaType type, int subtype, ut64 from, ut64 item->subtype = subtype; item->space = space; free (item->str); - item->str = str ? strdup (str) : NULL; - if (str && !item->str) { - if (!node) { // If we just created this - free (item); - } - return false; + if (R_STR_ISNOTEMPTY (str)) { + item->str = strdup (str); + // this breaks the `ecHw` command + // (highlights word in current instruction, which uses ansi + // r_str_ansi_strip (item->str); + } else { + item->str = NULL; } R_DIRTY (a); if (!node) { diff --git a/libr/bin/dwarf.c b/libr/bin/dwarf.c index cb1517aa627ed..561c0b6b601f4 100644 --- a/libr/bin/dwarf.c +++ b/libr/bin/dwarf.c @@ -431,6 +431,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u int i = 0; size_t count; const ut8 *tmp_buf = NULL; + char *fn = NULL; if (mode == R_MODE_PRINT) { print (" The Directory Table:\n"); @@ -464,10 +465,12 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u for (i = 0; i < 2; i++) { while (buf + 1 < buf_end) { - const char *filename = (const char *)buf; size_t maxlen = R_MIN ((size_t) (buf_end - buf - 1), 0xfff); ut64 id_idx, mod_time, file_len; - size_t len = r_str_nlen (filename, maxlen); + free (fn); + fn = r_str_ndup ((const char *)buf, maxlen); + r_str_ansi_strip (fn); + size_t len = strlen (fn); if (!len) { buf++; @@ -512,7 +515,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u } if (hdr->file_names) { - hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), filename); + hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), fn); hdr->file_names[count].id_idx = id_idx; hdr->file_names[count].mod_time = mod_time; hdr->file_names[count].file_len = file_len; @@ -525,7 +528,8 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u } count++; if (mode == R_MODE_PRINT && i) { - print (" %d %" PFMT64d " %" PFMT64d " %" PFMT64d " %s\n", entry_index++, id_idx, mod_time, file_len, filename); + print (" %d %" PFMT64d " %" PFMT64d " %" PFMT64d " %s\n", + entry_index++, id_idx, mod_time, file_len, fn); } } if (i == 0) { @@ -544,6 +548,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u } beach: + free (fn); sdb_free (sdb); return buf; @@ -677,7 +682,6 @@ static const ut8 *parse_line_header( static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, int mode, PrintfCallback print) { const char *p; - char *fileline; char offset[SDB_NUM_BUFSZ]; char *offset_ptr; @@ -706,7 +710,10 @@ static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 li #else p = file; #endif - fileline = r_str_newf ("%s|%"PFMT64d, p, line); + char *fileline = r_str_newf ("%s|%"PFMT64d, p, line); + r_str_ansi_strip (fileline); + r_str_replace_ch (fileline, '\n', 0, true); + r_str_replace_ch (fileline, '\t', 0, true); offset_ptr = sdb_itoa (addr, 16, offset, sizeof (offset)); sdb_add (s, offset_ptr, fileline, 0); sdb_add (s, fileline, offset_ptr, 0); @@ -1666,7 +1673,15 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len, break; case DW_FORM_string: value->kind = DW_AT_KIND_STRING; - value->string.content = *buf ? r_str_ndup ((const char *)buf, buf_end - buf) : NULL; + if (*buf) { + char *name = r_str_ndup ((const char *)buf, buf_end - buf); + r_str_ansi_strip (name); + r_str_replace_ch (name, '\n', 0, true); + r_str_replace_ch (name, '\t', 0, true); + value->string.content = name; + } else { + value->string.content = NULL; + } if (value->string.content) { buf += strlen (value->string.content) + 1; } @@ -1711,8 +1726,15 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len, value->kind = DW_AT_KIND_STRING; value->string.offset = dwarf_read_offset (hdr->is_64bit, &buf, buf_end); if (debug_str && value->string.offset < debug_str_len) { - const char *ds = (const char *)(debug_str + value->string.offset); - value->string.content = strdup (ds); // r_str_ndup (ds, debug_str_len - value->string.offset); + char *ds = r_str_ndup ((const char *)(debug_str + value->string.offset), debug_str_len); + if (ds) { + r_str_ansi_strip (ds); + r_str_replace_ch (ds, '\n', 0, true); + r_str_replace_ch (ds, '\t', 0, true); + value->string.content = ds; + } else { + value->string.content = NULL; + } } else { value->string.content = NULL; // Means malformed DWARF, should we print error message? } @@ -1903,8 +1925,11 @@ static const ut8 *parse_die(const ut8 *buf, const ut8 *buf_end, RBinDwarfAbbrevD // Or atleast it needs to rework becase there will be // more comp units -> more comp dirs and only the last one will be kept if (attribute->attr_name == DW_AT_comp_dir && is_valid_string_form) { - const char *name = attribute->string.content; - sdb_set (sdb, "DW_AT_comp_dir", name, 0); + char *name = strdup (attribute->string.content); + r_str_ansi_strip (name); + r_str_replace_ch (name, '\n', 0, true); + r_str_replace_ch (name, '\t', 0, true); + sdb_set_owned (sdb, "DW_AT_comp_dir", name, 0); } die->count++; } diff --git a/libr/cons/hud.c b/libr/cons/hud.c index 4a97cbac7ad4c..f172646354d80 100644 --- a/libr/cons/hud.c +++ b/libr/cons/hud.c @@ -1,4 +1,4 @@ -/* radare - LGPL - Copyright 2008-2021 - pancake */ +/* radare - LGPL - Copyright 2008-2023 - pancake */ #include #include @@ -9,6 +9,7 @@ R_API char *r_cons_hud_file(const char *f) { char *s = r_file_slurp (f, NULL); if (s) { + r_str_ansi_strip (s); char *ret = r_cons_hud_string (s); free (s); return ret; @@ -29,6 +30,7 @@ R_API char *r_cons_hud_line_string(const char *s) { } r_str_replace_ch (o, '\r', 0, true); r_str_replace_ch (o, '\t', 0, true); + r_str_ansi_strip (o); RList *fl = r_list_new (); int i; if (!fl) { @@ -66,6 +68,7 @@ R_API char *r_cons_hud_string(const char *s) { if (!o) { return NULL; } + r_str_ansi_strip (o); r_str_replace_ch (o, '\r', 0, true); r_str_replace_ch (o, '\t', 0, true); RList *fl = r_list_new (); diff --git a/libr/core/cmd_meta.c b/libr/core/cmd_meta.c index c517c0bf0274c..6d8e6f7ecc9aa 100644 --- a/libr/core/cmd_meta.c +++ b/libr/core/cmd_meta.c @@ -539,10 +539,10 @@ static int cmd_meta_comment(RCore *core, const char *input) { break; case '!': { - char *out; const char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); - out = r_core_editor (core, NULL, comment); + char *out = r_core_editor (core, NULL, comment); if (out) { + r_str_ansi_strip (out); //r_meta_set (core->anal->meta, R_META_TYPE_COMMENT, addr, 0, out); r_core_cmdf (core, "CC-@0x%08"PFMT64x, addr); //r_meta_del (core->anal->meta, input[0], addr, addr+1); @@ -560,6 +560,7 @@ static int cmd_meta_comment(RCore *core, const char *input) { char *text; char *nc = strdup (newcomment); r_str_unescape (nc); + r_str_ansi_strip (nc); if (comment) { text = malloc (strlen (comment) + strlen (newcomment) + 2); if (text) { diff --git a/libr/core/cmd_print.c b/libr/core/cmd_print.c index 68067cc3f52a0..ae02951562514 100644 --- a/libr/core/cmd_print.c +++ b/libr/core/cmd_print.c @@ -1,4 +1,4 @@ -/* radare - LGPL - Copyright 2009-2022 - pancake */ +/* radare - LGPL - Copyright 2009-2023 - pancake */ #include #include diff --git a/libr/util/str.c b/libr/util/str.c index 6cf6b3ebbd9fc..742e264784ad2 100644 --- a/libr/util/str.c +++ b/libr/util/str.c @@ -1957,14 +1957,16 @@ R_API size_t r_str_ansi_nlen(const char *str, size_t slen) { } // remove ansi escape codes from string, decolorizing it +// TODO : optimize by just using two counter variables instead of strcpy() R_API size_t r_str_ansi_strip(char *str) { size_t i = 0; while (str[i]) { size_t chlen = __str_ansi_length (str + i); if (chlen > 1) { - r_str_cpy (str + i + 1, str + i + chlen); + r_str_cpy (str + i, str + i + chlen); + } else { + i++; } - i++; } return i; } diff --git a/test/db/cmd/dwarf b/test/db/cmd/dwarf index 3edef10dcc1ad..534b0043b59d6 100644 --- a/test/db/cmd/dwarf +++ b/test/db/cmd/dwarf @@ -1,3 +1,55 @@ +NAME="ansi injection via dwarf" +FILE=bins/elf/dwarf_test_func_patched +ARGS=-AA +CMDS=<