SECCON Beginners CTF 2021 作問者writeup

## はじめに
5月22日14:00から24時間で初心者向けのSECCON Beginners CTF 2021を開催しました。私はMisc1問とReversing1問を担当したので、そちらのwriteupを公開します。

## [Misc 58pts] git-leak(410 solves)
Gitでコミット上書きされる前の情報を読み出す問題です。Gitのコミット上書きで証跡を消せたと思いこむのが危険なので、この問題を作問しました。

解法はいくつかあると思いますが、想定解法に利用するコマンド類は配布した`README.md`に全て記載してあります。正答率がかなり高かったので、きっとこのヒントを利用した方もいたのではないでしょうか？

Gitのオブジェクトには、ファイルの内容のみが格納されている`blob`と`blob`等をツリー構造で保持する`tree`オブジェクトがあります。これらのオブジェクトをコミットハッシュ(SHA-1)と紐づけることで管理しています。今回は、flagを含む`blob`を特定して中身を見れればflagが得られます。

さて、本題の解法に移ります。問題文から察するに、コミットを上書きしたことが分かります。そのため、コミット履歴を見るために`reflog`を使います。

```bash
$ 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: めもを追加

# (snip)
```

結果から、コミットハッシュ`7387982`に対して上書きが行われていることが分かります。

次に、コミットハッシュから中身のデータを確認するために、`cat-file`を使います。

```bash
$ git cat-file -p 7387
tree a5b6b52f47aba96730ab61471ddcdff864e5dd8c
parent 36a4809f1ae8013432eb52cfd2f9f062a3269499
author task4233 <29667656+task4233@users.noreply.github.com> 1620491725 +0900
committer task4233 <29667656+task4233@users.noreply.github.com> 1620491725 +0900

feat: めもを追加
$ git cat-file -p a5b6b52f47aba96730ab61471ddcdff864e5dd8c
100644 blob 16290835a0f74ccf30cbf30d791c84392a9dcce6    README.md
100644 blob 4cbb035d2ff072127b4e22919485127d2273e88e    flag.txt
100644 blob 62337fdb59ceb048f7da9eaf768923d744930842    note.md
$ git cat-file -p 4cbb035d2ff072127b4e22919485127d2273e88e
ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}
```

また、`checkout`, `reset --hard`を利用しても良いです。

```bash
$ git checkout 7387982
$ cat flag.txt
```

※@gamoutatsumi さん、ご指摘いただきありがとうございました！

別解として、全ての`blob`はzlibで圧縮されているので、全てのblobを解凍することでもflagは得られます。

```python
import os, glob, zlib

objects = glob.glob('./.git/objects/**', recursive=True)
for obj in objects:
    if os.path.isdir(obj):
        continue
    with open(obj, 'rb') as f:
        data = zlib.decompress(f.read())
        if b'ctf4b{' in data:
            print(data.decode())

# Output:
# blob 40ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}
```

## [Reversing 73pts] children(293 solves)
新たに生成される子プロセスの情報を確認する問題です。本問題は、実行ファイルの振る舞いを観察するための`strace`を使う問題を作りたかったので作問しました。

とはいえ、提出されたフラグを見ていると、ゴリゴリにReversingして解いている方もいたようですね。作問時に気づいてはいたのですが、Easy問なので抜け穴として残しておきました。

想定解では`strace`を使ってprocess IDを取得して回答し、最後に生成された子プロセスの数を回答すれば良いです。以下が実行例です。process IDや生成される子プロセスの数は変動するので、各自の環境で確認してください。

また、本問題は`$ ps`コマンドを併用しても解くことが出来ます。
@Takohabakaさん、ご指摘ありがとうございました。

```bash
$ strace ./children
execve("./children", ["./children"], 0x7fffe8e7b530 /* 21 vars */) = 0
brk(NULL)                               = 0x557ac1056000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=31525, ...}) = 0
mmap(NULL, 31525, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcc13353000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcc13351000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcc12d43000
mprotect(0x7fcc12f2a000, 2097152, PROT_NONE) = 0
mmap(0x7fcc1312a000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fcc1312a000
mmap(0x7fcc13130000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcc13130000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fcc13352500) = 0
mprotect(0x7fcc1312a000, 16384, PROT_READ) = 0
mprotect(0x557ac02cb000, 4096, PROT_READ) = 0
mprotect(0x7fcc1335b000, 4096, PROT_READ) = 0
munmap(0x7fcc13353000, 31525)           = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL)                               = 0x557ac1056000
brk(0x557ac1077000)                     = 0x557ac1077000
write(1, "I will generate 10 child process"..., 36I will generate 10 child processes.
) = 36
write(1, "They also might generate additio"..., 51They also might generate additional child process.
) = 51
write(1, "Please tell me each process id i"..., 58Please tell me each process id in order to identify them!
) = 58
write(1, "\n", 1
)                       = 1
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fcc133527d0) = 1390
write(1, "Please give me my child pid!\n", 29) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1390, si_uid=0, si_status=1, si_utime=0, si_stime=0} ---
write(1, "Please give me my child pid!\n", 29Please give me my child pid!
) = 29
fstat(0, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), ...}) = 0
read(0, 1390

# (snip)

"1400\n", 1024)                 = 5
write(1, "ok\n", 3ok
)                     = 3
wait4(-1, NULL, 0, NULL)                = 1390
write(1, "How many children were born?\n", 29How many children were born?
) = 29
read(0, 11
"11\n", 1024)                   = 3
write(1, "ctf4b{p0werfu1_tr4sing_t0015_15_"..., 40ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}       ) = 40
lseek(0, -1, SEEK_CUR)                  = -1 ESPIPE (Illegal seek)
exit_group(0)                           = ?
+++ exited with 0 +++
```