CVE-2023-0302 (C, published 2023-01-15T01:15Z)
Description: value: Failure to Sanitize Special Elements into a Different Plane (Special Element Injection) in GitHub repository radareorg/radare2 prior to 5.8.2.
Severity: nan (CVSS v3 base score: 7.8)
Weakness: CWE-74 \u2014 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
Repository: https://github.com/radareorg/radare2
Files changed:
libr/anal/meta.c
libr/bin/dwarf.c
libr/cons/hud.c
libr/core/cmd_meta.c
libr/core/cmd_print.c
libr/util/str.c
test/db/cmd/dwarf
Commit message: 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

Vulnerable code:
	item->str = str ? strdup (str) : NULL;
	if (str && !item->str) {
		if (!node) { // If we just created this
			free (item);
		}
		return false;
			const char *filename = (const char *)buf;
			size_t len = r_str_nlen (filename, maxlen);
					hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), filename);
				print ("  %d     %" PFMT64d "       %" PFMT64d "         %" PFMT64d "          %s\n", entry_index++, id_idx, mod_time, file_len, filename);
	char *fileline;
	fileline = r_str_newf ("%s|%"PFMT64d, p, line);
		value->string.content = *buf ? r_str_ndup ((const char *)buf, buf_end - buf) : NULL;
			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);
			const char *name = attribute->string.content;
			sdb_set (sdb, "DW_AT_comp_dir", name, 0);
/* radare - LGPL - Copyright 2008-2021 - pancake */
			char *out;
			out = r_core_editor (core, NULL, comment);
/* radare - LGPL - Copyright 2009-2022 - pancake */
			r_str_cpy (str + i + 1, str + i + chlen);
		i++;

Fixed code:
	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;
	char *fn = NULL;
			free (fn);
			fn = r_str_ndup ((const char *)buf, maxlen);
			r_str_ansi_strip (fn);
			size_t len = strlen (fn);
					hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), fn);
				print ("  %d     %" PFMT64d "       %" PFMT64d "         %" PFMT64d "          %s\n",
						entry_index++, id_idx, mod_time, file_len, fn);
	free (fn);
	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);
		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;
		}
			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;
			}
			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);
/* radare - LGPL - Copyright 2008-2023 - pancake */
		r_str_ansi_strip (s);
	r_str_ansi_strip (o);
	r_str_ansi_strip (o);
			char *out = r_core_editor (core, NULL, comment);
				r_str_ansi_strip (out);
		r_str_ansi_strip (nc);
/* radare - LGPL - Copyright 2009-2023 - pancake */
// TODO : optimize by just using two counter variables instead of strcpy()
			r_str_cpy (str + i, str + i + chlen);
		} else {
			i++;
NAME="ansi injection via dwarf"
FILE=bins/elf/dwarf_test_func_patched
ARGS=-AA
CMDS=<<EOF
CL
xc
EOF
EXPECT=<<EOF
file: /_test.c
line: 5
addr: 0x00001159
file: /_test.c
line: 11
addr: 0x00001184
file: /_test.c
line: 6
addr: 0x00001165
file: /_test.c
line: 11
addr: 0x00001186
file: /_test.c
line: 9
addr: 0x00001170
file: /_test.c
line: 8
addr: 0x00001168
file: /_test.c
line: 4
addr: 0x00001149
file: /_test.c
line: 10
addr: 0x0000117f
- offset -  6061 6263 6465 6667 6869 6A6B 6C6D 6E6F  0123456789ABCDEF  comment
0x00001060  f30f 1efa 31ed 4989 d15e 4889 e248 83e4  ....1.I..^H..H..  ; rip ; [16] -r-x section size 294 named .text ; arg3
0x00001070  f050 5445 31c0 31c9 488d 3de9 0000 00ff  .PTE1.1.H.=.....
0x00001080  1553 2f00 00f4 662e 0f1f 8400 0000 0000  .S/...f.........
0x00001090  488d 3d79 2f00 0048 8d05 722f 0000 4839  H.=y/..H..r/..H9  ; sym.deregister_tm_clones
0x000010a0  f874 1548 8b05 362f 0000 4885 c074 09ff  .t.H..6/..H..t..
0x000010b0  e00f 1f80 0000 0000 c30f 1f80 0000 0000  ................
0x000010c0  488d 3d49 2f00 0048 8d35 422f 0000 4829  H.=I/..H.5B/..H)  ; sym.register_tm_clones
0x000010d0  fe48 89f0 48c1 ee3f 48c1 f803 4801 c648  .H..H..?H...H..H
0x000010e0  d1fe 7414 488b 0505 2f00 0048 85c0 7408  ..t.H.../..H..t.
0x000010f0  ffe0 660f 1f44 0000 c30f 1f80 0000 0000  ..f..D..........
0x00001100  f30f 1efa 803d 052f 0000 0075 2b55 4883  .....=./...u+UH.  ; sym.__do_global_dtors_aux
0x00001110  3de2 2e00 0000 4889 e574 0c48 8b3d e62e  =.....H..t.H.=..
0x00001120  0000 e819 ffff ffe8 64ff ffff c605 dd2e  ........d.......
0x00001130  0000 015d c30f 1f00 c30f 1f80 0000 0000  ...]............
0x00001140  f30f 1efa e977 ffff fff3 0f1e fa55 4889  .....w.......UH.  ; sym.frame_dummy  ; dbg._func ; void _func(char * msg);
0x00001150  e548 83ec 1048 897d f848 8b45 f848 89c7  .H...H.}.H.E.H.. ; arg1 ; const char *s
EOF
RUN