boxcutter / windows

Virtual machine templates for Windows written in legacy JSON and Batch Scripting/JScript
Apache License 2.0
753 stars 266 forks source link

Install Windows Update KB2999226 on platforms which require it, and refactored vmtool.bat to use the executable for installing the VMware tools #243

Closed arizvisa closed 4 years ago

arizvisa commented 4 years ago

This PR adds a new provisioning script (script/KB2999226.cmd) which installs an update which s required for Microsoft's Visual C Runtime 2015. This runtime is necessary for installing VMware Tools and also for SaltStack when their installer tries to install Python3 (as per issues saltstack/salt#56296 and saltstack/salt#57594). This modifies all of the templates by executing the script after script/vagrant.bat and before script/vmtool.bat.

The KB itself actually has an issue in that it can't be installed if Windows Updates are disabled or the platform is unlicensed (all of our eval-*.json templates). This is because the KB is intended to be installed with wusa.exe which actually uses newer functionality of Windows Update to install said update. As some of our templates do not require the user to fully update them nor do they guarantee that wuauserv will be running by default, this would have conflicted with prior decisions made by the original maintainers of this project. As such, I prefer to retain this functionality as I use a fork of this project for deploying fuzzing campaigns and so being able to target specific patches on a platform are within scope. Because of this requirement on Windows Updates I had originally thought that we were fuxed when trying to figure out how to close issue #185 (which was a pretty critical issue).

Nonetheless I was able to figure out a way to install KB2999226 without requiring any other updates via extracting the .cab file and installing that directly with dism.exe. This results in byassing the requirement of using wusa.exe and its non-existent windows update functionality when install the patch. This means that Microsoft's Visual C Runtime can be used without needing to fiddle with any update settings. This also means that we don't have to restrict the user on needing a fully updated template (nonetheless it is definitely recommended to update).

This implements a workaround for issues saltstack/salt#56296, saltstack/salt#57594. This should also hopefully close issue #185.

(edited to reference the correct KB update)

arizvisa commented 4 years ago

Okay. So originally I blindly copied the KB article and used the first referenced update in the article to install which was KB2919355. This particular update is HUGE and after finally getting it downloaded and installing it, I discovered that it actually didn't remedy the issue. After noticing this failure, I checked my notes at the saltstack/salt#57594, which caused me to re-review the KB article and immediately recognized that I was installing the wrong update as KB2999226 is actually the correct one to install. As a result I had to update everything to reference the correct KB2999226. This update is available for pretty much all of the platforms, so I updated the KB2999226.cmd script to check all of the versions and choose the correct url to install it.

Other than fixing Microsoft's crt issue, another issue that needed fixing was that when the VMware Tools are installed via setup.exe and a reboot is rquired in order to complete the install, it will return the error code 3010. In batch files when checking the error code via the errorlevel, the specified error code and all the ones above it are included in the explicit test. So we were originally testing for failure when installing vmtools by checking for any non-zero (>=1) error code and then using that to determine whether to interrupt the provisioning step to fail the build.

It was discovered, however, that error 3010 is for "ERROR_SUCCESS_REBOOT_REQUIRED" which means that the install has in all actuality succeeded, but is incomplete until the next reboot. So in vmtool.bat we explicitly check for this error code and return success if we find it. It's prudent to note that error code 1641 is for "ERROR_SUCCESS_REBOOT_INITIATED", but fortunately it is irrelevant due to not needing 1641 as we don't let installers tamper with the state of the guest.

Some of the log messages in vmtools were also updated to display the detected virtualization platform, and list the paths that were being used so that distinguishing how far a particular case had gotten is now a little bit easier. Spacing was also added to all the vmtool cases in order to group related code and improve readability.

arizvisa commented 4 years ago

Testing with the following templates. Both the Windows 8 ones were used for development, so I'm mostly going to test the w7 ones and the w2k12 one.

arizvisa commented 4 years ago

So apparently errorlevels are signed and not unsigned 8-bit like I had thought all my life (maybe because this isn't command.com), but due to the integer type that's being used. This results in our errorlevel1 tests not being effective to detect all errors if something like dism.exe returns a signed windows error code. In this case the code is 0x800f081e which is "CBS_E_NOT_APPLICABLE". This means that we got our package urls incorrect.

To handle this errorlevel1 issue, we now explicitly check the errorlevel for this particular error code. We could be more robust by comparing the errorlevel variable against not "0", but we shouldn't be getting this error anyways.

To clean up the incorrect urls being used for the detected platform, we instead call systeminfo only twice instead of once per platform component check. The first time is for the major/minor version, and the second time is to detect the flavor. which is either "Client" or "Server". Each case for the platform version will just do a comparison against the flavor to determine which url to use.

It also turns out that we (and me too) really need to ensure that we quote _all_ assignments with set. Not just the value of the variable, but the name _and_ the value. Both provisioning scripts (script/vmtool.bat and script/KB2999226.cmd) have been modified to do this.

arizvisa commented 4 years ago

Lol. Okay...the Win7 templates have required me to completely refactor the vmware tools installer in the script/vmtool.bat provisioner. There's no way to install the VMware tools on these platforms without the new ucrt patch. The ucrt patch requires SP1 at the very fucking least (which isn't an option). So to work around this, I'm actually downgrading the VMware tools that're installed to the most recent in the 10.2x series.

This actually involved removing the whole vmware tar file that we download (which is super old anyways). Now the logic is much simpler where there's 2 iso urls. The first iso url is for the most recent version of the vmware tools (yes, we're now up-to-date with 11.1.0), and the second iso url is for the most recent version that doesn't require KB2999226 (which is 10.2.5).

The original tar logic was essentially extracting files from a tarball to get an iso, then the iso was extracted to get to setup.exe. Afterwards the tools are silently installed. Now we just download the iso, extract it, and then run setup.exe so there's much less trickery.

arizvisa commented 4 years ago

Omfg. Okay, finally got eval-win7x86-enterprise.json to install vmware tools properly. Let's try this again, shall we?

(edited to add the win2012r2-datacenter template)

arizvisa commented 4 years ago

Okay. So the previous new commits change from downloading an iso directly (it was too large because my internet sucks) to downloading the executables from packages.vmware.com directly. This is significantly faster for the install, and there's no more need to pre-install 7-zip which greatly reduces the complexity of script/vmtool.bat.

The other thing that's being done is we spin in a loop trying to download the files so that we guarantee the file is downloaded. I got tired of my connection dropping and then having to restart the build, but so far I've been able to build the 2 youngest evaluation templates for both architectures.

I also simplified the floppy/install-winrm.cmd script as on a number of templates winrm wouldn't start up reliably. The original logic of floppy/install-winrm.cmd was kind of racey where the original implementor would create fw rules to block ports, then disable the "Windows Remote Management" group, then sleep for 5 seconds, create fw rules to enable ports, remove the block poort rules, enable the group, etc. This is been shorted to just disable the group and then to re-enable the group. Windows blocks the ports as its default policy anyways.

arizvisa commented 4 years ago

Okay. One last review to double-check things...and I think I'm gonna merge.