読者です 読者をやめる 読者になる 読者になる

日々のおべんきょ

セキュリティに興味のある学生ニートのブログ。ハニーポット中心。

SSHハニーポットはKippoではなくCowrieを使え

Honeypot Cowrie

お久しぶりです。記事を書こうとして下書きが積もっていっております・・・。 今回はサクッと。

今回の内容

ハニーポット入門としてよく導入されるKippo。 しかしKippoは攻撃者に対策されたり、エラーが発生したりして思うようにマルウェアやログを取ることができません。
そういうときはKippoの改良版(?)的なCowrieを使っていきましょう。

Kippo全然うまくいかないよー、どうして?となっている人をたまに見かけます。ぜひともCowrieを使ってほしいです。

今回の記事では、Kippoが何故適さないのかを考えていきたいと思います。
あまり詳細には書きませんが、いわゆるKippoの挙動解説になります。

個人的にKippoは推奨していないので、挙動について書く意味は少ないと思います。
もしKippoの導入とかあれこれについて調べていてこの記事を見つけた方は、この記事を読むよりCowrieについて調べたほうがよいかもしれません。

なぜKippoが適さないのか

普通に使っていて気付いた点です。それ以上のことは特に調べてないです。(Kippoに関してはソースを全く読んでいないので)

コマンドのオプションやリダイレクトへの対応

echoコマンド

Kippoでエミュレートされるechoコマンドにはオプションは対応していません。 echoコマンドには-nや-eといったオプションが存在しますが、オプションを入力するとオプションがそのまま出力されます。

本来の動作

$ echo -n test
test

$echo -e "\ttest"
    test

Kippoでの動作

root@svr03:~# echo -n test
-n test

root@svr03:~# echo -t "\ttest"
-t \ttest

これを利用して、攻撃者はログインしたサーバがkippoであるかを判定します。
ほとんどの攻撃者がログイン時にecho -n testというコマンドを送り込み、-n testという文字列が帰ってきたら攻撃をやめてしまいます。

sshコマンド

たいていechoコマンドで判定されてしまうのでこちらは必要ありませんが、sshコマンドも完全ではありません。 -Vというオプションが実装されていないようです。

本来の動作

$ ssh -V
OpenSSH_7.2p2 Ubuntu-4ubuntu1, OpenSSL 1.0.2g-fips  1 Mar 2016

Kippoでの動作

root@svr03:~# ssh -V
usage: ssh [-1246AaCfgKkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]
           [-D [bind_address:]port] [-e escape_char] [-F configfile]
           [-i identity_file] [-L [bind_address:]port:host:hostport]
           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
           [-R [bind_address:]port:host:hostport] [-S ctl_path]
           [-w local_tun[:remote_tun]] [user@]hostname [command]

上記のように、バージョンを表示しないといけないところをKippoではオプションを表示しています。
しかし攻撃者はこのチェックを特に行わないので、あまり影響はありません。(私はSSHハニーポットのログはあまり見ていないので、チェックする奴もいたかもしれませんが。)

リダイレクト・パイプ

実装されていません。これはマルウェアを収集するにあたって、大問題となります。 まずは挙動をご覧ください。

リダイレクト本来の動作

$ echo test > test.txt
$ ls
test.txt

リダイレクトKippoでの動作

root@svr03:~# echo test > test.txt
test > test.txt

パイプ本来の動作

$ ls | echo test
test

パイプKippoでの動作

$ ls | echo test
ls: cannot access /root/|: No such file or directory
ls: cannot access /root/echo: No such file or directory
ls: cannot access /root/test: No such file or directory

(パイプについては、Kippoに実装されているコマンドから選んだため分かりづらいことに・・・)
リダイレクトの>も、パイプの|も、文字として判定されるためこうなります。

実は、マルウェアの送り込みはこれが主流となっていて、

root@svr03:~# cat >hogehoge
fugafugafugafuga.....(バイナリ)

という形で攻撃対象にマルウェアを設置します。
つまり、リダイレクトが使えないということはほぼマルウェアが取れないことを意味します。
わざわざ別サーバからwgetとか使ってダウンロードさせるものは滅多にお目にかかれません。SSSRぐらいですかね?

エラー

sshコマンドからコマンド入力されることによるエラー

リダイレクトが使えないことと同様、こちらも重大な問題となります。エラーなのでこちらのほうが重い。 正確な条件は分かりませんが、sshコマンドを使って直接コマンドを実行するときに起こります。

$ ssh -l ユーザ名 IPアドレス "cat >/tmp/hoge"
Password:
exec request failed on channel 0

kippo.logを見てみると

2016-06-30 01:46:44+0900 [-] New connection: 192.168.1.1:52378 (192.168.1.1:2222) [session: 27]
2016-06-30 01:46:44+0900 [-] Remote SSH version: SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu1
2016-06-30 01:46:44+0900 [HoneyPotTransport,27,192.168.1.1] kex alg, key alg: diffie-hellman-group-exchange-sha1 ssh-rsa
2016-06-30 01:46:44+0900 [HoneyPotTransport,27,192.168.1.1] outgoing: aes128-ctr hmac-sha1 none
2016-06-30 01:46:44+0900 [HoneyPotTransport,27,192.168.1.1] incoming: aes128-ctr hmac-sha1 none
2016-06-30 01:46:48+0900 [HoneyPotTransport,27,192.168.1.1] NEW KEYS
2016-06-30 01:46:48+0900 [HoneyPotTransport,27,192.168.1.1] starting service ssh-userauth
2016-06-30 01:46:48+0900 [SSHService ssh-userauth on HoneyPotTransport,27,192.168.1.1] root trying auth none
2016-06-30 01:46:48+0900 [SSHService ssh-userauth on HoneyPotTransport,27,192.168.1.1] root trying auth keyboard-interactive
2016-06-30 01:46:50+0900 [-] login attempt [root/test] succeeded
2016-06-30 01:46:50+0900 [SSHService ssh-userauth on HoneyPotTransport,27,192.168.1.1] root authenticated with keyboard-interactive
2016-06-30 01:46:50+0900 [SSHService ssh-userauth on HoneyPotTransport,27,192.168.1.1] starting service ssh-connection
2016-06-30 01:46:50+0900 [SSHService ssh-connection on HoneyPotTransport,27,192.168.1.1] got channel session request
2016-06-30 01:46:50+0900 [SSHChannel session (0) on SSHService ssh-connection on HoneyPotTransport,27,192.168.1.1] channel open
2016-06-30 01:46:50+0900 [SSHService ssh-connection on HoneyPotTransport,27,192.168.1.1] got global no-more-sessions@openssh.com request
2016-06-30 01:46:50+0900 [-] request_env: '\x00\x00\x00\x04LANG\x00\x00\x00\x0bja_JP.UTF-8'
2016-06-30 01:46:50+0900 [SSHChannel session (0) on SSHService ssh-connection on HoneyPotTransport,27,192.168.1.1] executing command "cat >/tmp/hoge"
2016-06-30 01:46:50+0900 [-] exec command: "cat >/tmp/hoge"
2016-06-30 01:46:50+0900 [-] Opening TTY log: log/tty/20160630-014650-2137.log
2016-06-30 01:46:50+0900 [-] /etc/motd resolved into /etc/motd
2016-06-30 01:46:50+0900 [-] Running exec command "cat >/tmp/hoge"
2016-06-30 01:46:50+0900 [-] CMD: cat >/tmp/hoge
2016-06-30 01:46:50+0900 [-] Command found: cat >/tmp/hoge
2016-06-30 01:46:50+0900 [SSHChannel session (0) on SSHService ssh-connection on HoneyPotTransport,27,192.168.1.1] Unhandled Error
        Traceback (most recent call last):
          File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 85, in callWithContext
            return context.call({ILogContext: newCtx}, func, *args, **kw)
          File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
            return self.currentContext().callWithContext(ctx, func, *args, **kw)
          File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
            return func(*args,**kw)
          File "/usr/local/lib/python2.7/dist-packages/twisted/conch/ssh/channel.py", line 137, in requestReceived
            return f(data)
        --- <exception caught here> ---
          File "/usr/local/lib/python2.7/dist-packages/twisted/conch/ssh/session.py", line 70, in request_exec
            self.session.execCommand(pp, f)
          File "/home/kippo/kippo/kippo/core/ssh.py", line 267, in execCommand
            serverProtocol.makeConnection(protocol)
          File "/usr/local/lib/python2.7/dist-packages/twisted/internet/protocol.py", line 487, in makeConnection
            self.connectionMade()
          File "/home/kippo/kippo/kippo/core/protocol.py", line 237, in connectionMade
            insults.ServerProtocol.connectionMade(self)
          File "/usr/local/lib/python2.7/dist-packages/twisted/conch/insults/insults.py", line 427, in connectionMade
            self.terminalProtocol.makeConnection(self)
          File "/usr/local/lib/python2.7/dist-packages/twisted/conch/insults/insults.py", line 59, in makeConnection
            self.connectionMade()
          File "/home/kippo/kippo/kippo/core/protocol.py", line 146, in connectionMade
            self.cmdstack[0].lineReceived(self.execcmd)
          File "/home/kippo/kippo/kippo/core/honeypot.py", line 68, in lineReceived
            self.runCommand()
          File "/home/kippo/kippo/kippo/core/honeypot.py", line 125, in runCommand
            self.honeypot.call_command(cmdclass, *rargs)
          File "/home/kippo/kippo/kippo/core/protocol.py", line 117, in call_command
            obj.start()
          File "/home/kippo/kippo/kippo/core/honeypot.py", line 26, in start
            self.call()
          File "/home/kippo/kippo/kippo/commands/fs.py", line 16, in call
            if self.fs.is_dir(path):
          File "/home/kippo/kippo/kippo/core/fs.py", line 172, in is_dir
            dir = self.get_path(os.path.dirname(path))
          File "/home/kippo/kippo/kippo/core/fs.py", line 87, in get_path
            p = [x for x in p[A_CONTENTS] if x[A_NAME] == i][0]
        exceptions.IndexError: list index out of range

2016-06-30 01:46:50+0900 [HoneyPotTransport,27,192.168.1.1] connection lost

うわああああああああああああああああああああああああああ!!!!!
となります。ちなみにこの状態になると~/kippo/log/tty/には何も出力されません。(ファイルは作成されます)

ちなみに下記のように>の前後を空白にするとエラーは出力されません。(正常な結果ではありませんが)

$ ssh -l root IPアドレス "cat > /tmp/hoge"
cat: >: No such file or directory
cat: /tmp/hoge: No such file or directory

また、catのすぐ横に>を置くとコマンドは認識されなくなります。
(前者も後者も>が文字扱いのため)

以上の結果から、おそらくcat>/が入力されたときに発生すると思われます。

このエラーは、sshコマンドからコマンドを入力されることで発生し、ログインしてから入力を行うと発生しません。 しかし、リダイレクトできないため内容を収集することはできません。

攻撃者の挙動とttyログについて

ここで一応説明しておきますが、攻撃者は基本的に
$ ssh -l ユーザ名 IPアドレス コマンド
で攻撃対象での活動を行います。

わざわざログインし続けて行う攻撃者もSSRぐらいですかね、あまり見ません。

ちなみにKippo、Cowrie共に~/kippo/log/tty/には1度のアクセスにつき1つlogファイルを作成します。
Kippoは日付-時間-ランダムな数値(?).logという命名規則であるのに対し、Cowrieは`日付-時間-送信元IP等の情報のハッシュ値(?)-アクセス回数eもしくはi.log'です。
eについてはsshコマンドからの実行、iについてはログインしてからの行動を指していると思われます。

Cowrieのほうがニーズに合いますね。

Cowrieについて

Cowrieでは上記の問題ほぼ全てが解決されています。
新たな問題点としては、ログイン後にcatコマンドで文字等を入力しファイルを作成する、ということができなくなっていることでしょうか。(この記事のために検証していたら気づいた) どうせ攻撃者はほとんどsshコマンドから直接実行しようとしてくるし、もしログインしてもバイナリを注入するまで気づくことはないでしょう。

というわけで、これからハニーポットに手を出そうと思ってる方はKippoではなくCowrieを使ってみるといいですよ。

参考

GitHub - desaster/kippo: Kippo - SSH Honeypot
GitHub - micheloosterhof/cowrie: Cowrie SSH Honeypot (based on kippo)
[技術|SEC] kippoで、echoを用いたハニーポット判定を防ぐ | 話譚でいいと思うよ

余談

ここにいろいろなハニーポットが集めてあります。

github.com

SSHハニーポットもいろいろありますが、見た感じKippo系列が一番使いやすそうですね。 Dockerのやつとか面白そうです。(Raspberry Piで使えないのが残念)



っと、結局5時間ぐらいかかったしそこそこがっつりやってしまったかも。でも書いたら書いたで勉強になるんだよなぁ。