生産性のない話

趣味の範囲でサイバーセキュリティの話

XdebugとNetBeansを使ったDrupalのデバッグ環境をdocker-composeのみで立てる

昨年の末ごろにデバッガを使って脆弱性検証を行う勉強会に参加させていただきました。

※好評につき追加開催※ デバッガでWordPress本体やプラグインの脆弱性を追いかけてみよう - connpass

とても参考になりました。その時の内容は下記の記事がとても詳しくまとめてくれています。

tigerszk.hatenablog.com

自分が脆弱性検証をやるときにデバッガを使うことはやったことがなかったのですが、そういう方法があるというのは新しかったです。

脆弱性検証の場合、別に開発するわけではないのであくまでプロジェクトは一時的なもので、また複数のバージョンを立てて壊してとしていくので、そういう点でDockerとの相性がよく、自分もかなりの頻度で使っています。 Dockerを使ってこういう環境を立てておくと、後々応用が利きそうだなと思いました。

ということで今回はXdebugNetBeansを使ったデバッグ環境を立てます。

対象としては先日 Drupalgeddon2(CVE-2018-7600) の脆弱性が見つかったDrupalデバッグ環境を立ててみます。

NetBeansのDockerコンテナとしては以下を参考にしました。

postd.cc

Dockerを使ってNetBeans IDEGUIで起動できます。

  • Dockerfile
FROM debian:latest

RUN apt-get update && apt-get install -y wget openjdk-8-jdk && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    rm -rf /tmp/*

ADD state.xml /tmp/state.xml

RUN wget http://download.netbeans.org/netbeans/8.2/final/bundles/netbeans-8.2-php-linux-x64.sh -O /tmp/netbeans.sh -q && \
    chmod +x /tmp/netbeans.sh && \
    echo 'Installing netbeans' && \
    /tmp/netbeans.sh --silent --state /tmp/state.xml && \
    rm -rf /tmp/*

CMD /usr/local/netbeans-8.2/bin/netbeans

NetBeansPHPIDEをインストールしています。state.xmlというのは一回インストールしたときに「--record」というオプションを付けて出力したファイルで、これを指定して 「--silent」オプションを付けることでGUIなしでインストールできます。

実行時にはGUIで起動するためにホスト側で「xhost +」とか実行してX Window Systemの認証を通しておく必要があります (終わったら「xhost -」とかで認証拒否の状態に戻すことを推奨します)。

次にDrupalのDockerコンテナです。公式のものにXdebugをインストールしています。

FROM drupal:7.57-apache

RUN pecl install xdebug
・・・

Xdebugの設定は以下の通りです。

[xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_connect_back=0
xdebug.remote_autostart=1
xdebug.remote_host=172.42.0.4
xdebug.remote_port=9000
xdebug.max_nesting_level=1000
xdebug.idekey="netbeans-xdebug"

設定についてはいろいろと必要なオプションがあります。 また、デバッガの接続元のIPを指定する必要があるので、NetBeansのIPを指定する必要があります。 そのため、docker-composeでネットワークを作成し、IPを固定しています。

また、デバッグ対象となるアプリケーションのファイルを共有しておく必要があるので、ボリュームを作成しています。 このボリュームを触るときに権限の設定が面倒なので、NetBeansはrootで動かしています。

以上から出来上がったDockerの設定ファイルは以下になります。

github.com

これをビルドします。結構時間かかります。

docker-compose build
docker-compose up

うまく起動すると、NetBeans IDEが起動します。

f:id:blueBLUE:20180523231849p:plain

あと、ローカルホストに行くとDrupalインストーラが起動します。 そのままだとベースになるコンテナのイメージは drupal:7.57-apache になっています。

f:id:blueBLUE:20180523231911p:plain

データベースはMySQLのコンテナが同時に立ちます。 パラメータは以下になっているので、入力してインストールします。

  • データベース名:drupal
  • データベースのユーザ名:drupal
  • データベースのパスワード:password
  • データベースのホスト:drupal-db
  • データベースホストのポート:3306

インストールが終わったら、NetBeansの設定です。 まずは新規プロジェクトを作ります。 PHPの既存のソースを選択します。

f:id:blueBLUE:20180523231932p:plain

ソースのフォルダにはDrupalのコンテンツがマウントしてある「/root/project/drupal」を指定します。

f:id:blueBLUE:20180523232014p:plain

ローカルのWebサイトとして、プロジェクトURLは対象となるDrupalのホスト(ここでは「http://drupal-vuln/」)とします。

f:id:blueBLUE:20180523232024p:plain

設定が終わったらデバッグを開始します。 メニューバーの一番右にあるデバッグ開始のボタンを押します。

リクエストを待ち受けているので、この状態で、攻撃コードを打てば、デバッグが開始されます。 その前にブレークポイントを設定しましょう。

三井物産セキュアディレクション (MBSD) の検証レポートによると、「includes/common.inc」の「#post_render」を処理する箇所でコード実行が行われるようなので、ここにブレークポイントを設定します。 Drupal 7系への攻撃ではリクエストは2回あり、1回目でキャッシュに実行するコマンドを仕込み、2回目で実行します。

f:id:blueBLUE:20180523232059p:plain

これで実行すると、1回目のリクエストでは何度もこの関数を通るのですが、そのうちの1回でパラメータで指定した値が変数に入っている処理があります。2回目のリクエストで1回目のリクエストでキャッシュされた値が取り出され、コード実行が行われることが確認できます。

f:id:blueBLUE:20180523232139p:plain

  • 2回目のリクエストで呼び出されている変数

f:id:blueBLUE:20180523232149p:plain

ここまでやってあれですが、結構処理が分かりにくい上に、リクエストが2つに分かれているので、初心者の勉強にはあまりいい例ではないのかな……と。

ただ、任意のコードが実行される個所は分かりました。

せっかくなのでDrupal 8系でもやってみました。

DrupalのDockerfileとdocker-compose.ymlのバージョン(7.57-apache ⇒ 8.5.0-apache)を書き換えてビルドするだけ…… と思ったらXdebugのインストールパスがかわっていました、、、

DrupalのDockerfileのphp.iniの値も書き換える必要があります。 (何かオプションとかで固定できそう?)

また、Dockerで共有したボリュームが残っているので、このままやると、Drupal 8のコンテンツがDrupal 7のコンテンツで上書きされます。 ので、先に作ったボリュームは削除しておきましょう。

f:id:blueBLUE:20180523232211p:plain

同じように「docker-compose up」のコマンドだけで、NetBeansが起動し、Drupal 8が立ちました。

f:id:blueBLUE:20180523232222p:plain

後の流れは同じです。ブレークポイントを張って、デバッグを開始して、攻撃コードを打ちます。

f:id:blueBLUE:20180523232306p:plain

ということで、簡単にXdebugNetBeansを使った脆弱性検証の環境が立ちました。

Drupal脆弱性の攻撃コードが出る前に用意しとけよ、という話ですね。 まったくもって、その通りです。

これ自体はもう少し応用が利きそうなので、PHP系のCMSJAVAミドルウェアを使ったアプリケーションは同じことができそうだなーと思っています。 そのへんは今後、頑張っていきたいです。

参考

デバッガを利用してWebアプリの脆弱性を分析してみた - とある診断員の備忘録

Dockerを用いたGUIアプリケーションの実行 | POSTD

GitHub - fgrehm/docker-netbeans: NetBeans in a container

NetBeans NetBeans 日本語サイト

NBIFAQ - NetBeans Wiki

Docker for Windowsでxdebugを使う

Drupalgeddon2に関する検証レポート(CVE-2018-7600)

Docker上でGoogle Chromeを使ったWebクローラを作る

最近Webサイトのクローリング(スクレイピング?)に興味を持ちまして、Webサイトのクローラ的なものを作りたいと思い、いろいろ試行錯誤していました。

Webサイトのコンテンツを取得するなら、一番簡単なものだとwgetcurl、ちょっと手を加えるならスクリプトを書く、Pythonならrequestsやmechanizeなどのライブラリを使うと、比較的単純なことなら簡単にできます。 より高度なことをやろうとすると、やはり実際のブラウザを利用するのが一番でしょう。

昨年末にこちらの記事を読みまして、

qiita.com

Docker上でGoogle ChromeをHeadlessモードで動かし、Seleniumで制御してスクレイピングしようという記事です。

とても面白そうだったのですが、自分の欲しい機能にあと一歩というところでした。

これにmitmproxyを組み合わせれば、幸せになれそうだったので、試してみました。

mitmproxy - an interactive HTTPS proxy

mitmproxyというのは、その名の通り、MITM(Man In The Middle)を行うプロキシです。 暗号化された通信に割り込んで、盗聴、改ざんを行う攻撃手法ですが、このテクニック自体は攻撃に限らず色々な場面で利用されています。

mitmproxyを利用すると、HTTPS(HTTP)の通信の中身を覗き見たり、書き換えたりが可能になります。

コンテンツを取得するだけであればそんなことをする必要はないのですが、これができると色々と便利なので、何とか組み込みたいと思いました。

で、さっそく、上の記事にある内容をトレースしつつ、mitmproxyを挟んでみたのですが、結論を言うとダメでした。 できました。

mitmproxyを利用するとき、「ブラウザ⇔mitmproxy⇔Webサイト」という形で通信が流れますが、ブラウザとmitmproxyの間はmitmproxyが発行する自己証明書が利用されます。こちらはブラウザから見ると不正な証明書になります。そこで、Chromeに「--ignore-certificate-errors」というオプションを付けてやることで、不正な証明書のエラーを無視して通常通りアクセスできるようになるはずです。

ですが、なぜかChromeをHeadlessモードで動かすと、このあたりのオプションが正常に動かないらしく、Chrome Headlessでmitmproxyを動かすのは現状難しそうという結論に至りました。

もう少ししたら、Chrome Headlessでも正常に動くようになるかもしれないので、そこは気長に待つことにします(あるいは僕の知らない別のオプションがあるのかもしれませんが、どなたか知っていたら教えていただきたい……)。

追記(2018/5/15)

個人のプロファイルにルート証明書をちゃんと読み込ませてやると、証明書のエラーがでなくなり、うまくいきました。 一番下に追記しています。

ということで、今回はChrome Headlessを使うことは諦めて、普通のGoogle ChromeをDockerから動かすことを考えました。

unskilled.site

こういう方法を使ってDocker内のGUIアプリケーションを起動させることができるようです。Linuxでリモートから(ここではローカルで動くコンテナ)のX Window Systemを許可してUNIXソケット経由でディスプレイを共有する方法です。

この方法を使ってGoogle ChromeをインストールしたコンテナでChromeを起動させると見事にChromeが立ち上がり、普通のGUIアプリケーションとして利用可能となりました。

f:id:blueBLUE:20180509211449p:plain

つまり、わざわざHeadlessモードを使わなくとも、GUIアプリケーションとしてDocker内で起動させることもできるということです。

ということで、Chrome Headlessは無視してとりあえず、GUIアプリケーションとして動作するGoogle Chromeのコンテナイメージを作ってみました。

インストールしたもの:

一応日本語環境で利用することを想定して日本語関係のフォントやパッケージも入れました。

本当はイメージを分けて作った方が後々やりやすいのかもしれませんが、mitmproxyの起動時に作成される自己証明書をChromeが入っているコンテナにインストールする必要があり、いろいろと面倒だったので、ひとまず全部一つのコンテナイメージにぶち込みました(イメージサイズが1.5Gくらいになってます……)。

出来上がったDockerfileがこちらになります。

github.com

起動時に色々やることがあるので、docker-entrypoint.shが色々面倒なことになっています。

docker-composeでそのまま起動すると、普通にGoogle Chromeが起動するはずです。mitmproxyのログはそのまま標準出力に流れていきます。 (追記 : 今はHeadlessでGoogleにアクセスするようになっています。GUIで利用する場合はdocker-compose.ymlと、実行スクリプトを書き換えるなどする必要があります)

ただし、X Window Systemの認証を許可するために、ホスト側で以下のコマンドを実行しておく必要があります。

xhost local:

認証を許可してそのままにしておくのはセキュリティ的によろしくないので、終わったら戻しておきましょう。

xhost -local:

Chromeを自動で動かしたい場合はscriptsフォルダ内に「crawling-script.sh」を作成すると、そこに記載されているコマンドを実行します。 例として、特定のサイトにアクセスするスクリプトを実行します。

  • scripts/crawling-script.sh
#!/bin/sh

python3 /home/chrome/scripts/crawling.py
  • scripts/crawling.py
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from datetime import datetime
from time import sleep

if __name__ == '__main__':

    url = 'https://www.google.co.jp/'

    outputdir = '/home/chrome/output/'
    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")

    options = webdriver.ChromeOptions()
    options.binary_location = '/usr/bin/google-chrome'
    options.add_argument('--no-sandbox')
#    options.add_argument('--headless')
    options.add_argument('--disable-gpu')

    options.add_argument("--start-maximized")

    options.add_argument('--ignore-certificate-errors')
    options.add_argument('--ssl-protocol=any')
    options.add_argument('--allow-running-insecure-content')
    options.add_argument('--disable-web-security')

    PROXY = 'localhost:8080'
    options.add_argument('--proxy-server=http://%s' % PROXY)

    LANGUAGE = 'ja'
    options.add_argument('--lang=%s' % LANGUAGE)

    capabilities = options.to_capabilities()

    driver = webdriver.Remote(command_executor='http://localhost:9515', desired_capabilities=capabilities)

    try:
        driver.get(url)
        sleep(3)
        print('title:', driver.title)
        driver.save_screenshot(outputdir + 'screenshot-' + timestamp + '.png')
    finally:
        driver.quit()

これが置いてある状態で「docker-compose up」すると、サイトにアクセスしてスクリーンショットを撮って終了します。

f:id:blueBLUE:20180509211734p:plain

「--headless」のオプションを付けると、Headlessモードで動きますが、先に述べた通りの理由でHTTPSのサイトではmitmproxyのエラーのために正常にアクセスできません。 アクセス先がHTTPのみのサイトであれば、問題はないですが。

次にscriptsフォルダに「mitmproxy-script.py」を作成します。例として、アクセス先のレスポンスからhtmlファイルをすべて保存するスクリプトです。 (こちらのサイトを参考にしました)

  • scripts/mitmproxy-script.py
#!/usr/bin/env python

from mitmproxy import io
from mitmproxy.exceptions import FlowReadException

outputpath = '/home/chrome/output/'

def response(flow):
    content_type = flow.response.headers.get('Content-Type', '')
    path = flow.request.url.replace('/', '_').replace(':', '_')
    if content_type.startswith('text/html'):
        with open(outputpath + path, 'w') as f:
            f.write(flow.response.text)

これで起動すると、outputフォルダに保存されたダウンロードしたhtmlファイルが保存されているのを確認できます。

f:id:blueBLUE:20180509212120p:plain

mitmproxyのサンプルはこちらにあります。

こんな感じでmitmproxyとseleniumスクリプトを書いて、うまくやれば好きなWebサイトに好きなようにアクセスした際の通信を解析できるようになる、と思います。 スクリプトについては今後作っていこうかと思います。 まあ、seleniumもmitmproxyも割とサンプルはあるので書きやすいのではないかなー、と。

とにかくWebサイトの解析用のクローラを作ることはできたので、満足はしました。ただ、Headlessで動かせなかったのは残念でした。 なにかしら方法はありそうなので、もうしばらく調べてみたいです。 あと、FirefoxにもHeadlessモードが搭載されているそうなので、いずれはそっちも試してみたいです。

最後に、Webサイトのクローリング、スクレイピングはマナーを守って行うようお願いします。

追記(2018/5/15)

headlessモードでうまく動作したので、追記です。 ルート証明書をちゃんとインストールすると、エラーがなくなりました。 docker-entrypoint.shの中でコンテナの起動時にやるようにしています(ので、コンテナ起動に若干余計な時間がかかります)。

まず、OSに証明書を認識させます(ここまでは前回やっていた)。

openssl x509 -in /home/chrome/.mitmproxy/mitmproxy-ca-cert.pem -inform PEM -out /home/chrome/.mitmproxy/mitmproxy-ca-cert.crt
mkdir /usr/share/ca-certificates/extra
cp /home/chrome/.mitmproxy/mitmproxy-ca-cert.crt /usr/share/ca-certificates/extra/
echo 'extra/mitmproxy-ca-cert.crt' >> /etc/ca-certificates.conf 
update-ca-certificates

chromeを一度起動させると、デフォルトのプロファイルが作成されます。 すると、ホームディレクトリの「.pkiディレクトリ配下に証明書を関連のデータベースができるので、ここにcertutilコマンドを使ってmitmproxyの証明書をインストールします。

for certDB in $(find /home/chrome/ -name "cert9.db")
do
  prefdir=$(dirname ${certDB});
  echo ${prefdir};
  certutil -A -n ${certname} -t "TCu,Cu,Tu" -i ${certfile} -d sql:${prefdir}
done

これで、headlessモードでchromeが動いてくれるようになりました。

ちなみに、Firefox版も作りました。こちらも同じように動いてくれるかと思います。 (Firefox版を作っていて証明書に気づいた)

これで幸せになれそうです。

参考

Dockerで手軽にスクレイピング環境を手に入れる - Qiita

Dockerコンテナの中でGUIアプリケーションを起動させる | Unskilled?

mitmproxyを使ってどんなサイトでもクローリング・スクレイピングする - Qiita

Making Chrome Headless Undetectable

AmazonLinuxでselenium + chromedriver + headlessするメモ - 私事ですが……

Spring Framework のリモートコード実行の脆弱性(CVE-2018-1270)について

久しぶりにブログ書きます。 最近あまりネタがなかったのでちょっとさぼり気味でした。

今月に公開されたSpring Framework脆弱性(CVE-2018-1270)についてです。

CVE-2018-1270: Remote Code Execution with spring-messaging | Security | Pivotal

Spring Framework の脆弱性に関する注意喚起

Apache Struts同様JAVAのアプリケーションフレームワークです。

概要

STOMP (Streaming Text Oriented Messaging Protocol) というメッセージプロトコルをWebSocketで利用している場合に、攻撃者から細工されたメッセージを受け取ることで、任意のコード実行が行われる脆弱性

同様に細工されたURLにアクセスすることでディレクトリトラバーサルが行われる脆弱性も報告されています(CVE-2018-1271)。

影響を受けるバージョン

また、すでにサポートが終了している過去のバージョンにおいても本脆弱性の影響を受けるとのことです。

修正バージョン

Spring Bootを利用している場合は 2.0.1.RELEASE で修正されています。

検証

PoCがすでに公開されており、検証用のアプリケーションもあったので、検証してみました。 ベースに「openjdk:8-jdk-alpine」のDockerコンテナを用い、Spring Boot 2.0.0.RELEASE で検証用のアプリケーションを動かしました。

8080ポートを開けてコンテナを動かします。

docker run -p 8080:8080 -it openjdk:8-jdk-alpine /bin/sh

このコンテナの中に、Spring Bootの脆弱性のあるバージョンを持ってきます(このへんから)。

解凍したSpring Bootのソースの中に検証用のアプリケーションのソースとpom.xmlを入れて、Mavenでビルドし、アプリケーションを動かします。

./mvnw spring-boot:run

f:id:blueBLUE:20180413134300p:plain

Spring Bootが色々と必要なものを落としてきて、アプリケーションを動かしてくれます。 終わったら、localhostの8080番にアクセスします。

f:id:blueBLUE:20180413134315p:plain

検証用のサンプルなので、すでにPoCが入力されており、あとはSendするだけという親切設計になっています。

で、Sendします。

アプリケーションを止めて、/tmp 配下を確認すると、確かに実行した通り、/etc/passwd の中身がコピーされていました。

f:id:blueBLUE:20180413134333p:plain

ついでに修正されたバージョンでもやってみました。 詳しくは上と同じなので書きませんが、Spring Boot 2.0.1.RELEASE を用意し、pom.xml の中身のバージョンを書き換えます。

<spring.boot.version>2.0.1.RELEASE</spring.boot.version>

これやらないと、せっかく修正バージョンを用意しても Spring Boot が気を利かせて、脆弱なバージョンを持ってきてビルドするみたいですね。

で、同じようにやってみましたが、コード実行は失敗、それ以外には変化はありませんでした。

攻撃時のパケット

パケットキャプチャをとってみました。

f:id:blueBLUE:20180413134348p:plain

GETリクエスト ⇒ 101(Switching Protocols) ⇒ WebSocketでやり取り(STOMP)

という感じですかね。 攻撃コードがバイナリになってどこが何をやっているのかがちょっとわからないです……。

f:id:blueBLUE:20180413134400p:plain

どうやらWebSocketがデータ圧縮を行っているため、攻撃コードが可読でなくなってるみたいです。 「Sec-WebSocket-Extensions: permessage-deflate」というヘッダのせいみたいですね。

試しにBurpを間に挟んで攻撃コードを実行してみました。

f:id:blueBLUE:20180413150801p:plain

例のヘッダがなくなり、一部平文で見えるようになりました。ただ、それでも攻撃コードはマスクされています。 (BurpってWebSocketも対応してるんですね)

ただ、WireSharkで見ると、マスクを解除してくれるので、攻撃コードがちゃんと見えています。

f:id:blueBLUE:20180413151231p:plain

普通のHTTP通信ならレスポンスが圧縮されることはあってもリクエストは平文だったのですが、WebSocketはリクエストが圧縮されたりマスクされたりするので、攻撃のポイントが見えにくくなり、検知がしにくくなります。 WebSocket経由の攻撃はこれまで見たことなかったのですが、割と面倒くさいなというのが今回の印象です。

追記(2018/04/17)

WebSocketのマスクついて調べてみました。

RFC 6455 - The WebSocket Protocol

RFC 6455 - The WebSocket Protocol (日本語訳)

ポイントとしては

  • クライアントからサーバへ送信される すべてのフレームはマスクされる
  • マスクに利用されるキーは32bitのランダムな値
  • ペイロードは「マスク用キー + マスクされたペイロード」という形で流れる
  • 元のペイロード = マスク用キー XOR マスクされたペイロード

ということらしいです。

攻撃者が任意のトラフィックを通信路に流せると、キャッシュ汚染の恐れがあるといった理由でこうなっているみたいです。

これをIDSなどで検知しようとすると、攻撃コードがWebSocketのマスクされた値の中にあるので、それを解除したうえで、検知を行う必要があり、かなり難しいと思われます。 WebSocket経由での攻撃というのは初めて聞いたのですが、このようなWebSocketのリクエストに対応した検知システムとかって、何かあるんでしょうかね……。

まとめ

Spring FrameworkApache Struts と同様JAVAのWebアプリケーションフレームワークなので、Struts脆弱性に懲りてSpring Framework に乗り換えようという人もいるかもしれませんが、こまめにアップデートする必要はいずれにせよありそうですね。 今回Spring Frameworkは初めて触ったのですが、割と開発の使い勝手は良さそうな印象でした。

今回の攻撃は影響は大きそうですが、まだ攻撃が行われたという話は聞かないです。 ただ、先に述べたように一般的なWebの攻撃に比べて検知が難しいので、気づかないうちに攻撃が行われている、なんてこともあるかもしれません。自分の管理するサーバに異変がないか、確認してみるのがいいかと思います。

参考

Spring Frameworkに含まれるリモートコード実行に関する脆弱性(CVE-2018-1270)についての検証レポート | NTTデータ先端技術株式会社

WOWHoneyhotを植えてみる

久しぶりにハニーポット関連。 morihi-soc 氏が作成した WOWHoneypot というWebハニーポットを使ってみました。

github.com

詳しい説明は以下のスライドで。

sssslide.com

Python3だけで動く極々単純な仕組みのハニーポットです。ざっくり言うと、待ち受けポートでHTTPが動いて、デフォルトではとりあえず200を返すWebサーバです。 正直初めてWebハニーポットを建てるのなら、これくらいシンプルなものでいいと思います。どうせ高機能なの入れてもデフォルトでしか動かさないだろうし……。

いつものようにDockerで動かします。 必要なのはPython3のみなので、別にそのままホスト上でやってもいいんですが、最近なんかツールを入れるときはとりあえずDockerに使うようになってきました。

こんな感じのDockerfileを作ります。

FROM ubuntu:latest

RUN apt-get update && apt-get -y upgrade
RUN apt-get -y install git python3

WORKDIR /root
RUN git clone https://github.com/morihisa/WOWHoneypot.git wowhoneypot
WORKDIR /root/wowhoneypot
CMD ["python3", "wowhoneypot.py"]

で、ビルドします。

docker build -t wowhoneypot .

で、立ち上げます。

docker run -it -v /home/blue/wowhoneypot/log:/root/wowhoneypot/log -p 80:8080 -d --name wowhp wowhoneypot

ポートは80番に接続し、コンテナ内のログ用のディレクトリを共有にしています。

1か月ほど動かしてみた

期間

2017年12月24日 ~ 2018年1月26日

アクセス数

全アクセス : 2149

ユニークなソースIP : 290

1つのIPからの最多アクセス回数 : 287

観測した攻撃の例

S2-045を狙った攻撃は色々なところから色々なコマンドを実行しようとしょっちゅう来ています。 D-Link製のルーターを狙った攻撃では、「cd /var/tmp && echo -ne \x00\xA0\xAF\x21\x20 >> drop && echo OK」というようなコマンド実行が大量にあり、おそらくバイナリファイルを直接echoで書き出そうとしているようでした。 Shellshockも一度来ると複数のURLパスに大量に同じコマンド実行を試みる攻撃があり、アクセス数がかなり増えました。 phpmyadmin脆弱性を狙った攻撃もかなり頻繁にあり、特にZmEuというツールを利用したスキャン(参考)がかなり多いです。

後は意味は分からないですが、/直下へのPOSTで謎のBase64で符号化されたデータを送ってくるリクエストが900件以上ありました(参考)。

それ以外には、Ruby on Railsを狙った攻撃や、魔法少女アパッチマギカTomcatの管理画面へのログイン試行、新年の挨拶なんかを観測できました。

WebLogicを狙う攻撃を観測してみたい

植えてからしばらくして、WebLogic脆弱性(CVE-2017-10271)のPoCが公開され、実際の攻撃に利用されだしました。前回の記事 でも書きましたし、WOWHoneypotでも観測できたようです。

ハニーポット観察記録(38)「WebLogic の WLS Security に対するコマンド実行の試み(CVE-2017-10271)」 at www.morihi-soc.net

ということで、うちでも観測してみたいなーと思い、記事では7001番ポート(WebLogicのデフォルトポート)に攻撃が来ていたので、こちらでも7001番ポートで待ち受けてみました。

docker run -it -v /home/blue/wowhoneypot/log_7001:/root/wowhoneypot/log -p 7001:8080 -d --name wowhp_7001 wowhoneypot

Dockerで立ち上げるポートを付け替えているだけです。 結果として、2017年12月28日 ~ 2018年1月26日の期間で42のアクセスがありました。

内CVE-2017-10271を狙った攻撃は全部で6つのIPから24件ありました。「/wls-wsat/CoordinatorPortType」へのPOSTですが、それとは別に、調査目的のGETリクエストも4つのIPから5件ありました。PoCによっては最初にGETしてWebLogicのコンテンツであるかを確認するようなものもあったので、そうした攻撃前の調査通信と思われます。

攻撃の内容はpingコマンドで攻撃の成功を確認するものや、wgetでファイルをダウンロードするもの、また、touchコマンドで「/tmp」配下にファイルを作成するものなどがありました(touchでファイルを作成したところで何がしたいのか不明ですが……)。

WebLogicの攻撃は事前にHTTPヘッダでWebLogicを利用していることを調べたり、GETでコンテンツがあるかを確認してから攻撃が来るパターンもあるようなので、ちゃんと観測しようとすると、その辺の調整は必要ですね。

(ちなみに、CVE-2017-10271を狙った攻撃を観測するようのルールはすでにあるようなので、アップデートすれば観測できそうです。)

今回は以上です。 漠然とハニーポットを立てて攻撃を観測するのもいいですが、何か特定の脆弱性を狙った攻撃を観測したいとなった場合はある程度カスタマイズは必要ですね。 WOWHoneypotでもルールにマッチした場合に応答を変えるような機能もありますし、単純なものなら、それだけで事足りそうです。 もしくは、WOWHoneypotを参考にして、自分で作ってもいいかなと思いました。ソースコードはそれほど複雑でもないので。

後はログの分析の方法を考える必要がありますね。同じ攻撃ばっかり見ててもつまらないので……。

Oracle WebLogic Server のWLS Security に関する脆弱性(CVE-2017-10271)について

10月にOracle WebLogicはパッチが出てましたが、その時に修正された脆弱性の攻撃コードが先週末あたりに公開されました。

実際に攻撃も来ているようで、探すと中国語での解説記事をちらほら見かけます。 morihi-soc 氏のハニーポットでも攻撃が観測されているそうです。

CVE-2017-10271について

JVN(JVNDB-2017-008734 - JVN iPedia - 脆弱性対策情報データベース)によると、脆弱性の内容は以下のようになっています。

概要

Oracle Fusion MiddlewareOracle WebLogic Server には、WLS Security に関する処理に不備があるため、機密性、完全性、および可用性に影響のある脆弱性が存在します。

影響を受けるシステム

オラクル

Oracle WebLogic Server 10.3.6.0.0

Oracle WebLogic Server 12.1.3.0.0

Oracle WebLogic Server 12.2.1.1.0

Oracle WebLogic Server 12.2.1.2.0

想定される影響

リモートの攻撃者により、情報を取得される、情報を改ざんされる、およびサービス運用妨害 (DoS) 攻撃が行われる可能性があります。

ただ、いくつかの中国語の記事を見る限り、場合によってはリモートコード実行が可能なようです。

【漏洞预警】Oracle WebLogic wls-wsat RCE CVE-2017-10271 & CVE-2017-3506|指尖安全|垂直互联网安全媒体

とりあえずGoogle翻訳に突っ込んだ結果をかいつまんで書くと以下のような感じです(間違っている可能性があることはご容赦ください)。

  • WebLogicのWLSコンポーネントにはリモートコード実行の脆弱性があり、該当するCVE-2017-3506のパッチが今年4月にリリースされた
  • CVE-2017-3506の攻撃コードは公開されていないが、攻撃には利用されていた
  • 4月に公開されたパッチをバイパスできる脆弱性(CVE-2017-10271)が見つかり、これは10月のパッチで修正された

ということのようです。 影響を受けるバージョンは限られていますが、リモートコード実行が可能なため、注意が必要です。

検証

WebLogic は有償のプロダクトですが、開発などの用途で使うための無償版があります(Oracleへの登録が必要です)。 今回はDockerでWebLogicの環境を作って本脆弱性の検証をやってみます。

環境構築

脆弱性のあるOracle WebLogic Server 12.1.3をDockerで建てます。

GitHub - oracle/docker-images: Official source for Docker configurations, images, and examples of Dockerfiles for Oracle products and projects

とりあえず、公式のDocker関連ファイルを持ってきます。

git clone https://github.com/oracle/docker-images.git

色々あるのを全部持ってきますが、使うのはOracleJavaとOracleWebLogicです。

まずベースとなるJavaのイメージを作成します。今回はJava8で。

cloneした「/OracleJava/java-8/」のディレクトリに「server-jre-8u151-linux-x64.tar.gz.download」というファイルがありますが、中身を見るとテキストでダウンロード先とファイルのハッシュが書いてあります。 このファイルを落としてこいということなので、リンクから同名のファイル(server-jre-8u151-linux-x64.tar.gz)を落としてきます。 落としてきたファイルは「~~.download」と同じディレクトリに置きます。

で、ビルドします。ビルドにはスクリプトが用意してあるので、叩くだけです。

sh build.sh

「doceker images」で確認するとoracle/serverjre:8のイメージができています。これが、WebLogicのベースになります。

次にWebLogicのイメージを作ります。やり方は上と同じです。今回は12.1.3なので、「/OracleWebLogic/dockerfiles/12.1.3/」のディレクトリを確認し、必要なファイルを落としてきます。 「fmw_12.1.3.0.0_wls.jar.download」と「wls1213_dev_update3.zip.download」があるので、それぞれのファイル内のリンクから同名ファイルをダウンロード(登録が必要)し、同じディレクトリに設置します。 その後、「/OracleWebLogic/dockerfiles/」にある、buildDockerImage.shを叩きます。

./buildDockerImage.sh -g -v 12.1.3

oracle/weblogic:12.1.3-genericのDockerイメージができます。

ようやくWebLogicのベースイメージができたので、ここからサンプルのDockerfileからWebLogicサーバを建てます。 「/OracleWebLogic/samples/1213-domain/」でREADME.mdの通りに実行します。

docker build -t 1213-domain --build-arg ADMIN_PASSWORD=admin1234 .

ADMIN_PASSWORDは英数8文字以上みたいな制約があるので気を付けてください。 これでWebLogicサーバのDockerイメージができました。 できたイメージはこんな感じ。

f:id:blueBLUE:20171226022002p:plain

これを起動します。

docker run -d --name wlsadmin --hostname wlsadmin -p 7001:7001 1213-domain

http://localhost:7001/console へアクセスして、こんな画面がでれば成功です。

f:id:blueBLUE:20171226022016p:plain

攻撃コード検証

まず、「http://localhost:7001/wls-wsat/CoordinatorPortType」へアクセスしてみます。このパスが今回の攻撃対象になります。

f:id:blueBLUE:20171226022035p:plain

PoCはこのパスに対して、POSTで実行するコマンドを含んだSOAPXMLを投げつけます。

f:id:blueBLUE:20171226022116p:plain

成功すると、サーバからは500 Internal Server Errorが返ります。コマンドの結果はレスポンスには載ってきません。

ここでは例として、「echo "HACKED!!" > /tmp/Hack」というコマンドを実行してみました。

コンテナの中に入って、確認します。

f:id:blueBLUE:20171226022053p:plain

確かにファイルが作成されていました。

ということで、リモートでコード実行ができました。

まとめ

日本ではあまり騒がれていませんが、すでに攻撃が行われており、該当するバージョンのWebLogicを利用している場合、おそらくデフォルトの状態で刺さる可能性がある危険な脆弱性です。 対策としては、WebLogicのバージョンアップ、暫定策として、wls-wsatへのアクセス制御や、関連するコンポーネントの削除が挙げられています。

WebLogicのログがどこにあるのか分からなかったのですが、もしログがあるなら、「/wls-wsat/CoordinatorPortType」へのPOSTでのアクセスログあるか、そのレスポンスが500になっていないかを確認するのがいいかと思います。

WebLogicの環境構築がちょっと面倒でしたが(有償の製品なので仕方ないですね)、とりあえずは検証まで行うことができて満足しました。

追記 (2017/12/28)

以下2点を補足として。

  • 今回利用したPoCでは「/wls-wsat/CoordinatorPortType」のパスへ攻撃しましたが、実際には「/wls-wsat/」配下の存在するパスであれば攻撃は成功するようです。アクセス制限を考えている場合は「/wls-wsat/」以下すべてのパスの制限をした方がいいです。

  • 検証したところ、上記の影響を受けるシステムとなっている以外のWebLogicのバージョンでも利用した攻撃コードが刺さりそうな感じでした。詳細な影響範囲は分かりませんが、WebLogicの10系と12系を利用している場合はとりあえず、攻撃影響・侵害の有無を確認した方がいいと思います。

SECCON 2017 Online CTF

今年も会社のチームで参加しました。 時間いっぱいの参加はできませんでしたが、 今年は昨年よりpwn以外の問題が増え、とっつきやすくなった感じです。 最近はどのCTFも軒並み難易度が高く、参加しても1番簡単な問題が1問解けるかどうかというくらいだったので、今回のような手ごろな問題を解いて達成感を得られるのはとてもありがたいです。 達成感、重要ですよね。

以下、軽くWrite up。

Run me! (Programming 100)

import sys
sys.setrecursionlimit(99999)
def f(n):
    return n if n < 2 else f(n-2) + f(n-1)
print "SECCON{" + str(f(11011))[:32] + "}"

再起でフィボナッチ数列を求めていますが、再起が深すぎて実行するとプログラムが止まります。なので、再起なしで、フィボナッチ数列を求めてやれば答えが出ます。

n={1:1,2:1}
for i in range(3,11012):
    n[i]=n[i-1]+n[i-2]
print("SECCON{" + str(n[11011])[:32] + "}")

この問題はすぐに解けました。再起の上限の設定なんてあるんだなーと。

Vigenere3d (Crypto 100)

$ python Vigenere3d.py SECCON{************} POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9

昨年のSECCONでも出てきたヴィジュネル暗号の3D版です。昨年と解き方は同じだろうということで、暗号処理の中身はあまり気にせず、頭の「SECCON{」を暗号し、出力の先頭と一致する鍵を探します。

s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"

def _l(idx, s):
    return s[idx:] + s[:idx]
def crypto(p, k1, k2):
    t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
    c = t[s.find(p)][s.find(k1)][s.find(k2)]
    return c

key = []
cp = [['S','P'], ['E','O'], ['C','R'], ['C','4'], ['O','d'], ['N','n'], ['{','y']]
for c in cp:
    keys = []
    for i in s:
        for j in s:
            if crypto(c[0], i, j) == c[1]:
                keys.append([i,j])
    key.append(keys[0])
print key

鍵は2つあり、14文字の鍵とその逆順を使います。1文字ごとの2つの鍵の組み合わせを総当たりしています。 この処理で鍵の前半7文字とその逆順の前半7文字(つまり後半7文字)の組み合わせが出てきます。 ここで、それぞれの鍵は変数sのパターン分66通り出てくるのですが、実行してみると、66通りのどの鍵を使っても出力は同じになることが分かります。 そのため、1文字目はすべて「A」となる鍵を持ってきています。 これで、14文字の鍵が全てわかりますので、その鍵で復号して暗号文に一致する文字を探します。

flag = ''
i = 0
tmp = []
for g in reversed(key):
    tmp.append([g[1], g[0]])
key = (key + tmp) * 3
cstr = 'POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9'
for p in cstr:
    for k in s:
        if crypto(k, key[i][0], key[i][1]) == p:
            flag += k
    i += 1
print flag

換字のテーブルの構造はほとんど考えず、ただ総当たりでやりました。鍵が66通りどれでやっても結果が同じことに気づくのに時間がかかりました。

Powerful_Shell (Binary 300)

難読化されたPowershellを実行する問題。 まず、ps1ファイルを実行できるよう、管理者権限のPowershellコンソールで「Set-ExecutionPolicy RemoteSigned」を実行します。

ファイルの中身を見ると、「$ECCON」という変数に色々入れて最後に実行しているっぽいので、ラスト1文を消して「echo $ECCON」にすると、難読化を解除したスクリプトが見えます。

最初に耐解析的なセクションがあり、イベントログの件数を確認し、少なすぎればサンドボックスと判定します。この処理におそらく管理者権限が必要で、管理者権限のあるコンソールでなければ処理が停止します。

管理者権限のコンソールでスクリプトを実行してみます。

f:id:blueBLUE:20171212204400p:plain

背景が黒くなり「SECCON」ロゴが出てきます。耐解析のセクションを抜けると鍵盤が出てきて、入力に応じて音がでます。 出力する音を決めているのは「$keytone」という変数なので、ここをechoとかで見てみる(難読化解除後の16~20行目をコピペしてコンソールに張り付けてから、「echo $keytone」)。

Name                           Value
----                           -----
j                              493.891672853823
s                              293.669745699181
y                              415.31173722644
w                              277.187329377222
u                              466.171663254114
g                              392.002080523246
e                              311.132257498162
t                              370.000694323673
h                              440.007458245659
f                              349.234151046506
d                              329.633144283996
a                              261.63
k                              523.26

91行目の「$secret」変数の値と一致するkeyが正解。

「$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349)」

「hhjhhjhjkjhjhf」を入力すると「さくらさくら」が流れて、次のステージに行けます。 (ロゴといい、すごい凝ってる) パスワードを求められるので、さらに100行目以降の難読化を解除していきます。

色々やっているっぽいけど、とりあえず、「$plain」変数をechoします。 すると、asciiが10進になっているようなものが出てくるので、これを文字列に変換。 また、意味の分からない難読化されたスクリプトが出てきます。

${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};
${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};
${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);
${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}

ここは本当に意味が分からなくて、しばらく悩みましたが、結局、一番最後についている「|&${;}」がスクリプトを実行している箇所だろうと考え、ここを削除し、「${;}」をechoすると、また10進数をcharに変換しているようだったので、これをascii化。

'$ECCON=Read-Host -Prompt \'Enter the password\'\r\nIf($ECCON -eq \'P0wEr$H311\'){\r\n\tWrite-Host \'Good Job!\';\r\n\tWrite-Host "SECCON{$ECCON}"\r\n\x0c'

でフラグにたどり着きました。

Powershellはあまり詳しくないのですが、思っていたよりかなり柔軟な難読化ができるんだなあ、という印象です。

その他

後は、Log search (Web 100) や SqlSRF (Web 400) に挑んではいましたが、答えにたどり着けず。Log search はElastic SearchのQuery DSLをインジェクションするのかと思って色々試していましたが、「違うじゃん」と分かったところで、諦めました。回答はもう少し単純だったようで、Elastic Searchももっと触れておかないとなと感じました。SqlSRF みたいな問題はいつも、割と好きで解きたいと思いつついつも解けない問題です。

後はCode Blueで坂井弘亮氏が話していたSOPの問題もありましたが、手を付けられませんでした。

今回もpwn系も少し解けるようになりたいなー、とCTFのたびに思っています。

Code Blue 2017 カンファレンス参加レポート

11月9~10日に開催された日本のセキュリティカンファレンスであるCode Blue 2017に参加してきました。

備忘録的に興味深かった内容をさらっと書いておこうかと思います。ちゃんと理解できていない部分もあるので、間違っている可能性もあるとご理解ください。

基調講演:サイバースペースにおける国家主権

サイバー犯罪と国家の主権に関する話。書いていたメモが消えたので、感想だけ軽く……。

講演者はNATO法律顧問であり、航空宇宙、海事、サイバー戦略および政策に関して企業として組織に助言しているとのこと。 陸・海・空の軍事関係にサイバー空間を足してどう対応していくべきかを考える。 原子力潜水艦や船舶、衛星などの実際の攻撃事例が面白かった。 様々な課題がありますが、協力していきましょうというのはよくある国際社会とサイバー犯罪に関する講演の結論です。 今回も教育や学習という面でこのカンファレンスを通じて理解を深めましょうといった内容で、最初の基調講演としてはふさわしい内容だったのではないでしょうか。

参考URL

Galileo atomic clocks failed: What can we learn from it?

FACT CHECK: Did Russia Hack the GPS System of the USS John McCain to Cause a Collision?

hacking-uk-trident.pdf

Step-Oriented Programming による任意コード実行の可能性

講演者の坂井弘亮氏は独自組み込みOS「KOZOS」を作成している。それと、SECCONの実行委員の方。

  • 組み込み機器はデバッグポートが有効になっていると基本的になんでも行えてしまう
  • ので、リリースの際にはデバッグポートは使えないようにしましょう

  • コードを実行できないからと言って、安全ではなく、SOP(Step-Oriented Programming)という方法で攻撃ができる(一般的な名称ではない?)

  • 組み込み機器ではRSPプロトコルを使ってリモートデバッグを行う
  • 組み込みのデバッグではプログラムカウンタを簡単にいじれるので、ROPのように既存のコードを使ったコード実行が容易
  • SECCONでSOPを利用して解く問題を出したところ、みんなSOPを利用して問題を解いていたので、この手法自体は誰もが簡単に思いつくものである

技術的な内容は難しかったですが、SECCONの問題の解説はなかなか面白かったです。 実際にリモートデバッグを使ったコード実行のデモを行っていたので、漠然と何をやっているのかは理解できました。 組み込み機器に対する攻撃手法はあまり詳しくありませんが、普段 Exploit する人たちからしたら、今回の攻撃の手法はROPからすぐに思いつくのかなあという感想。

参考URL

Howto: GDB Remote Serial Protocol

SECCON関連

産業制御システムに対するStuxnet以来最大の脅威

Industroyerという産業システムを狙ったマルウェアの解析に関する話

  • 産業システムを狙うマルウェアとしては、Stuxnet → HAVEX(Dragonfly) → BlackEnergy → Industroyer といった大きな事例があった
  • マルウェアは産業システムで行う破壊活動の内容の違いがある
  • 産業システムと言っても管理はWindowsで行われており、そこが狙われる
  • (正直 Industroyer のペイロードの解説などはちょっと理解ができなかった)
  • Industroyer というマルウェアはとても多機能で、後からモジュールをロードできる
  • 攻撃者は多数のモジュールを用意し、攻撃対象に合わせたモジュールをロードし、目的を達成する

結局のところ、狙われているのはWindowsであり、今回の解析対象もWindowsマルウェアでした。 質疑で日本も標的になりうるかとい質問に、個別システムのモジュールを攻撃者が用意することができれば、どんなシステムも標的になりうるという点が印象深かった。

参考URL

停電の原因は産業制御システム狙うマルウェアか 「Stuxnet以来、最大の脅威」 - ITmedia エンタープライズ

産業制御システムに最大級の脅威をもたらすマルウェア「インダストロイヤー」 | マルウェア情報局

WIN32/INDUSTROYER A new threat for industrial control systems

日本を狙うAPT攻撃の全体像 - APT攻撃インシデントSTIXデータベース

JPCERTの方の発表。日本で行われたAPTの利用されたマルウェア、攻撃キャンペーン、Threat Actorなどを紐づけて全体像を把握するための仕組みをつくりましたと言う内容

  • ここ数年日本で活動していた Blue termite、APT17、Tick/Daserf、ChChes が対象
  • STIX形式で各内容まとめてみると、攻撃者の動向が把握できる
  • 各キャンペーンの活動時期をTimelineとして並べるデモを行った

ただ、標的型攻撃のインシデント詳細をそこまで大量に持っているのはJPCERTくらいじゃないかと思う。問題提起がそもそもJPCERTの内部の問題なんじゃ……。 JPCERTの持っている情報も機微なものが含まれるので、そのまま公開はできないとのこと。 手軽な情報共有の基盤を作ったのなら分かるが、STIX形式の入力は現状「頑張って」やっているそうで、頑張らなきゃ使えないシステムは普及しないのでは……。 JPCERT以外の組織での利用シーンはあまり思いつかないのが正直なところ。 マルウェアの挙動なんかは面白かったので、もう少し掘り下げてほしかったけど、そこは次の講演者の発表で。

参考URL

脅威情報構造化記述形式STIX概説:IPA 独立行政法人 情報処理推進機構

GitHub - oasis-open/cti-stix-visualization: OASIS Open Repository: Lightweight visualization for STIX 2.0 objects and relationships

攻撃者の行動を追跡せよ -行動パターンに基づく横断的侵害の把握と調査-

引き続きJPCERTの方の発表。

  • 攻撃者の利用するツールはマルウェア以外(正規のツール、コマンド)も多くあり、それらは検知が困難
  • 攻撃者が侵入後行う活動に着目し、どのようなコマンドが実行されるかを調査

・初期調査
  tasklist ⇒ 仮想環境の検知など
・探索活動
  dir ⇒ 欲しいファイルの探索
  net ⇒ ローカルネットワークの探索
  ping⇒ネットワーク内のホストを探すため
  echo⇒スクリプトファイル(powershell)の作成
  dumpel、LogParser(デフォルトでは入っていない)
  cscript ⇒ ログオンイベントの探索
・感染拡大
  at,schtasks ⇒ コマンド実行
・痕跡の削除
  del
  wevtutil ⇒ イベントログの削除(イベントログを見ることもできるので、他の用途でも利用される)

  • こうしたマルウェアの挙動を見るにはイベントログがもっとも有用
  • ただし、デフォルトではコマンドの内容までは取れないので、監査ポリシーの設定は必要
  • Sysmonというツールを併用するとよい
  • 攻撃者によってイベントログが削除されることを考えて、イベントログサスクリプションを利用する

さすが、JPCERTは見ている量が違うなと。 ちゃんとやっているその内容も逐次公開してくれているので、ありがたい限りです。 ほとんどはJPCERTのサイトで公開している内容ですが、こうして改めて話を聞く機会があるのはとてもうれしい。

参考URL

インシデント調査のための攻撃ツール等の実行痕跡調査に関する報告書(第2版)公開(2017-11-09)

Sysmon - Windows Sysinternals | Microsoft Docs

インサイドShell:.NETハッキング技術を応用したPowerShell可視性の向上

スライド、実際のコードは公開されています。ASMIという機構については知らなかったので、勉強になりました。 Powershellは最近攻撃によく利用されるので、勉強しなくちゃならないなーと。

参考URL

DotNetHooking/CodeBlue_1110_JP.pdf at master · tandasat/DotNetHooking · GitHub

GitHub - tandasat/DotNetHooking

Releases · PowerShell/PowerShell · GitHub

国産IT資産管理ソフトウェアの(イン)セキュリティ

リクルートのRed Teamに所属する西村宗晃氏の講話。国産IT資産管理ソフトウェアと聞くと、最近注意喚起のあった某社製品を思い浮かべますが、今回の話はそれではなく、(その事例に端を発してはいますが、)国産IT資産管理ソフトウェア一般に色々な脆弱性がありますという内容。

  • IT資産管理ソフトウェアとは

社員のPCを一元管理するためのソフトウェア
ソフトウェアファイルの管理、デバイスの利用制限、プログラムの配布(アップデート配信)、社員のPCの遠隔操作といった機能と持つ(話者曰く、つまりMeterpreterみたいなもの)

  • 通常、社内のイントラ内で利用しているが、持ち出し用のPCでUSBタイプのモデムを使うなど、グローバルIPが振られたときに攻撃される恐れがある。

  • IT資産管理ソフトウェアの通信

 ・クライアントPCの遠隔操作用通信
 ・管理操作(管理者が専用クライアントソフトから管理機へアクセス)
 ・クライアントPCからのインベントリ情報の送信、管理指示(定常的な通信)
 ・管理機からの指示(緊急でのクライアントへの命令など)

  • 国産IT資産管理ソフトウェアの脆弱性

実際にいくつかの国産IT資産管理ソフトウェアに見つかった脆弱性の紹介

  1. 管理機通信の偽装
    クライアントPCと管理機は暗号化された独自プロトコルを利用して通信しているが、暗号化通信の鍵がインストーラに埋め込まれており、復号可能。
    復号した通信に管理機のドメインとポートが書いてあり、そこを書き換えることで管理機を偽装することができた。
    鍵は全て共通のものを利用しており、製品を利用している他社のPCにも同じことができる。

  2. クライアントPCの遠隔操作
    クライアントPCとVNCで接続するタイプのソフトウェアだが、認証がかけられていなかった。試したところ、特定のバージョンのVNCで接続すると、簡単にリモート接続ができてしまった。

  3. 管理機へのアクセスの不備
    管理機へ認証なしでアクセスが可能だった。さらに、管理機にSQLインジェクション脆弱性があり、社員のPCの情報をすべて見ることができるようになっていた。

  4. 管理機との通信の悪用
    通信内容は暗号化されているが、暗号方式が脆弱であったり、Windows のCryptAPIを利用しており、APIをフックするといった手法で暗号が解かれることがある。一度暗号化を解いてしまうと、SQLインジェクションや管理者のパスワードを窃取されるなどの攻撃が行われる。
    また、管理機に社員番号のディレクトリが作成されるようなタイプのソフトウェアでは、社員番号にディレクトリパスを指定することでディレクトリトラバーサルが可能な事例も存在した。

 

  • こうしたソフトウェアは体験版を個人で取り寄せることも可能で、おそらく攻撃者もそうやって脆弱性を探している

例のソフトウェアの脆弱性の話をするのかと思っていましたが、予想とは違っていました。ただ、なかなか面白い内容で、こういうソフトウェアって意外と脆弱性多いんだな、と率直に思いました。 別にIT資産管理ソフトウェアだけでなく、他の国産ソフトウェアもきっと似たような事例はあるんじゃないかと思っています。特定の国を狙った標的型攻撃にその国でよく利用されていているソフトウェアをハックする方法は以前からありますし、最近は特に増えている気もします。 今回のようなRed Teamの活動の重要性が分かりました。

基調講演: OSSによる自動車の自動運転化 –

車のネットワークをハックして自動運転を行おうというオープンソースプロジェクトの紹介

www.youtube.com

主に自動運転の話でしたが、リバースエンジニアリングや、自動車のAPIなど、普段聞かない話は面白かったです。 法整備や国ごとの特色など、課題は多そうですが、自動運転は未来の技術として期待したいです。

参考URL

https://techinfo.toyota.com/

GitHub - commaai/opendbc: democratize access to car decoder rings

comma cabana

Find the pattern in the S-Boxes and write a short program to generate them with - Pastebin.com

openpilot/SAFETY.md at devel · commaai/openpilot · GitHub

9 minutes of openpilot. unedited. - YouTube

聞いていないけど興味があった講演(参考資料だけ)

■SSRFの新時代 - 有名プログラミング言語内のURLパーサーを攻撃!
https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf

■マン・イン・ザ・NFC
DEF CON 25 - Haoqi Shan, Jian Yuan - Man in the NFC - YouTube

https://media.defcon.org/DEF%20CON%2025/DEF%20CON%2025%20presentations/DEFCON-25-Haoqi-Shan-and-Jian-Yuan-Man-in-the-NFC.pdf

大義のために:趣味と実益のためのVMware RPCインターフェースの活用
https://ruxcon.org.au/assets/2017/slides/ForTheGreaterGood.pdf

■商用ホワイトボックス暗号方式" に対する "鍵回復攻撃"
Practical attacks on commercial white-box cryptography solutions

https://eprint.iacr.org/2015/753.pdf

■Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes
GitHub - linkedin/qark: Tool to look for several security related Android application vulnerabilities

trueseeing 2.0.9 : Python Package Index

GitHub - monolithworks/trueseeing: Non-decompiling Android vulnerability scanner (DC25 demo lab, CB17)

全体の感想

日本の国内外問わず、セキュリティに関するさまざまなトピックを聞くことができました。普段聞かない領域の話も多くあり、とても勉強になりました。 今回は特に日本の事例が面白かったです。 色々なセキュリティの記事やニュースを見ていると国外のすごい人は色々いますが、国内にもすごい人はいるなあ、と感じました。 これからもセキュリティ業界をますます発展させていきたいですね。