SECCON Beginners CTF 2021 WriteUp

[SECCON Beginners CTF 2021](https://score.beginners.azure.noc.seccon.jp/)に参加しました。
今回は例年と比べて簡単な問題が多かった気がします。間口を広げたのかな。
Welcomeを除いた個人的な結果は以下のとおり。（過去との比較あり）

||2021|2020|2019|
|---|---|---|---|
|Web|2|1|1|
|Pwn|0|0|0|
|Crypto|1|1|0|
|Reversing|2|0|1|
|Misc|1|1+α|1|

簡単な問題が増えたことを加味すると上達したのか相変わらず不明ｗ
WebとMisc1問ずつあと一歩というところでした。
チームメンバーが解いた後に教えてもらいましたが、もうちょっとやればフラグゲットできていた気がします。
そして、Pwnは相変わらず敬遠している...


フラグまで得られなかったものの、途中まで解けて後から分かったものも含めてWriteup記載します。


# [crypto] simple_RSA (Beginner)

## 問題

```text:Description
Let's encrypt it with RSA!
```

`simple_RSA.tar.gz`というファイルが与えられます。
展開すると`proble.py`と`output.txt`が得られます。

output.txtの中身は以下

```text:output.txt
n = 17686671842400393574730512034200128521336919569735972791676605056286778473230718426958508878942631584704817342304959293060507614074800553670579033399679041334863156902030934895197677543142202110781629494451453351396962137377411477899492555830982701449692561594175162623580987453151328408850116454058162370273736356068319648567105512452893736866939200297071602994288258295231751117991408160569998347640357251625243671483903597718500241970108698224998200840245865354411520826506950733058870602392209113565367230443261205476636664049066621093558272244061778795051583920491406620090704660526753969180791952189324046618283
e = 3
c = 213791751530017111508691084168363024686878057337971319880256924185393737150704342725042841488547315925971960389230453332319371876092968032513149023976287158698990251640298360876589330810813199260879441426084508864252450551111064068694725939412142626401778628362399359107132506177231354040057205570428678822068599327926328920350319336256613
```

## 解法

RSA問題のときはいつもお世話になってます。

https://www.slideshare.net/sonickun/rsa-n-ssmjp

こちらを参考に、eが小さいのでLow Public-Exponent Attackを試します。
solverは以下を参考にさせていただきました。

https://blog.akashisn.info/entry/2018/08/07/150018

```python:solver.py
#!/usr/bin/env python3

#
# Low Public-Exponent Attack
#

import gmpy2
import sys

# ベタ打ちでかっこ悪い
n = int(17686671842400393574730512034200128521336919569735972791676605056286778473230718426958508878942631584704817342304959293060507614074800553670579033399679041334863156902030934895197677543142202110781629494451453351396962137377411477899492555830982701449692561594175162623580987453151328408850116454058162370273736356068319648567105512452893736866939200297071602994288258295231751117991408160569998347640357251625243671483903597718500241970108698224998200840245865354411520826506950733058870602392209113565367230443261205476636664049066621093558272244061778795051583920491406620090704660526753969180791952189324046618283)
e = int(3)
c = int(213791751530017111508691084168363024686878057337971319880256924185393737150704342725042841488547315925971960389230453332319371876092968032513149023976287158698990251640298360876589330810813199260879441426084508864252450551111064068694725939412142626401778628362399359107132506177231354040057205570428678822068599327926328920350319336256613)

m,result = gmpy2.iroot(c,e)
print("[+] gmpy2.iroot(c,e) : {}".format(result))
print("[+] m^e(mod n) == c? : {}".format(pow(m,e,n) == c))

try:
    flag = binascii.unhexlify(format(m, 'x')).decode()
except Exception as e:
    mint = int(m)
    msize = sys.getsizeof(m)
    flag = mint.to_bytes(msize,'big')

print("FLAG: {}".format(flag))
```

```shell:実行結果
> python solver.py
[+] gmpy2.iroot(c,e) : True
[+] m^e(mod n) == c? : True
FLAG: b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ctf4b{0,1,10,11...It's_so_annoying.___I'm_done}"
```

flagゲットです。
`ctf4b{0,1,10,11...It's_so_annoying.___I'm_done}`

# [reversing] only_read(Beginner)

## 問題

```text:Description
バイナリ読めなきゃやばいなり〜
```

`chall`というELFファイルが与えられます。
私の環境では実行はできませんでした。

## 解法

IDAで読み込むとわかります。以下抜粋。

```text:取り込み結果抜粋
.text:00000000000011E4                 cmp     al, 63h ; 'c'
.text:00000000000011F0                 cmp     al, 74h ; 't'
.text:00000000000011FC                 cmp     al, 66h ; 'f'
.text:0000000000001208                 cmp     al, 34h ; '4'
.text:0000000000001214                 cmp     al, 62h ; 'b'
.text:0000000000001220                 cmp     al, 7Bh ; '{'
.text:000000000000122C                 cmp     al, 63h ; 'c'
.text:0000000000001238                 cmp     al, 30h ; '0'
.text:0000000000001244                 cmp     al, 6Eh ; 'n'
.text:000000000000124C                 cmp     al, 35h ; '5'
.text:0000000000001254                 cmp     al, 74h ; 't'
.text:000000000000125C                 cmp     al, 34h ; '4'
.text:0000000000001264                 cmp     al, 6Eh ; 'n'
.text:000000000000126C                 cmp     al, 74h ; 't'
.text:0000000000001274                 cmp     al, 5Fh ; '_'
.text:000000000000127C                 cmp     al, 66h ; 'f'
.text:0000000000001284                 cmp     al, 30h ; '0'
.text:000000000000128C                 cmp     al, 6Ch ; 'l'
.text:0000000000001294                 cmp     al, 64h ; 'd'
.text:000000000000129C                 cmp     al, 31h ; '1'
.text:00000000000012A4                 cmp     al, 6Eh ; 'n'
.text:00000000000012AC                 cmp     al, 67h ; 'g'
.text:00000000000012B4                 cmp     al, 7Dh ; '}'
```

`ctf4b{c0n5t4nt_f0ld1ng}`

# [reversing] children(Beginner)

## 問題

```text:Description
これから10個の子プロセスを作るよ。 彼らの情報を正しく答えられたら、FLAGをあげるね。
ちなみに、子プロセスは追加の子プロセスを生む可能性があるから注意してね。
```

## 解法

### 試行実行

実行してみます。

```:試行実行
$ ./children
I will generate 10 child processes.
They also might generate additional child process.
Please tell me each process id in order to identify them!

Please give me my child pid!
```

PIDが分かればよいとのことですので、実行用のコンソールとPS用のコンソールを用意して、実行する都度PIDを確認して入力していきました。
「子プロセスは追加の子プロセスを生む可能性があるから注意してね」の部分の回避策がよくわからなかったので、想定解ではないと思います。

### ps側コンソール

```shell:ps側
$ ps auxf |grep children
hoge+    5012  0.0  0.0   2488   648 pts/0    S+   17:37   0:00      |   \_ ./children
hoge+    5013  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5015  0.0  0.0  10092   656 pts/1    S+   17:37   0:00          \_ grep --color=auto children

...snip...

$ ps auxf |grep children
hoge+    5012  0.0  0.0   2488  1496 pts/0    S+   17:37   0:00      |   \_ ./children
hoge+    5013  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5016  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5017  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5020  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5023  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5024  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5027  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5030  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5033  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5036  0.0  0.0      0     0 pts/0    Z+   17:37   0:00      |       \_ [children] <defunct>
hoge+    5039  0.0  0.0      0     0 pts/0    Z+   17:38   0:00      |       \_ [children] <defunct>
hoge+    5040  0.0  0.0      0     0 pts/0    Z+   17:38   0:00      |       \_ [children] <defunct>
hoge+    5043  0.0  0.0      0     0 pts/0    Z+   17:38   0:00      |       \_ [children] <defunct>
hoge+    5045  0.0  0.0  10092   724 pts/1    S+   17:38   0:00          \_ grep --color=auto children
```

### モジュール実行側コンソール

```shell:実行側
$ ./children
I will generate 10 child processes.
They also might generate additional child process.
Please tell me each process id in order to identify them!

Please give me my child pid!
5013
ok
Please give me my child pid!
5017 
ok
Please give me my child pid!
5020
ok
Please give me my child pid!
5024
ok
Please give me my child pid!
5027
ok
Please give me my child pid!
5030
ok
Please give me my child pid!
5033
ok
Please give me my child pid!
5036
ok
Please give me my child pid!
5040
ok
Please give me my child pid!
5043
ok
How many children were born?
13
ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}	
```
flagゲットです。
`ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}`

# [web]osoba(Beginner)

## 問題

```text:Description
美味しいお蕎麦を食べたいですね。フラグはサーバの /flag にあります！
https://osoba.quals.beginners.seccon.jp/
```

`osoba.tar.gz`というファイルが与えられます。
展開すると、Webアプリのディレクトリが得られます。

## 解法

ディレクトリトラバーサルです。ただ遡るだけです。
与えられたファイルで階層がわかるので、
`https://osoba.quals.beginners.seccon.jp/?page=public/../../flag`
にアクセスするとflagが得られます。

`ctf4b{omisoshiru_oishi_keredomo_tsukuruno_taihen}`


# [web]Werewolf(Easy)

## 問題

```text:Description
I wish I could play as a werewolf...

https://werewolf.quals.beginners.seccon.jp/
```

`app.py`というファイルが与えられます。


## 解法

この問題はあと一歩のところで解けませんでしたが、後でチームメンバーに教えてもらいました。

`app.py`を読むと、roleが`WEREWOLF`になればよいが、
`self.__role = random.choice(['VILLAGER', 'FORTUNE_TELLER', 'PSYCHIC', 'KNIGHT', 'MADMAN'])`
となっていることから、WEREWOLFが入らないことがわかります。
なんとかして、roleに`WEREWOLF`を入れるのが問題ということになります。

```python
for k, v in request.form.items():
player.__dict__[k] = v
```

これがあることから、適切な変数に入れ込めばOKなことはわかりましたが、肝心の変数名が分からず、結果的にはチームメンバーから確認方法を教えてもらいました。

### 変数の確認方法

ローカルでapp.pyを読み込めばわかりました。

```python
# app.pyと同じディレクトリでpythonを起動
>>> import app
>>> player = app.Player()
>>> player.__dict__
{'name': None, 'color': None, '_Player__role': 'MADMAN'}
```

以上より、`_Player__role`が変数であることがわかります。

BurpでHTTPのパラメーターに`_Player__role : WEREWOLF`を入れて流し込んだらflagが得られました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241323/d9b54cf1-fe61-e2f5-f2b1-979a66b2b0b6.png" width=75%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241323/49c42f4a-dda5-2125-70bc-53262d638f68.png" width=50%>

`ctf4b{there_are_so_many_hackers_among_us}`


# [web]check_url(Easy)

## 問題

```text:Description
Have you ever used curl ?
https://check-url.quals.beginners.seccon.jp/
```

`index.php`というファイルが与えられます。

## 解法

与えられた`index.php`を見てみます。

```php:index.php冒頭
<?php
  error_reporting(0);
  if ($_SERVER["REMOTE_ADDR"] === "127.0.0.1"){
    echo "Hi, Admin or SSSSRFer<br>";
    echo "********************FLAG********************";
  }else{
    echo "Here, take this<br>";
    $url = $_GET["url"];
    if ($url !== "https://www.example.com"){
    $url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing
    }
...snip...
```

いかに127.0.0.1をサニタイズされずに渡すかが肝ですね。

https://qiita.com/naka_kyon/items/88478be20b300e757fc0

こちらを参考にして、16進（0x7F000001）を渡せばflagが得られました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241323/9fee942a-8e34-be2b-5e58-94496218b89e.png" width=70%>

`ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}`

# [misc]git-leak(Easy)

## 問題

```text:Description
後輩が誤って機密情報をコミットしてしまったらしいです。
ひとまずコミットを上書きして消したからこれで大丈夫ですよね？
```

`git-leak.zip`というファイルが与えられます。
展開すると`dist`フォルダが得られます。gitのレポジトリだと思います。

## 解法

rebase前に戻せればOK
以下を参考にしました。

https://www.karakaram.com/git-rebase-i-usage/#abort

```shell
$ git reflog
e0b545f (HEAD -> master) HEAD@{0}: commit (amend): feat: めもを追加
80f3044 HEAD@{1}: commit (amend): feat: めもを追加
b3bfb5c HEAD@{2}: rebase -i (finish): returning to refs/heads/master
b3bfb5c HEAD@{3}: commit (amend): feat: めもを追加
7387982 HEAD@{4}: rebase -i: fast-forward
36a4809 HEAD@{5}: rebase -i (start): checkout HEAD~2
7387982 HEAD@{6}: reset: moving to HEAD
7387982 HEAD@{7}: commit: feat: めもを追加
36a4809 HEAD@{8}: commit: feat: commit-treeの説明を追加
9ac9b0c HEAD@{9}: commit: change: 順番を変更
8fc078d HEAD@{10}: commit: feat: git cat-fileの説明を追加
d3b47fe HEAD@{11}: commit: feat: fsckを追記する
f66de64 HEAD@{12}: commit: feat: reflogの説明追加
d5aeffe HEAD@{13}: commit: feat: resetの説明を追加
a4f7fe9 HEAD@{14}: commit: feat: git logの説明を追加
9fcb006 HEAD@{15}: commit: feat: git commitの説明追加
6d21e22 HEAD@{16}: commit: feat: git addの説明を追加
656db59 HEAD@{17}: commit: feat: add README.md
c27f346 HEAD@{18}: commit (initial): initial commit

$ git reset --hard ORIG_HEAD
HEAD is now at 7387982 feat: めもを追加

$ git log --oneline
7387982 (HEAD -> master) feat: めもを追加
36a4809 feat: commit-treeの説明を追加
9ac9b0c change: 順番を変更
8fc078d feat: git cat-fileの説明を追加
d3b47fe feat: fsckを追記する
f66de64 feat: reflogの説明追加
d5aeffe feat: resetの説明を追加
a4f7fe9 feat: git logの説明を追加
9fcb006 feat: git commitの説明追加
6d21e22 feat: git addの説明を追加
656db59 feat: add README.md
c27f346 initial commit

$ ls
README.md  flag.txt  note.md
$ more flag.txt
ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}
```

`ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}`

# [misc]Mail_Address_Validator(Easy)

## 問題

```text:Description
あなたのメールアドレスが正しいか調べます．

nc mail-address-validator.quals.beginners.seccon.jp 5100
```

いわゆるReDoSの問題です。

## 解法

こちらもあと一歩で解けませんでした。
流し込む文字列をしっかり考えれば解けていました。惜しいことをした...

```ruby:main.rb抜粋
begin
  Timeout.timeout(5) {
    if input =~ pattern
      puts "Valid mail address!"
    else
      puts "Invalid mail address!"
    end
  }
rescue Timeout::Error
  exit(status=14)
end
```

こちらから、正規表現の評価に5秒以上かければ勝ちなことがわかります。
ここまでは分かっていましたが、5秒以上かかる文字列を投げられませんでした。終わった後改めてやったらすぐにできました。なんだったんだろう...

```shell
$ echo "aaaaaaaaaaaaaaaaaaaaaaaaaa@aaaaaaaaaaaaaaaaaaaaaaaaaaa" | nc mail-address-validator.quals.beginners.seccon.jp 5100
I check your mail address.
please puts your mail address.
ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}
```

`ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}`

---
以上です。

jsonは管理者ページには入れたんですが、そこから先ができませんでした。
id2個入れはしたんですが、正常値でないの入れてしまったのがまずったな・・・

勉強そこまでできてないので当然ですが、実力はイマイチなままですね。