It's Turtles All The Way Down
2023-11-30 08:0:0 Author: objective-see.org(查看原文) 阅读量:5 收藏

It's Turtles All The Way Down 🐢

Analyzing the newly discovered "Turtle" ransomware

by: Patrick Wardle / November 30, 2023

Objective-See's research, tools, and writing, are supported by the "Friends of Objective-See" such as:


📝 👾 Want to play along?

As “Sharing is Caring” I’ve uploaded the malicious binaries Turtle.zip to our public macOS malware collection. The password is: infect3d

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


Background

A few years ago, @jacse mused that maybe turtles are the secret to avoiding ransomware. And while that may have been true in the past, today it appears that turtles instead may in fact be ransomware harbingers 😂

How Turtles are the secret to avoiding ransomware

— Jon Sawyer (@jcase) November 21, 2021

Yesterday (Nov 29th), Austin pinged me about a possible new ransomware specimen that was targeting macOS.

Found sample on VT 91a5faa41d19090e1c5c1016254fd22a - [possible] Mac ransomware. ...Couldn't find much on it so wondering your thoughts if you have time! -Austin

…thanks Austin! 🙏🏽

If we pop over to VirusTotal and search for a file with the hash 91a5faa41d19090e1c5c1016254fd22a, we find the sample:

Possible Ransomware on VirusTotal

Though uploaded just two days ago, 24 of the anti-virus engine are already flagging it as malicious. This is unusual, as generally new malware takes a while to get picked up by such engines. However, as we can see in the above screenshot, crowdsource YARA rules flag is on Windows APIs. Also the names the AV engines have assigned the malicious binary are rather vague such as “Other:Malware-gen”, “Trojan.Generic”, or “Possible Threat”. Others flag it as Windows malware (“Win32.Troj.Undef”). At first blush, yes kind of strange, but if you keep reading, you’ll see this actually all makes sense!

One AV engine, Rising, detects it as "Ransom.Turtle"
...we'll see shortly this is the internal name of the ransomware.

One of the neat features of VirusTotal is the ability to map out relationships. Using this, we find the sample came from a zip file, named “TR.zip”. This was also uploaded to VirusTotal (5 days ago):

TR.zip

…a lot of times, we see malware first developed for more popular platforms such as Windows, then ported to macOS. Perhaps (also recalling the YARA hit on Windows APIs), this is why there are already so many AV detections even for the macOS variant).

If we download the archive and unzip it, we find it contains files (prefixed with “TurtleRansom”) that appear to be compiled for common platforms, including, Windows, Linux, and yes, macOS:

Platform-specific binaries

Using macOS’s file utility, can confirm this:

% file TR/TurtleRansom-v0-windows-arm64.exe 
TR/TurtleRansom-v0-windows-arm64.exe: PE32+ executable Aarch64, for MS Windows

% file TR/TurtleRansom-v0-macos-arm64.pkg 
TR/TurtleRansom-v0-macos-arm64.pkg: Mach-O 64-bit executable arm64

% file TR/TurtleRansom-v0-macos-amd64-softfloat.pkg 
TR/TurtleRansom-v0-macos-amd64-softfloat.pkg: Mach-O 64-bit executable x86_64

Noting that the macOS .pkg files are not packages, but simple Mach-O executables, one compiled for Intel and one for Arm (aka Apple Silicon).

For the remainder of this analysis, we’ll focus on the Arm build ("TurtleRansom-v0-macos-arm64.pkg").

Triage

First, let’s see if its signed (and notarized?) using macOS’ codesign utility:

% codesign -dvv TR/TurtleRansom-v0-macos-arm64.pkg 
TR/TurtleRansom-v0-macos-arm64.pkg
Identifier=a.out
Format=Mach-O thin (arm64)
CodeDirectory v=20400 size=16446 flags=0x20002(adhoc,linker-signed) hashes=511+0 location=embedded
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements=none

Though it is signed so it can run on macOS, its only signed adhoc (and not notarized). This means Gatekeeper should block it (unless the user explicitly allows it to run, or it is deployed via some exploit).

Next let’s extract any embedded strings (via the aptly named strings utility), as such strings can often give us a sense of capabilities and guide continued analysis efforts.


% strings - TR/TurtleRansom-v0-macos-arm64.pkg

? Go build ID: "JZS5wyJGq5YWpqV3jo6B/mrrrnHE8O7C4AIP5rWHa/Jwu16Tp63gAWq6z_ByO1/eBbE7TLPTZlqPRrSlUyz"

TURTLERANSv0
D:/VirTest/TurmiRansom/main.go
...
_main..inittask
_main.en0cr0yp0tFile
_main.main
_main.main.func1
...

.doc
.docx
.txt
...

_crypto.init
_crypto/aes.(*KeySizeError).Error
_crypto/aes.(*aesCipher).BlockSize
_crypto/aes.(*aesCipher).Encrypt
_crypto/aes.(*aesCipherAsm).BlockSize
_crypto/aes.(*aesCipherAsm).Encrypt
_crypto/aes.(*aesCipherGCM).BlockSize
_crypto/aes.(*aesCipherGCM).Encrypt
_crypto/aes..inittask
_crypto/aes.KeySizeError.Error
_crypto/aes.NewCipher
...

syscall.init
syscall.Getwd
syscall.Open
syscall.read
syscall.readdir_r
syscall.Rename
syscall.Seek
syscall.write
syscall.execve
...

The binary doesn’t appear to obfuscate any of its strings, hence there are strings a plenty. Some of the ones I’ve included confirm the malware was written in Go, and internally referred to as “TURTLERANS” (aka “Turtle Ransomware”) or “TurmiRansom”. We also see a function named en0cr0yp0tFile and references to target file extensions (e.g. .docx), cryptographic routines and file I/O.

Though the strings command doesn’t support UTF-8 string, we find (for example in a disassembler that does support such strings), various strings in Chinese also related to ransomware operations, such as “加密文件” which translate to “Encrypt files”.

At this point, all signs point to well, yes, ransomware. Let’s now dive in deeper to see how the ransomware goes about encrypting files.

Analysis

In the strings output we saw a method named: main.en0cr0yp0tFile.

When analyzing binaries written in Go, you usually find the interesting logic (written by the malware author, vs just some linked in 3rd-party library) in the main.* routines.

Let’s take a look at the disassembly of the en0cr0yp0tFile function …focusing on the library/API calls it makes:

main.en0cr0yp0tFile:

   ...
   0x0000000100095e04         bl         _os.ReadFile                              

   ...
   0x0000000100095e24         bl         _crypto/aes.NewCipher

   ...
   0x0000000100095e5c         bl         _crypto/cipher.NewCTR

   ...
   0x0000000100095ec4         bl         _runtime.concatstring2

   ...
   0x0000000100095ee4         bl         _os.rename            

   ...
   0x0000000100095f08         bl         _os.WriteFile         

   ...
   0x0000000100095f18         ret
                        

Pretty easy to see given a file, it reads it into memory, encrypts it with AES (in CTR mode), renames the file, then overwrites the file’s original contents with the encrypted data. Pretty standard ransomware logic.

The en0cr0yp0tFile function is invoked by the main.func1. This function is called for each file in the malware’s working directory. (File enumerating is done via a call to the path_filepath_Walk function). However, it does not encrypt all files …only those matching the extensions .doc, .docx, or .txt (recall, we saw these as embedded strings):


0x0000000100096761         db  0x2e ; '.'                                    
0x0000000100096762         db  0x74 ; 't'
0x0000000100096763         db  0x78 ; 'x'
0x0000000100096764         db  0x74 ; 't'

...                        
0x0000000100096128         add        x1, x1, #0x761     ; 0x100096761 (".txt")
0x000000010009612c         orr        x2, xzr, #0x4
0x0000000100096130         bl         runtime.memequal                         

Let’s now hop into a virtual machine and execute the ransomware in a directory containing documents and text files. If we run file monitor at the same time, we can observe the ransomware in action:


# FileMonitor.app/Contents/MacOS/FileMonitor -pretty -filter TurtleRansom-v0-macos-arm64.pkg

{
  "event" : "ES_EVENT_TYPE_NOTIFY_OPEN",
  "file" : {
    "destination" : "/Users/user/Desktop/TR/file.docx",
    "process" : {
      "path" : "/Users/user/Desktop/TR/TurtleRansom-v0-macos-arm64.pkg",
      "name" : "TurtleRansom-v0-macos-arm64.pkg",
      "pid" : 938
    }
  }
}

{
  "event" : "ES_EVENT_TYPE_NOTIFY_RENAME",
  "file" : {
    "source" : "/Users/user/Desktop/TR/file.docx",
    "destination" : "/Users/user/Desktop/TR/file.docx.TURTLERANSv0",
    "process" : {
      "path" : "/Users/user/Desktop/TR/TurtleRansom-v0-macos-arm64.pkg",
      "name" : "TurtleRansom-v0-macos-arm64.pkg",
      "pid" : 938
    }
  }
}

{
  "event" : "ES_EVENT_TYPE_NOTIFY_WRITE",
  "file" : {
    "destination" : "/Users/user/Desktop/TR/file.docx.TURTLERANSv0",
    "process" : {
      "path" : "/Users/user/Desktop/TR/TurtleRansom-v0-macos-arm64.pkg",
      "name" : "TurtleRansom-v0-macos-arm64.pkg",
      "pid" : 938
    }
  }
}

Note that the encrypted files are suffixed with the hardcoded extension “TURTLERANSv0”.

Decryption

Can we decrypt files encrypted by the ransomware? 🤔 Good question!

Recall the encryption is done via Go’s crypto/AES library. If we set a breakpoint on the call to the aes.NewCipher function, which takes as its only argument a key, we should be able to recover the symmetrical encryption/decryption key:

% lldb TurtleRansom-v0-macos-arm64.pkg
...

(lldb) b 0x100095e24
Breakpoint 11: where = TurtleRansom-v0-macos-arm64.pkg`main.en0cr0yp0tFile + 84, address = 0x0000000100095e24

(lldb) c

Process 1002 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 11.1
  frame #0: 0x0000000100095e24 TurtleRansom-v0-macos-arm64.pkg`main.en0cr0yp0tFile + 84

TurtleRansom-v0-macos-arm64.pkg`main.en0cr0yp0tFile:
->  0x100095e24 <+84>: bl     0x100074c70               ; crypto/aes.NewCipher
    
(lldb) x/s $x0
0x14000106cb0: "wugui123wugui123"

Once the breakpoint is hit, we print out the first argument (found in the x0 register). It contains the value, “wugui123wugui123”, which is ransomware’s key.

ChatGPT says, “‘Wugui’ (乌龟) in Chinese translates to “turtle” or “tortoise” in English.

Back in the disassembly, we can see that address 0x100098545 is passed to the en0cr0yp0tFile function:


0x00000001000961c0         adrp       x5, #0x100098000          ; 0x100098545@PAGE
0x00000001000961c4         add        x5, x5, #0x545            ; 0x100098545@PAGEOFF, 0x100098545
0x00000001000961c8         ldp        x5, x6, [x5]                              
0x00000001000961cc         stp        x5, x6, [sp, #0x50]
...
0x00000001000961e4         bl         main.en0cr0yp0tFile                      

And if we go to the address 0x100098545 we found that this holds the (hard-coded) key “wugui123wugui123”:


0x0000000100098545         db  0x77 ; 'w'                     ; DATA XREF=_main.main.func1+292
0x0000000100098546         db  0x75 ; 'u'
0x0000000100098547         db  0x67 ; 'g'
0x0000000100098548         db  0x75 ; 'u'
0x0000000100098549         db  0x69 ; 'i'
0x000000010009854a         db  0x31 ; '1'
0x000000010009854b         db  0x32 ; '2'
0x000000010009854c         db  0x33 ; '3'
0x000000010009854d         db  0x77 ; 'w'
0x000000010009854e         db  0x75 ; 'u'
0x000000010009854f         db  0x67 ; 'g'
0x0000000100098550         db  0x75 ; 'u'
0x0000000100098551         db  0x69 ; 'i'
0x0000000100098552         db  0x31 ; '1'
0x0000000100098553         db  0x32 ; '2'
0x0000000100098554         db  0x33 ; '3'

As AES is symmetrical and here the key is hard-coded, its trivial for us to write a decryptor:

import sys
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

def decryptTurtle(key, iv):
    
    with open(sys.argv[1], 'rb') as file:
        ciphertext = file.read()

    cipher = Cipher(algorithms.AES(key.encode('utf-8')), modes.CTR(iv), backend=default_backend())
    decryptor = cipher.decryptor()

    plainText = decryptor.update(ciphertext) + decryptor.finalize()

    print(plainText)
    
iv = b'\x00' * 16
key = "wugui123wugui123"

decryptTurtle(key, iv)

Thanks to Ema 🇱🇹 for helping write the decryptor

Now, if we create a file with any content, run the ransomware so that it encrypts the file, then pass the now encrypted file to our decryptor it is able to fully decrypt and recover the orginal contents:

% echo "The quick brown fox jumps over the lazy dog" > test.txt

% ./TurtleRansom-v0-macos-arm64.pkg
加密文件 /Users/user/Desktop/TR/test.txt 成功

% python3 turtle.py test.txt.TURTLERANSv0
b'The quick brown fox jumps over the lazy dog\n'

Hooray! 🥳

Detection

Of course it goes without saying, having your files ransomed sucks! But good news, in this case the average macOS user is unlikely to be impacted by this macOS sample. Still the fact that ransomware authors have set their sights on macOS, should give us pause for concern and also catalyze conversions about detecting and preventing this (and future) samples in the first place!

First, Apple has been fairly proactive about mitigating ransomware attacks on macOS (and maybe this is why we’ve yet seen a major ransomware outbreak on macOS). So, kudos to Cupertino. Specifically Apple has implemented SIP (and now read-only system volumes) to protect OS-level files. This means even if ransomware finds its way onto a macOS system it won’t (easily) be able to mess with core OS files. Apple has also added (TCC) protections to user files founds in (now) protected directories such as ~/Desktop, ~/Documents, etc. etc. This means, that without an exploit or explicit user-approval users files will remain protected. (Though TCC is pretty easy to bypass …or worse case you just ask the user, and they’ll likely acquiesce).

Still an additional layer or detection/protection may be warranted, especially as we’ve all probably inadvertently clicked “Allow” on access prompts, while even Apple has been known to notarize malware.

If we stop to think specifically about ransomware, in theory, it should be trivial to detect (at least in most cases). Why? Simply put, ransomware’s actions provide us with a powerful detection heuristic.

In April 2016 (yes, wayyyy back then!) I posted a blog titled, “Towards Generic Ransomware Detection”. In this post, I mused,

“If we can monitor file I/O events and detect the rapid creation of encrypted files by untrusted processes, then ransomware may be generically detected” -(a younger) Patrick Wardle

To back this up, I released a free (and now open-source) tool called “RansomWhere?” that implemented this heuristic-based approach. Specifically it monitors file I/O events and for newly created files asks:

  1. Is the process creating file untrusted (e.g. not an Apple platform binary)?
  2. Is created file encrypted?
  3. Is the (untrusted) process rapidly creating several encrypted files?

If these are all true, “RansomWhere?” will suspend the process as its likely ransomware and alert the user and handle the response (resume/terminate).

As with any detection approach and security tool, there are limitations. I've aimed to clearly articulate these in "RansomWhere?"'s tool page:

RansomWhere?'s Limitations

Most notably, “RansomWhere?” is slightly reactive, meaning several files maybe be encrypted (and thus ransomed) before the tool detects and blocks the ransomware.

And though “RansomWhere?” is a bit dated, it appears to be able to generically detect the actions of Turtle Ransomware and thus thwart it …even though it had no a priori knowledge of this malware:

RansomWhere? ...doing it's thing!

Hooray! Free, open-source tools FTW! 🥳

Does your EDR product provide generic ransomware detection!? 🤔

Conclusion

Today we dove into a new ransomware sample, internally dubbed “Turtle”. And while in its current state it does not post much of a threat to macOS users, it yet again, shows that ransomware authors continue to set their sites on macOS.

Interested in learning more Mac Malware Analysis Techniques?

You're in luck, as I've written a book on this topic! It's 100% free online while all royalties from sale of the printed version donated to the Objective-See Foundation.
The Art Of Mac Malware, Vol. 0x1: Analysis
   
Or, come attend our macOS security conference, "Objective by the Sea" v6.0 in sunny Spain! ...where I'm teaching a class on Mac Malware Detection & Analysis
Sign up for the The Art of Mac Malware training.
❤️ Love these blog posts and/or want to support my research and tools?

You can support them via my Patreon page!


文章来源: https://objective-see.org/blog/blog_0x76.html
如有侵权请联系:admin#unsafe.sh