Webサービスの開発において,ペネトレーションテスト*1はセキュリティ対策上重要です.しかしながら,開発環境に脆弱性を伴ったウェブサイトを実行するサーバーをインストールするのはセキュリティ上不都合です.最近はDockerによる仮想環境が普及しており,Docker上に一時的にいろいろなものを構築することで,セキュリティを考慮しながらたくさんのツールを簡単に起動できるようになりました.
この記事では,WebGoatというわざと脆弱性を含ませたWebアプリケーションに対して,OWASP ZAPからペネトレーションテストを行い,脆弱性を見つける作業を行う方法をまとめます.
注意
この記事を実践する際は,決して他人に迷惑をかけないようお願いします.自分のパソコンの中で完結させてください.
この記事はあくまでもペネトレーションテストを実践する方法を紹介しています.悪用厳禁です.
環境
- MacOS 10.14.6
- Docker Desktop for Mac 2.1.0.1
- owasp/zap2docker-stable (OWASP ZAP 2.8.0)
- WebGoat 8.0
準備
docker-composeを使うと,WebGoatとOWASP ZAPを同時に簡単に起動できます.例えば以下のようなymlファイルを作成します.
# docker-compose-owasp-zap.yml version: '3' services: web: image: webgoat/webgoat-8.0 ports: - "8080:8080" networks: - goat tty: true owasp: image: owasp/zap2docker-stable command: bash -c "zap.sh -cmd -addonuninstall hud && zap-webswing.sh" volumes: - ./zap:/zap/wrk/ ports: - "8081:8080" - "8090:8090" depends_on: - web networks: - goat - default tty: true networks: goat: internal: true
このファイルを実行します.
$ docker-compose -f docker-compose-owasp-zap.yml up owasp
まず,webでwebgoatを実行します.webgoatはport 8080で起動されるため,portを8080に設定します.このアプリケーションがホストにブリッジされるのはセキュリティ上問題があるため,internalなnetworkであるgoatを作成し,それを割り当てます.
ホストのブラウザー(ここではChromeを使用)からhttp://0.0.0.0:8080/はアクセス不可であることを確認します.
これでは使えないので,上記の例ではこの隔離されたネットワークをowaspに接続しています.owaspもデフォルトでport 8080に起動されるため,8081に変更しています.
ホストのブラウザーからhttp://localhost:8081/zap/にアクセスすると,OWASP ZAPのGUIにアクセスできます.
OWASPはプロキシ機能を持っており,これをport 8090からホスト側よりアクセスできるようにします.Tools > Options > Local Proxies より,8090がプロキシ用のポートとなるよう設定します.
さて,プロキシからアクセスするための別のブラウザー(ここではFirefoxを使用)で,プロキシ設定画面より,localhost:8090を通じてアクセスするように設定します.
http://web:8080/WebGoatよりWebGoatにアクセスします.すると,「警告: 潜在的なセキュリティリスクあり.Firefox はセキュリティ上の潜在的な脅威を検知したため、web への接続を中止しました。このサイトに訪問すると、攻撃者がパスワードやメールアドレス、クレジットカードの詳細な情報を盗み取ろうとする恐れがあります。」というエラーが表示されます.OWASP用の証明書をインストールする必要があります.
OWASPよりTools > options > Dynamic SSL certificates から証明書をgenerateし,Viewすると.certがダウンロードできます.
これをブラウザーに登録します.
また,HUDプラグインが邪魔をするため,アンインストールしています.
zap.sh -cmd -addonuninstall hud
余談ですが,もともとOWASP ZAPはJavaのSwingを利用したGUIを採用していますが,Swingをブラウザーで動かすWebSwingというライブラリーがあり,Dockerで動くように工夫しているようです*2.
準備ができたので,http://web:8080/WebGoat/よりWebGoatにアクセスします.
以上で,ブラウザーから,OWASPのプロキシを通じて,外部から隔離されたWebGoatにアクセスできるようになりました.
終了するには,
$ docker-compose -f docker-compose-owasp-zap.yml down
を実行します.
contextの作成
Contextは例えば以下のような形で作成します.(拡張子が.contextであるxmlファイルはZAPにインポートできます.)
# main.context <?xml version="1.0" encoding="UTF-8" standalone="no"?> <configuration> <context> <name>main</name> <desc/> <inscope>true</inscope> <incregexes>http://web:8080/WebGoat.*</incregexes> <excregexes>http://web:8080/WebGoat/css.*</excregexes> <excregexes>http://web:8080/WebGoat/fonts.*</excregexes> <excregexes>http://web:8080/WebGoat/images.*</excregexes> <excregexes>http://web:8080/WebGoat/js.*</excregexes> <tech> <include>Db</include> <include>Db.CouchDB</include> <include>Db.Firebird</include> <include>Db.HypersonicSQL</include> <include>Db.IBM DB2</include> <include>Db.Microsoft Access</include> <include>Db.Microsoft SQL Server</include> <include>Db.MongoDB</include> <include>Db.MySQL</include> <include>Db.Oracle</include> <include>Db.PostgreSQL</include> <include>Db.SAP MaxDB</include> <include>Db.SQLite</include> <include>Db.Sybase</include> <include>Language</include> <include>Language.ASP</include> <include>Language.C</include> <include>Language.JSP/Servlet</include> <include>Language.PHP</include> <include>Language.XML</include> <include>OS</include> <include>OS.Linux</include> <include>OS.MacOS</include> <include>OS.Windows</include> <include>SCM</include> <include>SCM.Git</include> <include>SCM.SVN</include> <include>WS</include> <include>WS.Apache</include> <include>WS.IIS</include> <include>WS.Tomcat</include> </tech> <urlparser> <class>org.zaproxy.zap.model.StandardParameterParser</class> <config>{"kvps":"&","kvs":"=","struct":[]}</config> </urlparser> <postparser> <class>org.zaproxy.zap.model.StandardParameterParser</class> <config>{"kvps":"&","kvs":"=","struct":[]}</config> </postparser> <authentication> <type>2</type> <loggedin>\Q<span>testuser</span>\E</loggedin> <loggedout>\Qaction="/WebGoat/login"\E</loggedout> <form> <loginurl>http://web:8080/WebGoat/login</loginurl> <loginbody>username={%username%}&password={%password%}</loginbody> </form> </authentication> <users> <user>0;false;cQ==;2;cQ==~cXI=~</user> <user>1;true;dGVzdHVzZXI=;2;dGVzdHVzZXI=~dGVzdDEyMzQ=~</user> </users> <forceduser>1</forceduser> <session> <type>0</type> </session> <authorization> <type>0</type> <basic> <header/> <body/> <logic>AND</logic> <code>-1</code> </basic> </authorization> </context> </configuration>
GUIの項目ごとに対応しています.
- incregexes : コンテキストに含めるurlの正規表現
- excregexes : コンテキストに含めないurlの正規表現
- tech : 使用する技術 (サーバー側に使用しているライブラリなど)
- urlparser, postparser : クエリーで利用する区切り文字など
- authentication : ログイン状態を保つために必要な認証情報
- users : 事前に作成したWebGoatのユーザー
- forceduser : Forced user modeで使用されるユーザー
WebGoatに手動アクセス
プロキシを通じてブラウザーからWebGoatに手動でアクセスし,発生しうるリクエストをすべてOWASPに記録させていきます.メニューをクリックするだけではだめで,例えば以下の画面では,"search logs"ボタンをクリックして,POSTリスエストを発生させるのがコツです.
Active Scanの実行
contextと手動アクセスが完了したら,Active Scanを実行します.大量のリクエストが実行されたあと,Alertsに脆弱性候補がリスト化されます*3.
結果をレポートに出力します.
レポートの解析
OWASP ZAPが指摘するのは脆弱性となりうる可能性なので,実際に脆弱性となりうるかを検証していきます.
例えば,レポートに,
SQL Injection (SQL injection may be possible.)
URL http://web:8080/WebGoat/SqlInjection/assignment5a
Method: POST
Parameter: account
Attack: Smith AND 1=1 --
と記載があります.状況からはaccountがユーザー名と一致するかを確認していると推測されるため,Smithをダミーとして常にTrueとなりうるクエリーとなるように工夫します.以下のリクエストを送信してみます.
POST http://web:8080/WebGoat/SqlInjection/assignment5a
injection=1+1&operator=or&account=Smith' OR 1 = 1; --
下記のレスポンスを得ました.
You have succeeded:
USERID, FIRST_NAME, LAST_NAME, CC_NUMBER, CC_TYPE, COOKIE, LOGIN_COUNT,
101, Joe, Snow, 987654321, VISA, , 0,
101, Joe, Snow, 2234200065411, MC, , 0,
102, John, Smith, 2435600002222, MC, , 0,
102, John, Smith, 4352209902222, AMEX, , 0,
103, Jane, Plane, 123456789, MC, , 0,
103, Jane, Plane, 333498703333, AMEX, , 0,
10312, Jolly, Hershey, 176896789, MC, , 0,
10312, Jolly, Hershey, 333300003333, AMEX, , 0,
10323, Grumpy, youaretheweakestlink, 673834489, MC, , 0,
10323, Grumpy, youaretheweakestlink, 33413003333, AMEX, , 0,
15603, Peter, Sand, 123609789, MC, , 0,
15603, Peter, Sand, 338893453333, AMEX, , 0,
15613, Joesph, Something, 33843453533, AMEX, , 0,
15837, Chaos, Monkey, 32849386533, CM, , 0,
19204, Mr, Goat, 33812953533, VISA, , 0,
サーバーに保存されている全ユーザーの情報を取得することができました*4.ZAPが指摘する通り,SQL Injectionが可能であることが分かりました.
まとめ
実際に全ユーザー情報を取得できてしまうと,脆弱性の恐ろしさが実感できます.
こういった作業を複数のパソコンで実践するのはセットアップが非常に面倒ですが,Dockerのおかげでパソコン1台で完結するので便利です.
*1:実際に既知の技術を用いて侵入を試み,システムに脆弱性がないかどうかテストすること
*2:WebSwing · zaproxy/zaproxy Wiki · GitHub
*3:スクリーンショットに表示されている脆弱性はWebGoatのすべてを網羅していません.
*4:WebGoat/CreateDB.java に答えがあり比較.