Get statistics from Direct Access server(s)

    • Context

During this COVID period, your Direct Access servers is a good nice-to-have solution for remoting.
However, there’s a limit on the maximum number of connexions it can handle.
You should keep an eye on this limit and get an idea of the current workload.
You may as well report these figures to your boss.

    • Issue

The RemoteAccess module provides a cmdlet to get statistics 🙂

Measure-Command {

As you can see, it’s damn slow. It took about 31 seconds to get the result 😦

    • Solution

You can actually use the WMI repository directly to get a result more quickly

$HT = @{
 Namespace = 'root/Microsoft/Windows/RemoteAccess/Server'
 ClassName = 'PS_RemoteAccessAccountingStatisticsSummary'
 MethodName = 'GetByActiveStatistics'
 ErrorAction = 'Stop'
(Invoke-CimMethod @HT).cmdletoutput

As you can see it takes a few milliseconds and not seconds to get the result 😎

If you wonder how I found this, here are the steps I followed:

# Identify the module and what type of command
gcm  Get-RemoteAccessConnectionStatisticsSummary
# Check the content of the function
gc Function:\Get-RemoteAccessConnectionStatisticsSummary
# Once you have identified the relevant Namespace
# You can list classes and their methods
gwmi -ns root/Microsoft/Windows/RemoteAccess/Server -List | ogv

# Once you've the Class, you can query the methods:
Get-CimClass -Namespace `
root/Microsoft/Windows/RemoteAccess/Server `
-ClassName PS_RemoteAccessAccountingStatisticsSummary | 
Select -expand CimClassMethods

Get a DeepBlue analysis

At RSA Conference 2020, in this video The 5 Most Dangerous New Attack Techniques and How to Counter Them, Ed Skoudis presented a way to look for log anomalies – DeepBlueCLI by Eric Conrad, et al. as one of the C2 (Command&Control) defenses available.

I forked the original version from the commit made in Christmas 2019.

My intent is to make the DeepBlueCli:

    • available as a PowerShell module contained in a single .psm1 file
    • expose a single function with many parameters (instead of editing the original .ps1 file to change them)
    • more aligned with what PowerShell can do and other PowerShell coding style standards

Of course, you should first start reading what the original DeepBlueCLI can do in its README

I found the Deepblue.ps1 script great for various reasons:

    • First, it can analyze a live running Windows computer. It reads by default the Security event log.
      However, it’s not scalable because it loads regular expressions used for analyzing commands content from its side regexes.txt file.
    • Sencondly, it can analyze an exported .evtx file either from the ‘Application’, ‘System’, ‘Security’, ‘Applocker’, ‘Sysmon’ or ‘PowerShell’ event logs. That makes it cross-platform. You can use the script on Linux computer running PowerShell 7 🙂
    • Third, it’s a very fast way to find out indicators of compromise. It will tell you if a new account has been added, how many times an account was used to log on, if there are suspicious well known commands…
    • Last but not least, Eric Conrad stores many sample .evtx files in his GH repo.

Let’s see it in action!

I launched a Windows 10 Pro 1809 VM in Azure and ran the following:

# Install PowerShell 7 (msi x64), click, click...
iex "& { $(irm } -UseMSI"
# Open PS7
saps pwsh

In the new PowerShell 7 console, I ran:

# Download
iwr '' -OutFile ~/downloads/ -Verbose
# Unzip
Expand-Archive ~/downloads/ ~/downloads/DeepBlue-master
cd  ~/downloads/DeepBlue-master/DeepBlue-master
# Verify
$HT = @{
    CatalogFilePath = "./"
    Path = "./"
    Detailed = $true
    FilesToSkip = ''
Test-FileCatalog @HT
Set-ExecutionPolicy RemoteSigned -Scope Process -Force -Verbose
# Import
Import-Module .\DeepBlue.psd1 -Force -Verbose
# Run the function

I also downloaded that the original DeepBlueCLI script and repo from Eric Conrad and ran the same commands to see the difference between my forked version and his:

NB: Notice the tab completion for the Log parameter in my version 😉

# Capture results in a variable
$r = Get-DeepBlueAnalysis -File `

# Just to get an idea of what DeeBlueCli is able to report:
$r | group  Results -noEl| ft -Wrap -AutoSize

# Show other sample events:
$r | ? Results -match 'Meterpreter' | select -First 1

Nice, isn’t it?

What’s next? If I get Eric Conrad’s approval, I’ll digitally sign my forked version named DeepBlue and push it to the PowerShell Gallery so that you can do:

# Either Save...
Find-Module -Name DeepBlue -Repository PSGallery
Save-Module -Name DeepBlue -Repository PSGallery -Path ~/Downloads

#...or Install
Install-Module -Name DeepBlue -Verbose -Repository PSGallery

If you want to see what I did since the fork, all the changes are available on this page 😎

Get more info about Edge Chromium

    • Context

If you go on, you can download and deploy the new Edge-Chromium

On this page, you’ve first to choose a channel/build from the first drop-down menu:

Then you’ve to choose for what platform, you need the binary:

And you can hit the download button and/or get the latest policies’ templates.

    • Problem

At work I’ve some requirements for maintaining browsers. I need to know when there’s an update available and what it fixes.
I’m already following what Google, Mozilla and Microsoft (for built-in Edge-Html and IE11) do but the new Edge-Chromium (aka ChrEdge) is another beast.

    • Solution

It appears that the source code of the page contains some JSON data used to build the above drop-down menu and help select the channel, build, platform to be downloaded.
This JSON data much more data than what appears in the GUI.

I’ve built some helper functions to extract and expose all this data from the blob that is JSON formatted in HTML .
It requires PowerShell 6.x or greater because the code uses the -AsHashtable switch from the ConvertFrom-Json cmdlet.
After this core function named Get-MSEdgeEnterpiseData used to extract the JSON blob and convert it back to real JSON data, I could build the following functions:

  1. Get-MSEdgeEnterpiseBuild to mimic what the first drop-down menu does,
  2. Get-MSEdgeEnterpisePlatform to mimic what the 2nd drop-down menu does,
  3. Get-MSEdgeEnterpiseDownloadInfo to enhance and add metadata about the artifacts to be downloaded
  4. Get-MSEdgeEnterpisePolicy to retrieve the info about policies templates files
  5. Get-MSEdgeEnterpiseEdgeUpdateInfo to return info about the Edge Updates (only present in the JSON blob and not exposed in the GUI)

All these functions can be found in the following gist named MSEdgeChromium.ps1

Let’s see it in action!

# Show the version of PowerShell

# Load the functions by dot-sourcing
. ~/Documents/MSEdgeChromium.ps1

# Show what the raw JSON looks like
 Get-MSEdgeEnterpiseData | fl *

# Show all the builds from the Dev and Stable channels
Get-MSEdgeEnterpiseBuild -Channel Stable,Dev

NB: Notice for example the ExpectedExpiryDate and PublishedTime properties that aren’t exposed in the HTML page.

# Show the first 2 builds from the Stable channel for the Windows x64 platform
Get-MSEdgeEnterpisePlatform -Channel Stable -Platform 'Windows x64'|
Select -Last 2

# Show only the latest version released
Get-MSEdgeEnterpisePlatform -Channel Stable -Platform 'Windows x64' -Latest

# Use the Get-MSEdgeEnterpiseDownloadInfo function to
# Add the metadata about the artifact to be downloaded
Get-MSEdgeEnterpisePlatform -Channel Stable -Latest |

# Get the latest policies file published and
# Use the Get-MSEdgeEnterpiseDownloadInfo function to
# Add the metadata about the artifact to be downloaded
Get-MSEdgeEnterpisePolicy -Latest |

# Get the latest Edge Update published and
# Use the Get-MSEdgeEnterpiseDownloadInfo function to
# Add the metadata about the artifact to be downloaded
Get-MSEdgeEnterpisePolicy -Latest |

NB: This channel named ‘Edge Update’ is hidden and not presented in the web page at all for the moment…

Bonus: Last but not least, if you work behind a proxy, you may want to add more proxy related parameters to the Invoke-WebRequest cmdlet like the -Proxy parameter on line 32 of MSEdgeChromium.ps1

About AutoRuns version 13.95

It’s long overdue, I’ve published on Sunday the version 13.95 of the Autoruns module.
You can find the digitally signed version on the PowerShell Gallery
I’ve written some release notes on GitHub as well on this page that highlights the changes and fixes in this release.
I won’t repeat the “basics” about how to install it that you can find on the main page of the project. I’d like here to focus on the main changes:

  • Support for user shell folders

The original Microsoft Autoruns.exe executable added

support for user Shell folders redirections

last year (see release notes).
The Autoruns module had a check in “$($env:AppData)\Microsoft\Windows\Start Menu\Programs\Startup” assuming that both Startup value in the User Shell folders and Shell folders registry key haven’t been hijacked.
The other issue with that code was that it was still not compatible with the -User parameter introduced in version 13.90.1
I also fixed a third issue. When there’s a file located in these folders, it’s found even if its hidden attribute is set. I simply added a -Force switch to the Get-ChildItem cmdlet.

Get-PSAutorun -Logon | Where Path -match 'Shell\sFolders'

It displays the non expanded value of the Startup value under the ‘User Shell folders’. This value is expanded in this ‘Shell folders’ key. The code checks what’s in this path.
If it’s an executable, it shows this file and if it’s a shortcut, it follows it and displays its target.

Here’s what the original Autoruns shows when there are files in the location:

Here’s what the Autoruns PowerShell modules shows:

  • New -Raw parameter

As described in issue #56, the main idea is the avoid manipulating and trying to prettify found artifacts. The -Raw parameter aims at displaying artifacts “untouched”.
It’s therefore incompatible with the -ShowFileHash and -VerifyDigitalSignature parameters. That’s why there’s a 2nd parameterset added to the main function to handle this incompatibility.

Let’s see it in action:

Get-PSAutorun -Raw | ogv -PassThru 

Here’s a sample output of scheduled tasks

Here’s a sample output of drivers and services

  • New -PSProfiles parameter

This is what I merged from the experimental branch. PowerShell profiles can used in offensive or defensive way.

PowerShell profiles are currently not considered as a persistence mechanism by the original Autoruns.exe from Microsoft although they should.

PowerShell profiles can be used a persistence mechanism. It’s has demonstrated here.

PowerShell profiles have been used a persistence technique by the Turla group and PowerShell profiles is an attack technique listed in the MITRE matrix.

Get-PSAutorun -PSProfiles

NB:What the Get-PSAutorun function displays may not be exhaustive because it depends on the host. The Visual Studio Code (VSCode) host is not handled currently for example and will not in the output. (See more about_profiles)

Adding some Pester tests to Autoruns module

I’ve been working with Pester for a while and I thought it would be nice to have some Pester tests in the Autoruns module.

I don’t have very high expectations and thought I’d start with some tests to validate that previous issues encountered are still fixed and keep being remediated.

While writing these tests, I encountered two challenges.

  • First challenge

The first one is that the module exports a single function and there are many functions in the begin block of this exported function.
I needed to find a solution to be able to test anything in the code whatever the function.
I decided to use the Abstract Syntax Tree (a.k.a AST) to extract every function and inject them in a fake module. In other words the function tree in the original module would be flatten in this fake module.
This way I can use the InModuleScope and test anything I want.

Here’s the only exported function from the original Autoruns module:

Here are the inner functions extracted from the original module and loaded in the FakeAutoRuns module:

Here’s the code that extracts the functions and loads them in a flat (fake) module:

  • The 2nd challenge

The 2nd challenge was that I needed to mock some calls made to a .Net method.

I needed to mock the Test-Path, Get-Item cmdlets and especially the call to the method named GetSubKeyNames on the Microsoft.Win32.RegistryKey objects returned by the Get-Item cmdlet in the following example:

Here’s what I did to mock these cmdlets and their invocation of a .Net method

I feel that the learning curve is steep with Pester. If you know a better way to write Pester tests for this issue #26, please tell me, your input is more than welcome.

What to do after patching CVE-2020-0601

The FAQ section of CVE-2020-0601 includes the following:

How can I tell is someone is attempting to use a forged certificate to exploit this vulnerability?

NB: Once patched, events are generated after a reboot.

It appears you can also rely on Windows Defender to answer this question: exploit attempts are detected as Exploit:Win32/CVE-2020-0601.A and Exploit:Win32/CVE-2020-0601.B

    • Is my system patched against CVE-2020-0601 exploits?
# Updated against CVE-2020-0601 exploits?
if ($updated =Get-Item C:\Windows\System32\crypt32.dll |
Select-String '\[CVE-2020-0601\]' -Encoding unicode) {
 'Already Updated against CVE-2020-0601'
} else {
 'Protection against CVE-2020-0601 missing'

If your system is patched, you get:

If it’s not, you get:

    • Any exploit attempt detected?

There’s a provider named Microsoft-Windows-Audit-CVE that can generate 2 events:

# What kind of events we get from this provider
(Get-WinEvent -ListProvider 'Microsoft-Windows-Audit-CVE').Events

Once patched, you could know if an attempt to exploit this CVE has been made

# Anything that would require investigation
$HT = @{
 FilterHashTable = @{ProviderName ='Microsoft-Windows-Audit-CVE'}
 ErrorAction = 'SilentlyContinue'
 Verbose = [switch]::Present
if ($events = Get-WinEvent @HT) {
} else {
 'No CVE exploit detected'

# Display more properties
if ($events) {
 $events | 
 Select -Property * -Exclude MachineName,UserId

NB: The above query allows to find both events id 1 and 2 from the Application and System log.

There no known attempt to exploit it yet, according to this MSRC blog post.

This vulnerability is classed Important and we have not seen it used in active attacks.

Let’s say that there’s an exploit in the wild.
You can follow this guide to analyze the para field of Audit-CVE event ID 1 (mentioned in the FAQ of CVE-2020-0601):

Credit: Matt Graeber

Other links:

Quick post: find users who have an Exchange Online mailbox

If you have a hybrid Exchange infrastructure, it appears that you can query your local Active Directory to find out users who have already been migrated to Exchange Online.

Thanks to the attribute named msExchRecipientTypeDetails (values detailed here), you can find these accounts with a remote mailbox.

Here’s a small function that leverages this msExchRecipientTypeDetails attribute:

You can even bind cmdlets like this for example:

Get-RemoteUserMailbox  |
Get-ADUser -Properties AccountExpirationDate | 

Nice, isn’t it? 😀