Badseed

テキストファイル pwntools_intro と、ELFファイル badseed が与えられた。

badseedGhidra で逆コンパイルすると、以下の関数を順に実行していることがわかった。

  1. init()
    • バッファリングとタイムアウトの設定を行う。
  2. question_one()
    1. 計算を行い、何らかの値を生成する。
    2. scanf関数の書式 %d を用い、値を読み込む。
    3. 生成した値と読み込んだ値が違っていれば、実行を終了する。
  3. question_two()
    1. time関数を用い、時刻を取得する。
    2. scanf関数の書式 %d を用い、値を読み込む。
    3. 取得した時刻を引数として srand関数を呼び出す。
    4. rand関数を2回呼び出す。
    5. 2回目に呼び出された時のrand関数の返り値と読み込んだ値を比較し、違っていたら実行を終了する。
  4. question_three()
    1. time関数で時刻を取得し、それを引数として srand関数を呼び出す。
    2. rand 関数を呼び出し、その返り値を引数として srand 関数を呼び出す。
    3. rand 関数を呼び出す。
    4. 最初のrand関数の返り値を2番目のrand関数の返り値で割り、さらにその結果を 1000 で割った余りを求める。
    5. scanf関数の書式 %d を用い、値を読み込む。
    6. 求めた余りと読み込んだ値を比較し、違っていたら実行を終了する。
  5. gz()
    • system("/bin/sh"); を実行する。

A text file pwntools_intro and a ELF file badseed were given.

Decompiling badseed via Ghidra, I found it executing these functions in this order:

  1. init()
    • Configure buffering and timeout.
  2. question_one()
    1. Generate a value by some calculation.
    2. Read a value using the function scanf with the format specifier %d.
    3. Terminate execution if the generated value and the value read differ.
  3. question_two()
    1. Obtain the time using the function time.
    2. Read a value using the function scanf with the format specifier %d.
    3. Call the function srand using the time obtained as the argument.
    4. Call the function rand twice.
    5. Compare the second return value of the function rand and the value read, and terminate execution if they differ.
  4. question_three()
    1. Obtain the time using the function time, and call the function srand using that as the argument.
    2. Call the function rand, and call the function srand using the return value of as the argument.
    3. Call the function rand.
    4. Divide the first return value of rand by the second return value, and divide the quotient by 1000 to obtain the remainder.
    5. Read a value using the function scanf with the format specifier %d.
    6. Compare the remainder and the value read, and terminate execution if they differ.
  5. gz()
    • Execute system("/bin/sh");.

まず、question_one 関数で入力するべき値を調べるため、badseedCS50 IDEにアップロードし、GDB上で実行した。
この値をメモリに保存した直後である 0x40132b にブレークポイントを設定し、メモリに保存した値が入っているRAXレジスタの値を出力させると、この値は 662 であるとわかった。

question_two関数とquestion_three関数に関しては、同様の処理で値を求める以下のプログラムを用意した。

Firstly, to determine the value to input for the function question_one, I uploaded badseed to CS50 IDE and ran on GDB.
I set a breakpoint to 0x40132b, which is just after storing the value to the memory, and checked the value of the RAX register, which has the value stored to the memory. As a result, I found that the value is 662.

To determine the values for the function question_two and question_three, I created this program to obtain values via the process used in the functions.

solve.c

サーバに前の関数用の値を入力する際に時計を見て時刻を確認し、以下のページでUNIX時間に変換した。

日付⇒UNIX時間変換 - 高精度計算サイト

得られたUNIX時間をコマンドライン引数とし、CS50 IDE上でこのプログラムを実行することで、サーバに入力すると処理を進めることができる値が得られた。

処理を進めるとシェルが起動するので、ls -al コマンドを実行すると、ファイル flag.txt があることがわかった。
cat flag.txt コマンドを実行すると、flagが得られた。

I checked the time on a clock when I enter the values for functions executed before the targets to the server, and converted the time to UNIX timestamp using this page:

Convert Date & Time to Unix timestamp Calculator - High accuracy calculation

I succeeded to obtain the values to have the server move on the next steps by executing the program on CS50 IDE using the UNIX timestamps as the command-line argument.

The shell is launched after some proceeding. I executed a command ls -al and found that there is a file flag.txt.
I obtained the flag by executing a command cat flag.txt.

flag{i_0_w1th_pwn70ols_i5_3a5y}

K3RN3L CTF