2021年5月22日~23日に開催されたSECCON Beginners CTF 2021に参加したので、振り返りと学んだことをまとめたいと思います。結論から言うと、全然手も足も出なかったです… 期間中に触れたのはBeginnerの問題のみで、そのうち2問しか解けないというありさまでした。まあ勉強不足は仕方がないので、しっかり復習していきたいと思います。今回は僕が期間中に触れることのできたBeginner問題のみ復習していきます。その他の問題は僕の知識がついてからおいおい取り組んでいきたいと思っています。
1. crypto simple_RSA
タイトルの通りRSA暗号を解くというものですが、eが小さくc^e<nが明らかなので、cのe乗根をとるだけで解くことができるというものです。ぼくはcpawCTFで一度学んだことがあったのでここまでは思いつけましたが、そのコードを書くことができませんでした… この辺りはpythonの勉強不足ですね…
方法としてはgmpyのroot(c,e)で、cのe乗根をとることができるらしいです。それをlong_to_bytes関数で文字に戻すとflagが出てくるということですね。
import gmpy
e = 3
c = 213791751530017111508691084168363024686878057337971319880256924185393737150704342725042841488547315925971960389230453332319371876092968032513149023976287158698990251640298360876589330810813199260879441426084508864252450551111064068694725939412142626401778628362399359107132506177231354040057205570428678822068599327926328920350319336256613
gmpy.root(c,e)
from Crypto.Util.number import *
long_to_bytes(rootで出てきた値)
2. crypto Logical_SEESAW
期間内では、コードを見た時にどのような仕組みになっているのかを理解することができませんでした。これも、pythonの勉強不足です… どこかで書籍を買ってもう一度勉強し直そうかな…
さて、暗号としては50%の確率でflag
とkey
のand演算を行い、得られた値をcipher
として出力します。この時flag
もkey
もともに2進数なので、ともに1
でないとcipher
は1
になりません。つまりcipher
が1
と出ている場所は、もとのflag
も必ず1
なのです。また、cipher
が0
と出ている場所は、flag
は0
と1
のどちらも可能性があります。
この作業を16回繰り返したとき、もとのflag
が1
であるのに16個のcipher
がすべて0
である確率は極めて低くなります。このことから、一度も1
が出力されなければもとのflag
は0
、一回でも1
が出力されていればもとのflagは1
とみなすことができます。要するに、cipher
の各位に対して論理和を計算すればいいということです。
from Crypto.Util.number import *
cipher = ['11000010111010000100110001000000010001001011010000000110000100000100011010111110000010100110000001101110100110100100100010000110001001101000101010000010101000100000001010100010010010001011110001101010110100000010000010111110000010100010100011010010100010001001111001101010011000000101100', '11000110110010000100110001000000010001001111010010000110110000000110011010101110011010100110000010100110101100000100000000001110001001001000101000001010101001100000001010101010010110001001110001101010110100000110011010010110011000000100100011010000110010001001011001101010011000001101100', '11000010110010000100110001101000010001001111001000000110000100000110011000111110010010100110000000101110101101100000000010010110001001101000101010000010101000100000001000101110000010001001111001101010110100000010011010010110011000100000100011010010100010001001111001101010011000001101100', '11000110110010001100110000101000110001000111000000000110000000000110011010101110011000100110000010100110101101100100100010000100101001001000101010000010101000100000001010100110010010001001110001101010110000000110000010110110000000000000100011010010110010001011011001101010001000000111101', '11000110100010001100110000000000010001000111001010000110110100000110011010111110001010100110100011101110101110100010000000110100001001101000101010000010101001101000001000101000010010001001111001101010110000000010000010111110000000000010000011010010100010001001011001101010011000001111101', '11000010110010001100110001001000010001000011000000100110000000000110011010101110000010100110100011100110101110100010000000101100101001101000101010000010101001101000001010100010000010001011111001101010110100000110001010010110001010100100000011010010110010001011111001101010011000000101100', '11000110110010000100110001101000110001001011010000100110110000000110011000101110010000100110100001100110100110000000100010000110101001001000101010000010101001100000001000101110010010001011111001101010110000000010001010110110001010100110000011010000110010001011111001101010011000000101100', '11000010110010000100110000100000010001000111011000100110100000000110011000111110000010100110000001101110101111100100000010111110001001001000101000001010101001101000001000101010000110001011110001101010110000000110001010011110000010100010100011010010110010000011011001101010001000000111100', '11000010101010000100110001001000010001000011000000100110010000000100011000111110011000100110000001100110100101000010000000011100101001101000101000001010101001101000001010101110010110001001110001101010110000000010010010110110011000000010100011010000100010001011111001101010001000000101100', '11000010101010001100110000100000010001001111001010000110000000000100011010101110011000100110000011100110100111100110100000000110001001001000101010000010101000100000001000101100010010001011110001101010110000000110011010010110011010000000000011010010100010001011011001101010011000001101101', '11000010101010001100110001000000010001001011010010000110010100000100011000111110011000100110000010100110100111000100000000000100101001101000101010001010101000100000001000100000000110001001111001101010110000000110011010010110000010000100100011010000110010000011011001101010001000001101100', '11000110101010001100110001000000110001001111001010000110110000000110011010101110011000100110100001100110101111000100100010011110101001001000101010001010101000101000001000101100000110001011111001101010110100000010011010011110001000000100100011010010100010000001011001101010011000001111100', '11000110100010001100110001000000010001001011011010100110000000000100011000101110001000100110100001101110101101000110100010001100101001001000101010000010101000100000001010101100000010001001111001101010110100000110011010010110010000100110100011010010110010001001111001101010011000001101101', '11000110101010000100110000000000010001001111001010100110100100000100011010111110001000100110100001101110101100000000100000111110001001101000101000001010101001101000001010100110010010001011110001101010110100000110000010010110001010000010100011010010110010001001011001101010001000000101100', '11000010101010000100110000000000110001001011011010100110110000000110011000101110010010100110100000100110101111000010000000100100001001001000101000001010101001100000001000100000000010001011110001101010110000000010011010011110001010000000000011010010100010001001011001101010001000000101101', '11000110101010001100110001000000110001001111011000000110010100000100011000101110001010100110000001101110101110000100100000101110101001101000101000000010101000100000001010101010000010001011110001101010110000000010000010010110001000100100100011010000100010000001011001101010001000001111101']
flag = int(cipher[0], base=2)
for c in cipher:
flag |= int(c, base=2)
print(long_to_bytes(flag).decode("utf-8"))
|=
によって、論理和を計算することができるそうです。
3. reversing only_read
僕が期間内に初めて解いた問題です。内容は簡単で、デコンパイルしたもののmain
の部分を読めばflagが書いてあります。僕はghidraを使ったのですが、これのほうがいいというデコンパイラがあれば教えてほしいです。
4. pwnable rewriter
pwnの勉強を全然したことがなかったということもあり、この問題はサーバーに接続することしかできませんでした。
与えられたファイルを読むとwinという関数の部分にflagを出力してくれそうな部分があるのでsaved ret addr
をwin関数に書き換えるとflagがわかります。
$ nc rewriter.quals.beginners.seccon.jp 4103
Where would you like to rewrite it?
> 0x00007fff86f2e238
0x00007fff86f2e238 = 0x4011f6
5. web osoba
webサイトのリンクとwebサイトのファイルが与えられます。ファイルを見ると参照しているHTMLファイルの2つ上のファイルにflag
があることが分かるので、URLをhttps://osoba.quals.beginners.seccon.jp/?page=../flag
と指定することでflagが出てきます。(この作業をディレクトリトラバーサルというそうです)
6. misc git-leak
gitに触り慣れていないということもあり、この問題も何をすればいいのか全く分からないという状況でした。
まず、reflog
を使って、commitの履歴を見ます。すると7387982 HEAD@{7}
でめも
に対して上書きしているのが分かります。
cat-file
でファイルの中、ファイルツリーの中を見るとflagがあります。
$ git reflog
$ git cat-file -p 7387982
$ git cat-file -p a5b6b52f47aba96730ab61471ddcdff864e5dd8c
$ git cat-file -p 4cbb035d2ff072127b4e22919485127d2273e88e
7. 感想
今回初めて、CTFに参加させていただきました。普段cpawCTFやpicoCTFを解いている中では味わえない特別間や緊張感を味わうことができました。また、すぐにwriteupを見ることができないということから、解けるかもしれない問題に対していろいろググってみたり、時間尾をかけて考え込むということを初めてやったような気がします。writeupをみて知識を付けていくのもいいけど、新カリとググったり考え込む機会というのも大切だなと思いました。
ということで、これ以降は常設のCTFだけでなく、開催されている様々なCTFに参加してみたいと思います。そのなかで、知識と経験を蓄えていきたいです。今回のCTFではBeginner問しか触ることができませんでしたが、次に参加するときは少なくともeasy問まで解けることを目標に、勉強していきます!
最後までご視聴いただきありがとうございました! 指摘やアドバイス(内容についても記事についても)があれば、ぜひ教えていただけるとありがたいです。
8. 参考文献