Tarinai

TCPサーバの接続情報が与えられた。
また、ELFファイル chall やC言語のソースコード tarinai.c などのファイルが与えられた。

tarinai.c から、以下のことが読み取れた。

さらに、challTDM-GCCのobjdumpで逆アセンブルした結果から、 read関数による読み込み先は -0x100(%rbp) であることがわかった。
258バイトしか読み込めないので、保存された%rbpの値の下位2バイトを書き換えることはできるが、リターンアドレスを書き換えることができなそうである。

保存された%rbpの値を書き換えると、main関数に戻った時の%rbpの値に反映される。
さらに、これがmain関数のleave命令により、%rspに書き込まれる。
したがって、ROP (Return-Oriented Programming) のコードを読み込ませ、そのアドレスから(leave命令で%rbpをポップする分の)8を引いた値を%rbpに書き込めば、 main関数からROPを実行してくれるはずである。

まず、逆アセンブル結果の .plt.secsetbufprintfalarmreadの4個の関数が見えるので、 printf関数を用いてこれらの関数のメモリ上の位置を読み取ることにした。

まず、読み込ませるデータの先頭にprintf関数に渡す書式を書き込む。
次に、データを16バイトにアラインメントし、printfを実行させるROPのコードを入れる。
さらに、リターンアドレスが入る分1要素開け、出力させる関数のアドレスがあるアドレスを入れる。
最後に、残りの領域を埋め、%rbpを設定するためのデータを入れる。
これを行うのが以下のプログラムである。

Information to connect to a TCP server was given.
Also, files including an ELF file chall and a C source code baby_heap.c were given.

Reading tarinai.c, I found these things:

Also, disassembling chall using "objdump" of TDM-GCC, I found that data read by the function read is stored to -0x100(%rbp).
Since it can read only upto 258 bytes, we can rewrite the lowest 2 bytes of saved value of %rbp, but it looks difficult to modify the return address.

Changing the saved value of %rbp will affect the value of %rbp after returning to the function main.
Then, the value will be put to %rsp by the instruction leave in the function main.
Therefore, ROP (Return-Oriented Programming) should be executed from the function main after putting code for ROP and setting %rbp to the address of the code minus 8 (because %rbp is popped in the instruction leave).

Firstly, seeing 4 functions setbuf, printf, alarm, and read in .plt.sec in the disassembled result, I decided to obtain the addresses of these functions on the memory using the function printf.

Firstly, put the format specifier to pass to the function printf in the beginning of the data to feed.
Then, after aligning the data to 16 bytes, put ROP code to execute the function printf.
After adding one blank element instead of the return address, put the addresses of the addresses of the function to be printed.
Finally, pad the left spce and put data to set %rbp.
This is my program to to this:

leak.pl

得られた関数のアドレスと名前をlibc-databaseに入れ、FIND を押すと、
libc6_2.31-0ubuntu9.2_amd64libc6_2.31-0ubuntu9.1_amd64libc6_2.31-0ubuntu9.3_amd64 の3件の候補が出てきた。
この3件の候補については、printfsystemstr_bin_shの値は同じだった。

次に、これらの値を用いてシェルを起動する以下のプログラムを作成した。
まず、printf関数のメモリ上の位置を取得し、再びmain関数を呼び出す。
そして、取得したprintfの位置からsystemstr_bin_shの位置を計算し、system("/bin/sh");を実行する。

I put the names and addresses of the functions obtained to libc-database and pressed FIND,
finding 3 candidates libc6_2.31-0ubuntu9.2_amd64, libc6_2.31-0ubuntu9.1_amd64, and libc6_2.31-0ubuntu9.3_amd64.
The values of printf, system, and str_bin_sh are the same among these 3 candidates.

Then, I created this program to launch the shell using these values.
This program firstly obtain the address of the funciton printf on the memory and call the function main again.
Then, calculate the addresses of system and str_bin_sh from the obtained address of printf and execute system("/bin/sh");.

shell.pl

このプログラムにより、シェルを起動できた。
ls -al コマンドを実行するとファイル flag.txt があることがわかり、cat flag.txt コマンドを実行するとflagが得られた。

This program succeeded to launch the shell.
Executing a command ls -al revealed that there is a file flag.txt, and I obtained the flag by executing a command cat flag.txt.

FLAG{Now_You_Know_Function_Epilogue}

WaniCTF 2021