OSD Wizard Updates (0.95 release)

I’ve worked my way through a series of additional features for OSD Wizard (a ConfigMgr/ SCCM Task Sequence front-end/ modern HTA) this week – namely the introduction of run-time “modes” – Default, Set-Description, ExportOU, Test. With these modes you can now:

  • Set AD Computer Account description mid-Task Sequence using OSD Wizard/ Web Service as opposed to using a separate script with RunAs credentials
  • Perform a compatible OU export using the OSD Wizard script itself (and automate/ schedule this if so desired), rather than performing this manually
  • Fully test OSD Wizard outside of a Task Sequence environment (without the need for the SMS TS Environment COM Object) – including the ability to spoof platform information/ properties.

Grab a copy of the latest release here: https://gitlab.com/chrismbradford/osd-wizard

Introducing OSD Wizard – A PowerShell Front-End / HTA for ConfigMgr Task Sequences

When I first started working with SCCM/ ConfigMgr a few years ago I ran into several issues with upstream teams trying to deploy Task Sequences to devices that were untested (i.e. there were no drivers), power was not plugged in, the user supplied hostname was duplicated in target domain etc. This generated unnecessary Incidents, and delays in getting devices out to users. I became increasingly frustrated at the lack of ConfigMgr built-in capabilities to address these issues, so I turned to vbScript to write a HTA / front-end to address these issues. vbScript is now, several years later, a dying technology, so over time I have re-written the vbScript/ HTA in PowerShell, leveraging WPF and XAML to generate a user interface.

OSDWizard UI

OSD Wizard is a PowerShell script with a WPF/ XAML-based UI built for use within System Center Configuration Manager (SCCM / ConfigMgr) Task Sequences – it has two key purposes, the second of which is optional:

  1. Reduce “human error” factors during early stages of Operating System Deployment
  2. Enable location (network) derived automation for multi-language environments

You can read through the details of the project, download and review the source code (and even contribute!) via GitLab, here: https://gitlab.com/chrismbradford/osd-wizard

ConfigMgr Windows 10 Enterprise 1703 Stuck at “Just a moment”

I ran into an issue when testing Windows 10 Enterprise 1703  in the lab, when deploying via ConfigMgr Current Branch – essentially after image deployment the machine would reboot and just show a blue screen with “just a moment.”

I came across this post which led to the solution – a modification to the Unattend.xml:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="oobeSystem">
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <OOBE>
                <HideEULAPage>true</HideEULAPage>
                <HideLocalAccountScreen>true</HideLocalAccountScreen>
                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                <NetworkLocation>Work</NetworkLocation>
                <ProtectYourPC>1</ProtectYourPC>
                <SkipMachineOOBE>true</SkipMachineOOBE>
                <SkipUserOOBE>true</SkipUserOOBE>
            </OOBE>
        </component>
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <OOBE>
                <HideEULAPage>true</HideEULAPage>
                <HideLocalAccountScreen>true</HideLocalAccountScreen>
                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                <NetworkLocation>Work</NetworkLocation>
                <ProtectYourPC>1</ProtectYourPC>
                <SkipMachineOOBE>true</SkipMachineOOBE>
                <SkipUserOOBE>true</SkipUserOOBE>
            </OOBE>
        </component>
    </settings>
    <cpi:offlineImage cpi:source="wim:c:/temp/install.wim#Windows 10 Enterprise Evaluation" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>

 

Creating a Windows Server 2012 R2 KVM/ QEMU Guest

You’ll need to obtain the latest virtio-win-<version>.iso file and copy this to you host, alongside the Windows Server 2012 R2 ISO. Get the former from here: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/

Both of these ISO’s will be mounted on the guest as you’ll have to manually load the virtstor drivers during Windows setup.

Use the code below to create the guest machine, this assumes you have copied ISO images to /var/kvm/images/iso:

sudo virt-install \
--name vwinguest1 \
--ram 2048 \
--disk path=/var/kvm/images/vm/vwinguest1.qcow2,size=16,bus=virtio,format=qcow2 \
--disk /var/kvm/images/iso/win2012r2.ISO,device=cdrom,bus=ide \
--disk /var/kvm/images/iso/virtio-win.iso,device=cdrom,bus=ide \
--vcpus 1 \
--os-type windows \
--os-variant win2k12r2 \
--network bridge=br0,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--noautoconsole \
--accelerate \
--console pty,target_type=serial

Now open KVM and connect to the host IP on port 5901 (or the next free VNC port if you have other guests running with VNC graphics on this host).

Use the code below to auto-start the VMs on host start-up:

sudo virsh autostart vwindc1

How to make a Linux systemd service wait for a VPN interface before starting

Like me, you may have a requirement for a service to start only once a VPN interface is established.

This is quite easy to achieve by extending the systemd unit file for the service in question. In this example, based upon Ubunutu 16.04 but portable to other systemd-based distros, I will focus on docker.service, but the configuration is applicable to any service – provided you change the relevant folder/ filenames, in bold, appropriately.

For a service other than docker.service, find and replace “docker.service” with the relevant service name you want to wait for VPN connectivity.

You also need to identify the systemctl device id for you VPN connection.

# Identify the VPN interface name - commonly "tun0"
ifconfig

# Find the systemctl interface name based upon output from command above. In my case this output "sys-devices-virtual-net-tun0.device"
systemctl | grep tun0

With the systemctl device name, and having replaced docker.service if required proceed.

sudo mkdir /etc/systemd/system/docker.service.d/
sudo touch /etc/systemd/system/docker.service.d/depend.conf
sudo vi /etc/systemd/system/docker.service.d/depend.conf

# New conf file should only contain lines below
[Unit]
Requires=sys-devices-virtual-net-tun0.device
After=sys-devices-virtual-net-tun0.device

# Now save the file and exit vim

# Reload systemd daemons
sudo systemctl daemon-reload

# Test container connectivity following a reboot

Vulnerability scanning for MS17-010 / 4013389 / WannaCry using OpenVAS in a Docker Container

For instructions on how to install Docker on Ubuntu see my post here: https://www.cb-net.co.uk/linux/installing-docker-on-ubuntu-16-04-lts-16-10/

Updated 31/05/17 to include Ping Host and NMAP (NASL wrapper) tests due to feedback around reliability of results without these tests enabled.

Following on from my previous post around MS17-010 / 4013389 vulnerability patching assurance I thought I’d share a more robust scanning and reporting tool that is simple to deploy and use, OpenVAS. The deployment/ configuration of which is made even simpler through the availability of a Docker Image.

Assuming you have an Ubuntu 16.04 server/ client with the docker engine installed, use the following commands to get OpenVas up and running:

docker pull mikesplain/openvas:9

docker run -d -p 443:443 --name openvas mikesplain/openvas:9

# *** Alternatively *** use the host machines IP address rather than the docker0 interface/ a NAT'd address as above.

docker run -d --net host -p 443:443 --name openvas mikesplain/openvas:9
Next, browse to https://<machine IP> and login, using default credentials of admin / admin :

Now, from the top menu, browse to Configuration > Scan Configs

Click the “sheep” (clone) button next to empty

Hit the spanner icon at the top of the window:

Name the Scan Config “MS17-010 Vulnerability Check” or something else meaningful:

Scroll down to “Windows : Microsoft Bulletins” and hit the spanner icon next to this:

Search for 4013389 (the relevant MS ID), enable all instances for the scan and click save:

As per comments via this post, also enable the Port Scanners | Ping Host and NMAP (NASL wrapper) tests.

Click Save, then click save again.

Now browse to: Scans > Tasks

Click the “Pink Wand” icon: New > Advanced Task Wizard

Name the task and select the new scan config you just created. Specify IP, subnet etc you want to scan. Hit “Create” to start the scan for this specific vulnerability.

Check the reports as the scan progresses, anything identified needs to be patched, or hardened/ isolated if it is older than those O/S editions that this patch was released for.

Happy hunting…

MS17-010 Vulnerability Checking with PowerShell and Nmap

There have been several MS17-010 PowerShell scripts that have emerged over the last week or so, I wanted to call out a couple in particular, aimed at assurance/ understanding vulnerability within a network rather than the remediation/ clean-up.

The first uses Nmap to identify individual IPs/ hostnames that are vulnerable to MS17-010 exploit: https://gist.github.com/iwikmai/65b8a5b882e782d78fc5f466dfd2cde4

Using Nmap is important as simply installing the patch itself without a reboot is not enough to protect against this vulnerability. This script uses Nmap to confirm that this exploit is no longer available on a per-target basis, rather than simply looking for an installed hotfix.

The second script is good for checking that machines have the patch itself installed: https://github.com/kieranwalsh/PowerShell/blob/master/Get-WannaCryPatchState/Get-WannaCryPatchState.ps1

No doubt you’ll come across scripts that help you deploy the patch and even decrypt/ clean-up WannaCry itself – certainly lots of interesting reads in recent days.

Upgrading a Docker-based, Duo MFA enabled deployment of Guacamole 0.9.11-incubating to 0.9.12-incubating

To get guacamole deployed using docker containers, on Ubuntu 16.04, see my other post here: https://www.cb-net.co.uk/linux/enabling-duo-dual-multi-factor-authentication-mfa-for-guacamole-docker/

In this post I cover how to update your duo MFA-enabled, docker-based guacamole 0.9.11-incubating deployment to 0.9.12-incubating.

This guide assumes you have a working 0.9.11-incubating deployment, comprised of:

  • A guacd container named guacd
  • A guacamole/guacamole container names guacamole
  • A mysql container named guac-mysql
  • A pass-through volume that contains duo MFA extension and guacamole.properties file on the docker host in the following location: /var/docker/config/guacamole/

Finally, upgrading 0.9.11-incubating to 0.9.12-incubating does not require a database update, so this is not included below.

# Stop and remove the previous guacd/ guacamole instances
sudo docker stop guacamole
sudo docker stop guacd
sudo docker rm guacd
sudo docker rm guacamole

# Pull latest container images for guacd/ guacamole
sudo docker pull guacamole/guacd
sudo docker pull guacamole/guacamole

# Pull latest duo MFA extension
cd /var/docker/config/guacamole/extensions/
wget http://apache.mirrors.tds.net/incubator/guacamole/0.9.12-incubating/binary/guacamole-auth-duo-0.9.12-incubating.tar.gz
tar zxvf guacamole-auth-duo-0.9.12-incubating.tar.gz
mv guacamole-auth-duo-0.9.12-incubating/guacamole-auth-duo-0.9.12-incubating.jar /var/docker/config/guacamole/extensions/

# Ensure you clean-up older versions!

# Create/ start the new guacd/ guacamole containers
sudo docker run --name guacd -d guacamole/guacd

sudo docker run --name guacamole --link guacd:guacd --link guac-mysql:mysql \
-e MYSQL_DATABASE='guacamole' \
-e MYSQL_USER='guacamole' \
-v /var/docker/config/guacamole:/config \
-e GUACAMOLE_HOME=/config \
-e MYSQL_PASSWORD='<your password>' \
-d -p 8080:8080 guacamole/guacamole

# Set to auto-start on docker restart
sudo docker update --restart=always guacd
sudo docker update --restart=always guacamole

Using Let’s Encrypt with an NGINX Docker Container (plus bye-bye StartSSL!)

Updated June 2017 : reflecting move to certbot/certbot container.

I ran into an issue this week with my StartSSL certificates deployed on my personal lab/ infrastructure. It turns out the Google stopped trusting this CA with a recent release of Chrome, and that this had been on the cards for a while: https://security.googleblog.com/2016/10/distrusting-wosign-and-startcom.html

So, with this in mind, I decided to make the move to Let’s Encrypt.

My Environment

  • Ubuntu Server 16.04
  • Docker containers for:
    • Nginx (used as a reverse proxy) configured to redirect all HTTP traffic to HTTPS
    • A test website published at: test.cb-net.co.uk
    • A Guacamole instance, published at: remote.cb-net.co.uk

The fact that I was using docker containers would make this little more “interesting” or challenging.


Using Let’s Encrypt Certificates in a Docker Container

I came across the following post which I used as a foundation for the method below: https://manas.tech/blog/2016/01/25/letsencrypt-certificate-auto-renewal-in-docker-powered-nginx-reverse-proxy.html

Much is common in terms of the solution/ scripts.


NGINX Container/ Config

NGINX volumes passed-through to container from the docker host (you’ll use these later):

  • Config folder: /var/docker/volumes/nginx/conf.d
  • SSL certificate root:/var/docker/volumes/nginx/ssl
  • WWW root folder: /var/docker/volumes/nginx/www/ : Create a folder per domain – i.e.
    • /var/docker/volumes/nginx/www/test.cb-net.co.uk
    • /var/docker/volumes/nginx/www/remote.cb-net.co.uk

Create the directory structure on your docker host above (change domains to match your needs):

sudo mkdir -p /var/docker/volumes/nginx/conf.d
sudo mkdir -p /var/docker/volumes/nginx/www/test.cb-net.co.uk
sudo mkdir -p /var/docker/volumes/nginx/www/remote.cb-net.co.uk
sudo mkdir -p /var/docker/volumes/nginx/ssl

Now, re-create the NGINX container to include the config, root and the SSL folders:

sudo docker pull nginx
sudo docker run --name nginx -p 80:80 -p 443:443 \
-v /var/docker/volumes/nginx/ssl/:/etc/nginx/ssl/ \
-v /var/docker/volumes/nginx/conf.d/:/etc/nginx/conf.d/ \
-v /var/docker/volumes/nginx/www/:/var/www \
-d nginx

Modifying your HTTP to HTTPS Redirect Config

Skip this section if you have a new NGINX container/ no SSL in-place today.

Leaving a redirect all to HTTPS configuration in place will cause the Let’s Encrypt certificate request to fail (specifically the domain validation piece).

You need to modify the NGINX configuration to create a root folder, per domain, that Let’s Encrypt will use for domain validation. All other traffic will be redirected to HTTPS.

You’ll need to do this for each published site/ resource.

# Redirect http to https
 server {

 listen 80;
 server_name test.cb-net.co.uk;

#### Required for letsencrypt domain validation to work
 location /.well-known/ {
 root /var/www/test.cb-net.co.uk/;
 }

return 301 https://$server_name$request_uri;
 }

Ensure you allow port 80 traffic to hit your web server for the request to work.


Requesting the Certificate

We’ll use a docker image for this piece as well.

You can see below, I specify the SSL folder we created and mapped into the NGINX container:

  • /var/docker/volumes/nginx/ssl

Be sure to change the domain name, web root path and email address used in the request.

# Pull the docker image
sudo docker pull certbot/certbot

# Request the certificates - note one per published site
sudo docker run -it --rm --name letsencrypt \
 -v "/var/docker/volumes/nginx/ssl:/etc/letsencrypt" \
 --volumes-from nginx \
 certbot/certbot \
 certonly \
 --webroot \
 --webroot-path /var/www/test.cb-net.co.uk \
 --agree-tos \
 --renew-by-default \
 -d test.cb-net.co.uk \
 -m [email protected]

sudo docker run -it --rm --name letsencrypt \
 -v "/var/docker/volumes/nginx/ssl:/etc/letsencrypt" \
 --volumes-from nginx \
 certbot/certbot \
 certonly \
 --webroot \
 --webroot-path /var/www/remote.cb-net.co.uk \
 --agree-tos \
 --renew-by-default \
 -d remote.cb-net.co.uk \
 -m [email protected]

If successful, the new certificate files will be saved to: /var/docker/volumes/nginx/ssl/live/<domain name>

You will find four files in each domain folder:

  • cert.pem: Your domain’s certificate
  • chain.pem: The Let’s Encrypt chain certificate
  • fullchain.pem: cert.pem and chain.pem combined
  • privkey.pem: Your certificate’s private key

Pulling it all Together

We now need to configure NGINX to use these certificates, modify your config file as below, adding a new location to both HTTP and HTTPS listeners – these lines will need to be set for each published resource/ certificate as requested above, within the relevant server definition in your NGINX configuration file.

I have only included a single server definition in the config file example below, you can simply copy/ paste to create additional published resources/ modify as necessary.

# Redirect http to https
 server {
 listen 80;
 server_name remote.cb-net.co.uk;

#### Required for letsencrypt domain validation to work
 location /.well-known/ {
 root /var/www/remote.cb-net.co.uk/;
 }

return 301 https://$server_name$request_uri;
 }

# Guacamole Reverse Proxy HTTPS Server
server {
listen 443 ssl;
server_name remote.cb-net.co.uk;
rewrite_log on;

ssl_certificate /etc/nginx/ssl/live/remote.cb-net.co.uk/fullchain.pem;

ssl_certificate_key /etc/nginx/ssl/live/remote.cb-net.co.uk/privkey.pem;

ssl_trusted_certificate /etc/nginx/ssl/live/remote.cb-net.co.uk/fullchain.pem;

#### Required for letsencrypt domain validation to work
 location /.well-known/ {
 root /var/www/remote.cb-net.co.uk/;
 }
# Only needed for guacamole
location / {
 proxy_pass http://<guacamole instance>:8080/guacamole/;
 proxy_redirect off;
 proxy_buffering off;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection $http_connection;
 proxy_cookie_path /guacamole/ /;
 access_log off;
 }
}

# Create additional server blocks for other published websites.

Once modified/ saved, restart the nginx instance:

sudo docker restart nginx

Automating the Renewal

These certificates will only last 90 days, so automating renewal is key!

Create the script below as /etc/cron.monthly/letsencrypt-renew.sh

#!/bin/sh

# Pull the latest version of the docker image
 docker pull quay.io/letsencrypt/letsencrypt

# Change domain name to meet your requirement
docker run -it --rm --name letsencrypt \
 -v "/var/docker/volumes/nginx/ssl:/etc/letsencrypt" \
 --volumes-from nginx \
 certbot/certbot \
 certonly \
 --webroot \
 --webroot-path /var/www/test.cb-net.co.uk \
 --agree-tos \
 --renew-by-default \
 -d test.cb-net.co.uk \
 -m [email protected]

# Change domain name to meet your requirement
docker run -it --rm --name letsencrypt \
 -v "/var/docker/volumes/nginx/ssl:/etc/letsencrypt" \
 --volumes-from nginx \
 certbot/certbot \
 certonly \
 --webroot \
 --webroot-path /var/www/remote.cb-net.co.uk \
 --agree-tos \
 --renew-by-default \
 -d remote.cb-net.co.uk \
 -m [email protected]

# Chnage "nginx" to the nginx container instance
docker kill --signal=HUP nginx

Now enable execute permissions on the script:

chmod + x /etc/cron.monthly/letsencrypt-renew.sh

Finally, you can test the script:

./etc/cron.monthly/letsencrypt-renew.sh

Once executed, your published sites should reflect a certificate with a created time stamp of just a few seconds after running the script.