seccompによる制限下にある特権コンテナで breakout する

firefox で moz://a にアクセスすると https://www.mozilla.org/protocol にリダイレクトされる。moz://a ってカッコよくないですか?ズルい。 前回 は CAP_DAC_READ_SEARCH が許可されている状態で open_by_handle_at を利用することでホスト側のファイルを読み出したり、シェルを取得するなどした。 このとき、seccomp で open_by_handle_at が禁止されている場合は Operation not permitted で失敗する。 [root@b8bf54fb1c48 tmp]# ./a.out failed to open_by_handle_at: Operation not permitted しかし、このエントリ で書いたように、ptrace を使用することで seccomp による制限は回避することができる。 環境 今回は明示的に seccomp で open_by_handle_at を拒否し、DAC_READ_SEARCH を許可した Docker コンテナで試した。 なお、この設定は LXC と Docker の Privileged なコンテナとほぼ同じなので、それぞれの Pirivileged Container でも動作する。 $ cat seccomp.json | jq { "defaultAction": "SCMP_ACT_ALLOW", "syscalls": [ { "name": "open_by_handle_at", "action": "SCMP_ACT_ERRNO", "args": [] } ] } $ docker run --rm -ti --cap-add=DAC_READ_SEARCH --security-opt seccomp=seccomp.

open_by_handle_at(2) でコンテナから Break Out する

俺たちの夏休みはこれからだ!(今日が最終日) 前回は ptrace を使用して seccomp による制限を回避してみた 。 今回は seccomp とコンテナの関係、コンテナからホストへの break out についてのメモ。 コンテナと seccomp LXC や Docker でも seccomp が利用されており、コンテナを break out する危険があるようなシステムコールを禁止している。 LXCでは非常に小さなポリシーとなっている。 https://github.com/lxc/lxc/blob/master/config/templates/common.seccomp 2 blacklist reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 1 open_by_handle_at errno 1 init_module errno 1 finit_module errno 1 delete_module errno 1 カーネルに関する kexec_load や *_module などが禁止されていることが分かる。 Docker は結構いろいろある。 https://github.com/moby/moby/blob/master/profiles/seccomp/default.json しかし open_by_handle_at とは何なのだろうか?

CVE-2018-7160 と Chrome DevTools Protocol のメモ

機動戦士ガンダムユニコーン RE:0096を視聴したところ、感化されて Aimer を聴きながらユニコーンのガンプラを作って大変満足している。 Node.js の inspector モードで DNS Rebinding を利用した RCE (CVE-2018-7160) がどのようなものなのか手元で確認してみたのでメモ。 メモなのでかなり殴り書き。 Chrome DevTools Protocol CVE-2018-7160を理解する前に Chrome DevTools Protocol について知っておく必要があった。 Chrome DevTools Protocol を利用することで Blink ベースのブラウザのデバッグやら何やらが可能になる。 Headless Chrome での操作はすべて Chrome DevTools Protocol で制御され、その実体は WebSocket である。 ドキュメント を見ると分かるが、本当に色々なことができる。 VS Code や Node.js でデバッグを行うときは、この Chrome DevTools Protocol が使用され、Node.js アプリを --inspect オプションを指定して起動し、 chrome://inspect にアクセスすることで、デバッグすることができる。 このとき、 node のログには以下のようなメッセージが出現する。 Debugger listening on ws://127.0.0.1:9229/17d0639f-c36a-47da-9b95-9990b72bf8b7 For help, see: https://nodejs.org/en/docs/inspector ws://127.0.0.1:9229/17d0639f-c36a-47da-9b95-9990b72bf8b7 がデバッグを行う WebSocket のエンドポイントである。

Docker Remote APIを安全に利用する

Oculus Go で目がヤバ。 概要 Docker には REST API があって、クライアントはそれを通してDockerを自在に操作できる。 「開発環境だから…」という気持ちで dockerd -H tcp://0.0.0.0:2376 みたいに動作させると、悪意あるサイトを閲覧するだけでコンテナの Shell が取られるみたいなことが発生するので、開発環境でも証明書を使った認証を行うなどしたほうが良い。 https://docs.docker.com/engine/security/https/ 悪用例 docker remote api tcp とかで検索すると以下のようなエントリがヒットする。 How do I enable the remote API for dockerd /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 この設定はあまりよくなくて、例えば、悪意のあるサイトに以下のような JavaScript が設置されているとする。 var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://127.0.0.1:2376/containers/json', true); xhr.send(null); 上記の設定で Dockerd が動作している環境で、このような JavaScript が動作しているページへアクセスすると、当然ながらリクエストを処理してしまう。 なので、どのようなコンテナが動作しているかなど、 GET で取れる(というよりSOPで守られない)情報は取得される可能性がある。 Get a shell Docker Remote API は JSON を POST するAPIがある。例えばコンテナの作成などだ。

CookieのSameSite属性

概要 Cookieに新たにSameSite属性というものが提案され、主要なブラウザで実装が進んでいる。 かつてはFirst-Party-Only Cookieと呼ばれていたもの。 https://tools.ietf.org/html/draft-west-first-party-cookies-05 クロスオリジンへのリクエスト送信時にCookieを付与しないことで、予期せぬ形での情報漏洩を緩和するのが目的。 CSRFを防げるという話ではなく、あくまで緩和という感じ。 このエントリを書いている段階で、Safari以外の主要ブラウザでは実装済みという感じ。 https://caniuse.com/#feat=same-site-cookie-attribute SameSite属性の値と挙動 値は lax と strict の2種類。 Set-Cookie: test=1; path=/; samesite=strict strict はあらゆるクロスオリジンへのリクエストにそのCookieは付与されなくなる。 aタグなどで遷移するだけでもCookieは付与されない。 lax は付与される場合と付与されない場合がある。 top-levelリクエストで、かつ、GETリクエストであるものにCookieが付与される。 ただし、 img や iframe 、 XMLHttpRequests などでは付与されない。 表にすると以下のような感じ。( ✅ : Cookieが送信される、❌ : Cookieが送信されない ) HTML lax strict <a href="http://example.com/"> ✅ ❌ <form method="get" action="http://example.com/" > ✅ ❌ <form method="post" action="http://example.

機密情報の比較処理、secure_compareの実装について

ActiveSupport::SecurityUtils.secure_compareやRack::Util.secure_compareについてメモ。 文字列が等価であるかどうか確認するのにa == bという風に書くことが多い。 しかし、機密情報の比較にこの形式を用いると、処理に要する時間からアルゴリズムが特定されたり、機密情報自体が漏れる可能性がある(所謂、Timing Attack)。 例えば、クーポンや一時トークンの確認などではTiming Attackに気をつける必要がある。 通常の文字列比較の場合、1byte目から確認していき、文字列が異なる時点でFalseを返す実装が多いと思う。 'secret' == 'hoge' # F 'secret' == 'soge' # TF 'secret' == 'sege' # TTF ... 'secret' == 'secret' # TTTTT 早々にレスポンスが返ってくれば異なることが分かるし、少し返ってくるのが遅ければ、ある段階までは合っていることが分かる。 これを何度も繰り返せば、1byte目から順々に正解の文字列が分かる。これがTiming Arrackで、知っている人は多いと思う。 しかし、クーポンコードや一時トークンの比較などでは == が取られていることも多いのでは…という気がする。 では、どのように実装すればいいのか。 そこでRack::Util.secure_compareではどのように実装されているか見てみる。 https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L373 def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C*") r, i = 0, -1 b.each_byte { |v| r |= v ^ l[i+=1] } r == 0 end まず、Timming Attackを防ぐには以下の処理を行う必要がある。