With all the fuss going round about the latest Linux vulnerability you will probably get a request from your local Security Officer to produce a report which of your Linux systems are vulnerable to the Shellshock bug. And, seen there are already several known exploits, who can blame him for asking such a report.
Since a lot of these Linux boxes are running under vSphere, we can use PowerCLI to produce such a report. The Invoke-VMScript cmdlet is the vehicle I use in the following function. With the Invoke-VMScript cmdlet it is very easy to execute, what is considered the best test to check for the vulnerability.
Update2 September 29 2014: the 2nd test from the Shellshocker gives a syntax error. The test is replaced by the one found on Michael Boelen‘s website in How to protect yourself against Shellshock Bash vulnerability. Big thanks to Wil van Antwerpen for the pointer.
Update1 September 29 2014: the function was updated to include tests for most of the known Shellshock vulnerabilities. The tests were collected from the Shellshocker site.
The Linux Shellshock Bug
The Shellshock, or Bash Bug, is a security issue in the Unix Bash shell. With specially crafted environment variables, a hacker can have malicious code executed on a Linux system.
Seen the widespread use of the Bash Shell, the risk imposed by this bug can not be underestimated.
The Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
function Get-VMShellShock{ <# .SYNOPSIS Check for ShellShock vulnerability .DESCRIPTION The function will connect to all VMs, that run a Linux guest OS, to check if they are vulnerable for the ShellShock buug .NOTES Author: Luc Dekens .PARAMETER Location The function will check all VMs in this Location. This can be a Cluster, a Datacenter, a Folder, a Datastore... .PARAMETER VM The function will check all VMs passed on this parameter. .PARAMETER Credential The credential to logon to the Linux guest OS .EXAMPLE PS> Get-VMShellShock -VM vm1 -Credential $cred .EXAMPLE PS> Get-VMShellShock -Location $cluster -Credential $cred #> [CmdletBinding()] param( [parameter(Mandatory=$true,ParameterSetName = "Location")] [VMware.VimAutomation.Sdk.Types.V1.VIObject]$Location, [parameter(Mandatory=$true,ParameterSetName = "VM")] [PSObject[]]$VM, [System.Management.Automation.PSCredential]$Credential ) Begin{ $exploits = @{ 'CVE_2014_6271' = 'x=''() { :;}; echo VULNERABLE'' bash -c :' 'CVE_2014_7169' = 'env X=''() { (a)=>\'' bash -c "echo echo nonvuln" 2>/dev/null; [[ "$(cat echo 2> /dev/null)" == "nonvuln" ]] && echo "vulnerable" 2> /dev/null' 'CVE_2014_7186' = 'bash -c ''true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF'' || echo "vulnerable"' 'CVE_2014_7187' = '(for x in {1..200} ; do echo "for x$x in ; do :"; done; for x in {1..200} ; do echo done ; done) | bash || echo "vulnerable"' } $oldProgressPreference = $ProgressPreference $ProgressPreference = "SilentlyContinue" } Process{ if($PSCmdlet.ParameterSetName -eq "Location"){ $vms = Get-VM -Location $entity | where {$_.GuestId -match "rhel|sles"} } elseif($PSCmdlet.ParameterSetName -eq "VM"){ $vms = $VM| %{ if($_ -is [System.String]){ Get-VM -Name $_ | where {$_.GuestId -match "rhel|sles"} } else{ $_ } } } foreach($vm in $vms){ $logon = "ok" $CVE_2014_6271 = $CVE_2014_7169 = $CVE_2014_7186 = $CVE_2014_7187 = $null if($vm.Guest.State -ne "notRunning"){ $exploits.GetEnumerator() | %{ Try{ $result = Invoke-VMScript -VM $vm -ScriptText $_.Value -GuestCredential $Credential -ScriptType Bash -ErrorAction Stop Set-Variable -Name $_.Name -Value ($result.ScriptOutput -match "VULNERABLE") } Catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.InvalidGuestLogin]{ $logon = "Guest logon failed" } Catch [VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.VimException]{ if($error[0].Exception.Message -match "Failed to resolve host"){ $logon = "Failed to resolve host" } else{ $logon = $error[0].Exception.Message } } Catch{ $logon = $error[0].Execption.Message } } } New-Object PSObject -Property @{ VM = $vm.Name OS = $vm.GuestId "OS Full" = $vm.Guest.OSFullName "VMware Tools" = $vm.Guest.State Logon = $logon CVE_2014_6271 = $CVE_2014_6271 CVE_2014_7169 = $CVE_2014_7169 CVE_2014_7186 = $CVE_2014_7186 CVE_2014_7187 = $CVE_2014_7187 } } } End{ $ProgressPreference = $oldProgressPreference } } |
Annotations
Line 23-26: The function supports two parametersets, Location and VM
Line 31-36: The tests that are executed inside the Linux OS to determine if the guest OS is vulnerable to any of the known vulnerabilities. Tests 1,3 and 4 come from the Shellshocker website.
Line 33: Test 2 comes from the Linux Audit website
Line 43: The function currently only looks at Red Hat and SUSE systems, since these are currently the only ones I have to test. If someone needs to include other Linux distros, please contact me, and I can update the function.
Line 46-53: A simple implementation of Object By Name
Line 60: All the tests in the $exploits hash table are executed
Line 61-78: The Try part will use Invoke-VMScript to execute the test the vulnerability inside the guest OS. The Catch parts provide more information why a call to Invoke-VMScript might have failed. The last Catch code block is the “catch-all”.
Line 81-91: The results are returned as an object.
Sample Runs
The function accepts two types of calls, the first one uses the Location parameter. Then the function will check all VMs under that Location that run a Linux guest OS.
1 2 3 4 5 6 7 8 9 |
$username = "root" $pswd = "MyPassword" $pswdSecure = ConvertTo-SecureString -String $pswd -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$pswdSecure Get-VMShellShock -Location (Get-Cluster -Name MyCluster) -Credential $cred | Select VM,OS,"OS Full","VMware Tools",CVE_2014_6271,CVE_2014_7169,CVE_2014_7186,CVE_2014_7187,Logon | Export-Csv c:\shellshock.csv -NoTypeInformation -UseCulture |
The second way to call the function uses the VM parameter. On this parameter you can pass one or more VMs, beit by name or by object.
1 2 3 |
$vm = Get-VM -Name lsrv001 Get-VMShellShock -VM $vm -Credential $cred | Select VM,OS,"OS Full","VMware Tools",CVE_2014_6271,CVE_2014_7169,CVE_2014_7186,CVE_2014_7187,Logon |
The result, when saved in a CSV file, looks something like this.
Community Participation
As I mentioned in the Annotations, the current function only looks at Red Hat and SUSE installations. The simple reason for that is that I currently do not have any other distributions available for testing in my lab.
If you use other Linux distributions in your VMs, please let me know which tests are conclusive for that guest OS. And I will try to add them to the function.
Enjoy !
Mark Hensler
I changed my GuestID check to match “centos|rhel|sles|ubuntu”.
And, I used the following to start the process:
Add-PSSnapin -Name VMware.VimAutomation.Core
Connect-VIServer vcenter.mydomain.com
Get-VMShellShock -Location (Get-Cluster -Name “My Cluster”) -Credential (Get-Credential) |
Select VM,OS,”OS Full”,”VMware Tools”,CVE_2014_6271,CVE_2014_7169,CVE_2014_7186,CVE_2014_7187,Logon |
Export-Csv $env:USERPROFILE\Documents\shellshock.csv -NoTypeInformation -UseCulture
LucD
Thanks Mark