Analyzing ShinobuClipper


2023-05-20

I’m aware the malware’s name is a reference to Shinobu Kocho from Demon Slayer but I don’t watch mid anime.

While looking at the configs extracted by the ClipBanker pipeline I noticed something odd, the newest sample hadn’t been extracted correctly. And for good reason, it’s from a different family! In this blog post, we’ll analyse the new sample, write a yara rule and write a config extractor.

TL;DR

It’s a shit-tier open-source .NET clipboard hijacker, who would have thought ?

IOCS

Updated as of 23/05/2023.

SHA256(crack.exe):
b3743ecc2d4300e02d09cb45ca5310f0165e17199f24709bf3ac211aa003ed1e

Path:
C:\Users\user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\Clipper.exe

Pdb:
C:\Users\j0k3r\Downloads\Compressed\crypto-clipper-main\crypto-clipper-main\Clipper\obj\Release\Clipper.pdb

Mutex:
sdh34yszdfgb

Crypto addresses:
- BTC:
16LYjmErwNek2gMQkNrkLm2i1QVhjmxSRo
- ETH:
0xdF0f41d46Dd8Be583F9a69b4a85A600C8Af7f4Ad
- XMR:
42KwLVv18KiFRZNHzuYNocRrrGdnGbPYAGDT9oHzwh6sMk1f53SVNN26X877au2DPq73BGzLAz9VSbkdBdMPjvtn68qd4CP
- Stellar:
GBHLCKFUEXV2P4AFDNR6QMG7NC4GIJTIE7KDWGC2QX32T45V5KMXK3SV
- Ripple:
rj1eZxZbEJbYNuDTQd9kbaXs8WVpiEai1
- Litecoin:
LQDJ9142kMAPZmS6vZqRb2ty1r85t8nABG
- Nectar:
AT1Lp7MWN2X9HbxpNpsjvRdd978oS8ceGv
- Bitcoin Cash:
qpmd7ghltpdjm0n0vm534s7rjre2lh5ehsqcss3na4
- Dash:
XytymtGjkJJpUGsUjQgpNYumcWV9cT2SQA

Analyzing the clipper

Since it’s open-source the analysis won’t be very detailed. The clipper’s not much to write home about anyway, it hasn’t been obfuscated and the function names describe exactly what it does.

  1. Exit if mutex exists, if it doesn’t create it
  2. Install persistently (in the startup folder) the clipper if it isn’t already
  3. Hide file
  4. Set file to “system”
  5. Run the clipboard monitor

The clipboard monitor checks for changes in the clipboard regularly and replaces strings matching different cryptocurrency (BTC, XMR, XLM, ETH, XRP, LTC, BCH, NEC and DASH) address patterns. Threads are used to get/set the content of the clipboard.

The config is stored in plaintext in a dedicated class so writing a config extractor won’t be very hard.

Yara rule

rule shinobuclipper {
        meta:
                description = "Rule for ShinobuClipper"
                author      = "yarienkiva"
                date        = "2023-04-23"
                reference   = "https://heartathack.club/blog/shinobu-clipper"

        strings:
                $s1 = "Clipper"                 ascii fullword
                $s2 = "clipboard_changed"       ascii fullword

                $t1 = "AppMutex"                ascii fullword
                $t2 = "Attributes"              ascii fullword
                $t3 = "Autorun"                 ascii fullword
                $t4 = "Clipboard"               ascii fullword
                $t5 = "ClipboardMonitor"        ascii fullword
                $t6 = "RegexPatterns"           ascii fullword

                // config
                $c1 = "btc"                     wide fullword
                $c2 = "xmr"                     wide fullword
                $c3 = "xrp"                     wide fullword
                $c4 = "ltc"                     wide fullword
                $c5 = "neo"                     wide fullword
                $c6 = "bch"                     wide fullword
                $c7 = "dash"                    wide fullword

                $c8  = "autorun_enabled"        ascii fullword
                $c9  = "autorun_name"           ascii fullword
                $c10 = "clipboard_check_delay"  ascii fullword
                $c11 = "mutex"                  ascii fullword

        condition:
                uint16(0) == 0x5a4d
                and filesize < 20KB
                and all of them
}

Config extractor

Since the config is stored in plaintext in a dedicated class, if we had a way to dump the .cctor to a JSON object writing a config extractor would be trivial. I couldn’t find any references to this online so I made my own.

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;

namespace CCTOR_Dumper
{
    class Program
    {
        /// <summary>
        /// Extracts the payload from the .cctor of CONF_CLASS
        /// The config of the loader is printed to the console.
        /// </summary>
        /// <param name="file"></param>
        static void HandleFile(string file)
        {
            Console.Error.WriteLine("Processing, " + file);

            // Load the file
            Assembly assembly = Assembly.LoadFile(file);

            var conf_class = Environment.GetEnvironmentVariable("CONF_CLASS");
            
            if (conf_class == null)
                return;

            Type type = assembly.GetType(conf_class);

            if (type == null)
                return;

            var config = new Dictionary<string, object>();

            // For each field in the class constructor, add
            // it and its value to the config dictionary
            foreach (var field in type.GetFields())
                config.Add(field.Name, field.GetValue(null));

            string json = JsonSerializer.Serialize(config);

            Console.WriteLine(json);
        }

        /// <summary>
        /// Config extractor for ShinobuClipper but this can 
        /// be easily adapted to anything
        /// author: yarienkiva
        /// </summary>
        static void Main(string[] args)
        {
            foreach (string file in args) 
            {
                HandleFile(file);
            }
            Console.Error.WriteLine("Done!");
        }
    }
}

The program can be called with a quick and dirty Python wrapper.

#!/usr/bin/env python3

from os.path import abspath, expanduser
import subprocess
import json
import sys

print('ShinobuClipper config extractor - @yarienkiva', file=sys.stderr)

if len(sys.argv) == 1:
	print(f'{__file__} [sample1] [sample2] ... [sampleN]', file=sys.stderr)

for sample in sys.argv[1:]:
	path = abspath(expanduser(sample))
	print(subprocess.check_output(['dotnet', 'run', path]).decode())

"""
$ export CONF_CLASS=Clipper.config
$ python3 main.py ~/Downloads/airlock/new_clipper_owo.exe |jq
ShinobuClipper config extractor - @yarienkiva
Processing, /home/alol/Downloads/airlock/new_clipper_owo.exe
Done!
{
  "autorun_enabled": true,
  "autorun_name": "Clipper",
  "attribute_hidden": false,
  "attribute_system": true,
  "clipboard_check_delay": 1,
  "addresses": {
    "btc": "16LYjmErwNek2gMQkNrkLm2i1QVhjmxSRo",
    "eth": "0xdF0f41d46Dd8Be583F9a69b4a85A600C8Af7f4Ad",
    "xmr": "42KwLVv18KiFRZNHzuYNocRrrGdnGbPYAGDT9oHzwh6sMk1f53SVNN26X877au2DPq73BGzLAz9VSbkdBdMPjvtn68qd4CP",
    "xlm": "GBHLCKFUEXV2P4AFDNR6QMG7NC4GIJTIE7KDWGC2QX32T45V5KMXK3SV",
    "xrp": "rj1eZxZbEJbYNuDTQd9kbaXs8WVpiEai1",
    "ltc": "LQDJ9142kMAPZmS6vZqRb2ty1r85t8nABG",
    "nec": "AT1Lp7MWN2X9HbxpNpsjvRdd978oS8ceGv",
    "bch": "qpmd7ghltpdjm0n0vm534s7rjre2lh5ehsqcss3na4",
    "dash": "XytymtGjkJJpUGsUjQgpNYumcWV9cT2SQA"
  },
  "mutex": "sdh34yszdfgb"
}
"""