正しいサーバーの乗っ取り方〜OS Command Injection編〜
- 2018.10.11
- インフラ
初めまして。インフラエンジニアの田坂です。
先日OS Command Injection攻撃のテストをしてみたので内容を投稿したいと思います。
概要
セキュリティ等が正しく設定されていないLinuxサーバー上で運用されているアプリケーションに対して細工したURLを利用して、OS Command InjectionによりサーバーのOS側を操作出来るかテストします。
また、サーバーへのFirewall等の設定が正しく行われていない場合、OSへログイン可能となりサーバーそのものを奪取出来る事を確認します。
なお、実際のコマンドについてはセキュリティ上の観点から掲載致しません。
OS Command Injectionについてはこちらを参考に…
CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
CWE-78 OSコマンドインジェクション
準備
サーバー準備
- CentOS 7 minimal
- JDK 1.8.0
- Tomcat 7.0.x
- 簡単なWebアプリケーション
※今回はサンプルでログイン画面の雛形を表示するだけのものを用意しました(画面サンプルで実際には「Submit」ボタンは機能しません)
不正ユーザーのパスワード設定用SHA-512ハッシュを準備
$6$4KevkAwZaLI1bZG/$jmDr8TfqL.fcl57GMGP8SO4I8iZDQx0Z2LgxH4BdF(~略~)
今回のOS、アプリケーションはデモのため下記の設定を行なっています。
- OSインストール後にyum updateでパッケージを最新にする
- SELinux無効化
- visudo等でwheelグループへのsudo権限を付与
- Tomcatの動作Userをwheelグループへ追加
- TomcatはApache等と連携せず、Coyoteで8080ポートを利用
- Firewallはアプリが利用する8080ポート、SSHポートのみ外部接続を全て許可とする
- SSHのパスワードログイン許可(※許可しなくてもTomcatの実行ユーザーにroot権限があれば突破可能)
特定のアプリケーション、ミドルウェアが悪いと言った誤解をされないようにご注意ください。
動作確認
実際にサーバーがOS Command Injectionを受け付けるかをテストしてみます
まず、Tomcatが起動していることを確認します。
$ ps aux|grep [t]omcat root 2620 0.1 13.0 1533696 132720 ? Sl 02:04 0:51 /usr/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/opt/apache-tomcat/endorsed -classpath /opt/apache-tomcat/bin/bootstrap.jar:/opt/apache-tomcat/bin/tomcat-juli.jar -Dcatalina.base=/opt/apache-tomcat -Dcatalina.home=/opt/apache-tomcat -Djava.io.tmpdir=/opt/apache-tomcat/temp org.apache.catalina.startup.Bootstrap start $
ブラウザで細工したURL(CWE-78 参照)を使ってアクセスします。
Tomcatが停止したため、サイトへのアクセスが出来なくなりました!
実行例)
Javaのプログラムに対して、「java.lang.Runtime.getRuntime().exit(0);」を実行
$ ps aux|grep [t]omcat $
はい。Tomcatが停止しました。ほぼ期待通りです。
本来のテストのためにTomcatを再び起動しておきます。
テスト開始!
ユーザーを作成してみます
では早速tmpuserと言うユーザーを作成してみます。
まず、ユーザーが居ない事を確認します。
$ grep tmpuser /etc/passwd $
ブラウザで細工したURL(CWE-78 参照)を使ってアクセスします。
表示上変化は見られませんが実際にはユーザーが作成されています。
Shellでの実行例)
useradd tmpuser
再度確認すると作成されています。
$ grep tmpuser /etc/passwd tmpuser:x:501:501::/home/tmpuser:/bin/bash $
ついでにパスワードも設定しておきましょう。
ブラウザで細工したURL(CWE-78 参照)を使ってアクセスします。
やはり表示上変化は見られませんが先ほど作成したユーザーのパスワードが変更されています。
Shellでの実行例)
usermod -p $6$4KevkAwZaLI1bZG/$jmDr8TfqL.fcl57GMGP8SO4I8iZDQx0Z2LgxH4BdF(~略~) tmpuser
再度確認するとパスワードが設定されています。
$ sudo grep tmpuser /etc/shadow tmpuser:$6$4KevkAwZaLI1bZG/$jmDr8TfqL.fcl57GMGP8SO4I8iZDQx0Z2LgxH4BdF(~略~):17544:0:99999:7::: $
作成したユーザーをwheelグループへ追加しsudo権限を付与します
ユーザーの所属グループを確認します。
$ grep tmpuser /etc/group tmpuser:x:501: $
ブラウザで細工したURL(CWE-78 参照)を使ってアクセスします。
今回も、やはり表示上変化は見られませんが、wheelグループへ追加されています。
Shellでの実行例)
usermod -G wheel tmpuser
ユーザーがwheelグループに所属している事が確認出来ました。
$ grep tmpuser /etc/group wheel:x:10:tmpuser tmpuser:x:501: $
作成したユーザーでサーバーへログイン!
今回は自分のMacから接続してみます
$ ssh tmpuser@192.168.10.46 The authenticity of host '192.168.10.46 (192.168.10.46)' can't be established. RSA key fingerprint is c4:5f:48:ca:f9:(~略~):5f:2b:20:4f:5e. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.10.46' (RSA) to the list of known hosts. tmpuser@192.168.10.46's password: [tmpuser@localhost ~]$
はい。接続できました。
sudoコマンドも実行してみます。
[tmpuser@localhost ~]$ sudo grep tmpuser /etc/shadow tmpuser:$6$4KevkAwZaLI1bZG/$jmDr8TfqL.fcl57GMGP8SO4I8iZDQx0Z2LgxH4BdF(~略~):17544:0:99999:7::: [tmpuser@localhost ~]$ sudo shutdown -h now Broadcast message from tmpuser@localhost.localdomain (/dev/pts/1) at 11:04 ... The system is going down for halt NOW! [tmpuser@localhost ~]$
はい。サーバーも停止できました。
これでユーザー作成や、ログイン履歴も消し放題です!
知らない間に勝手にユーザーが作られています。怖いですね。。。
$ sudo tail /var/log/secure Jun 13 10:09:26 localhost useradd[4352]: new group: name=tmpuser, GID=501 Jun 13 10:09:26 localhost useradd[4352]: new user: name=tmpuser, UID=501, GID=501, home=/home/tmpuser, shell=/bin/bash Jun 13 10:16:05 localhost usermod[4380]: add 'tmpuser' to group 'wheel' Jun 13 10:16:05 localhost usermod[4380]: add 'tmpuser' to shadow group 'wheel' Jun 13 10:56:25 localhost usermod[4494]: change user 'tmpuser' password
もしパスワードでSSH出来ない場合
下記の項目を追加で設定しますが複雑になるため今回は割愛させて頂きます。
- sshdの設定に、パスワードログインを許可する設定を追加
- sshdを再起動
結果
セキュリティ、特に実行権限が正しく使用されていないサーバーに対して無事?にOS Command Injection攻撃が成立しました。
アプリケーションユーザーに設定されたsudo権限を悪用してサーバーを乗っ取る事が出来ました。
まとめ
実際に攻撃を行ってみることにより、攻撃者が何を行いたいのか、どこを攻撃したいのか等の部分が見えてきます。
最近は敷居が下がってきていて、自宅サーバーや、自前のクラウドサーバーを公開する方も増えてきていますが、攻撃されてしまった、乗っ取られてしまったという事が無い様に設定の見直しを行ってもらう機会になればと思います。
例えば、下記の様な事が考えられます。
- SELinuxを有効化しておく(ポリシーの設定はしましょう!)
- Firewallで不要なポートは閉じ、接続元のIP制限をしっかりしておく
- アプリケーションの実行ユーザーは最小限度の権限に設定しておく
- アプリケーションの実装を見直してみる
- ミドルウェアを常に最新状態に保つ
- 脆弱性発見ツール等を利用してみる
- etc…
今回のテストでは「アプリケーションの実行ユーザーは最小限度の権限に設定しておく」と言う部分で、root権限を持たないtomcatと言うユーザーでアプリケーションを起動してみたところ、アプリケーションで下記のようなエラーとなりユーザーを作成する事は出来ませんでした。
java.io.IOException: Cannot run program "useradd": error=13, 許可がありません
これだけでかなりリスクの軽減が期待できます。
最後に
OS(特にLinux系)や、オープンソース、アプリケーション等のセキュリティに興味をお持ちの方、ぜひ一緒に働きませんか?
ご応募お待ちしております!
-
前の記事
Aimingエンジニア有志が技術書典5で技術同人誌を頒布します 2018.10.01
-
次の記事
Unity reimport 差分警察24時 2018.10.25