2021-05-22 14:00 – 2021-05-23 14:00 (JST)に開催されたSECCON Beginners CTF 2021のWrite-upです。
友人であるmaa氏との2人チームで出場し、2219pt獲得して全1095チーム中52位でした。
children
category: reversing
ELFファイルが与えられ、次々に作成される子プロセスのprocess IDを追いかける問題です。
straceを使って生成された新しい子プロセスのprocess IDを入力していき、最後に生成された子プロセスの総数を答えればフラグが獲得できます。
$ strace ./children execve("./children", ["./children"], 0x7fff2cc240c0 /* 22 vars */) = 0 brk(NULL) = 0x55caadded000 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=91823, ...}) = 0 mmap(NULL, 91823, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4627b28000 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\20\35\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4627b26000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4627525000 mprotect(0x7f462770c000, 2097152, PROT_NONE) = 0 mmap(0x7f462790c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f462790c000 mmap(0x7f4627912000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f4627912000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f4627b27500) = 0 mprotect(0x7f462790c000, 16384, PROT_READ) = 0 mprotect(0x55caacec5000, 4096, PROT_READ) = 0 mprotect(0x7f4627b3f000, 4096, PROT_READ) = 0 munmap(0x7f4627b28000, 91823) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 brk(NULL) = 0x55caadded000 brk(0x55caade0e000) = 0x55caade0e000 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=0x7f4627b277d0) = 13958 write(1, "Please give me my child pid!\n", 29Please give me my child pid! ) = 29 fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 read(0, 0x55caadded670, 1024) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=13958, si_uid=1000, si_status=1, si_utime=0, si_stime=0} --- read(0, ===(略)=== "14367\n", 1024) = 6 write(1, "ok\n", 3ok ) = 3 wait4(-1, NULL, 0, NULL) = 13958 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 +++ → ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}
osoba
category: web
適当にページを開くとクエリにファイルパスらしきものが指定されています。
https://osoba.quals.beginners.seccon.jp/?page=public/wip.html
def index(): page = request.args.get('page', 'public/index.html') response = make_response(send_file(page)) response.content_type = "text/html" return response
配布ファイルと問題文を参照すると/flagにフラグがあることがわかるので、ディレクトリトラバーサルでflagが取得できます。
https://osoba.quals.beginners.seccon.jp/?page=../flag → ctf4b{omisoshiru_oishi_keredomo_tsukuruno_taihen}
check_url
category: web
配布されたindex.phpの中に以下のような記述があります。
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 } if(stripos($url,"localhost") !== false || stripos($url,"apache") !== false){ die("do not hack me!"); } echo "URL: ".$url."<br>"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 2000); curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); echo "<iframe srcdoc='"; curl_exec($ch); echo "' width='750' height='500'></iframe>"; curl_close($ch); } ?>
curl_execがあるのでSSRFでローカルからのアクセスだと判断させればフラグが得られそうですが、正規表現でアルファベットと数字以外が弾かれてしまうため127.0.0.1は指定できません。

127.0.0.1(localhost)を一番面白く表記できた奴が優勝 - Qiita
要約もしも127.0.0.1(localhost)を一番~~面倒くさく~~面白くIPv4表記できた奴が優勝するとしたらと妄想してみた個人的に 017700000001 が優勝!!!前書きSE…
上記記事を参考にし、アルファベットと数字のみで127.0.0.1を表せる表記をいくつか試したところ、
https://check-url.quals.beginners.seccon.jp/?url=0x7F000001 → ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}
で通りました。ちなみに0x7F000001は16進表記バージョンです。
所感
メンバーの応援をしながらいけそうな問題にちょこちょこ手を付けてました。
reversingもう1問くらい解きたかったので今後の課題ということで。