僕と技術とセキュリティ

セキュリティエンジニアの備忘録

令和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!!)、時間的な都合がなかったため断念...