Command Exploitation
Exploiting commands that are executed with elevated privileges to do more than you are supposed to
Last updated
Exploiting commands that are executed with elevated privileges to do more than you are supposed to
Last updated
Now that we have a list of programs we are allowed to use, we can see if we can get a shell in any way. To do this you look up the program on GTFOBins. If it has the Sudo tag set, it means you can use it to get some form of elevated privileges.
Then just use the command to get a shell. With the /usr/bin/find
binary it would be this for example:
If the binary does not allow you to get a shell instantly, you can try other things like #reading-files or #writing-files, which may achieve the same effect with some more effort.
Far from all binaries that are exploitable are included in this list. If you cannot find it there, because it is less known, look for yourself to see if any features that may be useful. The -h
or --help
and man
pages can be helpful here. Features like exporting data to write files, or loading configs to read content in error messages are common ideas, but you can get very creative here.
Just like command-line arguments and files on the filesystem, environment variables are just another piece of information a process can use. Some programs them in place of arguments, or to elicit specific behavior, and some of that behavior can be exploited.
Which variables are useful depends on the program, and you can use Reverse Engineering or canaries to find out which are used in what places. Here are a few common ones that have a special meaning and can often be exploited:
$LD_PRELOAD
& $LD_LIBRARY_PATH
Two especially dangerous ones are LD_PRELOAD
and LD_LIBRARY_PATH
, because they allow you to overwrite the libc path of the program to another file that you can control. This means you can execute any C library you make before the real sudo program runs.
The first LD_PRELOAD
just specifies the direct path to the library. To compile a malicious library yourself just make some C code to execute a privileged shell, and compile it like a library:
Now you have the malicious preload.so file that you can include by setting the LD_PRELOAD
before running the allowed sudo program (make sure to use the full path):
Then for the LD_LIBRARY_PATH
option there is another similar way. This variable only sets the directory to find the other libraries in, so we first need to know what libraries are loaded to then overwrite them. Do this using ldd
:
We can choose any of these filenames to overwrite. Let's take libcrypt.so.1
for example. We'll again compile some C code to a valid library with the functions that it will expect:
Then we compile it again to a library and set the LD_LIBRARY_PATH
to a directory containing our malicious library:
$PATH
When a program is executed with SetUID, the current environment variables are kept. This means you have even more control over the program's behavior by changing environment variables before executing it. One common trick is using the $PATH
variable, which has a :
colon-separated list of directories saying where to find programs without an absolute path.
To find what commands are executed by an unknown program, you can try to use Pspy to find commands executed on the system. Another way would be to use Reverse Engineering to find what the program exactly does. Tools like strace
will show execve()
calls for all executed processes, and if this command isn't available, it will be if you copy the binary to you locally.
Suppose you found the SUID program executes service
instead of /usr/sbin/service
, then it will search through directories in the PATH variable containing a file named "service".
But since we can change the PATH environment variable before executing the program, we could prepend a directory containing our own malicious program also named "service". When the service
command is then executed by the SUID binary, it will actually run the malicious binary from our directory, allowing us to run arbitrary code.
When you find a vulnerable command, you can simply create a binary with the same name that does whatever you want:
Then set the PATH variable before executing the vulnerable SUID program:
$PATH
for another userThe above example was focused on SUID binaries, but this idea of overwriting programs in the PATH variable goes further. If due to a misconfiguration you are able to write in one of the earlier $PATH
directories for a user, you can create a binary with the same name again to overwrite.
Bash scripts contain commands that are executed one by one. With logic like if
for for
this can become more powerful to script complex operations with support for user interaction. With this complexity also comes unexpected situations where an attacker can abuse your script in order to escape an environment or escalate privileges.
You can explicitly tell bash to evaluate a math expression using the $((EXPR))
syntax:
The vulnerability is the fact that this math syntax allows substituting shell commands with the a[$(COMMAND)]
syntax, normally used on array variables:
This can be exploited in many different contexts and is definitely worth a try whenever you have input into a bash script. Take this innocent-looking example:
With the a[$(id)]
input like above, this is vulnerable because math is evaluated here!
Here are some places where your input will be dangerously evaluated as a math expression:
$((here))
((here))
${var:here:here}
${var[here]}
var[here]=...
[[ here -eq here ]]
(and any others like -gt
or -le
)
[[
==
expressionAs this answer explains, there is a specific scenario where your user input can become a wildcard match by accident. An example is shown below:
This piece of code seems like it only compares the string $password
to $guess
, and there should be no way to bypass it without knowing the password. However, when a *
wildcard character is inputted, check passes as correct!
This is because the [[
is a shell built-in that interprets its arguments slightly differently than a regular binary. Otherwise, it would be a glob pattern and replaced with all filenames that match the inputted pattern. In this case the right argument of an ==
operation in [[
is treated as a pattern instead of a literal string (note: single =
is equivalent).
If $guess
were in quotes like "$guess"
it would be taken literally, not as a pattern. Using [
instead of [[
also prevents this but developers like using the built-in more because it handles special characters better. And lastly, this also doesn't work if your malicious input is on the left side of the comparison.
Something even better than bypassing the password check is recovering the password it was checking against, which is also very possible using this wildcard trick. Because we can try a string like s*
to see if that matches the password, and get a boolean response. Doing this for every first character we eventually find one that passes and thus find the first character. Continuing this we can find all other characters to recover the full password.
This idea can even be improved to Binary Search performance by requesting ranges of characters instead of individual ones, here is an implementation:
Bash allows you to use *
wildcards in commands to insert any files that match the wildcard. This works by inserting all the matched files after each other separated by spaces in the command since most commands allow you to add as many files as you want by just adding more arguments.
The problem arises when you can create files starting with -
, which are often flags to change the behavior of a command. Bash just pastes the files into the command, not bothering to check if any of them start with the -
dash. This means we can add flags to the command and make it do different things.
With the file
command, for example, something innocent we can do is use the -F
option to change the :
separator we saw earlier. Arguments often don't need a space character, so we can just create a file called -Fsomething
to add this argument to the file command if the wildcard is used. Another common way to pass arguments is by using the =
equals sign for --
arguments, like --separator=something
. Here are two examples:
Tip: Use the --
characters alone to not interpret the following arguments as flags. This is how you should secure a wildcard vulnerability like this, and also how you can easily place your payload using without touch
thinking they're flags too.
One limitation you have is the fact that the *
wildcard orders your arguments alphabetically. Luckily the -
dash character comes before other alphanumeric characters, meaning our injected arguments will always be first. You just have to find a way to add arguments that allow you to do unintended things.
Another bonus is that almost all special characters are allowed in filenames and arguments, many unexpected ones even, if you just escape enough with '
single quotes and/or escape sequences.
A common pattern is to use wildcards when making a backup of some files in a directory using Automated (Cron Jobs), so here are some ways to exploit such archiving tools:
Control over the start of any argument and at least one argument after your input can be exploitable. By injecting a ProxyCommand
option with -o
, the argument after becomes the host it tries to resolve. Even if this connection fails, the injected command will still execute:
For more Argument Injection payloads like this for different tools, see the following two collections:
This technique is a little more advanced. Programs often need libraries to do certain things, but sometimes you can overwrite some of these libraries with your own. Then the SUID program would load your malicious library instead of the normal one, executing your code.
You can find what libraries a program loads at runtime using strace
and looking for opened files:
In the example above, you can see a few libraries that it failed to access. The last one (libcalc.so
) is in my user's /home
directory, so we can write our own library there for it to be executed:
Then when the program loads /home/user/.config/libcalc.so
, it will actually find our malicious library giving us a shell: