March Patch Tuesday is Coming - the LDAP Changes will Change Your Life!

Published: 2020-02-12
Last Updated: 2020-02-13 01:21:56 UTC
by Rob VandenBrink (Version: 1)
2 comment(s)

Next month Microsoft will be changing the default behaviour for LDAP - Cleartext, unsigned LDAP queries against AD (over port 389) will be disabled by default -  .  You'll still be able to over-ride that using registry keys or group policy, but the best advice is to configure all LDAP clients to use encrypted, signed LDAPS queries (over port 636).

The problem here is that on many networks there have been many years of integrating printers, phone systems, time clocks, SIEMs, firewalls and all sorts of things into LDAP, using the default (unsigned, cleartext) port of 389.  The challenge many organizations face is that finding the last several years of LDAP configuration using that port will be difficult.

How is this do-able?  The easy way is to get AD to do the work for you.

First, enable logging of LDAP events, as described here:

In regedit, browse to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics

Set the value of "16 LDAP Interface Events" - any non-zero value will start logging of some type.  I set it to "3", which gives me sufficient logging for just finding the remote clients.

To set this quick on all DCs, store the following reg file and run it on each DC:

Windows Registry Editor Version 5.00

"16 LDAP Interface Events"=dword:00000003

Or, this script will make the reg change on all DCs for you:

$DomainName = (Get-ADDomain).DNSRoot
$AllDCs = Get-ADDomainController -Filter * -Server $DomainName | Select-Object Hostname,Ipv4address,isglobalcatalog,site,forest,operatingsystem

$regFile = @"
Windows Registry Editor Version 5.00

"16 LDAP Interface Events"=dword:00000003

ForEach ($DC in $AllDCS) {
    Invoke-Command -ComputerName $DC.hostname -ScriptBlock {param($regFile) $regFile | out-file $env:temp\a.reg;
    reg.exe import $env:temp\a.reg } -ArgumentList $regFile

Be sure that you make this change for all domain controllers!  Over the course of time, the DC that admins "prefer" will have likely drifted as servers are upgraded, new servers are installed and old ones are retired.  In a large complex network it's likely that many DC's are receiving LDAP queries from something or other.  If you miss the registry key or event collection from one DC, you are likely to miss any number of remote clients that only query that host.

Once this is done, let the LDAP events accumulate. 24 hours is usually sufficient, but depending on your environment you might want a longer interval.  Some LDAP queries only happen on login (vCenter and Linux come to mind for this), so you might want to login to various things if there's any question about how authentication works on those things.

Once we let things accumulate, we are looking for event ID 2889, which indicates a insecure LDAP query.  The message reads:

The following client performed a SASL (Negotiate/Kerberos/NTLM/Digest) LDAP bind without requesting signing (integrity verification), or performed a simple bind over a clear text (non-SSL/TLS-encrypted) LDAP connection.
Client IP address:
Identity the client attempted to authenticate as:
Binding Type:

After reading that message, my first thought (as it is so many times with Windows events) is - "that sounds serious - why isn't that message logged by default?". 

That being said, with several DCs and clients, collecting this info in a usable form can be a challenge.  The main thing we normally want to collect is the IP's of all of the clients making these queries, but the target DC and the userid being used can be useful as well.  For some reason, the log entries track the source port of each query, which is of course not of use to us, we'll want to filter that out.  Removing duplicate information is key in this - on a typical network we'll see hundreds or thousands of queries, but the goal is to distill this down to 10-15-20-ish unique IP addresses that we need to fix.

Putting all this together, and dropping the source port, then just collecting the information of interest, we have the script below.  Note that the $days variable should be set appropriately before you run this - for initial data collection, you'll want a larger value (maybe 5-7 days).  After you start remediation, you might want this set lower, maybe 1-2 days so that you can more easily verify that any client fixes are working as intended.

$reqlist = @()
# define the Event Log query, event id 2889 for the past "$days"
# if all entries are desired, remove StartTime and EndTime

$days = -2
$filter = @{
    Logname = 'Directory Service'
    ID = 2889
    StartTime =  [datetime]::now.AddDays($days)
    EndTime = [datetime]::now

# Get your ad information
$DomainName = (Get-ADDomain).DNSRoot
# Get all DC's in the Domain
$AllDCs = Get-ADDomainController -Filter * -Server $DomainName | Select-Object Hostname,Ipv4address,isglobalcatalog,site,forest,operatingsystem

foreach($DC in $AllDCs) {
    if (test-connection $DC.hostname -quiet) {
        # collect the events
        write-host "Collecting from server" $dc.hostname
        $events = Get-WinEvent -FilterHashtable $filter -ComputerName $DC.Hostname

        foreach ($event in $events) {
            $b = $[0].value
            $tempobj = [pscustomobject]@{
                TIME = $event.timecreated
                # use substr instead of ConvertFrom-String to account for IPv6 clients
                IP = $b.SubString(0,$b.LastIndexOf(":"))
                USERID = $[1].value
                DC = $DC.Hostname
            $reqlist += $tempobj
        else {write-host "ERROR - HOST " $DC.hostname " is not available" }

# now just collect unique addresses and userids
$clientips = $reqlist | select IP,USERID,DC | sort -property IP -unique
$clientips | out-gridview

Your output will look something like:

As always, modify this as needed - note that we're collecting the times the connections occurred in the $reqlist variable, as well as the server being queried, this info just isn't in the output.  This makes it easy to verify as remediation proceeds.

Note that you can cut/paste the $reqlist variable into excel to do any post-processing or further filtering that you might want (for instance - did the remediation I made 5 minutes ago work?)

Please - share what you find - use our comment form to let us know the oddest thing that you found that's using LDAP in your environment (NDA and classification permitting of course).  Even preparing for a life-altering patch is a good time to be doing discovery and recon on your own network!

Rob VandenBrink

Keywords: event log ldap ldaps
2 comment(s)
ISC Stormcast For Wednesday, February 12th 2020

Malpsam pushes Ursnif through Italian language Word docs

Published: 2020-02-12
Last Updated: 2020-02-12 00:12:13 UTC
by Brad Duncan (Version: 1)
0 comment(s)


For the past two weeks or so, I haven't found any malspam using password-protected zip archives with Word documents having macros for Ursnif.  However, on Tuesday 2020-02-11, malspam from this campaign has resumed.  This time, it used Italian language Word documents with macros for Ursnif.  @reecdeep started a Twitter thread with some of the details (link).

Shown above:  An infection chain from this campaign seen on Tuesday 2020-02-11.

Today's diary has a quick review of an infection from this campaign from Tuesday 2020-02-11.

Finding the associated Word documents

I searched VirusTotal Enterprise using the following criteria and found at least 66 password-protected zip archives containing the file info_02_11.doc from Tuesday 2020-02-11:

info_02_10.doc tag:zip fs:2020-02-10+

None of the associated emails had been submitted to VirusTotal, so I had to guess at the password.  Several of these zip archives used 111 as the password.  One of them used 222 as the password.  The example I used for an infection had 333 as the password.

Shown above:  Searching VirusTotal Enterprise for zip archives containing info_02_11.doc.

Shown above:  After a couple of guesses, I found the proper password for one of the zip archives from my VirusTotal search.

Shown above:  Word document extracted from the password-protected zip archive.

Infection traffic

Infection traffic was typical from what I've seen with this campaign.

Shown above:  Traffic from the infection filtered in Wireshark.

Indicators of Compromise (IoCs)

Traffic from an infected Windows host:

  • 194.61.2[.]16 port 80 - qr12s8ygy1[.]com - GET /khogpfyc8n/215z9urlgz.php?
  • port 443 - - HTTPS traffic (not inherently malicious)
  • 95.169.181[.]35 port 80 - lcdixieeoe[.]com - GET /images/[long string of characters].avi
  • 45.141.103[.]204 port 443 - q68jaydon3t[.]com - HTTPS/SSL/TLS traffic caused by Ursnif

Associated files:

SHA256 hash: 28931260f23f2b669be6bd26ddb7f93cf75b2c2790373a3a45a34b09fa9ef907

  • File size: 63,761 bytes
  • File name:
  • File description: Password-protected zip archive (password: 333)

SHA256 hash: 00d986b615d4082fe0ba0aa677b15eb97015f2b357ae87828be85b1e895e0d0b

  • File size: 70,429 bytes
  • File name: info_02_11.doc
  • File description: Word doc with macro for Ursnif

SHA256 hash: 4268d7a5f33d411ab4c4fae7363b21755ad9e576e2094df18f3615399945fd41

  • File size: 3,605 bytes
  • File location: C:\Windows\Temp\a6c9p.xsl
  • File description: XSL file dropped by Word macro

SHA256 hash: 996fcd8c55f923e86477d3d8069f9e9b56c6301cf9b2678c5c5c40bf6a636a5f

  • File size: 188,416 bytes
  • File location: hxxp://qr12s8ygy1[.]com/khogpfyc8n/215z9urlgz.php?
  • File location: C:\Windows\Temp\aVQl7d.dll
  • File description: Ursnif binary retrieved using XSL file

Final words

A pcap of the infection traffic along with the associated malware can be found here.


Brad Duncan
brad [at]

Keywords: malspam Ursnif
0 comment(s)


Diary Archives