diff --git a/install.ps1 b/install.ps1 index 57a54a6..b6ba759 100644 --- a/install.ps1 +++ b/install.ps1 @@ -469,6 +469,10 @@ Start-Sleep 1 $configXml = [xml](Get-Content $configPath) if (-not $noGui.IsPresent) { + + $errorColor = [System.Drawing.ColorTranslator]::FromHtml("#c80505") + $successColor = [System.Drawing.ColorTranslator]::FromHtml("#417505") + Write-Host "[+] Starting GUI to allow user to edit configuration file..." ################################################################################ ## BEGIN GUI @@ -502,7 +506,7 @@ if (-not $noGui.IsPresent) { [xml]$vm_packages = Get-Content $vmPackagesFile # Define the namespaces defined in vm-packages.xml to access nodes - # Each package resides in the entry node that is defined in the dataservices namespace + # Each package resides in the entry node that is defined in the dataservices namespace # Each node has properties that are defined in the metadata namespace $ns = New-Object System.Xml.XmlNamespaceManager($vm_packages.NameTable) $ns.AddNamespace("atom", "http://www.w3.org/2005/Atom") @@ -513,8 +517,8 @@ if (-not $noGui.IsPresent) { $vm_packages.feed.entry | ForEach-Object { $isLatestVersion = $_.SelectSingleNode("m:properties/d:IsLatestVersion", $ns).InnerText $category = $_.SelectSingleNode("m:properties/d:Tags", $ns).InnerText - # Select only packages that have the latest version and contain a category - if (($isLatestVersion -eq "true") -and ($category -ne "")) { + # Select only packages that have the latest version, contain a category and the category is not excluded + if (($isLatestVersion -eq "true") -and ($category -ne "") -and ($excludedCategories -notcontains $category)) { $packageName = $_.properties.Id $description = $_.properties.Description @@ -538,10 +542,31 @@ if (-not $noGui.IsPresent) { return $packagesByCategory } + # Function that returns an array of all the packages that are displayed sorted by category from $packagesByCategory + function Get-AllPackages{ + $listedPackages = $packagesByCategory.Values | ForEach-Object { $_ } | Select-Object -ExpandProperty PackageName + return $listedPackages + } + + # Function that returns additional packages from the config that are not displayed in the textboxes + # which includes both Choco packages and packages from excluded categories + function Get-AdditionalPackages{ + $additionalPackages=@() + + # Packages from the config that are not displayed + $additionalPackages = $packagesToInstall | where-Object { $listedPackages -notcontains $_} + return $additionalPackages + } + # Gather lists of packages $envs = [ordered]@{} $configXml.config.envs.env.ForEach({ $envs[$_.name] = $_.value }) + $excludedCategories=@('Command and Control','Credential Access','Exploitation','Forensic','Lateral Movement', 'Payload Development','Privilege Scalation','Reconnaissance','Wordlists','Web Application') + # Read packages to install from the config + $packagesToInstall = $configXml.config.packages.package.name $packagesByCategory = Get-Packages-Categories + $listedPackages = Get-AllPackages + $additionalPackages = Get-AdditionalPackages $formEnv = New-Object system.Windows.Forms.Form $formEnv.ClientSize = New-Object System.Drawing.Point(750,350) @@ -720,6 +745,7 @@ if (-not $noGui.IsPresent) { ## PACKAGE SELECTION BY CATEGORY ################################################################################ + # Function that adds the selected packages to the config.xml for the installation function Install-Selected-Packages{ $selectedPackages = @() @@ -732,10 +758,14 @@ if (-not $noGui.IsPresent) { foreach ($checkBox in $checkboxesPackages){ if ($checkBox.Checked){ - $package =$checkbox.Text.split(":")[0] - $selectedPackages+=$package + $package = $checkbox.Text.split(":")[0] + $selectedPackages += $package } } + + foreach ($package in $additionalPackagesBox.Items){ + $selectedPackages += $package + } # Add selected packages foreach($package in $selectedPackages) { $newXmlNode = $packages.AppendChild($configXml.CreateElement("package")) @@ -756,6 +786,28 @@ if (-not $noGui.IsPresent) { } } } + # Function that returns an array of packages that belong to a specific category + function Get-PackagesByCategory{ + param ( + [string]$category + ) + return $packagesByCategory[$category] + } + # Function that returns an array of all the packages that are displayed sorted by category from $packagesByCategory + function Get-AllPackages{ + $listedPackages = $packagesByCategory.Values | ForEach-Object { $_ } | Select-Object -ExpandProperty PackageName + return $listedPackages + } + + # Function that returns additional packages from the config that are not displayed in the textboxes + # which includes both Choco packages and packages from excluded categories + function Get-AdditionalPackages{ + $additionalPackages=@() + + # Packages from the config that are not displayed + $additionalPackages = $packagesToInstall | where-Object { $listedPackages -notcontains $_} + return $additionalPackages + } # Function that checks all the checkboxes function Select-AllPackages { @@ -766,60 +818,130 @@ if (-not $noGui.IsPresent) { # Function that unchecks all the checkboxes function Clear-AllPackages { - foreach ($checkBox in $checkboxesPackages){ + foreach ($checkBox in $checkboxesPackages){ $checkBox.Checked = $false } + $additionalPackagesBox.Items.clear() } - # Funtion that returns an array of packages that belong to a specific category - function Get-PackagesByCategory{ + # Function that adds a new package to the listBox of additional packages + # If the package already exists it returns $false + function Add-NewPackage { param ( - [string]$category + [Parameter(Mandatory=$true)] + [string]$packageName ) - return $packagesByCategory[$category] + $packageName = $packageName.Trim() + if ($packageName -notin $additionalPackagesBox.Items){ + $additionalPackagesBox.Items.Add($packageName) | Out-Null + return $true + } + else{ + return $false + } + + } + + function Get-ChocoPackage { + param ( + [Parameter(Mandatory=$true)] + [string]$PackageName + ) + + choco search $PackageName -e -r | ForEach-Object { + $Name, $Version = $_ -split '\|' + New-Object -TypeName psobject -Property @{ + 'Name' = $Name + 'Version' = $Version + } + } + } + + function Get-VMPackage { + param ( + [Parameter(Mandatory=$true)] + [string]$PackageName + ) + if ($PackageName -notlike "*.vm") { + $PackageName = $PackageName + ".vm" + } + choco search $PackageName --exact -r -s "https://www.myget.org/F/vm-packages/api/v2" | ForEach-Object { + $Name, $Version = $_ -split '\|' + New-Object -TypeName psobject -Property @{ + 'Name' = $Name + 'Version' = $Version + } + } + } + + function Set-AdditionalPackages { + $additionalPackagesBox.Items.Clear() + foreach($package in $additionalPackages) + { + $additionalPackagesBox.Items.Add($package) | Out-Null + } + } + + function Remove-SelectedPackages { + $additionalPackagesBox.BeginUpdate() + while ($additionalPackagesBox.SelectedItems.count -gt 0) { + $additionalPackagesBox.Items.RemoveAt($additionalPackagesBox.SelectedIndex) + } + $additionalPackagesBox.EndUpdate() } Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.Application]::EnableVisualStyles() - $packagesByCategory = Get-Packages-Categories $formCategories = New-Object system.Windows.Forms.Form - $formCategories.ClientSize = New-Object System.Drawing.Point(1015,800) - $formCategories.text = "FLAREVM Package selection" + $formCategories.ClientSize = New-Object System.Drawing.Point(1015,850) + $formCategories.text = "FLARE-VM Package selection" $formCategories.StartPosition = 'CenterScreen' $formCategories.TopMost = $true if ([string]::IsNullOrEmpty($customConfig)) { - $textLabel = "Select packages to install. The default configuration (recommended for reverse engineering) is pre-selected.`nClick on the reset button to restore the default configuration." + $textLabel = "The default configuration (recommended for reverse engineering) is pre-selected.`nClick on the reset button to restore the default configuration." } else { - $textLabel = "Select packages to install. The provided custom configuration is pre-selected.`nClick on the reset button to restore the custom configuration." + $textLabel = "The provided custom configuration is pre-selected.`nClick on the reset button to restore the custom configuration." } $labelCategories = New-Object system.Windows.Forms.Label - $labelCategories.text = $textLabel + $labelCategories.text = "Select packages to install" $labelCategories.AutoSize = $true $labelCategories.width = 25 $labelCategories.height = 10 $labelCategories.location = New-Object System.Drawing.Point(30,20) - $labelCategories.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $labelCategories.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10,[System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold)) + + + $labelCategories2 = New-Object system.Windows.Forms.Label + $labelCategories2.text = $textLabel + $labelCategories2.AutoSize = $true + $labelCategories2.width = 25 + $labelCategories2.height = 10 + $labelCategories2.location = New-Object System.Drawing.Point(30,40) + $labelCategories2.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) $panelCategories = New-Object system.Windows.Forms.Panel - $panelCategories.height = 700 + $panelCategories.height = 560 $panelCategories.width = 970 - $panelCategories.location = New-Object System.Drawing.Point(30,30) + $panelCategories.location = New-Object System.Drawing.Point(30,50) $panelCategories.AutoScroll = $true $resetButton = New-Object system.Windows.Forms.Button $resetButton.text = "Reset" $resetButton.AutoSize = $true - $resetButton.location = New-Object System.Drawing.Point(50,750) + $resetButton.location = New-Object System.Drawing.Point(50,800) $resetButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) - $resetButton.Add_Click({Set-InitialPackages}) + $resetButton.Add_Click({ + Set-InitialPackages + Set-AdditionalPackages + }) $allPackagesButton = New-Object system.Windows.Forms.Button $allPackagesButton.text = "Select All" $allPackagesButton.AutoSize = $true - $allPackagesButton.location = New-Object System.Drawing.Point(130,750) + $allPackagesButton.location = New-Object System.Drawing.Point(130,800) $allPackagesButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) $allPackagesButton.Add_Click({ [System.Windows.Forms.MessageBox]::Show('Selecting all packages considerable increases installation time and it is not desirable for most use cases','Warning') @@ -827,9 +949,9 @@ if (-not $noGui.IsPresent) { }) $clearPackagesButton = New-Object system.Windows.Forms.Button - $clearPackagesButton.text = "Deselect All" + $clearPackagesButton.text = "Clear" $clearPackagesButton.AutoSize = $true - $clearPackagesButton.location = New-Object System.Drawing.Point(210,750) + $clearPackagesButton.location = New-Object System.Drawing.Point(210,800) $clearPackagesButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) $clearPackagesButton.Add_Click({Clear-AllPackages}) @@ -838,23 +960,20 @@ if (-not $noGui.IsPresent) { $installButton.width = 97 $installButton.height = 37 $installButton.DialogResult = [System.Windows.Forms.DialogResult]::OK - $installButton.location = New-Object System.Drawing.Point(750,750) + $installButton.location = New-Object System.Drawing.Point(750,800) $installButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',12) $cancelButton = New-Object system.Windows.Forms.Button $cancelButton.text = "Cancel" $cancelButton.width = 97 $cancelButton.height = 37 - $cancelButton.location = New-Object System.Drawing.Point(850,750) + $cancelButton.location = New-Object System.Drawing.Point(850,800) $cancelButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',12) $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $formCategories.AcceptButton = $installButton $formCategories.CancelButton = $cancelButton - # Read packages to install from the config - $packagesToInstall = $configXml.config.packages.package.name - # Create checkboxes for each package $checkboxesPackages = New-Object System.Collections.Generic.List[System.Object] # Initial vertical position for checkboxes @@ -903,7 +1022,145 @@ if (-not $noGui.IsPresent) { # Select packages that are in the config.xml Set-InitialPackages - $formCategories.controls.AddRange(@($labelCategories,$panelCategories,$installButton,$resetButton,$allPackagesButton,$cancelButton,$clearPackagesButton)) + $additionalPackagesLabel = New-Object system.Windows.Forms.Label + $additionalPackagesLabel.text = "Additional packages to install:" + $additionalPackagesLabel.AutoSize = $true + $additionalPackagesLabel.width = 25 + $additionalPackagesLabel.height = 10 + $additionalPackagesLabel.location = New-Object System.Drawing.Point(50,615) + $additionalPackagesLabel.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10,[System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold)) + + $additionalPackagesBox = New-Object system.Windows.Forms.ListBox + $additionalPackagesBox.text = "listBox" + $additionalPackagesBox.SelectionMode = 'MultiSimple' + $additionalPackagesBox.Sorted = $true + $additionalPackagesBox.width = 130 + $additionalPackagesBox.height = 140 + $additionalPackagesBox.location = New-Object System.Drawing.Point(50,640) + + $deletePackageButton = New-Object system.Windows.Forms.Button + $deletePackageButton.text = "-" + $deletePackageButton.width = 24 + $deletePackageButton.height = 22 + $deletePackageButton.enabled = $true + $deletePackageButton.location = New-Object System.Drawing.Point(190,670) + $deletePackageButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',12,[System.Drawing.FontStyle]::Bold) + $deletePackageButton.Add_Click({Remove-SelectedPackages}) + + + $packageLabel = New-Object system.Windows.Forms.Label + $packageLabel.text = "FLARE-VM uses Chocolatey packages. You can add additional packages from:" + $packageLabel.width = 260 + $packageLabel.height = 35 + $packageLabel.AutoSize = $true + $packageLabel.location = New-Object System.Drawing.Point(300,620) + $packageLabel.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + + + $linkLabelChoco = New-Object System.Windows.Forms.linkLabel + $linkLabelChoco.Location = New-Object System.Drawing.Point(300,640) + $linkLabelChoco.Size = New-Object System.Drawing.Size(280,20) + $linkLabelChoco.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $linkLabelChoco.LinkColor = "BLUE" + $linkLabelChoco.ActiveLinkColor = "RED" + $linkLabelChoco.Text = "Community Packages" + $linkLabelChoco.add_Click({[system.Diagnostics.Process]::start("https://community.chocolatey.org/packages")}) + + + $linkLabelFlarevm = New-Object System.Windows.Forms.linkLabel + $linkLabelFlarevm.Location = New-Object System.Drawing.Point(300,660) + $linkLabelFlarevm.Size = New-Object System.Drawing.Size(280,20) + $linkLabelFlarevm.AutoSize = $true + $linkLabelFlarevm.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $linkLabelFlarevm.LinkColor = "BLUE" + $linkLabelFlarevm.ActiveLinkColor = "RED" + $linkLabelFlarevm.Text = "FLARE-VM Packages" + $linkLabelFlarevm.add_Click({[system.Diagnostics.Process]::start("https://github.com/mandiant/VM-Packages/wiki/Packages")}) + + Set-AdditionalPackages + + $chocoPackageLabel = New-Object system.Windows.Forms.Label + $chocoPackageLabel.text = "Enter package name:" + $chocoPackageLabel.AutoSize = $true + $chocoPackageLabel.width = 25 + $chocoPackageLabel.height = 10 + $chocoPackageLabel.location = New-Object System.Drawing.Point(300,705) + $chocoPackageLabel.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + + $packageTextBox = New-Object system.Windows.Forms.TextBox + $packageTextBox.multiline = $false + $packageTextBox.width = 210 + $packageTextBox.height = 20 + $packageTextBox.location = New-Object System.Drawing.Point(300,725) + $packageTextBox.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $packageTextBox.Add_TextChanged({ + if ($addPackageButton.Enabled -eq $true){ + $addPackageButton.Enabled = $false + } + + }) + + $chocoPackageErrorLabel = New-Object system.Windows.Forms.Label + $chocoPackageErrorLabel.text = "" + $chocoPackageErrorLabel.AutoSize = $true + $chocoPackageErrorLabel.visible = $false + $chocoPackageErrorLabel.width = 25 + $chocoPackageErrorLabel.height = 10 + $chocoPackageErrorLabel.location = New-Object System.Drawing.Point(300,755) + $chocoPackageErrorLabel.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10,[System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold)) + + + $findPackageButton = New-Object system.Windows.Forms.Button + $findPackageButton.text = "Find Package" + $findPackageButton.width = 118 + $findPackageButton.height = 30 + $findPackageButton.enabled = $true + $findPackageButton.location = New-Object System.Drawing.Point(520,720) + $findPackageButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $findPackageButton.Add_Click({ + $chocoPackageErrorLabel.Visible = $true + $chocoPackageErrorLabel.text = "Finding package ..." + $vmPackage = Get-VMPackage -PackageName $packageTextBox.Text + if ($vmPackage){ + $packageName = $vmPackage | Select-Object -ExpandProperty Name + $chocoPackageErrorLabel.text = "Found VM package" + $chocoPackageErrorLabel.ForeColor = $successColor + $packageTextBox.Text = $packageName + $addPackageButton.enabled = $true + } else { + $chocoPackage = Get-ChocoPackage -PackageName $packageTextBox.Text + if ($chocoPackage) { + $chocoPackageErrorLabel.text = "Found Choco package" + $chocoPackageErrorLabel.ForeColor = $successColor + $addPackageButton.enabled = $true + } else { + $chocoPackageErrorLabel.text = "Package not found" + $chocoPackageErrorLabel.ForeColor = $errorColor + $addPackageButton.enabled = $false + } + } + }) + + $addPackageButton = New-Object system.Windows.Forms.Button + $addPackageButton.text = "Add Package" + $addPackageButton.width = 118 + $addPackageButton.height = 30 + $addPackageButton.enabled = $false + $addPackageButton.location = New-Object System.Drawing.Point(650,720) + $addPackageButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10) + $addPackageButton.Add_Click({ + if (Add-NewPackage -PackageName $packageTextBox.Text){ + $chocoPackageErrorLabel.ForeColor = $successColor + $chocoPackageErrorLabel.text = "Package added" + }else { + $chocoPackageErrorLabel.ForeColor = $errorColor + $chocoPackageErrorLabel.text = "Error to add the package" + } + $addPackageButton.enabled = $false + }) + + $formCategories.controls.AddRange(@($additionalPackagesLabel,$packageLabel,$linkLabelChoco,$linkLabelFlarevm,$linkLabelFlarevm,$additionalPackagesBox,$deletePackageButton,$chocoPackageButton,$chocoPackageLabel,$packageTextBox,$chocoPackageErrorLabel,$findPackageButton,$addPackageButton)) + $formCategories.controls.AddRange(@($labelCategories,$labelCategories2,$panelCategories,$installButton,$resetButton,$allPackagesButton,$cancelButton,$clearPackagesButton)) $formCategories.Add_Shown({$formCategories.Activate()}) $resultCategories = $formCategories.ShowDialog() if ($resultCategories -eq [System.Windows.Forms.DialogResult]::OK){