ALDRYA

TCPサーバの接続情報と、以下のファイルが与えられた。

aldryaGhidraで逆コンパイルして読むと、以下の処理をしていることがわかった。

  1. コマンドライン引数としてELFファイルとALDRYAファイルのパスを受け取り、それらのファイルを開く。
  2. ELFファイルについて、先頭がELFファイルのマジックナンバーであることと、サイズがALDRYAファイルのデータと矛盾しないことをチェックする。
  3. ELFファイルを0x100バイトごとに区切り、この範囲のデータをもとに計算した値とALDRYAファイルに記録された値が一致するかをチェックする。
  4. 全てのチェックに通れば、ELFファイルを実行する。

また、server.py は、URLを入力するとそこからファイルをダウンロードし、 ELFファイルをダウンロードしたファイル、ALDRYAファイルをsample.aldryaとしてaldryaを実行するものだった。

そこで、まずはaldryaが行う値の計算を再現する以下のプログラムを用意した。

Information to connect to a TCP server and following files were given:

Decompiling aldrya via Ghidra, I found it doing these process:

  1. Get paths of a ELF file and a ALDRYA file from the command-line arguments and open the files.
  2. Check the ELF file to make sure that the prefix is the magic number for a ELF file and the size matches with the contents of the ALDRYA file.
  3. Divide the ELF file to 0x100-byte blocks and check if values calculated from the blocks and read from ALDRYA file matches.
  4. Execute the ELF file if it passed all checks.

Also, server.py accepts an input of URL, download a file from there, and execute aldrya using the downloaded file as the ELF file and samply.aldrya as the ALDRYA file.

Based on these, firstly I created this program to simulate the calculation of the value in aldrya.

get.pl

このプログラムを用い、sample.elfのいくつかのブロックについて計算した値がsample.aldryaに記録されているものと一致することを確認し、 他のブロックについても一致すると予想した。

そこで、sample.elfのエントリポイントに書かれているコードをシェルを起動するプログラムに差し替え、 差し替えたコードを含むブロックから計算した値がもともとのブロックから計算した値と一致するように実行しない部分を書き換えることにした。
エントリポイントは、readelf -hコマンドの実行結果より0x1060である。
「シェルを起動するプログラム」は、以下のコードをNASMでアセンブルして作成した。

I confirmed that values for some blocks in sample.elf matches with the values stored in sample.aldrya, and guessed that values for the other blocks should also match.

I decided to replace the code in the entry point of sample.elf with a program to launch the shell, and modify the data not to execute to match the value calculated from the modified block to the value from the original block.
The entry point is 0x1060, according to the result of the command readelf -h.
I created "a program to launch the shell" by assembling following code via NASM.

shell.asm

書き換え後、以下のプログラムを用い、Z3で値を一致させるようなデータを求めた。

After modifying, I used this program to find data to match the value via Z3.

solve.py

最終的に、差し替えたコードを含む0x1000バイト目(0-origin)からのブロックは以下のようになった。

This is the final block from the 0x1000-th byte (the first byte is 0th) that contains modified code.

sample_mod_part_1000.bin

書き換えたELFファイルをインターネットからHTTPアクセスできる場所に置き、 Tera TermでTCPサーバに接続してそのURLを送信することで、 シェルを起動することができた。
README.mdより、flagはルートディレクトリにあるようなので、 コマンド cd / を実行し、ls を実行した。
その結果、ファイル flag-4c147adf5f7a18258f6709ed9402d902.txt があることがわかり、コマンド cat *.txt によりflagが得られた。

I succeeded to launch the shell by placing the modified ELF file to where HTTP access from the internet is available, connecting to the TCP server via Tera Term, and sending the URL of the file.
The flag should be in the root directory according to README.md, so I executed cd / command and then ls command.
As a result, I found a file flag-4c147adf5f7a18258f6709ed9402d902.txt. I obtained the flag by executing a command cat *.txt.

CakeCTF{jUst_cH3ck_SHA256sum_4nd_7h47's_f1n3}

CakeCTF 2021