Saturday, 17 October 2020

Multicast packets dropped on OpenWRT VLANs

Multicast issue on OpenWRT.md

Multicast issue on OpenWRT

Issue

After setting up my hacked switches with VLANs, I wanted to create a pfSense cluster for more resilient internet access. pfSense uses CARP (closely related to VRRP) which uses multicast to detect when a router or interface goes down. When a router is in CARP master mode, it constantly sends out multicast packets to 224.0.0.18. If another router is in backup mode and cannot see the packets arriving from the master, it will attempt to become the master node.

The issue I was seeing was that the multicast packets weren’t arriving and therefore both nodes came up as master on all but one of the CARP IPs. The OpenWRT configuration I had initially only passed multicast on VLAN id 1, all multicast packets bound for VLAN id 1 were echoed to all ports on both switches. All of the multicast packets for the other VLANs were dropped.

Here is my original /etc/config/network configuration file:

Here’s how the CARP interfaces look. The only working network is LAN which is on VLAN id 1

Primary

Master CARP

Secondary

Backup CARP

It’s important to know that the VLANs all work and pass regular unicast and broadcast traffic just fine. Only the multicast CARP packets are not getting through.

Troubleshooting Steps

Packet capture on pfSense

Attempting to capture CARP on any of the affected VLANs shows no packets arriving.

CARP Packet Capture from pfSense

Nothing!

Nothing captured

tcpdump on the switch

Shows CARP packets arriving on the port destined for affected VLANs (Two IP ranges here are coming in on an untagged port on VLAN 9.) Also notice the CARP packets from VLAN id 1 are being echoed onto this port.

tcpdump -i eth1 -c 10 -n -e -T carp carp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
20:34:39.400955 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:34:39.401219 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
20:34:39.401370 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
20:34:40.415665 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:34:40.415871 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
20:34:40.416211 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
20:34:41.419605 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:34:41.419810 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
20:34:41.419956 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
20:34:42.429564 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
10 packets captured
12 packets received by filter
0 packets dropped by kernel
4 packets dropped by interface

tcpdump on a linux endpoint

Shows CARP packets only for VLAN 1, this Linux machine is on an untagged port on VLAN 9.

# tcpdump -i eth0 -c 10 -n -e -T carp carp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:37:24.422703 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:25.438853 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:26.458870 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:27.522734 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:28.560403 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:29.625900 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:30.635363 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:31.645144 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:32.667945 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:37:33.717977 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
10 packets captured
10 packets received by filter
0 packets dropped by kernel

Resolution

I noticed on the switch that the bridge interface was configured only on VLAN id 1 since it’s member adapters were all fixed to vid='1'. My fix was to create a bridge interface and eth0-3 vlan interfaces in each VLAN that I wanted the multicast packets to work on.

The changed parts in /etc/config/network are the new bridge interfaces:

config interface 'lan2'
    option type 'bridge'
    option force_link '0'
    option igmp_snooping '1'
    option ipv6 '0'
    list ifname 'vlan_eth0_2'
    list ifname 'vlan_eth1_2'
    list ifname 'vlan_eth2_2'
    list ifname 'vlan_eth3_2'
    option ip6assign '0'
    list pppoerelay ''

And the new vlan_ethX_xx interfaces:

config device 'vlan_eth0_2'
    option type '8021q'
    option ifname 'eth0'
    option name 'vlan_eth0_2'
    option mtu '1500'
    option vid '2'

config device 'vlan_eth1_2'
        option type '8021q'
        option ifname 'eth1'
        option name 'vlan_eth1_2'
        option mtu '1500'
        option vid '2'

config device 'vlan_eth2_2'
        option type '8021q'
        option ifname 'eth2'
        option name 'vlan_eth2_2'
        option mtu '1500'
        option vid '2'

config device 'vlan_eth3_2'
        option type '8021q'
        option ifname 'eth3'
        option name 'vlan_eth3_2'
        option mtu '1500'
        option vid '2'

I think the issue is due to the bridge interface being only on vlan id 1 and having multicast snooping enabled. I tried many other changes, like bridging the bare eth0-3 interfaces, but most changes either locked me out of the switch configuration interface or made no difference.

Here is my /etc/config/network configuration file now. It looks a mess, but it works and since I didn’t want to make huge changes to the config and lock myself out (again,) it’s left like this. There is for sure a better way to do this, but these changes are good enough for me!

Recieving packets on pfSense now

Packets arriving on the right interfaces now. Only multicast packets for the relevant VLAN are captured, I believe because VMware is stripping the other VLANs from the Port Group.

CARP Packet Capture from pfSense working

tcpdump on the switch now

All CARP packets for all VLANs arriving at the switch port shown earlier. All CARP packets from all vlans are echoed on all ports.

# tcpdump -i eth1 -c 10 -n -e -T carp carp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
20:04:38.379521 00:00:5e:00:01:63 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 15, p 0, ethertype IPv4, 192.168.99.1 > 224.0.0.18: CARPv2-advertise 36: vhid=99 advbase=1 advskew=0 authlen=7 counter=4683731516847153633
20:04:38.379922 00:00:5e:00:01:05 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 2, p 0, ethertype IPv4, 192.168.5.1 > 224.0.0.18: CARPv2-advertise 36: vhid=5 advbase=1 advskew=0 authlen=7 counter=9456878584255914769
20:04:38.380439 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:04:38.380625 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
20:04:38.380912 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
20:04:39.389533 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
20:04:39.389852 00:00:5e:00:01:05 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 2, p 0, ethertype IPv4, 192.168.5.1 > 224.0.0.18: CARPv2-advertise 36: vhid=5 advbase=1 advskew=0 authlen=7 counter=9456878584255914769
20:04:39.390086 00:00:5e:00:01:63 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 15, p 0, ethertype IPv4, 192.168.99.1 > 224.0.0.18: CARPv2-advertise 36: vhid=99 advbase=1 advskew=0 authlen=7 counter=4683731516847153633
20:04:39.390316 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
20:04:39.390533 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989

tcpdump on a linux endpoint now

tcpdump from a linux machine now shows carp packets from all VLANs on it’s physical port. Worth mentioning that the port is configured untagged on VLAN 15.

# tcpdump -i eth0 -c 10 -n -e -T carp carp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
18:15:14.122660 00:00:5e:00:01:63 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 70: 192.168.99.1 > 224.0.0.18: CARPv2-advertise 36: vhid=99 advbase=1 advskew=0 authlen=7 counter=4683731516847153633
18:15:14.122965 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
18:15:14.123263 00:00:5e:00:01:05 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 2, p 0, ethertype IPv4, 192.168.5.1 > 224.0.0.18: CARPv2-advertise 36: vhid=5 advbase=1 advskew=0 authlen=7 counter=9456878584255914769
18:15:14.123316 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
18:15:14.123878 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
18:15:15.134075 00:00:5e:00:01:05 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 2, p 0, ethertype IPv4, 192.168.5.1 > 224.0.0.18: CARPv2-advertise 36: vhid=5 advbase=1 advskew=0 authlen=7 counter=9456878584255914769
18:15:15.134351 00:00:5e:00:01:02 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 1, p 0, ethertype IPv4, 192.168.2.1 > 224.0.0.18: CARPv2-advertise 36: vhid=2 advbase=1 advskew=0 authlen=7 counter=3809067134136217446
18:15:15.134627 00:00:5e:00:01:63 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 70: 192.168.99.1 > 224.0.0.18: CARPv2-advertise 36: vhid=99 advbase=1 advskew=0 authlen=7 counter=4683731516847153633
18:15:15.134823 00:00:5e:00:01:01 > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 192.168.1.1 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 authlen=7 counter=13620309968023688989
18:15:15.134831 00:00:5e:00:01:0f > 01:00:5e:00:00:12, ethertype 802.1Q (0x8100), length 74: vlan 9, p 0, ethertype IPv4, 10.1.15.2 > 224.0.0.18: CARPv2-advertise 36: vhid=15 advbase=1 advskew=0 authlen=7 counter=13306912573729581052
10 packets captured
10 packets received by filter
0 packets dropped by kernel
3 packets dropped by interface

Wireshark from windows inside a VMware virtual machine only shows carp packets on the vlan that it’s port group is configured to. Presumably VMware is stripping irrelevant VLANs. To show CARP traffic in Wireshark, select a VRRP packet, right click, click decode as and choose CARP from the list.

Wireshark Windows

The CARP interfaces all now show Master/Backup correctly. Failover is also working as expected.

Backup CARP

Written with StackEdit.

Saturday, 10 October 2020

RDP File Signing

RDP File Signing.md

Removing unknown publisher errors from RDP connection files

Ever seen this error or had it reported by a customer?

The publisher of this remote connection can’t be identified. Do you want to connect anyway?

With a publisher name of Unknown publisher

Unknown RDP Publisher

Getting rid of this is a 2 step process, first sign the RDP file, then set your clients to trust the signing certificate. Unfortunately this is only possible through a policy setting so the client machine needs to be domain joined or you must edit the local policy of the client.

Signing the RDP File

Signing the RDP file is done with the rdpsign tool, I found this built in on Server 2012, Windows 10 and Server 2019 so it looks like it’s there across the board. I don’t think the certificate requires anything special except for the Digital Signature key usage. I tested this with both a public wildcard certificate issued by Let’s Encrypt and with an AD Certificate Services issued “Code Signing” certificate. Presumably this would work with a self-signed certificate since the thumbprint is pinned later in group policy.

The /sha256 switch appears to be missing in earlier versions (2012, non-R2), but I used the /sha1 switch in it’s place and it accepted a sha256 certificate.

Run the command as follows

rdpsign.exe /sha256 <certificate thumbprint> filename.rdp

Example output from rdpsign

Once signed, if you open the .rdp file with notepad, you’ll see a signature block at the bottom of the file. Modifying any of the signscope elements of the file will cause the original unknown publisher warning to appear.

Example signed RDP file

Now that the file is signed, the first step is complete, but now there is just a different warning asking if you trust the publisher. The publisher listed is the subject name of the certificate used.

Example signed publisher warning

Setting the SHA1 hash in policy

To actually make the warning go away, the Specify SHA1 thumbprints of certificates representing trusted .rdp publishers setting in policy needs to be changed. In group policy the setting is as follows, the list is comma separated and there is an equivalent setting in the user policy.

Computer Configuration\Administrative Templates\Windows Components\Remote Desktop Services\Remote Desktop Connection Client

Here it is in a GPO

Policy location

Once the policy is set, update group policy on the client and reopen the .rdp file.

gpupdate output

And now there is no warning!

no warning

Written with StackEdit.

Sunday, 4 October 2020

Verifying RDP connections with Kerberos and Certificates

Verifying RDP connections with Kerberos and Certificates.md

Removing Certificate warnings for RDP

Certificate Warning

Certificate warnings on connection to an RDS server are not uncommon and are in fact normal when connecting to a non domain joined PC. They can be annoying, look unprofessional and can cause concern when users are required to connect.

Defaults & Self signed certificates

By default a non-domain joined PC will present a self-signed certificate when connecting. Since this isn’t trusted by the connecting client then a warning will be displayed.

When connected via RDP to a machine with a non trusted certificate, no security icon is shown in the connection bar.

no security icon on bar

While it’s possible to generate another self signed certificate with the DNS names you require, the certificate needs to be trusted by all client machines that connect otherwise the warning is displayed. Managing client’s trusted certificates is complex and not possible if you do not control the clients. In fact, it’s probably easier to just tick the ‘Don’t ask me again for connections to this computer’ box than it is to deploy a certificate to each client.

Ticking this box caches the certificate’s thumbprint in the REG_BINARY registry value, CertHash. The location in the registry is as follows:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Terminal Server Client\Servers\COMPUTERNAME

Registry Key Location

This is a per user setting so could be included in a login script for example. Here is some example PowerShell to set the value in the registry:

$thumbprint = "36558bf53757dd5c2ada081001323a969f576f4a"
$ComputerName = "commando"

$regPath = "HKCU:\SOFTWARE\Microsoft\Terminal Server Client\Servers\$($ComputerName)"
$thumbprintBinary = [byte[]] -split ($thumbprint -replace '..', '0x$& ')
New-ItemProperty -Path $regPath -Name CertHash -PropertyType Binary -Value $thumbprintBinary

Unfortunately, both methods of using self-signed certificates are cumbersome to manage.

Kerberos & Service Principal Names (SPNs)

By default you won’t get a certificate warning from a domain joined machine if connecting to it using it’s host name or fully qualified domain name (FQDN) since it will have an SPN registered for TERMSVC/hostname and TERMSVC/fqdn.

If you have a domain joined machine that you want to RDP to using an alternative name, you can use an SPN to allow Kerberos authentication to work. This only works for a single RDP endpoint since SPNs must be unique in the forest.

To create a new SPN, use the setspn utility

Show current SPNs

setspn -l computername

setspn list

Set a new SPN

setspn -s TERMSRV/aliasname computername

setspn set

Once a new SPN is added, connecting to the machine with the aliasname will show the connection is verified with Kerberos.

kerberos verified

Public Certificate Authority (CA) Signed certificate

It’s possible to use a wildcard, public CA signed certificate to secure an RDP connection. If you have a CA cert that provides the DNS name you need for connection then it’s possible to use this on all of the RDS servers behind a simple load balancer. To do this you must import the certificate in Windows. In my example I’m using a let’s encrypt wildcard certificate, the only requirement I can see is that it must have a greater than 2048 bit private key and include the “Server Authentication” Enhanced Key Usage.

Create a pfx bundle of your certificate on a machine with openssl installed. The following command includes the CA chain in the pfx.

openssl pkcs12 -export -out certificate.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem

Once you have a pfx file you can import it in Windows. I imported to the default location, which is the local computer’s “personal” store. Right click on the pfx file and click import.

Import into Windows

Note that there is a private key available for the imported certificate

Imported certificate

Once imported, set the RDS certificate using PowerShell and WMI. WARNING: It’s worth mentioning that restarting the TermService service will kill current RDP connections so make sure to do this from the console of the machine. If the TermService service doesn’t find a valid certificate you could be locked out if you only have RDP access to the machine.

$GenSettingsPath = Get-WmiObject -Namespace "root\cimv2\TerminalServices" -Class "Win32_TSGeneralSetting"
Set-WmiInstance -Path $GenSettingsPath -Arguments @{SSLCertificateSHA1Hash="THUMBPRINT"}

Restart-Service TermService -Force

PowerShell output

Once connected, the connection is shown to be verified by a server certificate

certificate Verified image

Certificate from an Enterprise Active Directory (AD) CA

You can also secure an RDP connection to a single or group of machines using a digital certificate from your Enterprise, AD Certificate Authority. This is beneficial if you have a group of RDS servers behind a simple load balancer.

SECURITY WARNING: To generate a certificate from the Enterprise CA, we need to create a certificate template and publish in AD. Since we need arbitrary subject alternative names enabled in the template this is a dangerous template to create and leave enabled. For this example, I will create the template, publish it, request a certificate and then disable the template so it cannot be used automatically. This template could allow any domain computer to create a certificate for any name and therefore compromise the entire security of the CA. It would be best to secure the template so it requires CA manager approval before the certificate is issued. The following code snippets would need to be modified to handle a pending request.

Template creation steps

  1. On your enterprise CA, open the Certification Authority application
  2. Right click on Certificate Templates and click Manage

Click Manage

  1. The Certificate Templates Console opens, right click Computer and click Duplicate Template

Click Duplicate Template

  1. On the General tab, give the template an appropriate name, in this example I am using “RemoteDesktopComputer”

Name the template RemoteDesktopComputer

  1. Check the minimum key size is 2048-bits on the Cryptography tab

Crypto Tab

  1. Check that Server Authentication is enabled in the Application Polices section of the Extensions tab

Extensions Tab

  1. On the Subject Name tab, choose supply in the request. Note the security warning In a production environment, the “CA Certificate manager approval” option should be selected to ensure that certificates from this template are validated before issuance.

Subject Name Tab

  1. Review the Issuance Requirements tab, for this example the “CA Certificate manager approval” is unchecked, Do not do this in a production environment

Issuance Requirements Tab

  1. Click OK to save the template, close the Certificate Templates Console window
  2. In the Certification Authority window, Right click on Certificate Templates and click “Certificate Template to issue”

Click Certificate Template to issue

  1. Select the new template

Select the new template

Once you have a template created and published, the following PowerShell will request and issue a new certificate on the RDP server.

$CN = "CN=COMPUTER"
$dnsNames = @("COMPUTER", "computer.example.com", "loadbalancer.example.com")

$Cert = Get-Certificate -Template "RemoteDesktopComputer" `
	-SubjectName $CN -DnsName $dnsNames `
	-CertStoreLocation "cert:\LocalMachine\My" -Url ldap:

$Cert

At this point, check that the certificate in the computer certificates mmc is as expected and contains the correct DNS subject alternative names.

Issued Certificate

Once done, run the following in the same PowerShell session to apply the certificate. WARNING: It’s worth mentioning that restarting the TermService service will kill current RDP connections so make sure to do this from the console of the machine in case the certificate is invalid. If the TermService service doesn’t find a valid certificate you could be locked out if you only have RDP access to the machine.

if ($cert) {
	$GenSettingsPath = Get-WmiObject -Namespace "root\cimv2\TerminalServices" -Class "Win32_TSGeneralSetting"
	Set-WmiInstance -Path $GenSettingsPath -Arguments @{SSLCertificateSHA1Hash="$($Cert.Certificate.Thumbprint)"}

	Restart-Service TermService -Force
} else {
	Write-Host "Error generating certificate"
}

Once connected, the connection is shown to be verified by a server certificate

certificate Verified

IMPORTANT At this point, delete the published certificate template or secure it in another way

Delete the template

Written with StackEdit.

Saturday, 26 September 2020

Adding VLANs to OpenWRT

Adding VLANs to OpenWRT.md

Adding VLANs to a hacked OpenWRT router

Technicolor MediaAccess TG589vac

TG589vac Router

Warning: Incorrectly modifying the /etc/config/network file can cause switch/router inoperabilty, it could brick the device or cause it to lose network connectivity to it’s management interface. Follow these steps only with full knowledge that you could destroy your router or switch. I accept no responsibility!

I inherited one of these routers from a previous ISP and bought another from ebay since they make pretty competent 4-port gigabit switches once the firmware has been rooted. I have a guide to root your TG589vac here. Since setting them up as my home lab switches, I now have a requirement to implement VLANs on my network for segmentation and to make things tidyer on my virtualisation hosts.

Since these routers are running OpenWRT then adding VLANs to them is fairly straight forward. Log into the router as root and modify the network config file with vi /etc/config/network

The interesting section of this file is here:

config switch_vlan 'lan_switch'
	option ports '1* 2* 3* 4* 8t'
	option device 'bcmsw'
	option vlan '1'

Essentially this is setting up all 4 ports untagged on the default VLAN with id 1. In order to add additional VLANs, simply copy this segment and change some of the settings. For instance if the requirement was to set up a second VLAN with id 5, untagged on port 3 and changing port 4 to be a tagged port for an ESXi host we could do the following:

config switch_vlan 'lan_switch'
	option ports '1* 2* 4t 8t'
	option device 'bcmsw'
	option vlan '1'

config switch_vlan 'lan_switch_vlan5'
	option ports '3* 4t 8t'
	option device 'bcmsw'
	option vlan '5'

Notice that port 3 was removed and port 4 was switched to tagged on VLAN id 1, then VLAN id 5 has been configured on port 3 untagged and port 4 tagged. I’m unsure of the significace of port 8t but in my case it works with the port included in all additional VLANs.

* - denotes untagged
t - denotes tagged

Warning: DO NOT change the name of the vlan ‘lan_switch’ doing so caused a segfault when reloading the network on my switch and soft-bricked it. The switch was left restarting the network over and over. After much trial and error, I managed to factory reset it once all physical network ports were unplugged.

Once you have made your edits, restart the network with /etc/init.d/network reload or service network reload depending on the OpenWRT version.

root@dsldevice:~# /etc/init.d/network reload  
Success  
JUMBO_PORT_MASK:0x000001FF  
GPHY_0 port accepts jumbo frames.  
GPHY_1 port accepts jumbo frames.  
GMII_1 port accepts jumbo frames.  
GMII_2 port accepts jumbo frames.  
GPON_SERDES port accepts jumbo frames.  
MOCA port accepts jumbo frames.  
USB port accepts jumbo frames.  
GPON port accepts jumbo frames.  
MIPS port accepts jumbo frames.  
Success  
Success  
CDK_E_PORT  
CDK_E_PORT

Written with StackEdit.

Saturday, 19 September 2020

Windows Process Command Line Logging

Windows Process Command Line Logging

Windows Process Command Line Logging

Introduction

There are many reasons to gather process launch information in a Windows environment. Troubleshooting, Security forensics, Performance Analysis to name a few. By default, Windows does not log process launch information so it will need to be configured using local or group policy.

There are some security consequences of enabling process command line logging. Some commands, including some legacy AD commands require using a password or secret key as a parameter. Ideally we wouldn’t want these secrets appearing in logs, unfortunately the the only way to exclude them is to disable command line logging which substantially reduces the usefulness of enabling process logging in the first place.

Reading the logs requires local administrator rights on the system, however this could lead to privilege escalation; for instance if a logged command line included a Domain Admin password. The usefulness in forensics though, may be more benefit than the risk of having secrets in the Windows Event log. It may be prudent to configure log forwarding to a hardened server and regular log rotation on client and server systems.

Required Policy Settings

Warning: Enabling the Audit: Force audit policy subcategory settings policy will override any basic policy settings that are configured on the system. These should be translated to the equivalent advanced audit settings if they are required.

In order for Windows to log event ID 4688 so that you can see Windows process creation events and their command lines, there are several policy settings to configure:

Enable Audit: Force audit policy subcategory settings policy in Computer Configuration\Policies\Windows Settings\Local Policies\Security Options

Enable the Audit Process Creation policy in Computer Configuration\Policies\Windows Settings\Security Settings\Advanced Audit Configuration\Audit Policies\Detailed Tracking

Enable the Include command line in process creation events setting in Administrative Templates\System\Audit Process Creation

Audit: Force audit policy subcategory settings
Force sub policy

Audit Process Creation
Audit Process Creation

Include command line in process creation events
Include Command Line

If using Group Policy, once the policy is saved, run gpupdate /force on the targeted system. Once applied, running auditpol /get /category:* should show the appropriate audit policies being applied.

Troubleshooting

While deploying this group policy, I noticed that Process Creation was not being set when running auditpol /get /category:*. After enabling an unrelated advanced audit policy such as Account Lockout in the Logon/Logoff category, the Process Creation policy was applied. I was then able to remove Account Lockout while still keeping Process Creation. I’m not exactly sure why this issue ocurred, but I think it happened due to the order the policy elements were applied.

No Auditing Success and Failure

Reviewing the Windows Event Log

Once the above policy and audit settings are in place then the system will begin logging event ID 4866 in the System event log

Windows 4688

Gathering Process History for a machine in PowerShell

Looking at windows event logs can be time consuming and tedious, so here is a short PowerShell script to parse the event log on a target machine for recent commands:

Script Output:

Script Output

Extending with SysInternals Sysmon

While logging process creation events with the full command line is a powerful forensic tool, there is much more detailed logging available in SysInternals Sysmon. Next time I will be installing and configuring Sysmon to generate more verbose forensic logs including process creation and termination, generation of suspicious file modification and deletion logs, Registry modification and even WMI event logging.

Gathering Domain Controller Audit Policy

I’ve also written a quick script to gather the audit policy for all Domain Controllers in the domain. You can find it here.

Written with StackEdit.

Quick Script: DC Audit Policy

Quick Script: DC Audit Policy

Quick Script: Check all Domain Controllers for Audit Policy Settings

Introduction

Here’s a quick script to gather the detailed audit policy for all Domain Controllers in the domain. This is useful if you have domain controllers in different OUs with different policies applied. It will give a quick overview of each audit policy on each machine and since it’s in a GridView it’s easy to filter and sort the list so you can check a single policy against all your DCs.

The Script

Written with StackEdit.

Wednesday, 13 May 2020

Quick Script to Modify user home directory permissions

Quick Script to Modify user home directory permissions

Home Drive Permissions

common user home folder location from dsa.msc
common user home folder location from dsa.msc

Migrating user home drives can be a pain if permissions are not copied over at the same time. Permissions can also get messed up for other reasons like improper data restore or an admin clicking the wrong button.

Provided your home folder share is configured as \\server\share\%username% then this quick script can add the user with Full Control rights to their folder.

$usersfolder = "\\server\share\"

foreach ($folder in (gci $usersfolder)) {
    Write-Host $folder.FullName -ForegroundColor Yellow
    $Acl = Get-Acl $folder.FullName
    $AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\$($folder.name)", "FullControl","ContainerInherit,ObjectInherit","None","Allow")
    $Acl.SetAccessRule($AccessRule)
    Set-Acl -Path $folder.FullName -AclObject $Acl
}

This will iterate through the folders and add DOMAIN\username (provided the folder is named the same as the user’s samaccountname) with Full Control.

Written with StackEdit.