IERAE CTF 2025
チームwithout_std1nで参加し、32/538位でした
解いた問題のうちpwnのメモです
Length Calculator
ギャグ枠
サイズ0を指定するとmmapに失敗して-1が返るのでif (!buf)にも引っ掛からずにfgetsで落ちる。
Stdio Studio
load_flag関数では、フラグがスタック上に読み込まれた後にmemsetで0埋め処理がされている。
しかしgdbで追ってみると実際は0埋めが行われていないことが判明した(retでスタックポインタが戻る直前なのでコンパイラの最適化によって消されたのかもしれない)
スタック上に残っているフラグをecho関数でリークすることを考える。サイズ80を指定することで丁度フラグの位置にbufポインタを置けるが、fgetsで入力を行うとどうしても改行が入ってしまいそこで出力がストップしてしまう。
強制的にfgetsを終了させる方法がないか探すと、pwntoolsのshutdown("send")を用いると入力に対してはEOFを送信して終了させる一方出力はそのまま表示することが可能なようなので、これを使うと改行を入力することなくfgetsをスキップしてフラグが出力される。
code:_
def exploit():
sendafter(": ", b"1")
sendafter(": ", b"2")
sendafter(": ", b"80")
recv(": ")
io.shutdown("send")
return 0
Gotcha-Go (todo: upsolve)
解けなくて悲しい…
goに何も詳しくなかったので調べていると、コンパイルオプションに-gcflags=-Bが指定されているので境界チェックが無効化されて配列外参照が可能になっていることが分かった。
itabというc++のvtableに似た仕組みがあるようなので、lの関数テーブルを配列外参照で書き換えることでRIPを取ることが出来たが、そこからが分からず諦めてしまった