Loki 1.8:若くて新進気鋭のデータスティーラーに関する書類





6月中旬、カザフスタンでのコロナウイルスとの戦いが本格化しました。事件の増加に警鐘を鳴らし(その後、Nursultan Nazarbayev前大統領でさえ感染した)、地方自治体はすべてのショッピングおよびエンターテイメントセンター、チェーンストア、市場、バザールを再び閉鎖することを決定しました。当時、サイバー犯罪者はこの状況を利用して、ロシアや国際的な企業に悪意のあるメールを送信していました。



カザフスタン共和国の保健大臣の訴えを装った危険な手紙は、脅威検出システム(TDS)グループIBによって傍受されました。添付ファイルには、起動時に、感染したコンピューターからログインとパスワードを盗むように設計されたLoki PWS(Password Stealer)ファミリーの悪意のあるプログラムをインストールしたドキュメントが含まれていました。将来的には、攻撃者はそれらを使用して、金融詐欺やスパイ行為のために電子メールアカウントにアクセスしたり、ハッカーフォーラムで販売したりする可能性があります。



この記事では、CERT-GIBのアナリストであるNikita Karpovが、現在最も人気のあるデータスティーラーの1つであるLokiのインスタンスを調べます。



今日は、ボットの人気のあるバージョンの1つである1.8について検討します。それは活発に販売されており、管理パネルはパブリックドメインにもあります:ここ



管理パネルの例:







LokiはC ++で記述されており、感染したコンピューターからユーザー情報を盗むために使用される最も人気のあるマルウェアの1つです。私たちの時代の惨劇-身代金ウイルス-DataStealerは、被害者のコンピューターに攻撃された後、非常に高速でタスクを実行します-足場を築いてシステムでの特権を増やす必要はなく、攻撃から身を守る時間はほとんどありません。したがって、ユーザーデータを盗むマルウェアのイベントでは、インシデントの調査が主な役割を果たします。



実行可能なマルウェアダンプを解凍して取得する



ほとんどの場合、配布はメーリングリストの添付ファイルを介して行われます。正当なファイルを装ったユーザーが添付ファイルをダウンロードして開き、マルウェアを起動します。



注入マーカーは、ローダーの存在を示唆しています。





DIEの助けを借りて、ソースファイルがVB6で書き込まれているという情報を取得します。





エントロピーグラフは、大量の暗号化されたデータを示しています。





起動されると、最初のプロセスは子プロセスを作成し、それを注入して終了します。2番目のプロセスは、マルウェアの動作を担当します。しばらくすると、プロセスを停止してメモリダンプを保存します。Lokiがダンプ内にあることを確認するには、コマンドセンターのURL内を調べます。これは、ほとんどの場合、fre.php終わります。





Lokiを含むメモリフラグメントをダンプし、PEヘッダーを修正します。



TDSハントボックスシステムを使用して、ダンプのパフォーマンスを確認します。





ボット機能



逆コンパイルされたマルウェアコードを調べる過程で、操作に必要なライブラリの初期化の直後に実行される4つの関数を含む部分が見つかりました。それらのそれぞれを内部で分解した後、マルウェアの目的と機能を決定します。





関数名は、わかりやすくするために名前が変更されました。

ボットの機能は、次の2つの主要な機能によって決定されます。



  1. Data Stealerは、101個のアプリケーションからデータを盗んでサーバーに送信する最初の機能です。
  2. ダウンローダー-実行のためのCnC(コマンド&コントロール)コマンドからの要求。


便宜上、次の表に、調査対象のLokiインスタンスがデータを盗もうとするすべてのアプリケーションを示します。

機能ID 応用 機能ID 応用 機能ID 応用
1 Mozilla Firefox 35 FTPInfo 69 ClassicFTP
2 コモドアイスドラゴン 36 LinasFTP 70 PuTTY / KiTTY
3 アップルサファリ 37 FileZilla 71 サンダーバード
4 K-メレオン 38 スタッフ-FTP 72 Foxmail
海猿 39 BlazeFtp 73 ポコメイル
6 群れ 40 NETFile 74 IncrediMail
7 NETGATE BlackHawk 41 GoFTP 75 Gmail通知プロ
8 ルナスケープ 42 ALFTP 76 メールをチェックする
ナイン グーグルクローム 43 DeluxeFTP 77 WinFtp
オペラ 44 総司令官 78 マーティン・プリクリル
十一 QTWebブラウザ 45 FTPGetter 79 32BitFtp
12 QupZilla 46 WS_FTP 80 FTPナビゲーター
13 インターネットエクスプローラ 47 メールクライアント構成ファイル 81 郵送

(softwarenetz)
14 オペラ2 48 フルチルトポーカー 82 オペラメール
15 Cyber​​fox 49 ポーカースター 83 ポストボックス
16 淡い月 50 ExpanDrive 84 FossaMail
17 ウォーターフォックス 51 スティード 85 ベッキー!
18 ピジン 52 FlashFXP 86 POP3
19 SuperPutty 53 NovaFTP 87 見通し
20 FTPShell 54 NetDrive 88 Ymail2
21 NppFTP 55 トータルコマンダー2 89 Trojitá
22 MyFTP 56 SmartFTP 90 TrulyMail
23 FTPBox 57 FARマネージャー 91 .spnファイル
24 シェロッドFTP 58 Bitvise 92 To-Doデスクリスト
25 今すぐFTP 59 RealVNC

TightVNC
93 スティッキー
26 NexusFile 60 mSecure Wallet 94 NoteFly
27 Xftp 61 同期性 95 NoteZilla
28 EasyFTP 62 FreshFTP 96 ポストイット
29 SftpNetDrive 63 BitKinex 97 KeePass
30 AbleFTP 64 UltraFXP 98 エンパス
31 JaSFtp 65 FTP Now 2 99 私のRoboForm
32 自動化 66 Vandyk SecureFX 100 1パスワード
33 サイバーダック 67 Odin Secure FTP Expert 101 Mikrotik WinBox
34 フルシンク 68 フリング
この段階で、マルウェアの静的分析が完了します。次のセクションでは、Lokiがサーバーと通信する方法について検討します。



ネットワーキング



ネットワークの相互作用を記録するために対処する必要がある2つの問題があります。



  1. コマンドセンターは、攻撃時にのみ使用できます。
  2. Wiresharkはループバックでボット通信を記録しないため、他の手段を使用する必要があります。


最も簡単な解決策は、Lokiが通信するCnCアドレスをlocalhostに転送することです。ボットの場合、サーバーは応答しませんが、いつでも使用できるようになりましたが、ボットの通信を記録する必要はありません。2番目の問題を解決するために、RawCapユーティリティを使用します。これにより、pcapに必要な通信を記述できます。次に、Wiresharkで記録されたpcapを解析します。





各通信の前に、ボットはCnCの可用性をチェックし、利用可能な場合はソケットを開きます。すべてのネットワーク通信は、TCPプロトコルを使用してトランスポートレベルで行われ、アプリケーションレベルではHTTPが使用されます。



次の表は、Lokiが標準で使用するパケットヘッダーを示しています。

フィールド 説明
ユーザーエージェント Mozilla / 4.08(Charon; Inferno) Lokiの典型的なユーザーエージェント
受け入れる * / *
コンテンツタイプ アプリケーション/オクテットストリーム
コンテンツエンコーディング バイナリ
コンテンツキー 7DE968CC 以前のヘッダーのハッシュ結果(ハッシュは、多項式0xE8677835を使用したカスタムCRCアルゴリズムによって実行されます)
接続 閉じる
パッケージの本体に注意を払いましょう:



  1. 記録されるデータの構造はボットのバージョンによって異なり、以前のバージョンでは、暗号化と圧縮のオプションを担当するフィールドはありません。
  2. サーバーは、要求のタイプによって、受信したデータの処理方法を決定します。サーバーが読み取ることができるデータには、次の7種類があります。

    • 0x26盗まれたウォレットデータ
    • 0x27盗まれたアプリケーションデータ
    • 0x28サーバーからのコマンド要求
    • 0x29盗まれたファイルのアンロード
    • 0x2A POS
    • 0x2Bキーロガーデータ
    • 0x2Cスクリーンショット
  3. 調べた例では、0x27、0x28、および0x2Bのみが存在していました。
  4. 各リクエストには、ボットと感染したシステムに関する一般的な情報が含まれています。これにより、サーバーは1台のマシンのすべてのレポートを識別し、リクエストのタイプに応じた情報があります。
  5. ボットの最新バージョンでは、データ圧縮のみが実装されており、暗号化されたフィールドは将来のために準備され、サーバーによって処理されません。
  6. オープンソースのAPLibライブラリは、データの圧縮に使用されます。


盗まれたデータを使用してリクエストを作成する場合、ボットはサイズ0x1388(5000バイト)のバッファーを割り当てます。0x27リクエストの構造を次の表に示します。

バイアス サイズ 説明
0x0 0x2 0x0012 ボットバージョン
0x2 0x2 0x0027 リクエストタイプ(盗まれたデータの送信)
0x4 0xD ckav.ru バイナリID(XXXXX11111も発生します)
0x11 0x10 - ユーザー名
0x21 0x12 - コンピュータネーム
0x33 0x12 - コンピューターのドメイン名
0x45 0x4 - 画面の解像度(幅と高さ)

0x49 0x4 -
0x4D 0x2 0x0001 ユーザー権限フラグ(管理者の場合は1)
0x4F 0x2 0x0001 SIDフラグ(設定されている場合は1)
0x51 0x2 0x0001 システムビットネスフラグ(x64の場合は1)
0x53 0x2 0x0006 Windowsバージョン(メジャーバージョン番号)
0x55 0x2 0x0001 Windowsバージョン(マイナーバージョン番号)
0x57 0x2 0x0001 追加のシステム情報(1 = VER_NT_WORKSTATION)
0x59 0x2 -
0x5B 0x2 0x0000 盗まれたデータは送信されましたか
0x5D 0x2 0x0001 データ圧縮が使用されました
0x5F 0x2 0x0000 圧縮タイプ
0x61 0x2 0x0000 データ暗号化が使用されました
0x63 0x2 0x0000 暗号化の種類
0x65 0x36 - MachineGuidレジスタ値からのMD5
0x9B - - 圧縮された盗難データ
サーバーとの対話の第2段階は、システムで修正された後に始まります。ボットは、タイプ0x28の要求を送信します。その構造を以下に示します。



バッファーサイズ:0x2BC(700バイト)

バイアス サイズ 説明
0x0 0x2 0x0012 ボットバージョン
0x2 0x2 0x0028 リクエストタイプ(コマンドセンターからのコマンドリクエスト)
0x4 0xD ckav.ru バイナリID(XXXXX11111も発生します)
0x11 0x10 - ユーザー名
0x21 0x12 - コンピュータネーム
0x33 0x12 - コンピューターのドメイン名
0x45 0x4 - 画面の解像度(幅と高さ)
0x49 0x4 -
0x4D 0x2 0x0001 ユーザー権限フラグ(管理者の場合は1)
0x4F 0x2 0x0001 SIDフラグ(設定されている場合は1)
0x51 0x2 0x0001 システムビットネスフラグ(x64の場合は1)
0x53 0x2 0x0006 Windowsバージョン(メジャーバージョン番号)
0x55 0x2 0x0001 Windowsバージョン(マイナーバージョン番号)
0x57 0x2 0x0001 追加のシステム情報(1 = VER_NT_WORKSTATION)
0x59 0x2 0xFED0
0x5B 0x36 - MachineGuidレジスタ値からのMD5
要求後、ボットはサーバーから番号とコマンド自体を含む応答を受信することを期待しています。可能なコマンドバリアントは、逆コンパイルされたマルウェアコードの静的分析を使用して取得され、以下に示されています。



バッファサイズ:パケット内の各コマンドに対して0x10(16バイト)+ 0x10(16バイト)。

HTTPヘッダー(データの開始) \ r \ n \ r \ n [0D 0A 0D 0A] 4バイト
- - 4
2 [00 00 00 02] 4


4


4


4


4



()

#0

EXE-
[00 00 00 00] [00 00 00 00] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
#1

DLL
[00 00 00 00] [00 00 00 01] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.dll
#2

EXE-
[00 00 00 00] [00 00 00 02] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
#8

(HDB file)
[00 00 00 00] [00 00 00 08] [00 00 00 00] [00 00 00 00] -
#9

[00 00 00 00] [00 00 00 09] [00 00 00 00] [00 00 00 00] -
#10

[00 00 00 00] [00 00 00 0A] [00 00 00 00] [00 00 00 00] -
#14

Loki
[00 00 00 00] [00 00 00 0E] [00 00 00 00] [00 00 00 00] -
#15

Loki
[00 00 00 00] [00 00 00 0F] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
#16

サーバーからの応答をチェックする頻度を変更する
[00 00 00 00] [00 00 00 10] [00 00 00 00] [00 00 00 01]
#17

ロキを削除して終了します
[00 00 00 00] [00 00 00 11] [00 00 00 00] [00 00 00 00] -


ネットワークトラフィックパーサー



この分析のおかげで、Lokiのネットワーク相互作用を解析するために必要なすべての情報が得られました。



パーサーはPythonで実装され、入力としてpcapファイルを受け取り、その中のLokiに属するすべての通信を検索します。



まず、dkptライブラリを使用してすべてのTCPパケットを検索しましょう。httpパケットのみを受信するために、使用するポートにフィルターを設定しましょう。受信したhttpパケットの中から、よく知られているLokiヘッダーを含むパケットを選択し、読み取り可能な形式で情報を抽出するために解析する必要のある通信を取得します。



for ts, buf in pcap:
    eth = dpkt.ethernet.Ethernet(buf)
    if not isinstance(eth.data, dpkt.ip.IP):
        ip = dpkt.ip.IP(buf)
    else:
        ip = eth.data
 
    if isinstance(ip.data, dpkt.tcp.TCP):
        tcp = ip.data
        try:
            if tcp.dport == 80 and len(tcp.data) > 0:  # HTTP REQUEST
                if str(tcp.data).find('POST') != -1:
                    http += 1
                    httpheader = tcp.data
                    continue
                else:
                    if httpheader != "":
                        print('Request information:')
 
                        pkt = httpheader + tcp.data
                        httpheader = ""
                        if debug:
                            print(pkt)
                        req += 1
                        request = dpkt.http.Request(pkt)
                        uri = request.headers['host'] + request.uri
                        parsed_payload['Network']['Source IP'] = socket.inet_ntoa(ip.src)
                        parsed_payload['Network']['Destination IP'] = socket.inet_ntoa(ip.dst)
                        parsed_payload_same['Network']['CnC'] = uri
                        parsed_payload['Network']['HTTP Method'] = request.method
 
                        if uri.find("fre.php"):
                            print("Loki detected!")
                        pt = parseLokicontent(tcp.data, debug)
                        parsed_payload_same['Malware Artifacts/IOCs']['User-Agent String'] = request.headers['user-agent']
 
                        print(json.dumps(parsed_payload, ensure_ascii=False, sort_keys=False, indent=4))
                        parsed_payload['Network'].clear()
                        parsed_payload['Compromised Host/User Data'].clear()
                        parsed_payload['Malware Artifacts/IOCs'].clear()
                        print("----------------------")
            if tcp.sport == 80 and len(tcp.data) > 0:  # HTTP RESPONCE
                resp += 1
                if pt == 40:
                    print('Responce information:')
                    parseC2commands(tcp.data, debug)
                    print("----------------------")
                    pt = 0
        except(dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
            continue


すべてのLokiリクエストでは、最初の4バイトがボットのバージョンとリクエストタイプを担当します。これらの2つのパラメーターを使用して、データの処理方法を決定します。



def parseLokicontent(data, debug):
    index = 0
 
    botV = int.from_bytes(data[0:2], byteorder=sys.byteorder)
    parsed_payload_same['Malware Artifacts/IOCs']['Loki-Bot Version'] =  botV
 
    payloadtype = int.from_bytes(data[2:4], byteorder=sys.byteorder)
    index = 4
    print("Payload type: : %s" % payloadtype)
    if payloadtype == 39:
        parsed_payload['Network']['Traffic Purpose'] =  "Exfiltrate Application/Credential Data"
        parse_type27(data, debug)
    elif payloadtype == 40:
        parsed_payload['Network']['Traffic Purpose'] = "Get C2 Commands"
        parse_type28(data, debug)
    elif payloadtype == 43:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Keylogger Data"
        parse_type2b(lb_payload)
    elif payloadtype == 38:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Cryptocurrency Wallet"
    elif payloadtype == 41:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Files"
    elif payloadtype == 42:
        parsed_payload['Network'].['Traffic Purpose'] = "Exfiltrate POS Data"
    elif payloadtype == 44:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Screenshots"
 
    return payloadtype


次の行は、サーバーからの応答を解析することです。有用な情報のみを読み取るには、\ r \ n \ r \ nシーケンスを探します。これは、パケットヘッダーの終わりとサーバーからのコマンドの始まりを定義します。



def parseC2commands(data, debug):
    word = 2
    dword = 4
    end = data.find(b'\r\n\r\n')
    if end != -1:
        index = end + 4
        if (str(data).find('<html>')) == -1:
            if debug:
                print(data)
            fullsize = getDWord(data, index)
            print("Body size: : %s" % fullsize)
            index += dword
            count = getDWord(data, index)
            print("Commands: : %s" % count)
            if count == 0:
                print('No commands received')
            else:
                index += dword
                for i in range(count):
                    print("Command: %s" % (i + 1))
 
                    id = getDWord(data, index)
                    print("Command ID: %s" % id)
                    index += dword
 
                    type = getDWord(data, index)
                    print("Command type: %s" % type)
                    index += dword
 
                    timelimit = getDWord(data, index)
                    print("Command timelimit: %s" % timelimit)
                    index += dword
 
                    datalen = getDWord(data, index)
                    index += dword
 
                    command_data = getString(data, index, datalen)
                    print("Command data: %s" % command_data)
                    index += datalen
        else:
            print('No commands received')
    return None


これでパーサーのアルゴリズムの主要部分の分析が終了し、出力で得られる結果に移ります。すべての情報はjson形式で表示されます。



以下は、さまざまなボットの通信から取得され、さまざまなCnCを使用し、さまざまな環境で記録されたパーサーの作業結果の画像です。



Request information:
Loki detected!
Payload type: 39
Decompressed data: 
{'Module': {'Mozilla Firefox'}, 'Version': {0}, 'Data': {'domain': {'https://accounts.google.com'}, 'username': {'none@gmail.com'}, 'password': {'test'}}}
{'Module': {'NppFTP'}, 'Version': {0}, 'Data': {b'<?xml version="1.0" encoding="UTF-8" ?>\r\n<NppFTP defaultCache="%CONFIGDIR%\\Cache\\%USERNAME%@%HOSTNAME%" outputShown="0" windowRatio="0.5" clearCache="0" clearCachePermanent="0">\r\n    <Profiles />\r\n</NppFTP>\r\n'}}
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": true
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


上記は、サーバー0x27(アプリケーションデータのアップロード)への要求の例です。テストのために、アカウントはMozilla Firefox、NppFTP、FileZillaの3つのアプリケーションで作成されました。Lokiには、アプリケーションデータを記録するための3つのオプションがあります。



  1. SQLデータベースの形式(パーサーはデータベースを保存し、その中の使用可能なすべての行を表示します)。
  2. 例のFirefoxのように、開いた形式で。
  3. NppFTPやFileZillaのようなxmlファイルとして。


Request information:
Loki detected!
Payload type: 39
No data stolen
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": false
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


2番目の要求はタイプ0x28で、サーバーからのコマンドを要求します。



Responce information:
Body size: 26
Commands: 1
Command: 1
Command ID: 0
Command type: 9
Command timelimit: 0
Command data: 35


キーロガーの開始に応答して1つのコマンドを送信したCnCからの応答の例。そして、その後のキーロガーデータのアンロード。



Request information:
Loki detected!
Payload type: : 43
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Keylogger Data"
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


作業の最後に、パーサーはボットからの各要求に含まれる情報(ボットとシステムに関する情報)、およびLokiに関連付けられた要求と応答の数をpcapファイルに出力します。



General information:
{
    "Network": {
        "CnC": "nganyin-my.com/chief6/five/fre.php"
    },
    "Compromised Host/User Description": {
        "User Name": "-",
        "Hostname": "-",
        "Domain Hostname": "-",
        "Screen Resolution": "1024x768",
        "Local Admin": true,
        "Built-In Admin": true,
        "64bit OS": false,
        "Operating System": "Windows 7 Workstation"
    },
    "Malware Artifacts/IOCs": {
        "Loki-Bot Version": 18,
        "Binary ID": "ckav.ru",
        "MD5 from GUID": "-",
        "User-Agent String": "Mozilla/4.08 (Charon; Inferno)"
    }
}
Requests: 3
Responces: 3 




完全なパーサーコードは、github.com / Group-IB / LokiParserで入手できます。



結論



この記事では、Lokiマルウェアを詳しく調べ、その機能を分解し、インシデント分析プロセスを大幅に簡素化し、感染したコンピューターから何が盗まれたかを正確に理解するのに役立つネットワークトラフィックパーサーを実装しました。Lokiの開発はまだ進行中ですが、バージョン1.8(およびそれ以前)のみがマージされています。これは、セキュリティの専門家が毎日遭遇するバージョンです。



次の記事では、別の人気のあるデータスティーラーであるポニーを分析し、これらのマルウェアを比較します。



侵害の指標(IOC):



ウルス:



  • nganyin-my.com/chief6/five/fre.php
  • wardia.com.pe/wp-includes/texts/five/fre.php
  • broken2.cf/Work2/fre.php
  • 185.141.27.187/danielsden/ver.php
  • MD5ハッシュ:B0C33B1EF30110C424BABD66126017E5
  • User-Agent String: «Mozilla/4.08 (Charon; Inferno)»
  • Binary ID: «ckav.ru»



All Articles