lfcode.ca notes compiled for future reference

Auditing world-writable high-privilege executables on Windows

I was reading Matt Nelson's post on a permissions issue causing privilege escalation and thought "I have too much software installed, I wonder if any of it is vulnerable". So on to PowerShell! I developed all of this by interactive exploration using Get-Member, Format-List *, and Get-Command.

At the end of this exploration, I did indeed find a vulnerable service, however, it was because the application was installed in a world-writable parent directory due to my own carelessness (a situation I fixed). This finding leaves the open question of whether it is the job of the service's installer to set secure permissions on its install directory or just follow the permissions of the parent directory.

PS> # First, let's define a function to find if a given path is interesting
PS> function Get-InterestingAccess($path) {
>> get-acl $path | %{$_.access} | ? {$_.filesystemrights.hasflag([System.Security.AccessControl.FileSystemRights]::Modify)} | ? {-not ($_.identityreference -in @('NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators', 'NT SERVICE\TrustedInstaller'))}
>> }
PS> # stolen shamelessly from StackOverflow (it is ridiculous that you need P/Invoke for this)
PS> $src = @"
using System;
using System.Runtime.InteropServices;
public class ParseCmdline{
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);

public static string[] CommandLineToArgs(string commandLine)
    int argc;
    var argv = CommandLineToArgvW(commandLine, out argc);
    if (argv == IntPtr.Zero)
        throw new System.ComponentModel.Win32Exception();
        var args = new string[argc];
        for (var i = 0; i < args.Length; i++)
            var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
            args[i] = Marshal.PtrToStringUni(p);

        return args;
PS> add-type -TypeDefinition $src
PS> # let's look for services with vulnerabilities. First find all service executables:
PS> $targets = gcim win32_service | %{[ParseCmdline]::CommandLineToArgs($_.pathname)[0]}
PS> $targets | where { Get-InterestingAccess -path $_ }
# redacted
PS> # also try:
PS> $targets = Get-ScheduledTask | %{ [System.Environment]::ExpandEnvironmentVariables($_.actions.execute) } | ? {$_}

Tags: PowerShell, windows

Hyper-V Manager throws obscure errors if the target computer calls itself something else than you do

I started testing Server 2019 as a Hyper-V host a few days ago, but getting the GUI manager to connect was a bit challenging. This article will be about as much documentation for me to set this machine up again as it will be instructive.

This machine is non domain joined.

First, name the computer what you want its final DNS name to be with Rename-Computer. Then reboot so you will avoid the issue described in the second half of the post.

Secondly, get a remote shell into it. Enable-PSRemoting, and ensure the firewall rules are allowing connections from the subnets you're OK with remote connections from with Get-NetFirewallRule piped to Get-NetFirewallAddressFilter and Set-NetFirewallAddressFilter.

Next, enable CredSSP with Enable-WSManCredSSP -Role Server and ensure that the appropriate fresh credential delegation, trusted hosts, and permit-CredSSP GPOs are applied on the client. Check also that the WinRM service is running on the client, and if there are still issues with lacking "permission to complete this task" while connecting with the manager, also run Enable-WSManCredSSP with the client role, delegating to the appropriate host.

Then, hopefully, the Hyper-V manager will just connect.

Now, for the problem I had, and as many details as feasible so the next person Googling for it will find this post.

The error that appeared was:

"Hyper-V encountered an error trying to access an object on computer 'LF-HV02' because the object was not found. The object might have been deleted. Verify that the Virtual Machine Management service on the computer is running".

Object not found error

I then investigated the event logs on the target system. In the WMI-Activity/Operational log, I found an error with event ID 5858, and result code 0x80041002:

Id = {8FA5E5DB-34E0-0001-31E6-A58FE034D401}; ClientMachine = WIN-QKHK3OGNV1V; User = WIN-QKHK3OGNV1V\Administrator; ClientProcessId = 2532; Component = Unknown; Operation = Start IWbemServices::GetObject - root\virtualization\v2 : Msvm_VirtualSystemManagementService.CreationClassName="Msvm_VirtualSystemManagementService",Name="vmms",SystemCreationClassName="Msvm_ComputerSystem",SystemName="LF-HV02"; ResultCode = 0x80041002; PossibleCause = Unknown


When poking around at the mentioned CIM object with Get-CimInstance -ClassName 'Msvm_VirtualSystemManagementService' -Namespace 'root\virtualization\v2', I found that the system name was some randomized name starting with WIN-. So, I renamed it to what it was supposed to be called with Rename-Computer, rebooted, and that fixed the issue.

Tags: hyper-v, Windows Server, PowerShell, Server 2019

Launching PowerShell using the Win32 API

I was working on a personal project in C on Windows when I stumbled upon a really strange roadblock: a PowerShell instance would not actually run the script given to it when started via Windows API but it would when launched manually from a cmd.exe.

Eventually the realisation came to me: PowerShell doesn't like the DETACHED_PROCESS option for CreateProcess(). I have no idea what it was doing with it there, but it didn't involve actually working.

I changed it to CREATE_NO_WINDOW and all is fine in the world.

Tags: windows, PowerShell, win32

Setting up DHCP on a DC with secure dynamic DNS

So, in my virtual homelabbing, I decided I was going to get a Windows based network set up with more or less only PowerShell. In these efforts, I discovered a pretty poor pile of documentation (such as this insanity where they tell you to create credentials with netsh, restart the service, then delete the credentials and restart again [optional step: wonder why it doesn't work]).

Here's how I set it up:

Create AD account:
# Get username and password for the new account (remember to include your domain!)
$cred = Get-Credential

# Create the user (it needs no special permissions)
New-ADUser -Enabled $true -SamAccountName $cred.UserName -AccountPassword $cred.Password
Make the DHCP server use it:
# Set the credentials for the DHCP server
Set-DhcpServerDnsCredential $cred

# Restart the DHCP Server
Restart-Service DhcpServer

You're set!


Also remember to set the DNS server to only allow secure updates!

Set-DnsServerPrimaryZone -DynamicUpdate Secure

Tags: PowerShell, Active Directory, dhcp, dns

General Network Error when running Install-ADDSForest

When I was messing about with AD DS a bit on Windows Server 2016 TP 2, I encountered the error General Network Error, with error ID 54. This is obviously a very unhelpful error. In troubleshooting, I noticed that the VM was being assigned an address in 169.254.x.x. This wasn't part of my intended IP range, so I started investigating.

It turns out that 169.254.x.x is a reserved range for APIPA (Automatic Private IP Addressing), where an operating system automatically assigns an IP when there is no DHCP available (which there wasn't because I intended to set up Windows DHCP). After disabling this, the AD setup worked correctly.

You may be wondering how to disable this problematic system. Here's how you do it (in PowerShell):

# Disable DHCP
Get-NetAdapter | Set-NetIPInterface -Dhcp Disabled
# Disable APIPA
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters' -Name IPAutoconfigurationEnabled -Value 0 -Type DWord
# Reboot to apply

Tags: PowerShell, Windows Server, Active Directory