A low-privileged user on a Linux machine can obtain the root
privileges if:
iptables
and iptables-save
with sudo
as they can inject a fake /etc/passwd
entry in the comment of an iptables
rule and then abusing iptables-save
to overwrite the legitimate /etc/passwd
file.iptables
with sudo
and the underlying system misses one of the kernel modules loaded by iptables
. In this case they can use the --modprobe
argument to run an arbitrary command.If you’ve ever played with boot2root CTFs (like Hack The Box), worked as a penetration tester, or just broke the law by infiltrating random machines (NO, DON’T DO THAT), chances are good that you found yourself with a low-privileged shell - www-data
, I’m looking at you - on a Linux machine.
Now, while shells are great and we all need to be grateful when they shine upon us, a low-privileged user typically has a limited power over the system. The path ahead becomes clear: we need to escalate our privileges to root
.
When walking the path of the Privilege Escalation, a hacker has a number of tricks at their disposal; one of them is using sudo
.
As the reader might already know well, the sudo
command can be used to run a command with the permissions of another user – which is commonly root
.
Ok, but what’s the point? If you can
sudo <command>
already, privilege escalation is complete!
Well, yes, but actually, no. In fact, there are two scenarios (at least, two that come to mind right now) where we can’t simply leverage sudo
to run arbitrary commands:
sudo
requires the password of the user, and even though we have a shell, we don’t know the password. This is quite common, as the initial access to the box happens via an exploit rather than regular authentication.sudo
, but the commands that the user can run with sudo
are restricted.In the first case, there’s only one way to leverage sudo
for privilege escalation, and that is NOPASSWD
commands. These are commands that can be launched with sudo
by the user without a password prompt. Quoting from man sudoers
:
NOPASSWD and PASSWD
By default, sudo requires that a user authenticate him or herself before running a command. This behavior can be modified via the NOPASSWD tag. Like a Runas_Spec, the NOPASSWD tag sets a default for the commands that follow it in the Cmnd_Spec_List. Conversely, the PASSWD tag can be used to reverse things. For example:
ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm would allow the user ray to run /bin/kill, /bin/ls, and /usr/bin/lprm as root on the machine rushmore without authenticating himself.
The second case is a bit different: in that scenario, even though we know the password, there will be only a limited subset of commands (and possibly arguments) that can be launched with sudo
. Again, the way this works you can learn by looking at man sudoers
, asking ChatGPT or wrecking your system by experimenting.
In both cases, there is a quick way to check what are the “rules” enabled for your user, and that is running sudo -l
on your shell, which will help answering the important question: CAN I HAZ SUDO?
Now, back to the topic of privilege escalation. The bad news is that, when sudo
is restricted, we cannot run arbitrary commands, thus the need for some more ingredients to obtain a complete privilege escalation. How? This is the good news: we can leverage side-effects of allowed commands. In fact, Linux utilities, more often than not, support a plethora of flags and options to customize their flow. By using and chaining these options in creative ways, even a simple text editor can be used as a trampoline to obtain arbitrary execution!
For a simple use case, let’s consider the well-known tcpdump
command, used to listen, filter and display network packets traveling through the system. Administrators will oftentimes grant low-privileged users the capability to dump traffic on the machine for debugging purposes, so it’s perfectly common to find an entry like this when running sudo -l
:
|
|
Little do they know about the power of UNIX utilities! In fact, tcpdump
automagically supports log rotation, alongside a convenient -z
flag to supply a postrotate-command
that is executed after every rotation. Therefore, it is possible to leverage sudo
coupled with tcpdump
to execute arbitrary commands as root by running the following sequence of commands:
|
|
The good folks at GTFOBins maintain a curated list of these magic tricks (including the one just shown about tcpdump
), so please bookmark it and make sure to look it up on your Linux privilege escalation quests!
Recently, during a penetration test, we were looking for a way to escalate our privileges on a Linux-based device. What we had was a shell for a (very) low-privileged user, and the capability to run a certain set of commands as sudo
. Among these, two trusted companions for every network engineer: iptables
and iptables-save
.
Sure there must be an entry for one of these two guys in GTFOBins, or so we thought … which lead in going once more for the extra mile™.
Back in the 2017 we organized an in-person CTF in Turin partnering with the PoliTO University, JEToP, and KPMG.
The CTF was based on a set of boot2root boxes where the typical entry point was a web-based vulnerability, followed by a local privilege escalation. One of the privilege escalations scenarios we created was exactly related to iptables
.
The technique needed to root the box has been documented in a CTF writeup and used to root a PAX payment device.
iptables
has a --modprobe
, which purpose we can see from its man
page:
--modprobe=command
When adding or inserting rules into a chain, use command to load any necessary modules (targets, match extensions, etc).
Sounds like an interesting way for to run an arbitrary command, doesn’t it?
By inspecting the iptables
source code we can see that if the --modprobe
flag has been specifies, then the int xtables_load_ko(const char *modprobe, bool quiet)
function is called with as first parameter the modprobe command specified by the user.
As a first step the xtables_load_ko
function checks if the required modules have been already loaded, while if they have been not it calls the int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
function with as second parameter the modprobe command specified by the user.
Finally, the xtables_insmod
function runs the command we specified in the --modprobe
argument using the execv
syscall:
|
|
Wrapping all together, if we can run iptables
as root
then we can abuse it to run arbitrary system commands and with the following script being greeted with an interactive root
shell:
|
|
While this technique is quite powerful, it has an important requirement: the kernel modules iptables
is trying to access should not be loaded.
(Un)fortunately, in most of the modern Linux distributions they are, making the attack impracticable. That being said, it is still powerful when it comes to embedded devices as demonstrated by Giulio.
What about our target? Unlikely it had all the kernel modules loaded, so this technique couldn’t be applied. Time to find a new one then 👀
Time for the Metamoran Fusion Dance!
Before diving into the privilege escalation steps, let’s setup a little lab to experiment with.
To test this, you can do the following things on a fresh Ubuntu 24.04 LTS machine:
iptables
package via apt-get
./etc/sudoers
file:
|
|
|
|
As expected, running sudo -l
will yield the following response:
|
|
So either running sudo iptables
or sudo iptables-save
executes the command without asking for authentication.
In the next section, we’ll see how an attacker in this system can escalate their privileges to root
.
This section will demonstrate how core and side features of the iptables
and iptables-save
commands, plus some Linux quirks, can be chained together in order to obtain arbitrary code execution.
Spoiler alert, it boils down to these three steps:
iptables
to attach arbitrary comments, containing newlines, to rules.iptables-save
to dump to a sensitive file the content of the loaded rules, including the comment payloads./etc/passwd
file with an attacker-controlled root
entry, crafted with a known password.In the following sections, we will give some more details on these steps.
Let’s consider a simple iptables
command to add a firewall rule:
|
|
the effect of this rule is to append a rule to the input chain to accept every inbound packet where the input interface is the local one. We can immediately verify the effect of this rule by running sudo iptables -L
. The output of this command, as expected, contains the ACCEPT rule that we just loaded.
By looking into interesting flags supported by iptables
, we stumble on this one:
comment
Allows you to add comments (up to 256 characters) to any rule. –comment comment Example: iptables -A INPUT -s 192.168.0.0/16 -m comment –comment “A privatized IP block”
Let’s test this by slightly modifying our previous rule:
|
|
Then again, listing the rules, we can see the effect of the comment:
|
|
iptables
also provides a way to simply dump all the loaded rules, by running iptables -S
:
|
|
How much can we control this output? A simple test is to insert a newline:
|
|
NOTE
By using the $’ quoting, we can instruct bash to replace the \n character with a newline!
Now, let’s dump again the loaded rules to check whether the newline was preserved:
|
|
This is definitely interesting – we’ve established that iptables
preserves newlines in comments, which means that we can control multiple arbitrary lines in the output of an iptables
rule dump.
…can you guess how this can be leveraged?
Before starting to shoot commands out, let’s RTFM:
iptables-save and ip6tables-save are used to dump the contents of IP or IPv6 Table in easily parseable format either to STDOUT or to a speci‐ fied file.
If this man page is right (it probably is), by simply running iptables-save
without specifying any file, the rules will be dumped to STDOUT:
|
|
it seems iptables-save
, too, is preserving the injected newline. Now that we know this, we can proceed to test its functionality by specifying a filename, supplying the -f
switch. The output shows us we’re onto a good path:
The screenshot gives us two important informations:
iptables-save
.sudo
, the file is owned by root
.Where can we point this armed weapon? Onto the next section!
Recap: by leveraging arbitrary comments containing \n
via iptables
, and running iptables-save
, we can write arbitrary files as root
, and we partially control its lines – partially, yes, because the iptables-save
outputs some data that can’t be controlled, before and after our injected comment.
How can this be useful? Well, there’s at least one way to turn this into a good privilege escalation, and it is thanks to the (in)famous /etc/passwd
file. In fact, this file contains entries for each user that can log into the system, which includes metadata such as the hash of the password, and the UID of the user. Can you see where this is going?
Yes, we’re going to write a perfectly valid passwd root
entry into an iptables
rule, and we’re going to overwrite the /etc/passwd
file via iptables-save
. Since the injected line will also contain the password hash of the user, after the overwrite happens, we should be able to simply run su root
and input the injected password.
At this point, we only have one doubt: will the other lines (which are not valid entries) break the system beyond repair? Clearly, there’s only one way to find out.
The steps to reproduce the privilege escalation are simple:
root
password in the right format by running openssl passwd <password>
root
in the /etc/passwd
, and copy it somewhere, replacing the x
value of the encrypted password with the value generated at step 2root
entry in a new iptables
rule comment/etc/passwd
by running sudo iptables-save -f /etc/passwd
su root
with the password chosen at step 1The main limitation of this technique lies in its reduced likelihood: in fact, in order for the privilege escalation to be executed, a user must be granted sudo
on both the iptables
and iptables-save
commands; while this certainly happens in the wild, it would be great if we could make this scenario even more likely. This might be doable: iptables-save
is actually part of the iptables
suite, as the latter supports an argv[0]
-based aliasing mechanism to select from the full suite the command to run. Therefore, if it were possible to force iptables
to act as iptables-save
, then the iptables-save
command would not be necessary anymore.
Moreover, while for this scenario overwriting /etc/passwd
was provably enough, your imagination is the limit: there might be other interesting gadgets to use in a Linux system! Mostly, the requirements for a “good” overwrite target are:
Are you developing network appliances with limited shells for the operators and wondering if they can elevate their privileges? We’ve got you covered - hire us to go with the extra mile and find unknown privilege escalation vectors.