- Portspoof は 65535 個の TCP ポートすべてを開いているように見せ、サービスシグネチャをエミュレートすることで、攻撃者の偵察フェーズを高速スキャンから長時間かつ高コストな作業へと変える
- すべての接続試行に
SYN+ACK を返し、9000 個以上の正規表現ベースの 動的サービスシグネチャ により、各ポートが別々の正当なサービスのように応答する
- ポートごとに、即時バナー送信、遅延応答、無応答維持といった 混合配信モード を起動時に割り当て、接続維持時間にジッターを加えることで、タイミングベースのフィルタリングを難しくする
- デフォルトの tarpit 設定では、フルバージョンスキャン
nmap -sV -p- に 10時間以上 かかり、数百 MB の偽データを生成できるため、攻撃者スキャナの時間とスレッドを消費させる
- 実装は単一スレッドの
epoll イベントループを使用し、ユーザー空間で root 権限なしに動作し、実行インスタンスごとに 1つの TCP ポート のみをバインドする
Portspoof が解決しようとする問題
- Portspoof の目標は、攻撃者の 偵察を遅く、高コストにし、信頼しにくくする こと
- 一般的な 5 秒の Nmap スキャンではシステムの実際のサービスをマッピングできるが、Portspoof の前では 65535 個のポートがすべて開いているように見える
- 各ポートはそれぞれ異なる正当なサービスのように見え、どのポートが実際のサービスなのかを素早く見分ける方法がないよう設計されている
主な機能
-
65535 個の TCP ポートすべてが開いているように応答
- ポートが
CLOSED または FILTERED であると知らせる代わりに、すべての接続試行に SYN+ACK を返す
-
サービスエミュレーション
- 9000 個以上の正規表現ベースの動的サービスシグネチャを使用
- ポートごとに、スキャナのプローブへ異なる説得力のあるサービスアイデンティティで応答する
-
混合配信モード
- 各ポートは起動時に異なる動作プロファイルを割り当てられる
- 即時バナー送信、遅延応答、無応答維持モードが混在する
- 維持時間は広い範囲に分散され、フルレンジのバージョン検出
nmap -sV -p- が実用限界を超えるようにする
-
攻撃的防御
- 攻撃者のスキャンツール自体の脆弱性を狙う「Exploitation Framework Frontend」として使える
-
軽量な実行モデル
- ユーザー空間で動作
- root 権限不要
- 実行インスタンスごとに 1つの TCP ポート のみをバインド
- CPU とメモリ使用量は小さい
スキャナとバージョン検出を混乱させる仕組み
- 単純なポートスキャンでは、ポート 1〜20 のような小さな範囲でもすべて
open と表示される
- 出力例では
tcpmux、compressnet、echo、daytime、ftp-data などのサービス名が混在して表示される
- バージョン検出スキャンでは、サービスプローブに対して有効な動的シグネチャを返す
- ポート 1〜100 の例では、
irc、http、pop3、ssh、ftp、smtp、telnet、tor-control など多様なサービスとバージョン文字列が現れる
- その結果、攻撃者はシステムが実際に使用しているポート番号を判断しにくくなる
- フルバージョンスキャン
nmap -sV -p- は、デフォルトの tarpit 設定で 10時間以上 かかり、数百 MB の偽データを生成する
- スキャナは実際の成果につながらない接続に時間とスレッドを費やす
設計アプローチ: 単一スレッド epoll tarpit
- 実際のサービスである SSH、SMTP、FTP、HTTP は、バナーを送信し、接続を維持し、クライアント入力を待つ
- 説得力のあるエミュレーションも同様に accept, send, hold の流れに従う必要がある
- クライアントごとにスレッドを持つモデルはメモリと CPU を消費し、コンテキストスイッチのコストにより防御側が先に資源を使い果たす可能性がある
- Portspoof は単一スレッドの
epoll イベントループを使用する
- 各ポートには起動時に配信モードが割り当てられる
- 一部のポートは即座にバナーを送り、一部はクライアントデータの後に応答し、一部は沈黙する
- 維持時間は数十ミリ秒から数分まで、複数桁の範囲にわたって分散される
- 接続ごとにジッターがあるため、同じポートを繰り返し調べても同じタイミングは返らない
- この方式により、すべてのポートに無意味なデータを送って応答タイミングを測る攻撃が難しくなる
- 単純な tarpit は数秒間接続を引き延ばし、実際のサービスは誤ったプロトコルに対して素早く切断するという差が生じうる
- 混合モードと広いタイミング分散では、数千の偽ポートも実サービスに近い範囲で閉じる
- フィルタリングに使える明確な閾値がなくなる
コストの非対称性
- 防御側のコストは、アイドル接続 1 件あたり約 1〜2KB のカーネルメモリ
epoll ループは単一スレッドのため、コンテキストスイッチのオーバーヘッドがない
- 一般的な水準の機器でも 1 万件以上の同時接続に耐えられる
- 攻撃側のコストは時間と労力へと移る
- ポートスキャンだけでは、すべてのポートが開いて見えるため有意な情報を得にくい
- 実際のサービスを見つけるには、65535 個すべてのポートに対するバージョン検出と、もっともらしい対象へのプロトコルレベルの探索が必要になる
- 5 秒のスキャンが 10 時間以上の能動的作業に変わり、結果もなお干し草の山の中の針のような状態のままになる
v2.0 の変更点
- v2.0 は従来の、バナー送信後に接続を終了する方式から脱却した
- 従来方式は、Vicarius/Hored1971 のブログ記事で扱われた接続終了回避に弱かった
- 新しい tarpit エンジンは、すべての接続を混合タイミングで開いたまま維持する
- この方式は、接続終了フィルタリング、タイミングフィンガープリント、バナー分析、統計的パターンモデリングを防ぐことを目指している
インストールと基本設定
- ビルドには C++ コンパイラと CMake 3.10+ が必要
- ソースからのビルド手順は次のとおり
mkdir build && cd build
cmake -DCMAKE_INSTALL_SYSCONFDIR=/etc ..
make
sudo make install
- Portspoof はユーザー空間で動作するが、他ポート宛てのトラフィックを横取りするにはシステムのファイアウォールルールが必要
- デフォルトポートは 4444 で、実サービスのポートを先に除外したうえで、残りの TCP トラフィックを Portspoof にリダイレクトする
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22 -j RETURN
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 4444
eth0 は実際のネットワークインターフェースに置き換える必要がある
- 実際のサービスが動作している各ポートには
RETURN ルールを追加する必要がある
- 永続適用には iptables ルールの保存、または
system_files ディレクトリ内の iptables-config を利用できる
- 起動スクリプトには
system_files/init.d/ の例を利用できる
実行モード
- サービスエミュレーションモード が推奨モード
- ポートスキャナ向けに偽のサービスシグネチャを生成して返す
portspoof -c /etc/portspoof.conf -s /etc/portspoof_signatures -D
- カスタム tarpit タイミングは
-t と -T で指定する
portspoof -s /etc/portspoof_signatures -t 10 -T 60 -D
- Open Port Mode は、サービスバナーなしで、すべての接続試行に
OPEN 状態だけを返す
portspoof -D
- Fuzzing Mode は、スキャンツールにランダムまたはワードリストベースのペイロードを送るのに使える
portspoof -1 -v
portspoof -f payloads.txt -v
iptables ベースの強化
- 基本の
REDIRECT ルールだけでも動作するが、攻撃的なスキャナは接続数で Portspoof に圧力をかけられる
- 強化ルールではレート制限と自動遮断を追加する
- 実サービスのポートはリダイレクト対象から除外する
- 例では SSH の 22 番ポートを除外
- グローバル遮断ルールは実サービスにも適用される
- ルール例には次の要素が含まれる
- ループバック許可
PORTSCAN として記録された IP を 60 秒間ドロップ
- 送信元 IP ごとの新規 SYN を毎秒 10 個、バースト 30 個超でドロップ
- 単一 IP が Portspoof ポート 4444 に 100 件超の接続を維持した場合、記録後にドロップ
- established/related トラフィックと新規 SYN を許可し、その後は残りをドロップ
- 高トラフィック環境では
xt_recent リストサイズを増やせる
echo "options xt_recent ip_list_tot=10000" > /etc/modprobe.d/xt_recent.conf
- カーネルのコネクショントラッキングや backlog 関連設定も調整できる
sysctl -w net.netfilter.nf_conntrack_max=131072
sysctl -w net.core.somaxconn=4096
Portspoof Pro
- Portspoof Pro は、単一ホストではなくネットワーク全体のレベルへ deception を拡張する
- 単一のセンサーがネットワーク全体の
/16 をエミュレートする
- 数千の IP を提供
- 各 IP は全ポートにわたり固有のサービスを持つ
- 状態を持つ多段階の対話を維持する
- ネットワーク全体にわたる deception 機能を提供する
- ダーク IP 空間や未使用サブネットをアクティブな deception グリッドへ変える
- エミュレートされた各ホストは、送信元 IP ごとに異なる性格を持つ固有サービスを提示する
- アクティブな tarpit は攻撃者のソケットプールを枯渇させ、自動化ツールを throttling する
- スキャン検知とツールフィンガープリントをサポートする
- SYN、FIN、NULL、XMAS、ACK スキャン手法を検知
- Nmap、Masscan、ZMap、カスタムスキャナをフィンガープリント
- MITRE ATT&CK マッピングを含む構造化 JSON テレメトリを SIEM にストリーミングする
- 運用環境への配備を想定
- 本番トラフィック横のサンドボックス環境で動作
- ルーティングポリシーで deception トラフィックをセンサーへ送る
- インラインタップは不要で、実ワークロードへのリスクはないと案内している
- NIS2、DORA、ISO 27001、NIST CSF、CIS Controls をサポート
ライセンスとイシュー報告
- Portspoof は GNU GPLv2 ライセンスを採用
- 商用かつ合法的なアプリケーションについては、適切なライセンス協議のため著者に連絡するよう案内している
- バグや機能要望は GitHub Issue Tracker またはメールで報告できる
1件のコメント
Hacker Newsのコメント
ポートは65536個あり、ポート0も一部のOSではインターネットから到達可能なサービスを載せられるポートである
そしてMariaDB開発者がこれを見るなら、データベースをポート0でlistenさせればインターネットアクセスを防げるというデフォルト設定は、実際にはかなり多くのシステムでDBへのインターネットアクセスを防げていない
if (mysqld_port)はmysqld_portが0ではないことを意味し、少なくとも MariaDB 5.5 からある挙動のようだコンピュータセキュリティは結局、上のような能動防御へと進化していくしかないように見える
免疫系がどれほど複雑で多層的かを見れば、いつかコンピュータやネットワークもそれに似た姿になる気がする
いつかITも十分に熟達した分野になるだろうが、今日はまだそうではない
ただ、そうした点まで含めると、むしろ不安になるような平行関係も見えてくる
メール収集スパムボットを防ぐため、無限にランダムなメールアドレスを生成するWebページを作ったことがある: http://web.archive.org/web/20020610054821/http://www.sourtim...
これを動かすと、誰かが自分のマシンをスキャンして、「既知の脆弱なバージョンのXが動いている」としてバグバウンティ申請を何十件も送ってくるかもしれない
90年代半ばには CyberCop Sting というハニーポット製品があり、Secure NetworksのBallistaより先行していた
CyberCop Stingは複数実装のTCP/UDPサービスをシミュレートでき、記憶が正しければ、異なるOSに見えるようTCP/IPスタックの挙動まで設定できた。約30年前としてはかなり革新的な機能だった
[1] https://theswissbay.ch/pdf/Gentoomen%20Library/Security/0321...
[2] https://news.ycombinator.com/item?id=26440139
当然誰かがやっていそうなことなのに、前は一度も思いつかなかったのが少し驚きだし、このアイデアを初めて聞くというのはさらに驚きだ
こうすると結局、ハッカーやボットがサーバーをより詳しく調べるか、少なくともトラフィックがさらに集まる結果にならないだろうか
ほとんどのスクリプトキディが、自分のツールで潜在的なハニーポットやこうした仕掛けを除外しているとは思えない
しかしホストが生きていると分かった後は、どのポートを触るかが問題になる。各サーバーの各ポートをスキャンまたは攻撃するコストが同程度だと仮定すれば、スプーフィングされたポートを見分けられても、成功確率が高い別のマシンを探すほうがよい。ローカルの127.0.0.35でportspoofを動かして応答データやタイミング差を比較することもできるが、探索空間は通常開いている数個のポートから突然5000倍ほどに広がり、別のサーバーのポートのほうが成功可能性が高く見えるかもしれない
たいていのツールは、すべてのポートが開いていて偽陽性を示す状況を想定していない。ペネトレーションテストではよくある話で時間を浪費させはするが、攻撃者に自分のインフラをさらに見る理由を与えたくはない。むしろこの方式のほぼ正反対であるポートノッキングのほうが好みだ
広範な攻撃に対しては、何千万台ものホストに展開されてはじめてある程度効果が出て、そうなって初めて攻撃者がハニーポットだけを探して相互作用するのが非現実的になる。特定標的型攻撃を受けるなら、ハニーポットのポートをエクスプロイトしようとして多少遅延することはあるかもしれないが、脆弱なサービスを動かしていれば結局突破される。またベンダーであれば、潜在顧客のセキュリティチームにスキャンされた際、非常に厄介なセキュリティ質問票に答えなければならなくなるかもしれない
私のウェブサイトでも似たようなことをしている。https://bini.wales はすべてのエンドポイントで 200 を返し、すべての試行を記録するので、自動化攻撃に対するなかなか良いハニーポットになっている
たいていは脆弱な WordPress プラグインや放置されたバックドアを大量スキャンするものを捕まえる。同様に https://varun.ch/login は、ちょっとしたひねりのある WordPress サイトを装っている
いいね。「ハニーポット」という単語が一度も出てこないのがありがたい
昔「本物の」ハニーポットを引き継いで確認したら、30個くらいのポートが開いていて、実際に思わず「これは何のゴミだ」と口にした
ポートを開けておいて、スクリプトキディに何かへアクセスしたと思わせて喜ばせるが、実際には何でもない。閉じたままのハニーポットは、その時点であまりハニーポットらしくない
ハニーポットは攻撃者を引き寄せて検知するために使われ、通常はその挙動やパターンを記録して分析したり遮断したりする。このツールは iptables 以外にももっと多くのロギングがあるとよいし、それ自体だけではハニーポットではないが、発想としてはそれほど遠くない。ただ、GitHub ページがこれを「OS のセキュリティを強化する」と言っているのはまったく信じられない。自動サービススキャナに対する難読化は多少提供するだろうが、MySQL サーバーが 3306 で listen していて、攻撃者が 3306 に接続すれば、結局は MySQL と対話することになる。残りの 65534 個のポートがゴミ応答を返しているかどうかは関係ない
「実行中のインスタンス1つにつき TCP ポート1つにしかバインドしない」とあるが、どう動くのか気になる
すべてのポートをカバーするには 65535 個のインスタンス を動かす必要があるのか?
その後
getsockoptを呼び出して、元のポートが何だったのかを調べている: https://github.com/drk1wi/portspoof/blob/c3f3c34531c59df229e...実際のハードリミットやメモリ使用量はわからないが、たぶん ポートリダイレクト のほうが単純なのだろう
これは潜在的に DoS 増幅器 になり得るのでは?
適切に偽装したパケットを送れば、見かけ上の送信元へ大量のパケットを送り返せるのか?
UDP なら本当にひどいことになり得る