UECTF2022 WriteUp(編集中)

UECTFさん主催のUECTF2022に参加しました。
結果は787pt、44/105th。
100pt問題を完答できなかったのは悔しかったですが、自力でそこそこ解けたCTFは初めてだったのでとても楽しめました。
復習も兼ねてWriteUpを書いていきます。
「きれいにしてから公開しよー」だと何時まで経っても完成しないのが目に見えてるので、解きながら書いたメモ書きでとりあえず公開します。しばらく汚い状態ですがお許しください。
なんかごちゃごちゃやってたら解けちゃったのもあるのですが、それも含めて追々整理していこうと思います。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">11/18 20:00(JST)～11/20 20:00(JST)で初心者向けCTF <a href="https://twitter.com/hashtag/UECTF2022?src=hash&amp;ref_src=twsrc%5Etfw">#UECTF2022</a> を開催します！<br>オンライン開催で何時からでも、どなたでも参加可能です。<br>ぜひご参加ください！<br><br>ルール: <a href="https://t.co/R5EXp9FAOM">https://t.co/R5EXp9FAOM</a><br>参加登録: <a href="https://t.co/ny28E068u1">https://t.co/ny28E068u1</a><a href="https://twitter.com/hashtag/UECTF?src=hash&amp;ref_src=twsrc%5Etfw">#UECTF</a> <a href="https://twitter.com/hashtag/UECTF2022?src=hash&amp;ref_src=twsrc%5Etfw">#UECTF2022</a> <a href="https://twitter.com/hashtag/%E8%AA%BF%E5%B8%83%E7%A5%AD?src=hash&amp;ref_src=twsrc%5Etfw">#調布祭</a> <a href="https://t.co/YDu4Rf2FQ5">pic.twitter.com/YDu4Rf2FQ5</a></p>&mdash; UECTF (@uec_ctf) <a href="https://twitter.com/uec_ctf/status/1593262746875105280?ref_src=twsrc%5Etfw">November 17, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

# 環境
* Ubuntu 20.04.4 LTS
* Python 3.8.10

# PWN
## buffer_overflow

#### 参考サイト
・[変数の型](https://www.javadrive.jp/cstart/var/index2.html)
・[はじめてのgdb](https://qiita.com/arene-calix/items/a08363db88f21c81d351)
・[【入門】はじめてのバッファオーバーフロー](https://qiita.com/Kuroakira/items/82446f083ee2fd05e925)
・https://nodachisoft.com/common/jp/article/jp000028/

記事読む
ncでつないでみる
15byte以上のデータ入れてdebug_flagのデータを書き換えればいい
gccでa.out作る


# REV
## a file
#### 参考サイト
・[【 xz 】コマンド／【 unxz 】コマンド――ファイルを圧縮／伸張する](https://atmarkit.itmedia.co.jp/ait/articles/1810/12/news037.html)
・(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が２つ以上あったらこのあとめんどくさい
今回は最初に求めたxがそれぞれ正解だったからよかったけど、もっと賢いやりかたありそう。

#### 参考サイト
・[ランダムな文字列を作る方法!!](https://kiwamiden.com/how-to-make-random-character-in-python)
・[string---一般的な文字列操作---Python3.11.0b5 ドキュメント](https://docs.python.org/ja/3/library/string.html)
・[【Python入門】改行コードの使い方！出力・削除・置換方法まとめ](https://camp.trainocate.co.jp/magazine/python-new-line/)

## 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」を簡単にインストールして使う](http://baker-street.jugem.jp/?eid=496)
・[アニメーションGIFを静止画に分割する方法](https://laboradian.com/split-animated-gif/)
・[Python Tips: アニメーション GIF から静止画をまとめて抽出したい](https://www.lifewithpython.com/2017/10/python-extract-gif-frames.html)
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}'で後半２つの連結うまく行ったのが不思議

## GIF2
またgif画像
ただし今回はフラッグを映してるものの、かっこの間がない
とりあえず分解してみる
お、なんかでてきたー！
flag発見

疑問
なんでこれ見えなかったの？

# FORENSICS
## Deleted
rawの画像データだ、開けないかな〜
eogとやらで見れそう.やってみる
まあ開けない
raw画像のヘッダ部分が壊れてるとか？->rawのヘッダ調べてみる

参考サイト
・[【 eog 】コマンド――画像ファイルを表示する](https://atmarkit.itmedia.co.jp/ait/articles/1905/10/news017.html)

## Compare
bmpが２枚
差があるっぽいけど小さすぎてわからん
差を２値化して確認
なんか下に違いがあることはわかったけど、文字にならない
サイトに使ってみても同じ結果


参考サイト
・[Python, OpenCV, NumPyで画像を比較（完全一致か判定、差分取得など）](https://note.nkmk.me/python-opencv-numpy-image-difference/)
・[画像比較-カラーサイト.com](https://www.color-site.com/image_compares)

疑問
最大値化がいまいちピンとこない。なんで割ってる？

# WEB
## webapi
url渡されて開くとこんなん
とりあえずソース見てみる
flag_urlを見つけてアクセスしてみる->アクセスできん
ソース開いてネットワークタブで失敗してるところクリックしたら別ページに飛んだ
生データってタブ見たらflagあった

正しいやり方わからん

# CRYPTO
## RSA
#### 参考サイト
・[RSA暗号とは？仕組みや応用事例を初心者にもわかりやすく解説！](https://it-trend.jp/encryption/article/64-0056)
・[CTFでRSAの問題が解けないので勉強してみた](https://qiita.com/uneyamauneko/items/b88f26a9c8150705aec5)

思考の流れ
記事読む
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の出力結果は１６進数ってこと？
・decodeの第二引数hexがよくわからん.公式docにない.
・実行途中にエディタの機能で「codecs.decode(hex(p_text)[2:],"hex")」ってやったらflag確認できたのに、実際に動かすと「それstrだからbyteにして渡してね」って怒られたのはなぜ？