Experimenting with the OMIGOD vulnerabilities!
Setting The Scene
Lots has been written about OMIGod already by now, but up until a few weeks ago, the OMI agent was something relatively unknown. All of that changed recently when the team over at WIZ discovered 4 sets of vulnerabilities hiding within its source code. If you haven’t heard of OMIGOD before I would hike recommend you pause right here and give the articles from the WIZ team a quick read (omigod-critical-vulnerabilities-in-omi-azure, secret-agent-exposes-azure-customers-to-unauthorized-code-execution). These will go down deep into the nitty-gritty details of this particular set of vulnerabilities. In this post, I mainly want to focus on creating an environment to safely play around with them. But for those who just need the TLDR, let me set the scene real quickly. OMIGOD is a set of vulnerabilities discovered to be lurking around in some Linux VM’s running on Azure. There are 4 CVE’s in total:
- CVE-2021-38645 - Local Privilege Escalation
- CVE-2021-38647 - Unauthenticated Remote Command Execution as Root
- CVE-2021-38648 - Local Privilege Escalation
- CVE-2021-38649 - Local Privilege Escalation
It’s a bit of a mixed bag, but all are critical vulnerabilities nonetheless. CVE-2021-38647 is especially a juicy one given it’s a textbook RCE that is dead simple to execute. Most of the articles online refer to the OMI agent as the secret management agent installed by Azure. The reason for this is that the OMI agent doesn’t come pre-installed by default. Installing a new VM on Azure with a vanilla Ubuntu will give precisely what you expect a basic Ubuntu image like you would get on any other platform. It’s not until you enable any of the following services until Azure starts provisioning OMI for you:
- Azure Automation
- Azure Automatic Update
- Azure Operations Management Suite
- Azure Log Analytics
- Azure Configuration Management
- Azure Diagnostics
- Azure Container Insights
All of this happens behind the scenes without most users knowing about it. But not all of these services will grant an attacker access to remote code execution. As we saw earlier the list of CVE’s is a mixed bag between remote code execution and local privilege escalation attacks. Each service you enable configures the OMI agent slightly different and in order to get remote code execution (CVE-2021-38647) the OMI agents needs to be configured to listen on port 5986
. For this some extra configuration is required that tells the agent to expose its HTTP API on that port. Some of these services will not set expose the agent and leave it configured to a UNIX socket which reduces the attack surface and that’s where the local privilege escalation CVE’s come into play. This makes it rather confusing and difficult to figure out what combination of services leaves you exposed to what vulnerability. Luckily the folks over at bleeping computer have done a fantastic job documenting each of the services and their potential attack vectors.
Extension | Deployment Model | Vulnerability Exposure | Fixed Version |
---|---|---|---|
OMI as standalone package | On Premises/Cloud | Remote Code Execution | OMI module v1.6.8-1 |
System Center Operations Manager (SCOM) | On Premises | Remote Code Execution | OMI version v1.6.8-1 |
Azure Automation State Configuration, DSC Extension | Cloud | Remote Code Execution | DSC Agent versions: 2.71.1.25, 2.70.0.30, 3.0.0.3 |
Azure Automation State Configuration, DSC Extension | On Premises | Remote Code Execution | OMI version v1.6.8-1 |
Log Analytics Agent | On Premises | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Log Analytics Agent | Cloud | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Azure Diagnostics (LAD) | Cloud | Local Privilege Elevation | LAD v4.0.11 and LAD v3.0.133 |
Azure Automation Update Management | Cloud | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Azure Automation Update Management | On Premises | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Azure Automation | Cloud | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Azure Automation | On Premises | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Azure Security Center | Cloud | Local Privilege Elevation | OMS Agent for Linux GA v1.13.40-0 |
Container Monitoring Solution | Cloud | Local Privilege Elevation | See Note 2 |
Creating The Environment
Microsoft has already patched the agent, hence new VM’s in Azure will get provisioned with a more recent version of the agent that isn’t vulnerable anymore. So in this post, I’ll walk through the steps required to get a vulnerable OMI agent up and running from scratch. In this particular case, I opted for a CentOS flavoured distro called AlmaLInux. But basically, any CentOS or Debian OS will do the job just fine. Spin any of these up in your favourite hypervisor and create yourself a standard user named azureuser, and with that, it should be easy to follow along with the rest of this article.
The OMI agent itself gets developed in the open, and the source is available on GitHub. From here, we can grab a version of the OMI agent from the releases page. The last vulnerable version before things got patched up is v1.6.8-0
, and depending on the OS you can choose to install via a .deb
or .rpm
. There are few different installers available on this page, so to figure out if you need the ssl_100 or the ssl_110 link you’ll need to check your openssl
version:
If this returns version 1.1.x, then go for the ssl_110 download, otherwise grab the ssl_100 link. On a CentOS flavoured machine to download and install OMI run the following commands:
Whereas on a Debian flavoured machine it will be something like
This might take a minute or two to get fully installed, hence this might be the right time to go and grab a quick coffee. When everything is installed we can do a bit of reconnaissance and get a sense of the lay of the land. See what binaries are installed and features get exposed how. All binaries for the agent are installed in /opt/omi
and are split up over a bin
and lib
folder:
The installation itself registered a service called omid
which should be running and reporting as active:
It shows that it has 2 processes up and running named omiserver
and omiengine
, which we can easily verify with
To get a better understanding of what is going on here, we need to have a closer look at OMI’s architecture. OMI has a frontend-backed architecture as we can see here it split up in the omiserver
and the omiengine
. A user doesn’t directly communicate to the omiserver
. As we can see from our ps
command the server is running as root, whereas the frontend process called omiengine
has lower privileges and is running as the omi
user. With ss
we can get bet understanding of how these processes communicate with one another:
As we can see here the only way to communicate with the server is through a UNIX socket found in the /etc/opt/omi/conf/sockets
directory, which is only accessible to the omi user. This means that only processes under the omi user can communicate with omiserver
. Any local user can communicate with the engine through /var/opt/omi/run/omiserver.sock
which has full RWX permissions. To put this into a picture the following image from the WIZ article does a great job at visualizing this setup
The omicli
in /opt/omi/bin
can be used to send a command to the server:
This returns an error indicating that the target namespace does not exist. We’ll only run into this error when trying to run the OMI agent locally, when provisioned on Azure it will have this namespace set up by default. As it turns out the OMI has an extensibility module that allows user to extend it features set by installing particular providers. For example, users can query docker container information using the appropriate docker provider or retrieve and create Unix processes using the SCX Provider. It’s this latter here that will install the root/scx
namespace. This provider is also open-source and can be installed directly from GitHub https://github.com/microsoft/SCXcore. When looking at the releases there might be a couple of newer versions already. In essence, it doesn’t really matter what version we choose because the vulnerability lies in the OMI agent, not in this provider. But the version published at the time the vulnerability got reported was 1.6.6-0
, so let’s pick that one:
Again for CentOS flavoured machine run:
Or on a Debian flavoured machine run:
Restart the omid
service with systemctl restart omid
and try running the command again, it should now successfully return the current user id:
All of this results in an environment that enables playing around with the local privileges escalation bugs. But as mentioned before to play around with the remote code execution one we’ll need the agent to listen on 5986
. At the moment there isn’t anything listening on that port;
We talked about it earlier but not every service you enable in Azure will configure the OMI agent to listen on port 5986
, that also count for the default OMI installation. To get it to listen on this port we’ll need to configure this manually by modifying the following file /etc/opt/omi/conf/omiserver.conf
Restart the omid
service with systemctl restart omid
and we should now have it listen on port 5986
:
At this point everything should be in place to play around with the 4 different set of vulnerabilities reported. Let’s have a quick look at the remote code execution vulnerability (
Remote Code Execution
The vulnerability is pretty straightforward, it allows passing a simple SOAP message to the service and without setting any authorization headers it will execute a given command as the root user. The soap message to execute the id
command looks as follows;
Save this to a file named omi-soap-payload.xml
so that we can post this to the OMI service with curl:
The response should return a bit XML with the output of the command. This makes it a bit more difficult to figure out if the command ran successfully. But you should be able to find the <p:StdOut>
tag containing the result of the command.
Conclusion
Everything about this set of vulnerabilities is so intriguing. It shows how these undocumented agents that cloud providers install on our VM’s can open us to a wide range of attacks. Having an environment to play around with the vulnerability is really helpful, in my opinion. It will allow us as blue teamers to get a good sense of the attack surface and validate any measures we put into our environments. Because until this point, it’s still unclear who is responsible for patching up vulnerabilities like this. Is it the user that isn’t even aware the agent exists? Or is it the cloud provider that should be messing with our setups and have admin rights on our machines? Whoever you think is responsible, I hope this article provided you with the right tools to start taking matters into your own hands!