Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ヒント #1

Open
hiroakis opened this issue Oct 29, 2021 · 4 comments
Open

ヒント #1

hiroakis opened this issue Oct 29, 2021 · 4 comments

Comments

@hiroakis
Copy link
Member

hiroakis commented Oct 29, 2021

ヒント

リバースプロキシや X-Forwarded-For、出題されたアプリケーションの説明を書きますので参考にしてみてください。ある程度時間が経過したらこちらの issue のコメント欄に徐々にヒントを投下していきます。この概要欄が最初のヒントになります。

アプリケーションの説明

docker run で HTTP Server を起動すると Front Proxy, Middle Proxy, Backend 3つの HTTP サーバが起動 します。Front Proxy は 127.0.0.1:8000 で接続を待ち受け、HTTP リクエストを受信するとその内容をそのまま Middle Proxy に転送 ( httputil.NewSingleHostReverseProxy(murl).ServeHTTP(w, r) ) します。Middle Proxy は 127.0.0.1:<※ランダムなポート> で接続を待ち受け、HTTP リクエストを受信するとその内容をそのまま Backend に転送 (httputil.NewSingleHostReverseProxy(burl).ServeHTTP(w, r))します。Backend は 127.0.0.1:<※ランダム なポート> で接続を待ち受け、HTTP リクエストを受信すると、 X-Forwarded-For という HTTP ヘッダをカンマ区切りで分割し、先頭のものを Source IP とみなします。ここで Source IP が 127.0.0.1 であれば flag.txt へのアクセスができます。

※ Backend および Middle Proxy は httptest.NewServer で起動しています。httptest.NewServer はランダムなポートで起動します。

HTTPリクエストの流れ

このアプリケーションに HTTP リクエストを投げてからどのように HTTP リクエストが Backend まで渡るかを追ってみます。
まず試しに、docker run してから http_client_example にあるサンプルで HTTP リクエストを送信してみます。Front Proxy, Middle Proxy, Backend が受信する HTTP リクエストのダンプが表示されます。加えて r.RemoteAddr の内容も表示されます。そのダンプの内容およびそれを図で表すと次のようになります(IPやポートは環境によって変わります)。

ダンプ

==========================
Welcome to Kanmu Office hour @ Go Conference 2021 Autumn
Go version: go1.16.4
---------------- Front Proxy ----------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1

--- Front Proxy が受信した RemoteAddr ---
RemoteAddr: 172.17.0.1:56968

---------------- Middle Proxy ----------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1
X-Forwarded-For: 172.17.0.1

--- Middle Proxy が受信した RemoteAddr ---
RemoteAddr: 127.0.0.1:44034

---------------- Backend Server ------------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1
X-Forwarded-For: 172.17.0.1, 127.0.0.1

--- Backend Server が受信した RemoteAddr ---
RemoteAddr: 127.0.0.1:37698

--- 最終的な X-Forwarded-For と送信元IP ---
X-Forwarded-For: 172.17.0.1, 127.0.0.1
Source IP: 172.17.0.1

残念!送信元IP が 127.0.0.1 になるようにリクエストを送ってください!(172.17.0.1 != 127.0.0.1)
==========================

gocon2021autumn

本問題を解くために重要となる r.RemoteAddr と X-Forwarded-For の動きを追ってみます。
まず Client (あなた)が HTTP リクエストを送信すると、r.RemoteAddr = 172.17.0.1 として Front Proxy に到達します。 r.RemoteAddr にはリクエストを送信したコンポーネントのIPが入ります。
続いて Front Proxy は Middle Proxy に HTTP リクエストを転送するのですが、Client から送られてきた r.RemoteAddr を X-Forwarded-For に入れて Middle Proxy に転送します。これにより、Middle Proxy は r.RemoteAddr = 127.0.0.1 (Front Proxy の IP), X-Forwarded-For = 172.17.0.1 (Client の IP) と してリクエストを受け取ります。
Middle Proxy は Front Proxy と同様、前段である Front Proxy の r.RemoteAddr を X-Forwarded-For に入れてから Backend に転送します。
このように、直前のコンポーネントの IP は X-Forwarded-For に入れて転送されるため、多段構成になっていたとしても、X-Forwarded-For をたどることで大本の送信元IPを知ることができます。

本問題の関門はどこなのか?

ここで本問題なのですが、Backend は X-Forwarded-For の先頭を取り出して、それが 127.0.0.1 であれば flag.txt へのアクセスを許可しています。しかしながらこの図の通り、X-Forwarded-For の先頭には大本のリクエスト送信元である Client の IP 入っています。Client の IP は 127.0.0.1 ではないため flag.txt にアクセスできません。どうにかして送信元IPを 127.0.0.1 として Backend に到達させる必要があります。

最初のヒント

コードの中から脆弱性を探しましょう。そしてその脆弱性は問題のコードの中だけに潜んでいるとは限りません。使われている Go のバージョンは 1.16.4 です。

@hiroakis
Copy link
Member Author

ヒント追加です!起動したときに出る Go のバージョン 1.16.4 に注目してください!

@hiroakis
Copy link
Member Author

Go で HTTPリクエストヘッダは次のようにして送ることができます。サンプルコード https://github.com/kanmu/gocon-2021-autumn/blob/main/http_client_example/client.go を使う場合次のようになります。またヘッダはいくつも送ることができます。

req, err := http.NewRequest("GET", "http://localhost:8000/flag.txt", nil)
if err != nil {
  log.Fatal(err)
}

// リクエストヘッダを送る
req.Header.Add("Header1", "Value1")
req.Header.Add("Header2", "Value2")

@hiroakis
Copy link
Member Author

ところでGo 1.16.5 のリリースノートを見てみましょう。Go 1.16.4 で見つかったいくつかセキュリティ issue が修正されていますね?

@hiroakis
Copy link
Member Author

Go 1.16.4 には次のような Issue が立てられていたようです。

そして次のコミットで問題が修正されています。

この問題は CVE-2021-33197 として登録されている脆弱性です。Connection ヘッダは

先ほどのコミットのテストコードのこのあたりが参考になりそうです。これを利用すると X-Forwarded-For が1つ消せるかも?

golang/go@0410005#diff-94fbfd2113a685abada242cd95e27e61f8577413f03f50c10606cd018d90ccadR273-R276

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant