# Ricerca CTF 2023 writeup 2023/04/23に行われた株式会社リチェルカセキュリティさん主催のCTF大会に個人出場しました。(Team Name: buds, User Name: HydrangeA) CTF初心者だったため、cryptoとreversingそれぞれ1問のみの解答で終えました。初心者なりに考えたwrite-upを残しておきます。 ## 解答した問題 * (reversing warmup) crackme * (crypto warmup) Revolving Letters ![](https://i.imgur.com/aifmdgD.png) ## 環境 * Windows 11 Home 22H2 * WSL2 Ubuntu 22.04 ## crackme 添付されたファイルはcrackmeのみ。 ファイル拡張子の見えないものはとりあえずどんなファイルかを見ておくのが良さそう。なのでfileコマンドをまず使います。 ``` # file crackme crackme: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e109ac8573ee031e7432c0d27a973fb37e492c80, for GNU/Linux 3.2.0, stripped ``` ELF(Executable and Linking Format)形式のファイルでした。なのでとりあえず実行してみる。 ``` # ./crackme Password: eee [-] Permission denied ``` パスワードを要求されたので、これを探るのだと知る。 次にファイルの中を見ようと考えたので、stringsコマンドを使いました。 ``` # strings crackme /lib64/ld-linux-x86-64.so.2 libc.so.6 __printf_chk ~(省略)~ The flag is "%s" Password: %99s N1pp0n-Ich!_s3cuR3_p45$w0rD [+] Authenticated [-] Permission denied 3333333333333333 ~(省略)~ ``` 文字列の中にPassword:とそれに続くパスワードっぽい文字列がある...? とりあえずこれを打ってみる。 ``` # ./crackme Password: N1pp0n-Ich!_s3cuR3_p45$w0rD [+] Authenticated The flag is "RicSec{U_R_h1y0k0_cr4ck3r!}" ``` Authenticated出来たためflagを取れました。 <details> <summary>感想</summary> 他の方のwrite-upを見て、reveringはIDAなどで逆アセンブリをかける、が序盤の基本な気がしました(その方がコードが読みやすいはず)。今回はstringsコマンドでたまたま読める形で出てきたから解けたのかなぁ?という気持ちもあったり。<br> この時CpawCTFの~~exec_me~~Can you execute?を学んだくらいの知識でしたが、それでも解けたので非常に嬉しかったですね。 </details> ## Revolving Letters 添付ファイルはchall.pyとoutput.txtの2つ。 2つのファイルの中身を見比べて、output内には * 暗号化に使った鍵(秘密鍵) * 一組の平文と暗号文のセット * flagの暗号文 が出力されていました。 またchall.py内にはencrypt関数があり、以下のように定義されています。 ``` def encrypt(secret, key): assert len(secret) <= len(key) result = "" for i in range(len(secret)): if secret[i] not in LOWER_ALPHABET: # Don't encode symbols and capital letters (e.g. "A", " ", "_", "!", "{", "}") result += secret[i] else: result += LOWER_ALPHABET[(LOWER_ALPHABET.index(secret[i]) + LOWER_ALPHABET.index(key[i])) % 26] return result ``` keyは秘密鍵、secretは暗号化したい文(平文)、LOWER_ALPHABETは英小文字の配列を表します。 ``` if secret[i] not in LOWER_ALPHABET: # Don't encode symbols and capital letters (e.g. "A", " ", "_", "!", "{", "}") result += secret[i] ``` このif文はコメントに書いてある内容が示していて、記号や英大文字はそのまま文字列に連結するようにしています。 ``` else: result += LOWER_ALPHABET[(LOWER_ALPHABET.index(secret[i]) + LOWER_ALPHABET.index(key[i])) % 26] ``` このelse文で英小文字の暗号化を行っています。仕組みは、i番目の平文のindexと秘密鍵のindexを足して26でmod(剰余)を取る、となっています。 このため ``` 暗号文のi番目のindex = (平文のi番目のindex + 鍵のi番目のindex) % 26 | V 平文のi番目のindex = (暗号文のi番目のindex - 鍵のi番目のindex) % 26 ``` と移項できます。 これを関数にしてflagの暗号文を引数に入れれば正しく復号できます。以下ではchall_dec.pyという別ファイルを作成して編集した結果を出しています。(コンテスト中はchall.pyをそのままいじりましたが...) ```python= # encrypt関数のelseを以下に変更 else: result += LOWER_ALPHABET[(LOWER_ALPHABET.index(secret[i]) - LOWER_ALPHABET.index(key[i]) + 26) % 26] ``` ``` # python3 chall_dec.py RpgSyk{qsvop_dcr_wmc_rj_rgfxsime!} key='thequickbrownfoxjumpsoverthelazydog' decrypt(flag, key): RicSec{great_you_can_do_anything!} ``` これでflagを復元することができました。 <details> <summary>感想</summary> もともと競技プログラミングを触っていたことと、暗号などの勉強を大学でしていたため素早く解けたと思います。もっと難しいのも触っていきたい。<br> もともとCやC++を使っていたため引き算のある剰余計算で(...+mod)%modとやるんですが、pythonは必要なかった。こういうとこ便利だ。 </details> ## まとめ 今回でCTFへの参加は2回目なんですが、初心者でも取り組める難易度の問題もあって非常に楽しかった。 今はとある常設CTFサイトの問題をひとつずつやっているので、それを継続していきます。 最後まで読んでいただきありがとうございます。