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

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

Windows folder extremely slow to load

Due to some weirdness and presumably thumbnail rendering, if a folder is set to "Optimize for Pictures", it takes 10+ times as long as it should to load. This was happening for my Downloads folder. It seems to only apply when it's accessed through "This PC".

Anyway, to fix it, in the properties of the folder in question, under customize, change Optimize this folder for: to General Items and it will work much better.


Tags: windows, small-fixes