Pentester’s tricks: Local privilege escalation in OpenVAS
It’s not a common scenario but if during a pentesting you get access to some machine with a user that has sudo
rights to execute openvas
, you could escalate privileges to get root!
In this post I’m going to describe some OpenVAS workflows and then dive into this particular local privilege escalation.
A bit of background about OpenVAS workflows
OpenVAS is one of the most well-known vulnerability scanners. When you install OpenVAS you’ll get the openvas
binary as outcome but it’s not a ready-to-call executable. You need two more components:
- A project that implements the OSP protocol like ospd-openvas.
- A library like python-gvm that provides the programming interface to be able to speak to OpenVAS using OSP conventions via
ospd-openvas
.
From python-gvm
documentation, we have the following example:
It’s one of the simplest and lightest workflows to execute OpenVAS. There are more workflows like using a virtual machine but that involves more components.
Returning to our example, to run successfully the previous code snippet we must be able to communicate with ospd-openvas
(it’s a unix socket). To achieve that, we can either set the socket permissions or run ospd-openvas
with our user.
Additionally, an important recommendation in OpenVAS installation’s docs (point 5) is about running OpenVAS as root.
Please note that although you can run
openvas
as a user without elevated privileges, it is recommended that you startopenvas
asroot
since a number of Network Vulnerability Tests (NVTs) require root privileges to perform certain operations like packet forgery. If you runopenvas
as a user without permission to perform these operations, your scan results are likely to be incomplete.[…]
The sudo
rights are thought for the user running ospd-openvas
. For instance, in Ubuntu Groovy (20.10) there’s a package for ospd-openvas
that executes this service under the user _gvm
. User _gvm
will have the sudo
rights to call openvas
. This user has nologin
as shell so I imagine that openvas
is thought to be:
- Scheduled by another process running as
_gvm
. - Scheduled by a high-privileged process (i.e. root) that can fork a process with
_gvm
as owner.
In my opinion, it seems a safe way of running OpenVAS.
From my own experience implementing workflows with OpenVAS, there are some differences:
- There are coordinated releases for all the involved packages (i.e.
v20.8.1
) so you are kind of motivated to upgrade manually to get the latest features. - OS packages are a bit outdated or they don’t exist (in Ubuntu 20.04
ospd-openvas
doesn’t exist) so people have to build their own packages and that leads to custom running user and permissions. - A scan could get stuck or not finish so you need to have some monitoring solution around OpenVAS.
- There are more protocols to talk to OpenVAS too.
In the end, there are several ways to implement an OpenVAS workflow that could derive in different permission/ownership schemes and end up with a user having sudo
rights to execute openvas
. What’s important to us, as pentesters, is to know that if we got a shell as a user which has sudo
rights to execute openvas
, we can escalate privileges to root. Let’s go that path.
Finding the step to climb
So our user has sudo
rights to execute openvas
. An interesting feature of the openvas
binary is that the configuration can be changed in runtime with the option -c
. In the screenshot below I demonstrate that displaying the configuration using the option -s
.
After looking at the different settings and how I could take advantage of them, I stumbled upon this article:
openvas
binary loads plugins from a location defined by the setting plugins_folder
. What about changing plugins_folder
setting on runtime to point to a directory where I store a malicious plugin that will get executed when a OpenVAS scan runs? That’s the way to escalate privileges 🆙
Creating the exploit
To exploit this privilege escalation we have to create a scenario that consists of several steps. First, we’re going to create the malicious plugin in the directory /tmp/plugins
:
This malicious NASL plugin will create a rootshell when it gets executed (line 15–18
). It’s important to remember the plugin ID 1.2.3.4.5
declared on line 3
because it will be used later. Additionally, to be considered a valid plugins_folder
, it needs to contain a file called plugin_feed_info.inc
with a valid date string:
PLUGIN_SET = "202006091543"
Then we’re going to create our malicious configuration file at /tmp/openvas.conf
that will be provided to openvas
via -c
option.
plugins_folder = /tmp/plugins
db_address = /tmp/redis-server.sock
It makes reference to our rogue plugin folder and to a Redis socket. I haven’t mentioned that but OpenVAS uses a Redis database to store some scan information. In Ubuntu Groovy, a Redis instance is initiated specially for OpenVAS but I can’t use it because it has strict permissions:
To get over this condition, I’ve started my own instance of Redis listening on socket /tmp/redis-server.sock
and set it in my malicious configuration.
The next step is important. As explained before, we need to run ospd-openvas
to communicate with openvas
binary. Looking at the code, official ospd-openvas project calls openvas
with sudo
which is good, but it doesn’t set the -c
option. So I had to create a fork to add a -c
option referring to my malicious configuration. You can see it in the diff:
So, in my exploit scenario, I’ll run my fork with the following configuration:
This configuration aims to create a ospd-openvas
socket at /tmp/ospd-openvas.sock
so I have full control over it.
The last step is to trigger a scan and for that purpose we will use this script:
It’s pretty similar to the example from python-gvm
. In fact, it’s an adaptation from this test. Let’s review the code:
- In line
8
I make a reference to myospd-openvas
socket. - In line
14
I add my malicious plugin to be run as part of the vulnerability tests. - In line
19
I make a call to start a scan.
If everything went well, a root shell is waiting for us at /tmp/rootshell
!
Running the exploit
In case you want to try in a closed environment, I provide a sample Vagrantfile to do the escalation from the user runner
(so remember to switch from vagrant
to runner
user).
The requirements are to install python-gvm and my ospd-openvas fork. I’ve done that using a virtual environment.
After that, you’re ready to run the exploit. The code is here. It’s a bit long to embed here because of the configuration files but I expect it’s easy to understand. You can see it in action in the video below:
Final words
I don’t want to try to convince anyone that it’s the default scenario but it’s possible and if in one of your penetration testing engagements you find a user account with sudo
rights to run openvas
, take advantage of it!
I reached out to Greenbone Security Team about the issue because it’s on the project’s contact page but in the end we realized it was a specific scenario and not the default one. Their response time was impressive and we could interchange around 8 emails in less than a day.
The recommendation is, as seen in the Ubuntu Groovy package, set the sudo
rights to a user without shell access so the interaction is restricted to be done via ospd-openvas
and that way is not possible to manipulate openvas
command-line options.