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便利すぎる。