Ghidraを使ってCTFの問題を解いてみる
前回の記事でGhidraのインストールと基本操作を学習したので、今回はGhidraを使って実際にCTFの問題を解いてみましょう。
まだ、前回の記事を見ていない人は下記のリンクからどうぞ!
問題紹介
今回解析した問題はSECCON_CTF_Beginner'sのmaskという問題です。
問題ファイルは下記のサイトにあるのでダウンロードしてみてください。
実際に解いてみる
1. fileコマンドでmaskファイルの形式を調べる
するとx86/x64のELF形式のファイルだと分かる。よって、Ghidraでファイルの中身を見てみることにする。
2. Ghidraで解析作業をする
maskファイルをGhidraで読み込んで解析すると
undefined8 main(int param_1,long param_2) { int input_len; size_t input_len; long in_FS_OFFSET; int (long)idx; byte input_arg [64]; byte param1 [64]; byte param2 [72]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); if (param_1 == 1) { puts("Usage: ./mask [FLAG]"); } else { strcpy((char *)input_arg,*(char **)(param_2 + 8)); input_len = strlen((char *)input_arg); input_len = (int)sVar2; puts("Putting on masks..."); (long)idx = 0; while ((long)idx < iVar1) { param1[(long)idx] = input_arg[(long)idx] & 0x75; param2[(long)idx] = input_arg[(long)idx] & 0xeb; (long)idx = (long)idx + 1; } param1[input_len] = 0; param2[input_len] = 0; puts((char *)param1); puts((char *)param2); input_len = strcmp((char *)param1,"atd4`qdedtUpetepqeUdaaeUeaqau"); if ((input_len == 0) && (input_len = strcmp((char *)param2,"c`b bk`kj`KbababcaKbacaKiacki"), input_len == 0) ) { puts("Correct! Submit your FLAG."); } else { puts("Wrong FLAG. Try again."); } } if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) { return 0; } /* WARNING: Subroutine does not return */ __stack_chk_fail(); }すると上のようなソースコードが「decompiler」ウィンドウに表示されると思います。
(上のコードは分かりやすいように若干書き換えてあります)
3. maskファイルがどのようなプログラムなのか考える
まず、先ほどのGhidraで解析したソースコードの以下の部分に注目してください。
param1[(long)idx] = input_arg[(long)idx] & 0x75; param2[(long)idx] = input_arg[(long)idx] & 0xeb;
上記よりparam1には入力した任意の文字列と0x75との論理積が代入され、
param2の値には入力した任意の文字列と0xebとの論理積が代入される。
また、下記のコードより
input_len = strcmp((char *)param1,"atd4`qdedtUpetepqeUdaaeUeaqau"); if ((input_len == 0) && (input_len = strcmp((char *)param2,"c`b bk`kj`KbababcaKbacaKiacki"), input_len == 0) ) { puts("Correct! Submit your FLAG."); }
param1が『atd4`qdedtUpetepqeUdaaeUeaqau』
param2が『c`b bk`kj`KbababcaKbacaKiacki』になるのであれば、それがflagと言える。
4. 解析コードを書いてみる
先ほど考えたmaskのアルゴリズムからflagを逆算するコードをpythonで書いてみる。
また、flag文字列はparam1かparam2のどちらかになればいい(論理和)のでORを求めるのが良いと思う。
# -*- coding: utf-8 -*- param1 = 'atd4`qdedtUpetepqeUdaaeUeaqau' param2 = 'c`b bk`kj`KbababcaKbacaKiacki' ans = '' for i,j in zip(param1, param2): ans += chr(ord(i) | ord(j)) # ordでASCIを取得、chrでASCIを文字列にする print(ans)
これを実行することで以下のflagを得ることが出来た。
ctf4b{dont_reverse_face_mask}