UECTFさん主催のUECTF2022に参加しました。
結果は787pt、44/105th。
100pt問題を完答できなかったのは悔しかったですが、自力でそこそこ解けたCTFは初めてだったのでとても楽しめました。
復習も兼ねてWriteUpを書いていきます。
「きれいにしてから公開しよー」だと何時まで経っても完成しないのが目に見えてるので、解きながら書いたメモ書きでとりあえず公開します。しばらく汚い状態ですがお許しください。
なんかごちゃごちゃやってたら解けちゃったのもあるのですが、それも含めて追々整理していこうと思います。
11/18 20:00(JST)~11/20 20:00(JST)で初心者向けCTF #UECTF2022 を開催します!
— UECTF (@uec_ctf) November 17, 2022
オンライン開催で何時からでも、どなたでも参加可能です。
ぜひご参加ください!
ルール: https://t.co/R5EXp9FAOM
参加登録: https://t.co/ny28E068u1#UECTF #UECTF2022 #調布祭 pic.twitter.com/YDu4Rf2FQ5
環境
- Ubuntu 20.04.4 LTS
- Python 3.8.10
PWN
buffer_overflow
参考サイト
・変数の型
・はじめてのgdb
・【入門】はじめてのバッファオーバーフロー
・https://nodachisoft.com/common/jp/article/jp000028/
記事読む
ncでつないでみる
15byte以上のデータ入れてdebug_flagのデータを書き換えればいい
gccでa.out作る
REV
a file
参考サイト
・【 xz 】コマンド/【 unxz 】コマンド――ファイルを圧縮/伸張する
・(https://www.softel.co.jp/blogs/tech/archives/5282)
思考の流れ
とりあえずfileコマンドで中身をチェックする→「XZ compressed data」なので圧縮ファイルらしい
解答方法を調べる
unxz -k chall->ファイル名は未知の拡張子を持っています。スキップします。と出る
名前を変更して「.xz」つけてみる
そんなことしなくてよかった。ただディレクトリから展開すればよかった
展開して実行しようとするとglibcのバージョンがなくてエラー?になってるっぽい
glibcがそもそも入ってるか確認のためにバージョン確認コマンドを打ってみる
サイトを参考にさろうとしてもないので、rpmをインストールする
glibcのインストール方法がわからずもやもや
ダメ元でstringsコマンドにかけてみる
あっさりflag見えちゃったので解答
正規のやり方が知りたい
revPython
pythonコードっぽいファイルとflag.jpg
案の定、jpg開けない
MISC
caesar
プログラム確認
ascii_uppercaseとかわかんないから調べる
関数encodeにおいてその文字のletter上でのindexを取得し、そのindexに14足してletterの長さ(=94)で割った余りをindexとして文字を暗号化してる
だから元々のindexをとればいいのか
とりあえず(index+14)%len(letter)の結果である変換後のindexを求めた
暗号化の計算は元々のindexの値をx,商をy,余りをzとすると「(x+14)/94=y...z」となる
実際に文字になるのは余りのzでそれはさっき求めた
そこで式を変形して(x+14-z)/94のxへfor文で0から93まで順に代入させていき、余りが0になったときのxが元々のindexになると仮定してxを求める
出てきたxを変換し、flagとしてまとめる
0-93の間に条件にあうxが2つ以上あったらこのあとめんどくさい
今回は最初に求めたxがそれぞれ正解だったからよかったけど、もっと賢いやりかたありそう。
参考サイト
・ランダムな文字列を作る方法!!
・string---一般的な文字列操作---Python3.11.0b5 ドキュメント
・【Python入門】改行コードの使い方!出力・削除・置換方法まとめ
redaction gone wrong 1
pdfファイル開く
なんかコピペできそう
全選択でコピペしてテキストエディタに貼り付け
文字列検索したらflag見えた
redaction gone wrong 2
flagが黒塗りされたpng画像が。
このままでも読めそうだけど、ちょっと編集してみる
gimpで影とかマックスにしたら見やすくなった
GIF1
(画像)
マウスでUECと書くgif画像が与えられました。そのうち1フレームにflagが表示されてるっぽいです。
gif画像の分解を調べてみるとIrfanviewでできるとのこと。
なのでインストールし、日本語化していざ分解!と思ったのですが参考サイトにある選択肢がタブから消えてました。
おそらく同じことができる「全フレーム抽出」を選択したのですが、保存先ディレクトリの変更ができません(okボタン的なのが出ない)
直接保存先のパス書いて動かしても何も出てきません。
ここで「むきー!もういい!!自分でコード書く!!」となり、Pythonで分解するやり方を調べてコード書きます。
#memo--------------
#gif分解するコード
#----------------
import datetime
from pathlib import Path
from PIL import Image, ImageSequence
def get_frames(i_path):#パスで指定されたファイルのフレーム一覧を取得する
im = Image.open(i_path)
return (frame.copy() for frame in ImageSequence.Iterator(im))
def write_frames(frames, i_name, d_path):#フレームを別個の画像ファイルとして保存する
stem=i_name.stem#拡張子なしのファイル名を取得
extension = i_name.suffix#保存の拡張子
# 出力先のディレクトリが存在しなければ作成しておく
if not d_path.is_dir():
d_path.mkdir(0o700)#0oは0xみたいなもん.700はchmodと多分同じ
if DEBUG_MODE:
print(f'Destionation directory is created: {d_path.stem}.')
#フレームの保存プロセス
for i, f in enumerate(frames):
name = f'{d_path}/{stem}{i+1}{extension}'
f.save(name)#これはPILのsave
if DEBUG_MODE:
print(f'A frame is saved as {name}.')
if __name__ == '__main__':
#初期設定
dt_now=datetime.datetime.now().strftime("%y%m%d_%H%M%S")
DEBUG_MODE = True # 現在の状況を標準出力に表示するかどうか
c_path=Path().cwd() #カレントディレクトリの取得
i_name=Path(input("gif:"))
d_name=Path(input("destination:"))
i_path=c_path/i_name
d_path=c_path/d_name
frames=get_frames(i_path)
write_frames(frames, i_path, d_path)
print("[break_gif FIN]")
ほぼ参考サイト()のコードを流用させていただきました。
そうして無事gifを分解した結果、flagが映ってるフレームを得ることができました。
参考サイト
・Linux Mint 19.x : 画像ビューア「IrfanView」を簡単にインストールして使う
・アニメーションGIFを静止画に分割する方法
・Python Tips: アニメーション GIF から静止画をまとめて抽出したい
https://docs.python.org/ja/3/library/pathlib.html#pathlib.Path.mkdir
https://note.nkmk.me/python-pathlib-name-suffix-parent/
https://hibiki-press.tech/python/getcwd/5125#toc2
https://dot-blog.jp/news/python-pathlib-path-join/
https://note.nkmk.me/python-pathlib-mkdir-rmdir/
https://www.javadrive.jp/python/file/index11.html
https://www.javadrive.jp/python/string/index24.html
https://note.nkmk.me/python-pillow-basic/
疑問
getframesのcopyって何してるんだ
name = f'{d_path}/{stem}{i+1}{extension}'で後半2つの連結うまく行ったのが不思議
GIF2
またgif画像
ただし今回はフラッグを映してるものの、かっこの間がない
とりあえず分解してみる
お、なんかでてきたー!
flag発見
疑問
なんでこれ見えなかったの?
FORENSICS
Deleted
rawの画像データだ、開けないかな〜
eogとやらで見れそう.やってみる
まあ開けない
raw画像のヘッダ部分が壊れてるとか?->rawのヘッダ調べてみる
参考サイト
・【 eog 】コマンド――画像ファイルを表示する
Compare
bmpが2枚
差があるっぽいけど小さすぎてわからん
差を2値化して確認
なんか下に違いがあることはわかったけど、文字にならない
サイトに使ってみても同じ結果
参考サイト
・Python, OpenCV, NumPyで画像を比較(完全一致か判定、差分取得など)
・画像比較-カラーサイト.com
疑問
最大値化がいまいちピンとこない。なんで割ってる?
WEB
webapi
url渡されて開くとこんなん
とりあえずソース見てみる
flag_urlを見つけてアクセスしてみる->アクセスできん
ソース開いてネットワークタブで失敗してるところクリックしたら別ページに飛んだ
生データってタブ見たらflagあった
正しいやり方わからん
CRYPTO
RSA
参考サイト
・RSA暗号とは?仕組みや応用事例を初心者にもわかりやすく解説!
・CTFでRSAの問題が解けないので勉強してみた
思考の流れ
記事読む
dが必要なのか→じゃあdを求めよう
どうやってやろうかな。とりあえずp,qわかってるからnは求められるな。ただめちゃくちゃでかいね。
(p-1)(q-1)も求まるな
プログラム書いてとりあえずdを一つ求めてみる
サイトに従ってciepher textをd乗してnで割ったあまりを求める(pow)->これでflagが数字に置き換えられたp_textを入手
サイト2を参考にp_textを16進数に変換した上でbyteに変換し、それをcodecs.decodeを使ってdecodeしたらflag出た
memo
・bytes_to_longの出力結果は16進数ってこと?
・decodeの第二引数hexがよくわからん.公式docにない.
・実行途中にエディタの機能で「codecs.decode(hex(p_text)[2:],"hex")」ってやったらflag確認できたのに、実際に動かすと「それstrだからbyteにして渡してね」って怒られたのはなぜ?