UECTF2022 Writeup
はじめに
3819点で9位(88人参加*1)でした。普段解いていないジャンルの問題も沢山解けて楽しかったです。運営の皆さん、ありがとうございました。
MISC
caesar (68 solves)
ガイウス・ユリウス・カエサル Gaius Iulius Caesar [caesar_source.py] [caesar_output.txt]
問題名から、シーザー暗号でFlagが暗号化されているのだろうと推測できました。caesar_source.py
の処理を確認してみると、通常のシーザー暗号とは異なるテーブルで変換していることがわかります。
ascii_all = '' for i in range(len(ascii_uppercase)): ascii_all = ascii_all + ascii_uppercase[i] + ascii_lowercase[i] letter = ascii_all + digits + punctuation
処理自体は複雑なものではないので、caesar_source.py
と逆の処理をするようなスクリプトを書いて実行することで、Flagが得られました。
from string import ascii_uppercase, ascii_lowercase, digits,punctuation def decode(ciphertext): plaintext = '' for i in ciphertext: index = letter.index(i) plaintext = plaintext + letter[(index - 14) % len(letter)] return plaintext ascii_all = '' for i in range(len(ascii_uppercase)): ascii_all = ascii_all + ascii_uppercase[i] + ascii_lowercase[i] letter = ascii_all + digits + punctuation with open('caesar_output.txt', 'r') as cipher_file: ciphertext = cipher_file.read() plaintext = decode(ciphertext[:-1]) print(plaintext)
UECTF{Th15_1s_a_b1t_Diff1Cult_c43seR}
redaction gone wrong 1 (71 solves)
NOBODY SHOULD JUST COPY AND PASTE MY FILES! 何人もコピペすべからず! [challenge.pdf]
LibreOffice Drawで challenge.pdf
を開き、PDF内のFlagを隠している黒い四角形を移動もしくは削除することでFlagが得られました。他にも解き方はたくさんあり...
- PDFをテキスト形式に変換するツールを使用する
- 問題文にて示唆されている通り、適当な場所をC&Pして内容をテキストファイルに貼り付ける
といった方法でも解けると思います。
UECTF{PDFs_AR3_D1ffiCulT_74d21e8}
redaction gone wrong 2 (54 solves)
We have found this image floating on the internet. Can you tell us what is the redacted text? インターネット上でこの画像を見つけた。隠されたテキストは何だろうか? [flag.png]
StegOnlineに flag.png
をアップロードして、"LSB Half" オプションを選択することでFlagが薄く見える状態になりました。
UECTF{N3ver_ever_use_A_p3n_rofl}
GIF1 (59 solves)
GIFアニメの中にフラグを隠したよ。え?隠れてないって?そんなぁ… I tried to hide the flag with GIF animation. Huh? Not hidden...? Oh no... [UEC_Anime.gif]
ffmpeg等のツールで UEC_Anime.gif
をフレームごとに画像ファイルに分割することで、Flagが含まれている画像ファイルが得られました。
ffmpeg -i UEC_Anime.gif -vsync 0 frame%d.png
UECTF{G1F_4N1M4T10NS_4R3_GR34T!!}
GIF2 (30 solves)
今度こそGIFアニメにフラグを隠したよ。人の目で見えるものだけが全てじゃないよ。 I tried to hide the flag in a GIF animation. It's not all about what people can see. [UECTF.gif]
StegOnlineに UECTF.gif
をアップロードして、"LSB Half" オプションを選択することでFlagが薄く見える状態になりました。
UECTF{TH1S_1S_TH3_3NTR4NC3_T0_ST3G4N0GR4PHY}
OSINT (13 solves)
There is this link to a Twitter account. However, Twitter says that "This account doesn’t exist." Could you somehow use your magic to find this person? I'm pretty sure he's still using Twitter. Thanks!! あるTwitterアカウントへのリンクがありました。アクセスすると"このアカウントは存在しません"と表示されて困っているんだ...😖 他の情報源によるとTwitterをまだやっているはずなんだけどなぁ🤔 https://twitter.com/__yata_nano__
Wayback MachineでURLを検索してみると、10月の時点のキャプチャが存在することがわかります。HTMLソースを確認してみると、アカウントIDを見つけることができました。
"additionalName": "__yata_nano__", "description": "", "givenName": "name", "homeLocation": { "@type": "Place", "name": "" }, "identifier": "1585261641125416961",
これをidtwiというサービスで検索することで現在のアカウントを特定することができました。
11月19日の午後7時59分のツイートに書かれているPastebinのURLにアクセスすることでFlagが得られます。
Congratulations!!!! Enter the password and get the 🚩.
— name (@ftceu) 2022年11月19日
password: qRh8EvEtFyhttps://t.co/Mb1ZOIbR6J pic.twitter.com/xWUdD0277A
UECTF{ur_a_tw1tter_mast3r__arent_y0u}
WHEREAMI (16 solves)
あなたの元に友人から「私はどこにいるでしょう?」という件名の謎の文字列が書かれたメールが送られてきました。 さて、これは何を示しているのでしょうか? You receive an email from your friend with a mysterious string of text with the subject line "Where am I?" Now, what does this indicate? [mail.txt]
ヒント: 彼はこの文字列はPlus codeだと言っていましたがよく分かりません。 He said it was a "plus code", but I have no idea what plus code is. Is any string with "+" character in it a "plus code"???
ヒントを確認することで、配布された mail.txt
内の文字列がPlus codeという場所を表すコードであることがわかります。それが約550個あり、かつ各コードの示す地点があまり離れていないことから、地図上にコードが示す地点をプロットしていくことで、Flagが得られると考えました。以下は配布ファイルを読み込み、それから得られた緯度・経度を folium
というライブラリを用いて地図上にプロットするスクリプトです。
from openlocationcode import openlocationcode as olc import folium PLUS_CODE_FILE = 'mail.txt' with open(PLUS_CODE_FILE, 'r') as pcfile: plus_code = pcfile.readlines() flag_map = folium.Map(tiles='OpenStreetMap') for pc in plus_code: decoded = olc.decode(pc[:-1]) folium.Marker(location=[decoded.latitudeLo, decoded.longitudeLo]).add_to(flag_map) flag_map
これをJupyter Notebookで実行することで、Flagが得られます。
UECTF{D1d_y0u_Kn0w_aB0ut_Km1?}
FORENSICS
Deleted (53 solves)
USBメモリに保存してたフラグの情報消しちゃった。このイメージファイルからどうにか取り出せないものか… I have deleted the flag information I saved on my USB stick. I wonder if there is any way to retrieve it from this image file... [image.raw]
FTK Imagerで配布されたイメージファイルを読み込むと、flag.png
というFlagが書かれたファイルを確認することができます。
UECTF{TH1S_1M4G3_H4S_N0T_B33N_D3L3T3D}
compare (33 solves)
新しくUECTFのロゴを作ったよ。え?元々あったロゴと同じじゃないかって?君はまだまだ甘いなぁ。 I made a new logo for UECTF. What, do you think it's the same as the original logo? You are still a bit naive. [UECTF_org.bmp] [UECTF_new.bmp]
2つのビットマップ画像が配布されていたので、とりあえず xxd
で16進数ダンプの状態にしたうえで、diff
で差分を見てみました。UECTF_new.bmp
にはFlagが1文字ずつ、数バイトごとに含まれていることがわかり、これを繋ぎ合わせるとFlagになります。
$ cat UECTF_org.bmp | xxd > org.txt $ cat UECTF_new.bmp | xxd > new.txt $ diff org.txt new.txt 6366c6366 < 00018dd0: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 00018dd0: ffff ffff 55ff ffff ffff ffff ffff ffff ....U........... 6427c6427 < 000191a0: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 000191a0: ff45 ffff ffff ffff ffff ffff ffff ffff .E.............. 6490c6490 < 00019590: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 00019590: ffff ffff ffff ffff ffff ffff ffff 43ff ..............C. 6547c6547 < 00019920: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 00019920: ffff ffff ffff ffff ffff ffff ffff ff54 ...............T 6588c6588 < 00019bb0: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 00019bb0: ffff ffff ffff ffff 46ff ffff ffff ffff ........F....... 6628c6628 < 00019e30: ffff ffff ffff ffff ffff ffff ffff ffff ................ --- > 00019e30: ffff ffff ff7b ffff ffff ffff ffff ffff .....{..........
UECTF{compare_two_files_byte_by_byte}
discord1 (30 solves)
数日前、CTFの作問をやっている友達が送ってきたフラグの書かれた画像がいつの間にか消されていた。あれがあればこの問題にも正解できるはず… 調べたらDiscordのデータはこのフォルダに色々保存されているらしい。何とかして消された画像を見つけられないだろうか… A few days ago, a friend of mine who is doing a CTF composition question sent me an image with the flag written on it, which was deleted. If I had that one, I should be able to answer this question correctly... I checked and it seems that Discord data is stored in this folder. I wonder if there is any way to find the deleted image... [discord1.zip]
問題文から画像形式のFlagであること、Cache
というフォルダが怪しいことを踏まえて、以下のように strings
および grep
コマンドで画像ファイルのURLを探してみました。
$ strings Cache/* | grep media.discordapp.net/attach ... Fehttps://media.discordapp.net/attachments/1039034703644205099/1043039290101350401/flag.png?width=400&height=297 ...
Flagらしきファイルは他にもありましたが、上記のURLにアクセスすることでFlagが得られました。
UECTF{D1SC0RD_1S_V3RY_US3FUL!!}
discord2 (21 solves)
前に思いついたフラグ送信しようとして止めたんだけど、やっぱりあれが良かったなぁ… でもちゃんと思い出せないなぁ。このフォルダにはキャッシュとかも残ってるし、どこかに編集履歴みたいなの残ってないかなぁ… I tried to send to a friend the flag I thought of before and stopped, but I still liked that one... But I can't remember it properly. I'm sure there's a cache or something in this folder, and I'm wondering if there's some kind of edit history somewhere... [discord2.zip]
Local Storage/leveldb
内のファイルにFlagが含まれていました。総当たりで全てのディレクトリに strings <directory_name>/* | grep UECTF
していたのですが、Discordの編集中の内容をここから確認できることは初耳でした。勉強になります。
$ strings Local\ Storage/leveldb/* | grep UECTF
UECTF{Y0U_C4N_S33_Y0UR_DR4FT}
REV
A file (81 solves)
誰かがファイルの拡張子を消してしまった。どのような中身のファイルなのか? Someone erased a file extension. What contents is the file? [chall]
file
コマンドで配布ファイルを調べると、xz
アーカイブ形式であることがわかったので、ファイルの名前を変更した上で解凍しました。解凍後のELFファイルにFlagの文字列が含まれていました。
$ mv ./chall ./chall.xz $ unxz ./chall.xz $ strings ./chall | grep UECTF UECTF{Linux_c0mm4nDs_ar3_50_h3LPFU1!}
UECTF{Linux_c0mm4nDs_ar3_50_h3LPFU1!}
revPython (20 solves)
What does this pyc file do? これは? [a.cpython-39.pyc] [flag.jpg]
pycdcなどのツールを使用することで、(不完全ですが)配布されたPythonのバイトコードファイルをデコンパイルすることができます。
デコンパイル後のコードを読むと、ファイルを UECTF{
という鍵でXORエンコードしているような処理が読み取れるので、以下のようなデコードスクリプトを作成してみました。
実行後に生成される flag_out.jpg
からFlagが得られます。
FLAG_INPUT_FILE = 'flag.jpg' FLAG_OUTPUT_FILE = 'flag_out.jpg' prefix = b'UECTF{' with open(FLAG_INPUT_FILE, 'rb') as flag_file: flag_dat = bytearray(flag_file.read()) for i in range(len(flag_dat)): flag_dat[i] ^= prefix[i % len(prefix)] with open(FLAG_OUTPUT_FILE, 'wb') as decoded_file: decoded_file.write(flag_dat)
UECTF{oh..did1s0meh0wscr3wup??}
captain-hook (21 solves)
haha, good luck solving this 運も実力のうち! [captainhook]
IDAで captainhook
を静的解析すると、XORデコードしていそうな処理が見つかったので、以下のようなデコードスクリプトを書いて解きました。
encoded = bytes.fromhex('58960A710308090860BE247A2D1C163A69BA2D7A3C1C143A7EBC2553202C150D64A0765845') key = 0x656173452549D30D flag = '' for i in range(0x25): a = ((i & 7) << 3) & 0xff flag += chr((encoded[i] ^ (key >> a)) & 0xff) print(flag)
UECTF{hmmmm_how_did_you_solve_this?}
dotnet (11 solves)
簡単にデコンパイルできるフレームワークを使って書いたので、難読化を施しました。 なので、難読化が正しく行われていれば秘密情報にはアクセスできないはずです・・・ (アプリケーションはLinux-x64で動作させることを想定しています) I obfuscated this because I made this using an easily decompilable framework. So, if the obfuscation is done correctly, the secret information should not be accessible... (The application is intended to run on Linux-x64) [chall_x86_64_linux]
まず binwalk
コマンドで chall_x86_64
に含まれているDLLファイルを全て抽出しました。
$ binwalk --dd="microsoft executable" chall_x86_64_linux --rm
たくさんのDLLファイルが抽出できますが、"Original Filename" が "UECTF2022_dotnet.dll" であるファイルが解析対象であると推測することができます。
問題文から、難読化が施されていると予想できたので、de4dot というツールを使用して難読化を解除しました。
> .\de4dot.exe .\A48B70 de4dot v3.1.41592.3405 Detected Unknown Obfuscator (C:\REDACTED\A48B70) Cleaning C:\REDACTED\A48B70 Renaming all obfuscated symbols Saving C:\REDACTED\A48B70-cleaned
dnSpy等のツールに生成されたDLLファイルを読み込んで解析すると、XORエンコードらしき処理が読み取れるので、デコードスクリプトを書いて実行したところ、Flagが得られました。
encoded = [255, 238, 235, 253, 232, 212, 237, 221, 210, 207, 201, 194, 199, 211, 205, 202, 212, 200, 149, 218, 204, 218, 221, 201, 215, 215, 157, 198, 223, 195, 220, 152, 206, 228, 252, 231, 235, 251, 161, 227, 231, 230, 228, 172, 242, 232, 169, 231, 255, 182, 254, 236, 242, 243, 229, 176, 226, 225, 255, 229, 243, 244, 224, 240, 142, 202, 149] flag = '' for i in range(len(encoded)): flag += chr(encoded[i] ^ i ^ 170) print(flag)
UECTF{Applications-created-with-Dotnet-need-to-be-fully-protected!}
discrete (16 solves)
Jumping around in memory 記憶の中でジャンプする [chall]
angrでシンボリック実行を適用することでFlagを得ることができました。
import angr EXEC_NAME = './chall' FLAG_ADDR = 0x402144 # puts("Correct!"); p = angr.Project(EXEC_NAME, load_options={"auto_load_libs": False}) state = p.factory.entry_state() simgr = p.factory.simulation_manager(state) simgr.explore(find=FLAG_ADDR) try: flag = simgr.found[0].posix.dumps(0) print(flag[:flag.find(b'\x00')].decode()) except IndexError: print("Something went wrong :(")
UECTF{dynamic_static_strings_2022}
WEB
webapi (42 solves)
サーバーからフラグを取ってきて表示する web ページを作ったけど、上手く動かないのはなんでだろう? I created a web page that fetches flags from the server and displays them, but why doesn't it work? http://uectf.uec.tokyo:4447
FLAG_URL
という定数に代入されているURLを開くことでFlagが得られました。
</div> </body> <script> const FLAG_URL = 'https://i5omltk3rg2vbwbymc73hnpey40eowfq.lambda-url.ap-northeast-1.on.aws/'; fetch(FLAG_URL) .then(data => { document.getElementsByClassName('flag-data')[0].innerText = data;
UECTF{cors_is_browser_feature}
request-validation (21 solves)
GET リクエストでオブジェクトを送ることはできますか? ※ まずは、自分の環境でフラグ取得を確認してください。 Can you request a object? First, please check the flag acquisition in your environment. http://uectf.uec.tokyo:4446 [request-validation.tar.gz]
GETリクエストのパラメータ q
の型が object
の場合のみ、Flagを返すようなWebアプリケーションが題材となった問題でした。
if (req.query.q && typeof req.query.q === 'object') { res.send(FLAG) } else { res.send('invalid request') }
全く事前知識がなかったので、とりあえず javascript object
と検索すると、以下のページを見つけることができました。
なんと、JavaScriptの typeof
では配列等を渡した場合、 object
としか返されないらしいです。これを利用すれば良いと直感的に理解したので、以下のようなスクリプトを書いて実行してみたところ、Flagが得られました。
import requests TARGET_URL = 'http://uectf.uec.tokyo:4446' PAYLOAD = {'q': [1, 2, 3, 4, 5]} req = requests.get(TARGET_URL, PAYLOAD) print(req.text)
UECTF{javascript_is_difficult_dee36611556508c702805b45289d0f65}
CRYPTO
RSA (57 solves)
RSA暗号でフラグを暗号化してみました!解読してみてください。 I encrypted the flag with the RSA cipher! Please try to decode it. [output.txt] [rsa_source.py]
output.txt
に含まれている p
, q
, e
, cipher text
を RsaCtfTool に渡して実行すると、Flagが得られました。
$ python3 RsaCtfTool.py --uncipher 40407051770242960331089168574985439308267920244282326945397 -p 1023912815644413192823405424909 -q 996359224633488278278270361951 -e 65537 private argument is not set, the private key will not be displayed, even if recovered. Results for /tmp/tmpyznhht1g: Unciphered data : HEX : 0x55454354467b5253412d69532d566552792d35314d7031657d INT (big endian) : 535251971441201547690579709091650584058216076608475543725437 INT (little endian) : 787118965001959771733939931024213066609133944657257179596117 utf-8 : UECTF{RSA-iS-VeRy-51Mp1e} STR : b'UECTF{RSA-iS-VeRy-51Mp1e}' HEX : 0x55454354467b5253412d69532d566552792d35314d7031657d INT (big endian) : 535251971441201547690579709091650584058216076608475543725437 INT (little endian) : 787118965001959771733939931024213066609133944657257179596117 utf-8 : UECTF{RSA-iS-VeRy-51Mp1e} STR : b'UECTF{RSA-iS-VeRy-51Mp1e}'
UECTF{RSA-iS-VeRy-51Mp1e}
さいごに
pwnが全然解けなかったし、頭の回転も遅いので、もっと勉強しないといけないと思いました。頑張ります。 :innocent:
*1:WELCOME問を解いた人数