令和CTF Writeup
自分の地域ではネットワーク障害があったため2時間だけ開催されたが、1問だけ解くことができました。
力技のWriteupが多かったので解説を自分も書くことに。
bREInWAck (Misc)
Brainfuck問題
以下は問題とヒント
元号が変わる。記号も変わる。
参考: https://ja.wikipedia.org/wiki/Brainfuck
令和和和和和和和和和和和和和和和和「令和 和和和和令和和和和令和和和和和和和令和和 和和和和令和和平平平平平成」令和和和。令 和和和和和。成成。。平成成成成。成。令令 和和和和和和和和和和和。令和和。平平平和 和和和。令和和。和和和和。令令和和和和和 和和和和和和和。平平平和和和和和和和和和 和和和和。成成成成成成成成。令成成成成成 成成成。令令。成成成成成。成成成成成成。 令和。平平和和。令令令和和和和和和和和和 和。
Wikiよりbrainfuck問題であることがわかる。
以下のサイト二つが特に参考になった。
http://www.kmonos.net/alang/etc/brainfuck.php
https://fatiherikli.github.io/brainfuck-visualizer/
Brainfuckについて
プログラムの実行中に一つの配列を扱い、数値を格納できる。
また、その配列上を移動できるポインタを持つ。
配列のイメージ
数値を格納できる [72, 101, 108, 108, 111]
また、命令は8つしかない
命令 | 意味(C言語での意味) |
---|---|
> | ++ptr; |
< | --ptr; |
+ | ++(*ptr); |
- | --(*ptr); |
. | putchar(*ptr); |
, | *ptr = getchar(); |
[ | while(*ptr) { |
] | } |
使い方
「H」を画面に出力するのであれば上記の配列の1番目の要素にポインタを合わせて「.」を使う。
出力はASCⅡコードで考えれば良い。
命令 //C言語の対応 . //putchar(*ptr);...① > //++ptr; ...② . //putchar(*ptr);...③
[72, 101, 108, 108, 111] ^ >H //配列の1番目の要素72を出力...①
[72, 101, 108, 108, 111] ^ //配列の2番目の要素に移動...② >H
[72, 101, 108, 108, 111] ^ >He //配列の2番目の要素101を出力...③
本命のWriteup
与えられた問題文より令和平成「」。
の7文字を><+-.,[]
に置き換えれば実行できそうなことがわかる。
パッと見た感じ
配列の要素をインクリメントする手段が1つしかないため
一番出現頻度の高い和
は+
に置き換わりそう。
また、[]で配列の要素をインクリメントしながら文字コードを調整するので[
の直前の文字は+
で間違いなさそう
和 -> +
次に、文中にそれぞれ一箇所しか出現しない「」
はwhileを意味する[]
に置き換えることができそう。(FlagのSECCON{~~}より出現頻度の少ない文字が+.
に置き換わることはない)
「 -> [
」 -> ]
続いてここのインタプリタを実行してみてwhileのループを行う配列の要素は[
の直前の値を参照し、]
がくると参照した要素をデクリメントして0
になった場合に]の次の命令を実行することがわかったので
]の後の要素には-
と.
が使われないことがわかる。
ポインタの概念的には配列の左から始まり、><
で移動することからも以下のことが推測できた。
令 -> >
そして、<
の出現頻度は>
より多くなることはないため、
平 -> <
問題分の末尾にputchar(*ptr);
の意味をもつ.
が来ていることから
。 -> .
残った成
は-
か,
に置き換わると考えられるが、
ここまでの推察から残りは2パターンしか考えられないので以下の様に置換してみて、インタプリタに実行させると、一発目でFlagにたどり着けた。
この問題はかなり頭の体操になった。
他にも楽しそうな問題が多かったが(特にWeb!!)、時間的な都合がなかったため断念...