TCPサーバの接続情報と、ファイル Dockerfile および money-printer が与えられた。
file コマンドを使うと、ファイル money-printer は64bitのELFファイルらしいことわかった。
main 関数が得られたが、役立ちそうな処理は見当たらなかった。
Information for connecting to a TCP server, and files Dockerfile and money-printer were given.
Using file command, I found that the file money-printer should be a 64-bit ELF file.
I decompiled the file using main, but I found nothing look useful from here.
ファイル money-printer を
fgets で読み込んだ内容を printf の第一引数に渡し、その後 puts および exit を呼び出している以下の部分が見つかった。
I disassembled the file money-printer using objdump from
Then, I found this part that passes what is read via fgets to the 1st argument of printf, and calls functions puts and exit.
main 関数の冒頭は、以下のようになっていた。
Also this is the first part of the function main.
%rsp は %rbp - 0xc0、fgets で文字列を読み込む位置は %rbp - 0x70 であり、その差は 80 バイトである。
レジスタに置かれる引数6個と合わせて、読み込まれる文字列の前には8バイトの引数が16個あるとみなせる。
さらに、逆アセンブル結果の以下の部分は、読み込んだ数値がある値以下かをチェックしているようである。
The value of %rsp is %rbp - 0xc0, and where to read a string using fgets is %rbp - 0x70. Their difference is 80 bytes.
Therefore, adding 6 arguments on the registers, it can be seen as there are 16 8-byte arguments before the string to be read.
Also, this part of the disassembled program looked like checking if the number read is not greater than some value.
指定のサーバに
I tried connecting to the server with
-1 を入力すると、以下のメッセージが出力された。
Entering -1, this message appeared.
そこで、以下の文字列を入力してみた。
Then, I entered this string.
すると、以下のメッセージが出力され、入力した文字列の最初が printf 関数で16番目のデータとして用いられるらしいことがわかった。
As a result, this message appeared. This is suggesting that the first part of the string entered is used as the 16th data in the function printf.
これを利用して、まずはいくつかの標準ライブラリ関数のアドレスを調べることにした。
.plt セクションの逆アセンブル結果より、printf 関数のアドレスが 0x601030 に、fopen 関数のアドレスが 0x601048 に格納されることがわかる。
これらのアドレスを利用した以下のデータを Tera Term の「ファイル送信」で送信し、通信内容を
Using this, I firstly obtained the addresses of some standard library functions.
According to the disassembled code of the .plt section, the address of the function printf will be stored at 0x601030 and one of the function fopen will be stored at 0x601048.
I sent this data, using these addresses, via "Send File" on Tera Term, and watched the communication using
その結果、(例えば) printf 関数のアドレスは 0x7f2aa39ace40、fopen 関数のアドレスは 0x7f2aa39c6de0 であった。
これらのアドレスを
これにより printf 関数と system 関数のアドレスの差が求まるので、以下の手順によりシェルを起動することができる。
printf のアドレスを取得しつつ、繰り返し入力できるように exit として実行する関数のアドレスを main 関数のアドレスにする。printf として実行する関数のアドレスを system 関数のアドレスにする。/bin/sh を入力し、system("/bin/sh"); を実行させる。
これを行う以下のプログラムを作成した。
printf のアドレス全部を書き換えようとすると入力文字数制限に引っかかったので、下位3バイトだけを書き換えるようにした。
As a result, I found that (for example) the address of the function printf is 0x7f2aa39ace40 and one of the function fopen is 0x7f2aa39c6de0.
I queried
We can use this to calculate the difference between the address of the functions printf and system, so the shell can be launched by these steps.
printf, and at the same time set the address to be executed as exit to the address of the function main to have it accept inputs repeatedly.printf to the address of the function system./bin/sh to have it execute system("/bin/sh");.
I wrote this program to perform these steps.
I failed to have it rewrite the whole address for printf due to the length limit for inputs, so I had it rewrite only the lower 3 bytes.
このプログラムを実行すると、シェルを起動できた。
シェルで ls -al コマンドを実行すると、ファイル flag.txt があることがわかった。
コマンド cat flag.txt を実行すると、flagが得られた。
I succeeded to launch the shell by running this program.
Executing a command ls -al on the shell revealed that a file flag.txt exists.
I obtained the flag by executing a command cat flag.txt.