Overview

In general clipboard hijackers are used to monitor clipboard activity on a target host, and swap valuable data like BTC addresses. We would like a generic static method for detecting this behaviour.

Samples

  • 8d7f0e6b6877bdfb9f4531afafd0451f7d17f0ac24e2f2427e9b4ecc5452b9f0 Malshare

Analysis

Mutex: M5/610HP/STAGE2

Copies itself to %APPDATA%\\Microsoft\\Network\mstsca.exe

Uses scheduled task to run newly copied malware with a 1 min delay.

Watches clipboard and replaces wallet strings.

Pulling hard coded coind addresses

import re

def get_unicode_strings(buf, n=4):
    ASCII_BYTE = b' !\"#\$%&\'\(\)\*\+,-\./0123456789:;<=>\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\}\\\~\t'
    if type(buf) == str:
        buf = buf.encode('utf-8')
    reg = b'((?:[%s]\x00){%d,})' % (ASCII_BYTE, n)
    uni_re = re.compile(reg)
    out = []
    for match in uni_re.finditer(buf):
        try:
            out.append(match.group().decode("utf-16"))
        except UnicodeDecodeError:
            pass
    return out


coin_eggs = {
    "btc": "[13][a-km-zA-HJ-NP-Z1-9]{25,34}",
    "bch": "((bitcoincash|bchreg|bchtest):)?(q|p)[a-z0-9]{41}",
    "eth": "0x[a-fA-F0-9]{40}",
    "ltc": "[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}",
    "doge": "D{1}[5-9A-HJ-NP-U]{1}[1-9A-HJ-NP-Za-km-z]{32}",
    "dash": "X[1-9A-HJ-NP-Za-km-z]{33}",
    "xmr": "4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}",
    "neo": "A[0-9a-zA-Z]{33}",
    "xrp": "r[0-9a-zA-Z]{33}"}


coin_eggs2 = {
    "bitcoin": r"[13][a-km-zA-HJ-NP-Z1-9]{25,34}",
    "bech32": r"bc(0([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})",
    "bitcoin_cash": r"[13][a-km-zA-HJ-NP-Z1-9]{33}",
    "dash": r"X[1-9A-HJ-NP-Za-km-z]{33}",
    "ethereum": r"0x[a-fA-F0-9]{40}$",
    "litecoin": r"[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}",
    "monero": r"4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}$"}

file_data = open('/tmp/8d7f0e6b6877bdfb9f4531afafd0451f7d17f0ac24e2f2427e9b4ecc5452b9f0.bin','rb').read()

u_strings = get_unicode_strings(file_data)


for u_string in u_strings:
    for coin_name in coin_eggs.keys():
        coin_egg = coin_eggs[coin_name]
        m = re.match(coin_egg, u_string)
        if m:
            print(f"{coin_name}: {m.group()}")

            
            
coin_eggs2 = {
    "bitcoin": r"[13][a-km-zA-HJ-NP-Z1-9]{25,34}",
    "bech32": r"bc(0([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})",
    "bitcoin_cash": r"[13][a-km-zA-HJ-NP-Z1-9]{33}",
    "dash": r"X[1-9A-HJ-NP-Za-km-z]{33}",
    "ethereum": r"0x[a-fA-F0-9]{40}$",
    "litecoin": r"[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}",
    "monero": r"4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}$"}

print("\nTry 2\n")
for u_string in u_strings:
    for coin_name in coin_eggs2.keys():
        coin_egg = coin_eggs2[coin_name]
        m = re.match(coin_egg, u_string)
        if m:
            print(f"{coin_name}: {m.group()}")
btc: 1My2QNmVqkvN5M13xk8DWftjwC9G1F2w8Z
btc: 3NLzE3tXwoagBrgFsjNNkPZfrESydTD8JP
ltc: 3NLzE3tXwoagBrgFsjNNkPZfrESydTD8JP
ltc: LLiNjWA9h4LxVtDigLQ79xQdGiJYC4oHis
ltc: MBD2C8QV7RDrNtSDRe9B2iH5r7yH4iMcxk
eth: 0xa6360e294DfCe4fE4Edf61b170c76770691aA111
xmr: 42UxohbdHGMYGPvW5Uep45Jt9Rj2WvTV958B5G5vHnawZhA4UwoD53Tafn6GRmcGdoSFUfCQN6Xm37LBZZ6qNBorFw3b6s2
doge: DBbgRYaKG993LFJKCWz73PZqveWsnwRmGc
neo: Ae2tdPwUPEZDqNhACJ3ZT5NdVjkNffGAwa

Try 2

bitcoin: 1My2QNmVqkvN5M13xk8DWftjwC9G1F2w8Z
bitcoin_cash: 1My2QNmVqkvN5M13xk8DWftjwC9G1F2w8Z
bitcoin: 3NLzE3tXwoagBrgFsjNNkPZfrESydTD8JP
bitcoin_cash: 3NLzE3tXwoagBrgFsjNNkPZfrESydTD8JP
litecoin: 3NLzE3tXwoagBrgFsjNNkPZfrESydTD8JP
bech32: bc1qx8vykfse9s9llguez9cuyjmy092yeqkesl2r5v
litecoin: LLiNjWA9h4LxVtDigLQ79xQdGiJYC4oHis
litecoin: MBD2C8QV7RDrNtSDRe9B2iH5r7yH4iMcxk
ethereum: 0xa6360e294DfCe4fE4Edf61b170c76770691aA111
monero: 42UxohbdHGMYGPvW5Uep45Jt9Rj2WvTV958B5G5vHnawZhA4UwoD53Tafn6GRmcGdoSFUfCQN6Xm37LBZZ6qNBorFw3b6s2

Yara Rule

First we can take a look at how they parse out the coin addresses from the clipboard.

General Check

text:004014B1 6A 30                                   push    30h ; '0'       ; wMatch

.text:004014B3 56                                      push    esi             ; pszStart
.text:004014B4 FF 15 18 40 40 00                       call    StrChrW
.text:004014BA 85 C0                                   test    eax, eax
.text:004014BC 0F 85 83 00 00 00                       jnz     loc_401545
.text:004014C2 6A 4F                                   push    4Fh ; 'O'       ; wMatch

.text:004014C4 56                                      push    esi             ; pszStart
.text:004014C5 FF 15 18 40 40 00                       call    StrChrW
.text:004014CB 85 C0                                   test    eax, eax
.text:004014CD 75 76                                   jnz     short loc_401545
.text:004014CF 6A 49                                   push    49h ; 'I'       ; wMatch
.text:004014D1 56                                      push    esi             ; pszStart
.text:004014D2 FF 15 18 40 40 00                       call    StrChrW
.text:004014D8 85 C0                                   test    eax, eax
.text:004014DA 75 69                                   jnz     short loc_401545

BTC Check

cmp     eax, 2Ah ; '*'
.text:004015C3 75 5B                                   jnz     short loc_401620
.text:004015C5 66 39 1E                                cmp     [esi], bx
.text:004015C8 75 56                                   jnz     short loc_401620
.text:004015CA 66 39 4E 02                             cmp     [esi+2], cx
.text:004015CE 75 50                                   jnz     short loc_401620

.text:004015D0 6A 31                                   push    31h ; '1'
.text:004015D2 58                                      pop     eax
.text:004015D3 66 39 46 04                             cmp     [esi+4], ax
.text:004015D7 75 47                                   jnz     short loc_401620

.text:004015D9 6A 4F                                   push    4Fh ; 'O'       ; wMatch
.text:004015DB 8D 5E 06                                lea     ebx, [esi+6]
.text:004015DE 53                                      push    ebx             ; pszStart
.text:004015DF FF 15 18 40 40 00                       call    StrChrW
.text:004015E5 85 C0                                   test    eax, eax
.text:004015E7 75 34                                   jnz     short loc_40161D

.text:004015E9 6A 49                                   push    49h ; 'I'       ; wMatch
.text:004015EB 53                                      push    ebx             ; pszStart
.text:004015EC FF 15 18 40 40 00                       call    StrChrW
.text:004015F2 85 C0                                   test    eax, eax
.text:004015F4 75 27                                   jnz     short loc_40161D

rule $ btc_find = {6A 31 [4-16] 75 ?? 6A 4F [4-16] 75 ?? 6A 49}

https://riskmitigation.ch/yara-scan/

rule clipboard_hijack {
    meta:
        description = "Identifies clipboard hijacking"

   strings:

       $btc_find = {6A 31 [4-16] 75 ?? 6A 4F [4-16] 75 ?? 6A 49}   
       $coin_find = {6A 30 [4-16] 75 ?? 6A 4F [4-16] 75 ?? 6A 49}
       $s1 = "GetClipboardData" ascii wide
       $s2 = "SetClipboardData" ascii wide
   condition:
       all of them
}