Absolute Dice

TCPサーバの接続情報と、サーバのプログラム(ELFファイル)AbsoluteDiceが与えられた。
AbsoluteDiceGhidraで逆コンパイルすると、 main関数は"/dev/urandom"を引数として以下の_main関数を呼び出していた。

Information to connect to a TCP server and a server program (ELF file) AbsoluteDice were given.
Decompiling AbsoluteDice via Ghidra, I found the function main calling this function _main with "/dev/urandom" as the argument.

_main.c

この関数は、乱数の値を31回連続で当てるとflag.txtの内容を出力するというものである。
ループでは、毎回fopen関数でファイルを開いて読み込み、その値を用いてsrand関数を呼び出していた。
また、逆コンパイルでは100回ループするようになっていたが、サーバに繋いで試すと32回で止まった。

CS50 IDE上でGDBを用いてAbsoluteDiceの挙動を調べた結果、 32回目のループでスタック上にあるファイル名へのポインタを入力値で上書きしており、 そのためにファイルの読み込みに失敗して落ちていることがわかった。
これを踏まえ、次の手順により乱数のシードを固定して正解の値を固定し、サーバにflagを出力させることができた。

  1. 31回、適当な値を入力する。
  2. 32回目の入力として、Ghidra上でわかる"flag.txt"のアドレス134515641を入力する。
  3. 1回、適当な値を入力する。ここで次のステップで入力するべき正解の値がわかる。
  4. 31回、出力された正解の値を入力する。

This function prints the contents of flag.txt after successfully guessing the value of the random number 31 times in a row.
It opens a file via the function fopen, read the file, and uses the value to call the function srand in each iteration.
Also, the result of decompilation suggested that the loop will run 100 times, but I found it stopping after 32nd iteration when I connected to the server and observed the behavior.

I observed the behavior of AbsoluteDice on CS50 IDE. As a result, I found it overwriting the pointer to the file name on the stack in the 32nd iteration and it is leading to aborting due to failure in reading the file.
Based on this, I had the server print the flag by fixing the value to guess by fixing the seed value for the random number generator.

  1. Enter some random value 31 times.
  2. As the 32nd input, enter 134515641 (the address of "flag.txt" on Ghidra).
  3. Enter some random value once. This reveals the expected value to enter in the next step.
  4. Enter the printed expected value 31 times.
ractf{Abs0lute_C0pe--Ju5t_T00_g00d_4t_th1S_g4me!}

RACTF 2021