TCPサーバの接続情報が与えられた。
また、ELFファイル chall
やC言語のソースコード tarinai.c
などのファイルが与えられた。
tarinai.c
から、以下のことが読み取れた。
main
関数からvuln
関数が呼び出される。vuln
関数はローカル配列Name
のアドレスを出力し、そこにread
関数で258バイトまで読み込む。
さらに、chall
をread
関数による読み込み先は -0x100(%rbp)
であることがわかった。
258バイトしか読み込めないので、保存された%rbp
の値の下位2バイトを書き換えることはできるが、リターンアドレスを書き換えることができなそうである。
保存された%rbp
の値を書き換えると、main
関数に戻った時の%rbp
の値に反映される。
さらに、これがmain
関数のleave
命令により、%rsp
に書き込まれる。
したがって、ROP (Return-Oriented Programming) のコードを読み込ませ、そのアドレスから(leave
命令で%rbp
をポップする分の)8を引いた値を%rbp
に書き込めば、
main
関数からROPを実行してくれるはずである。
まず、逆アセンブル結果の .plt.sec
に setbuf
、printf
、alarm
、read
の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:
main
calls the function vuln
.vuln
prints the address of a local array Name
and read at most 258 bytes using the function read
there.
Also, disassembling chall
using "objdump" of 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:
得られた関数のアドレスと名前を
libc6_2.31-0ubuntu9.2_amd64
、libc6_2.31-0ubuntu9.1_amd64
、libc6_2.31-0ubuntu9.3_amd64
の3件の候補が出てきた。
この3件の候補については、printf
、system
、str_bin_sh
の値は同じだった。
次に、これらの値を用いてシェルを起動する以下のプログラムを作成した。
まず、printf
関数のメモリ上の位置を取得し、再びmain
関数を呼び出す。
そして、取得したprintf
の位置からsystem
とstr_bin_sh
の位置を計算し、system("/bin/sh");
を実行する。
I put the names and addresses of the functions obtained to
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");
.
このプログラムにより、シェルを起動できた。
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
.