Posts A bash wildcard expansion to arbitrary command line arguments (globbing abuse) whitepaper
Post
Cancel

A bash wildcard expansion to arbitrary command line arguments (globbing abuse) whitepaper

Background

A lot of my research into bugs goes unfounded, and very seldom do I find a bug by actually looking for it, so much as it was just a typo or something. So when I realized that the wildcard character was actually a bash thing, and not the way that another called program parses arguments, it was because I accidentally typed * in a directory with a file I had accidentally generated somehow with xargs doing something unrelated. The file happened to have a dash in front of it, and that’s where things got more interesting.

Edit:
Also note that setting GLOBIGNORE=-* or GLOBIGNORE=* if you’re paranoid should negate all this. Thanks Kerin Millar for this.

PoC

This is going to be a little different because I don’t have a use case where this can be abused yet to actually get local privilege escalation or anything yet, but it’s most obviously a bug, and I think it probable that in the wrong context could definitely break scripts that use wildcards, and even calling binaries that use silly things like bash -c. So my example is going to be a bit hypothetical, and this may be updated in the future when I find something it works on.

The basic gist of how it looks in the terminal is:

[marshall@jerkon]{12:22 PM}: [~/bashful] $ touch a
[marshall@jerkon]{12:23 PM}: [~/bashful] $ mkdir b
[marshall@jerkon]{12:23 PM}: [~/bashful] $ mv a b
[marshall@jerkon]{12:23 PM}: [~/bashful] $ mv b/a .
[marshall@jerkon]{12:23 PM}: [~/bashful] $ ls -l
total 4
-rw-rw-r-- 1 marshall marshall    0 Nov 18 12:23 a
drwxrwxr-x 2 marshall marshall 4096 Nov 18 12:23 b
[marshall@jerkon]{12:24 PM}: [~/bashful] $ touch -- '--version'
[marshall@jerkon]{12:24 PM}: [~/bashful] $ ls -l
total 4
-rw-rw-r-- 1 marshall marshall    0 Nov 18 12:23 a
drwxrwxr-x 2 marshall marshall 4096 Nov 18 12:23 b
-rw-rw-r-- 1 marshall marshall    0 Nov 18 12:24 --version
[marshall@jerkon]{12:24 PM}: [~/bashful] $ mv * b/
mv (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Parker, David MacKenzie, and Jim Meyering.
[marshall@jerkon]{12:24 PM}: [~/bashful] $ echo lol wut
lol wut
[marshall@jerkon]{12:34 PM}: [~/bashful] $ touch c d
[marshall@jerkon]{12:35 PM}: [~/bashful] $ cp * b/
cp (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering.
[marshall@jerkon]{12:35 PM}: [~/bashful] $ 
[marshall@jerkon]{12:36 PM}: [~/bashful] $ 
[marshall@jerkon]{12:36 PM}: [~/bashful] $ rm -- --version
[marshall@jerkon]{12:36 PM}: [~/bashful] $ cp * b/
cp: -r not specified; omitting directory 'b'
[marshall@jerkon]{12:36 PM}: [~/bashful] $ cp --version
cp (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering.
[marshall@jerkon]{12:36 PM}: [~/bashful] $ 

You can even type just * on the command line and the first file the globbing routine spits out is going to be your command. It becomes obvious now that bash globbing will let you add arguments to a command if you only can drop a file. So dropping a file called --version is going to make the called application show its version info. What if the scenario went more like a cron job running as root:

5 * * * * /usr/bin/supersecure * blah

Where part of supersecure’s code is something like:

if [[ $EUID -ne 0 ]]; then
  echo "Sorry no can do.";
  exit 1;
fi;
  if [[ $1 == "--levelup" ]]; then
    cp /bin/bash /tmp/lvl99;
    chmod a+s /tmp/lvl99;
  fi;

Then dropping a file called --levelup in it’s working directory would copy a suid 0 copy of /bin/bash to /tmp/lvl99, subsequently owning the system.

Conclusion

So as with our simplistic example, attacks like this are possible, though you may need to get creative with more than one file, etc. Once you can drop a file, you can let the “*” character’s expansion do the rest. I intend to update this if I find a real-world example of where this attack leverages local priv escalation.

Edit:
It has been suggested that fixing this would break POSIX compatability, so stuff like this won’t be fixed in the future.

Thanks for reading, and happy haxxoring.

This post is licensed under CC BY 4.0 by the author.