Docker
Slack
Docker2Day 20

Dockerを使ってOSコマンドインジェクションが出来るSlack botを作った話

More than 1 year has passed since last update.


はじめに

この記事はDocker2 Advent Calendar 2016 の20日目の記事です.


所属している部活の部内コンテストで,部員にDockerの宣伝も兼ねてOSコマンドインジェクションが出来るSlack botを作ったので,そのことについて書きます.


動機

元々オンラインジャッジに興味がありDocker実戦活用ガイド を読んで自分も似たようなものを開発したい,部活のメンバーにDockerを布教したいなどの思いから開発しました.

またideoneのようなオンラインコンパイラのAPIを利用しなかったのは自身の勉強のためです.


Dockerとは

Dockerとはコンテナ型仮想化を行うソフトウェアのことで,起動が早く軽量なことが特徴です.オンラインジャッジは任意コードを実行可能なサービスであり,環境が破壊されないように仮想化技術などで保護してやる必要があります.また,レスポンスの速さを考えるとDockerはその軽量さからオンラインジャッジに向いていると言えます.


OSコマンドインジェクションとは

ググると次のように書いてありました.


閲覧者からのデータの入力や操作を受け付けるようなWEBサイトで、プログラムに与えるパラメータにOSに対する命令文(コマンド)を紛れ込ませて不正に操作する攻撃。


http://senmon.cfc.ac.jp/studentreport/report2/OS.html


作ったもの

odanado/slackbot-os-command-injection においてあります.


botアカウントの取得

https://slack.com/apps/build を開きます.

スクリーンショット 2016-12-20 23.31.24.png

右のMake a Custom Integrationを選択します.

スクリーンショット 2016-12-20 23.31.16.png

Botsを選択します.

スクリーンショット 2016-12-20 23.31.40.png

作りたいbotの名前を入力します.今回はos-command-injectionという名前にしました.

これでbotアカウントの取得は完了です.

API Tokenを控えておきます.


Docker in Docker

Dockerコンテナの中でDockerを利用することはDocker in Dockerと呼ばれ公式のリポジトリでそのイメージが配布されていました.

https://hub.docker.com/_/docker/

Docker in Dokcerを実現する方法には2種類あり http://qiita.com/sugiyasu-qr/items/85a1bedb6458d4573407 で解説されています.

今回は,ホストマシン上の Docker daemon を共有することでDockerの中でDockerを利用しました.

そのためdocker-compose.ymlではホスト側のdocker.sockをコンテナにマウントしています.


python-rtmbot

言語は普段書き慣れているpythonを使い,Slack botのフレームワークを調べるとpython-rtmbotがヒットしたのでこれを利用しました.

使い方としてはplugins以下に自分のbot用のディレクトリを掘り,その中にメソッドprocess_messageを持つpythonスクリプトを配置するだけです.process_messageの引数dataにbotが参加しているメッセージが流れてくるのでそれを処理してやります.


リソースの割り当て

任意コマンドを実行するコンテナにはDocker実戦活用ガイドを参考にある程度の制限を設けています.


constant.py

StartArgs = {}

StartArgs['--net'] = 'none'
StartArgs['--cpuset-cpus'] = '0'
StartArgs['--memory'] = '128m'
StartArgs['--memory-swap'] = '128m'
StartArgs['-w'] = '/workspace'
StartArgs['--hostname'] = 'os-command-injection'
StartArgs['--ulimit'] = ['fsize=1000000']
StartArgs['--pids-limit'] = '10'

今回の場合だと,ネットワークは無効,CPUは0番目を割り当てる,メモリとスワップは128MB,生成できるファイルの上限は1MB,プロセスの上限は10個となっています.


実行方法

$ git clone https://github.com/odanado/slackbot-os-command-injection

$ cd slackbot-os-command-injection/
$ docker-compose run -d -e SLACK_TOKEN=$SLACK_TOKEN bot

OSのコマンドを実行する環境だけでなく,botが動作する環境もDokcer上で構築したため,新しいソフトウェアのインストールをすることがなく,少ないコマンドをただ叩くだけで動作します.美しい


動作の様子

スクリーンショット 2016-12-20 23.57.15.png

このようにbot宛にメンションを飛ばしてやると実行結果を返してくれます.