ClipBanker.3 Writing a yara rule


2023-02-16

While preparing the 4th blog post, I realized I needed a way to differentiate the generic clipper from other malware. The obvious solution was to use a ‘yara rule’.

“YARA is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns.”

https://virustotal.github.io/yara/

Yara rules can be classified into two categories: string-based and binary/code-based. String-based yara rules use strings found inside the sample and have the advantage of being fast to write but less resilient to change. On the flip side, code-based rules rely on the actual semantics of the program (ie. the assembly instructions) so they’re harder to write but can be far more fine-grained and resilient (changing a string is easy, modifying a program’s logic is hard).

The right balance has to be found in the “strictness” of the yara rule: if the rule is too rigid we might miss out on variations from the same family but if the rule is too lax it will have a high false positive rate.

Handmade rule

Examining two different ClipBanker samples shows that they are almost identical, the only differences being (a part of) the sample’s configs (0x3740 through 0x38bf) and their TimeDateStamp (0x88 through 0x8b).

$ ssdeep -d crack.exe.{1,2}
/samples/crack.exe.2 matches /samples/crack.exe.1 (94)

$ colordiff -y --suppress-common-lines <(xxd crack.exe.1) <(xxd crack.exe.2)
00000080: 5045 0000 4c01 0300 0b88 8163 0000 0000  PE..L..... | 00000080: 5045 0000 4c01 0300 ce77 cb63 0000 0000  PE..L....w
00003740: 6500 0055 3000 7800 3900 6500 3600 3000  e..U0.x.9. | 00003740: 6500 0055 3000 7800 6400 4600 3000 6600  e..U0.x.d.
# [...] cut for readability
000038b0: 0033 0068 005a 0079 0037 0032 0045 0039  .3.h.Z.y.7 | 000038b0: 0056 0068 006a 006d 0078 0053 0052 006f  .V.h.j.m.x

# 0x6381880B -> [Sat Nov 26 03:29:15 2022 UTC]
# 0x63CB77CE -> [Sat Jan 21 05:27:42 2023 UTC]

The sample’s config, documented in the previous blog post, seems to be a good target for a string-based yara rule. IMHO it’s an OK compromise, the rule isn’t too strict but it has most of the key strings that aren’t likely to change. However, if you think it’s terrible please tell me on twitter.

rule clipbanker {
   meta:
      description = "This rule detects the clipbanker bundled with leaked software from BHR"
      author      = "yarienkiva"
      date        = "2023-02-16"
      reference   = "https://heartathack.club/blog/analyzing-clipbanker"

   strings:
      $m1 = ".NET Framework"             ascii fullword
      $m2 = "AddClipboardFormatListener" ascii fullword
      $m3 = "ClipboardNotification"      ascii fullword

      // config

      $c1 = "Mutexx"    ascii fullword
      $c2 = "startup"   ascii fullword
      $c3 = "url"       ascii fullword

      $c4 = "ethereumE" ascii fullword
      $c5 = "xmrE"      ascii fullword
      $c6 = "btcE"      ascii fullword

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

Tool-assisted rule

Even though it won’t be as good as a handcrafted rule, I still wanted to try out automatically (programmatically) generating rules. For this, we’ll use yarGen by Florian Roth (the great God of Yara Rules).


// Install:
// 	git clone https://github.com/Neo23x0/yarGen
// 	cd yarGen && pip3 install -r requirements.txt && chmod +x yarGen.py
// 	./yarGen.py --update
// 	./yarGen.py --opcodes -m /path/to/samples/

// Far from perfect but not too bad
rule _c3a6f41b0991f67f2a9cb77abea87ee06fb8e5c0f6db9b1ce6bc833dbe45c96c_0a1a408b104d16cc870b9064b3357ca0af01c371ec857f4f23a644e8af_0 {
   meta:
      description = "samples - from files c3a6f41b0991f67f2a9cb77abea87ee06fb8e5c0f6db9b1ce6bc833dbe45c96c.exe, 0a1a408b104d16cc870b9064b3357ca0af01c371ec857f4f23a644e8af849dfb.exe, b38006408e2229c1c23c56e4efba5df476d7ee13931ec7766cb6940b1b397679.exe, b4b1dd5fc206b0089ca1e7d613d6475a9a06bbcf4c207830d7c0cf02a94ae79a.exe, a9f1bd2ec79646bce488a69a3809de067415d434e6269721dd0d4ad568992871.exe, e3cb33466bed760b23a24bd723b68ccb5da82ee350793f4cde7aa5ad53541b94.exe, 1bf7585f2020daa5ede6f77cacc1a4c80c4359ca101939e267ecd9cfbca5b4f8.exe, cb184f8c1aeb967c72b3ff6093ba3e275e3bdec4b40de4d570e92bceaaced1e9.exe"
      author = "yarGen Rule Generator"
      reference = "https://github.com/Neo23x0/yarGen"
      date = "2023-05-21"
      hash1 = "c3a6f41b0991f67f2a9cb77abea87ee06fb8e5c0f6db9b1ce6bc833dbe45c96c"
      hash2 = "0a1a408b104d16cc870b9064b3357ca0af01c371ec857f4f23a644e8af849dfb"
      hash3 = "b38006408e2229c1c23c56e4efba5df476d7ee13931ec7766cb6940b1b397679"
      hash4 = "b4b1dd5fc206b0089ca1e7d613d6475a9a06bbcf4c207830d7c0cf02a94ae79a"
      hash5 = "a9f1bd2ec79646bce488a69a3809de067415d434e6269721dd0d4ad568992871"
      hash6 = "e3cb33466bed760b23a24bd723b68ccb5da82ee350793f4cde7aa5ad53541b94"
      hash7 = "1bf7585f2020daa5ede6f77cacc1a4c80c4359ca101939e267ecd9cfbca5b4f8"
      hash8 = "cb184f8c1aeb967c72b3ff6093ba3e275e3bdec4b40de4d570e92bceaaced1e9"
   strings:
      $s1 = "lSystem.Resources.ResourceReader, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.R" ascii
      $s2 = "Crypto.exe" fullword ascii
      $s3 = "http://www.example.com/log.php" fullword wide
      $s4 = "4System.Web.Services.Protocols.SoapHttpClientProtocol" fullword ascii
      $s5 = "?Target Address : " fullword wide
      $s6 = "Mutexx" fullword ascii
      $s7 = "MyTemplate" fullword ascii
      $s8 = "My.Computer" fullword ascii
      $s9 = "System.Windows.Forms.Form" fullword ascii
      $s10 = "ethereum" fullword ascii
      $s11 = "ThreadSafeObjectProvider`1" fullword ascii
      $s12 = "m_MyWebServicesObjectProvider" fullword ascii
      $s13 = "m_UserObjectProvider" fullword ascii
      $s14 = "Crypto.Crypto" fullword ascii
      $s15 = "My.WebServices" fullword ascii
      $s16 = "Crypto.Resources.resources" fullword ascii
      $s17 = "m_ComputerObjectProvider" fullword ascii
      $s18 = "m_ThreadStaticValue" fullword ascii
      $s19 = "MyWebServices" fullword ascii
      $s20 = "Crypto.Resources" fullword wide

      $op0 = { 0b 00 00 11 00 02 03 6f 33 00 00 0a 28 34 00 00 }
      $op1 = { 03 00 34 09 ca 04 27 00 ec 28 }
      $op2 = { 02 00 05 00 f0 30 00 00 9c 2f 00 00 01 }
   condition:
      ( uint16(0) == 0x5a4d and filesize < 50KB and ( 8 of them ) and all of ($op*)
      ) or ( all of them )
}

If you want to see the yara rule put to good use, check out part 4 where we’ll setup an extraction pipeline with MWDB and Karton.