Chainblock

TCPサーバの接続情報、サーバのプログラム(C言語のソースコードとELFファイル)、 そしてELFファイルlibc.so.6ld-linux-x86-64.so.2が与えられた。

与えられたソースコードを読むと、gets関数で入力を読み込む処理を含む関数verifyを呼び出していた。
TDM-GCCobjdumpで逆アセンブルした結果より、 読み込み先はRBPの0x100バイト前で、RBPの8バイト先にリターンアドレスがあることが読み取れた。

そこで、リターンアドレスの手前までを埋めるデータplaceholder.binと、 ROP (Return-Oriented Programming) を用いて以下の処理を行うデータleak.binを用意した。

  1. pop rsi; pop r15; retというgadgetを用い、RSIをputsのアドレスが格納されているアドレスに設定する。
  2. pop rdi; retというgadgetを用い、RDIを"Hi %s!\n"のアドレスに設定する。
  3. printf関数を呼び出す。
  4. verify関数の先頭 (スタックのアラインメントを考え、プロローグの次) に制御を移す。

Information to connect to a TCP server, the program of the server (C source code and a ELF file), and ELF files libc.so.6 and ld-linux-x86-64.so.2 were given.

Reading the source code given, I found that a function verify that reads some input via the function gets called.
Disassembling via objdump in TDM-GCC, I found that the data is read to 0x100 bytes before RBP, and that the return address is 8 bytes after RBP.

Based on these, I created a data to fill the stack before the return address placeholder.bin and a data to do following things via ROP (Return-Oriented Programming) leak.bin.

  1. Set RSI to the adddress where the address of puts is stored via a gadget pop rsi; pop r15; ret.
  2. Set RDI to the address of "Hi %s!\n" via a gadget pop rdi; ret.
  3. Call the printf function.
  4. Jump to the beginning of the function verify (after the function prologue, considering the stack alignment).

placeholder.bin

leak.bin

Tera Termの「ファイル送信」でplaceholder.binleak.binの順に送信し、 Wiresharkでサーバの応答を観測することで、puts関数のアドレスを知り、 再び入力を受け付けさせることができた。

次の手順の準備のため、libc.so.6をTDM-GCCのobjdumpで逆アセンブルし、 先頭の以下の関数のアドレスをlibc-databaseに入れて検索を行った。

I sent placeholder.bin and then leak.bin via "Send file" with Tera Term and observed the response from the server via Wireshark to know the address of the function puts and have the server accept another input.

To prepare for the next step, I disassembled libc.so.6 via objdump in TDM-GCC, and put the addresses of following functions to libc-database for searching.

結果は複数出たが、使いたいputsstr_bin_shsystemの値は共通しており、特定ができたといえる。

この情報を利用し、ROPにより以下を行うデータを生成するプログラムgen.plを作成した。

  1. pop rdi; retというgadgetを用い、RDIをstr_bin_shに設定する。
  2. retというgadgetを用い、スタックのアラインメントを調整する。
  3. systemに制御を移す。

There were several results, but the values of puts, str_bin_sh, and system to use were the same, so this can be considered as identified.

Using this information, I created a program gen.pl to generate a data to do following things via ROP.

  1. Set RDI to str_bin_sh via a gadget pop rdi; ret.
  2. Adjust the stack alignment via a gadget ret.
  3. Jump to system.

gen.pl

もう一度placeholder.binを「ファイル送信」した後、生成したデータを「ファイル送信」することで、シェルを起動できた。

シェルでlsコマンドを実行することでファイルflag.txtが存在することがわかり、 cat flag.txtコマンドを実行することでflagが得られた。

I sent placeholder.bin again via "Send file", and then sent the generated data via "Send file" to launch the shell.

Using a command ls in the shell revealed that there is a file flag.txt. I obtained the flag by executing a command cat flag.txt.

corctf{mi11i0nt0k3n_1s_n0t_a_scam_r1ght}

corCTF 2021