Angular of the Universe
You know, everything has the angular.
A bread, you, me and even the universe.
Do you know the answer?
http://universe.chal.ctf.westerns.tokyo
universal-angular.zip
ソースコードが大きいので、とりあえずflagで検索
PS> rg -i flag
docker-compose.yml
11: - FLAG=FLAG{xxxxx}
12: - FLAG2=FLAG{yyyyy}
app\src\polyfills.ts
33: * user can disable parts of macroTask/DomEvents patch by setting following flags
34: * because those flags need to be set before `zone.js` being loaded, and webpack
36: * in this directory (for example: zone-flags.ts), and put the following flags
38: * import './zone-flags';
40: * The flags allowed in zone-flags.ts are listed here.
42: * The following flags will work for all browsers.
49: * with the following flag, it will bypass `zone.js` patch for IE/Edge
app\src\app\debug\answer\answer.component.ts
13: public flag: string;
19: this.flag = process?.env?.FLAG
app\src\app\debug\answer\answer.component.html
3:<p class="lead">You want this? {{flag}}</p>
app\package-lock.json
2475: "has-flag": {
2477: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
2487: "has-flag": "^4.0.0"
5123: "regexp.prototype.flags": "^1.2.0"
6710: "has-flag": {
6712: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
7358: "has-flag": {
7360: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7396: "has-flag": "^4.0.0"
7794: "has-flag": {
7796: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7821: "has-flag": "^4.0.0"
7922: "has-flag": {
7924: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7934: "has-flag": "^4.0.0"
8777: "has-flag": {
8779: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
8789: "has-flag": "^4.0.0"
9916: "has-flag": {
9918: "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
9937: "has-flag": "^4.0.0"
10459: "has-flag": "^3.0.0"
10801: "has-flag": "^3.0.0"
11813: "regexp.prototype.flags": {
11815: "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
12043: "has-flag": "^3.0.0"
13574: "has-flag": "^3.0.0"
15195: "has-flag": "^3.0.0"
app\server.ts
37: res.json(`hello admin, this is true answer: ${process.env.FLAG2}`)
45: if (process.env.FLAG && req.path.includes('debug')) {
フラグは2つあるようだ。
/debug/answerにアクセス/api/true-answerに127.0.0.1でアクセス
Writeup
とりあえず何をすべきかは分かったが、それから手も足も出なかった。
TokyoWesterns CTF 2020 | writeups by @terjanq
うーん、なるほどというべきか、どうやってこの辺身に着けていけばいいんかな。
nginxのバックスラッシュバイパスは見たことあるし、パーセントエンコーディングバイパスも見たことあるけど、
ぱっと引き出せないな…
フラグ1
/debug/answerにアクセスできれば勝ち。だが、以下に阻まれてアクセスできない。
- nginxのWAF
location /debugでDENYになっている
- expressのエントリーポイントでのチェック
if (process.env.FLAG && req.path.includes('debug')) {
どちらもバイパスできるいい方法を探そう。
nginxのWAFをバイパスする
/debug/answerにアクセスしようとすると、location /debugに阻まれてダメになる。
なので、バックスラッシュによるバイパスを使おう。
/\debug/answerとする。こうすると、locationは/\debugとなるので引っかからなくなる。
これで今後の処理は問題ないかという話であるが、このURLは最終的にはAngularに渡される。
Angularでは\はスラッシュ扱いになるので、//debug/answerと解釈される。
URLではスラッシュ続きは無視されるだけなので、問題なく動作する。
これで403 Forbidden nginx/1.19.0からdebug page is disabled in production envに応答が変化する。
一歩前進。
expressのエントリーポイントでのチェック
パーセントエンコーディングでバイパスする。
dを%64に変換して送る。これでフラグが出てくる。
/\%64ebug/answer
これはnginxではパーセントエンコーディングはデコードされるけど、expressではパーセントエンコーディングはデコードされなくて、Angularではパーセントエンコーディングはデコードされるってこと?
たぶんそういう事だよね。
ちゃんと確認したいけれど、wslがwinupしたらぶっこわれたから環境作るのめんどくさかった。
フラグ2
解説を読んだ。
ライブラリのこういう特性を使うとHostに適当なやつ入れておけばSSRFできるパターンあるんだな…
Angularの仕様
AngularからHTTPリクエストを飛ばすときは、Hostヘッダーを使うらしい。
Angularでthis.http.get('/api/answer')のようにリクエストを飛ばしている箇所があれば、PROTOCOL + HOST + / PATHでアクセスする。
なので、適当なサイトに誘導してリダイレクトで127.0.0.1/api/true-answerへ飛ばせば、SSRFを達成できる。
https://repl.it/repls/BaggyStrongPaint
こんな感じに受けてを作って、リクエストさせればいい。
repl.it便利すぎる。