本記事は、オライリージャパンから発行されている「サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考(原題:Black Hat Python)」の学習メモとして、書籍ではPython2で書かれていますが、自分なりに解釈した上でPython3に書き直しをしています。
前回では、PythonのParamikoというパッケージを用いてSSHリバースシェルツールを作成しました。
今回はSSHポートフォワーディング(SSHフォワードトンネリング)という技術について学んでいきます。
SSHポートフォワーディングとは
リモート先のSSHサーバのローカルネットワークに接続したいとき、SSHサーバにアクセスすれば、直接ローカルネットワークにアクセスできますが、SSHサーバに必要なツールがインストールされていなかったりする場合があります。
その際にSSHのポートフォワード機能(ポート転送機能)を使用すれば、ローカルホスト上のポートとリモート先のローカルネットワークのサービス(ポート)間にSSHトンネルを作成し、あたかも直接アクセスしているかのような環境を作ることができます。
SSHポートフォワーディングをしてみる
まず、VM上のUbuntuで以下コマンドを実行し、簡易Webサーバを起動してみます。
> while :; do (echo hello) | nc -lp 8000; > done
上記は、ポート番号8000に接続してきたTCPクライアントに対して"hello"の文字列を返します。
直接アクセスした場合は、もちろんファイアウォールの設定により、外部ネットワークからはアクセスすることができません。
それでは、SSHクライアントからポートフォワーディング機能を用いてアクセスしてみます。
なお、書籍のコマンドではうまくアクセスできないので、以下コマンドを実行します。
> ssh -L 8080:192.168.0.1:8000 -N ubuntu@192.168.0.1 ubuntu@192.168.0.1's password: > nc 127.0.0.1 8080 hello
上記ではローカルホストのポート番号8080とリモートサーバのポート番号8000との間にSSHトンネルを作成しています。
ローカルホストで別ターミナルを開き、ncコマンドで、ローカルホストのポート番号8080にアクセスすると"hello"の文字列が送られてきます。
SSHリバーストンネリング
前述では、UNIX系のOSのような比較的SSHサーバが起動しているようなシステムを想定していますが、ターゲットがWindowsシステムでは基本的にSSHサーバは起動してません。
その時にPythonのParamikoがあれば、ターゲットのWindowsシステムをSSHクライアントとして、リモートのSSHサーバに接続させるようにすれば、同じようなことができるようになります。
書籍ではParamikoの"demos"の中にある"rforward.py"のスクリプトを使用して、SSHリバーストンネリングの方法を解説しています。
以下のGitHubからダウンロードすることが可能です。
GitHub - paramiko/paramiko: The leading native Python SSHv2 protocol library.
ParamikoでSSHリバーストンネリングをしてみる
WindowsのWSL Ubuntu上でApacheを起動し、VM上のUbuntuのSSHサーバにポートフォワーディングさせてみます。
コマンドプロンプトを開いて以下コマンドを実行します。
> python rforward.py 192.168.0.1 -p 8080 -r 192.168.2.1:80 --user ubuntu --password Enter SSH password: Connecting to ssh host 192.168.0.1:22 ... C:...\paramiko\client.py:822: UserWarning: Unknown ssh-ed25519 host key for 192.168.0.1: b'a77c7b5f103bca330f1fd11ace092971' key.get_name(), hostname, hexlify(key.get_fingerprint()) Now forwarding remote port 8080 to 192.168.2.1:80 ...
ローカルホストのポート番号80とリモート先のポート番号8080との間にSSHトンネルが作成されました。
この状態で、VM上のUbuntuでWebブラウザを開き、ローカルホストのポート番号8080にアクセスしてみます。
コマンドプロンプト上で以下のログが出力され、Webサーバとの接続も問題なくできました。
Connected! Tunnel open ('127.0.0.1', 57454) -> ('192.168.0.1', 22) -> ('192.168.2.1', 80) Connected! Tunnel open ('127.0.0.1', 57456) -> ('192.168.0.1', 22) -> ('192.168.2.1', 80) Tunnel closed from ('127.0.0.1', 57454) Tunnel closed from ('127.0.0.1', 57456)
最後に
今回はSSHポートフォワーディングを利用した、SSHリバーストンネリングについて学びました。
説明だけ読んでいるとイメージし難いですが、実際に動作を確認しながら行ったほうが理解が早いと思います。