its just an xor

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

itsjustanxorGhidraで逆コンパイルすると、以下のmain関数があった。

Information to connect to a TCP server and an ELF file itsjustanxor were given.

Decompiling itsjustanxor via Ghidra, I found this function main:

main.c

これは、fgets で入力を読み込んだ後、最初の8バイトと xor_key のXORをとり、その結果が "yoteyeet" と一致すれば flag.txt の内容を出力する、というプログラムである。

Ghidraで見ると xor_key の値は 0539053905390539h だったので、以下のCyberChefのRecipeで入力するべき値を求めた。

This program reads some input via fgets, calculates an exclusive-or of the first 8 bytes of the input and xor_key, and prints the contents of flag.txt if the result matches with "yoteyeet".

Ghidra revealed that the value of xor_key is 0539053905390539h, so I obtained the value to input using this Recipe for CyberChef:

Reverse, XOR, Reverse - CyberChef

得られた @jM`@`\q をサーバに入力したところ、「that aint it dawg」が出力されてしまった。

そこで、ファイル itsjustanxorCS50 Sandboxにアップロードし、調査を行った。
すると、GDB上で実行した時は @jM`@`\q を入力すると flag.txt の内容を出力するが、 そのまま実行した時は @jM`@`\q を入力すると「that aint it dawg」が出力されることがわかった。

そこで、プログラムを書き換えて実行時の xor_key の内容を出力させることにした。
TDM-GCCのobjdumpで逆アセンブルした結果のうち、以下の部分で xor_key の値を読み出している。

However, entering the resulting @jM`@`\q to the server just had it print "that aint it dawg".

Seeing this, I uploaded the file itsjustanxor to CS50 Sandbox to investigate.
I found that entering @jM`@`\q has it print the contents of flag.txt when executed on GDB, but entering @jM`@`\q has it print "that aint it dawg" when executed directly.

Therefore, I decided to modify the program to have it print the value of xor_key when it is executed.
Among the result of disassembling via "objdump" in TDM-GCC, this part retrieves the value of xor_key:

1342: 48 8b 05 c7 2c 00 00 mov 0x2cc7(%rip),%rax # 4010 <xor_key>

さらに、printf関数を呼び出す以下の部分もある。

It also has this part that calls the function printf:

13d0: 48 89 c6 mov %rax,%rsi 13d3: 48 8d 3d 6e 0c 00 00 lea 0xc6e(%rip),%rdi # 2048 <_IO_stdin_used+0x48> 13da: b8 00 00 00 00 mov $0x0,%eax 13df: e8 0c fd ff ff callq 10f0 <printf@plt>

そこで、この xor_key の値を %rax に読み出すコードの次の部分を、この %rax の値を printf 関数で出力するコードに飛ぶコードに書き換えた。
すなわち、0x13490x1e4e をnop (0x90) で埋め、0x134f にjmp命令 (0xeb 0x7f) を書き込んだ。
さらに、0x2048 に配置されている書式文字列を、"%016llx\n" に書き換えた。
なお、直接jmp命令を置かずにnop命令を入れたのは、直接jmp命令を置こうとするとオフセットが1バイトのjmp命令では届かないためである。

書き換えたファイルをCS50 Sandboxにアップロードして実行すると、0420042004200420 と出力された。
そこで、これに基づいて入力するべき文字列を求めた。

I changed the next part of the code to load the value of xor_key to %rax to a code to jump to the code to print the value of %rax via the function printf.
In other words, I filled 0x1349 to 0x1e4e with nop (0x90) and put a jmp instruction (0xeb 0x7f) to 0x134f.
I also changed the format string placed at 0x2048 to "%016llx\n".
Note that I added nop instructions because the part to print is beyond the limit of the jmp instruction with 1-byte offset placed just after the part to load xor_key.

I uploaded the modified file to CS50 Sandbox and executed that. As a result, it printed 0420042004200420.
Then, I obtained the string to enter using this value.

Reverse, XOR, Reverse - CyberChef

得られた文字列 YkTaYaEp をサーバに入力すると、flagが得られた。

I obtained the flag by entering the resulting string YkTaYaEp to the server.

flag{ok_maybe_there_was_a_little_more_than_an_xor}

SquareCTF 2021