2020年01月06日

SECCON CTF 2019 Final での syzbot panic クイズについて

2019年は熊猫にとって syzbot イヤーだったので、CTFの Jeopardy 問題として1問だけ出題させていただきましたが、いや〜、ここまで酷評されるとは思っていませんでしたよ。(笑)

出題したのは以下の問題です。表面的には、目的のページやパッチを如何に効率よく見つけられるかを競う出題なのですが、その裏には気づいて/考えてもらいたい話を含めていました。

Solve 5 questions listed below, and submit concatenated answers in SECCON{$answer_for_Q1+$answer_for_Q2+$answer_for_Q3+$answer_for_Q4+$answer_for_Q5} format.
Hint: Total length of answer string in SECCON{$answer_for_Q1+$answer_for_Q2+$answer_for_Q3+$answer_for_Q4+$answer_for_Q5} format will be 73 characters.

(Q1) What is FQDN (in all lower characters) of a website that manages the state of bugs syzbot has found?

(Q2) What is SHA-1 (only first 10 characters, in lower hexadecimal format) of a commit that explains the following improvement?

syzbot was unable to parse Linux kernel's messages when multiple threads concurrently emitted kernel messages. As a result, many reports had been discarded as "corrupted" indicating that "something went wrong but syzbot could not understand what has happened". After this patch was merged, ability to understand what has happened improved significantly. This patch was written by Tetsuo Handa.

(Q3) What is SHA-1 (only first 10 characters, in lower hexadecimal format) of a commit that fixed the following problem?

A local unprivileged user was able to trigger soft lockup using a reproducer shown below. This patch was written by Linus Torvalds.

----------------------------------------
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <termios.h>

static void *thr(void *arg)
{
        char c;
        read(*(int *) arg, &c, 1);
        return 0;
}

int main(int argc, char *argv[])
{
        char buf[sizeof(struct termios) + 64] = { };
        int zero = 0;
        int ptyno = 0;
        int fd = open("/dev/ptmx", O_RDONLY);
        int fd2;
        pthread_t th;
        buf[0x9] = 0xfd;
        buf[0xc] = buf[0xd] = buf[0xe] = buf[0xf] = buf[0x10] = 0xff;
        ioctl(fd, TCSETS, buf);
        ioctl(fd, TIOCSPTLCK, &zero);
        ioctl(fd, TCXONC, TCIOFF);
        if (ioctl(fd, TIOCGPTN, &ptyno))
                return -1;
        sprintf(buf, "/dev/pts/%d", ptyno);
        fd2 = open(buf, O_RDONLY);
        pthread_create(&th, 0, thr, &fd2);
        sleep(1);
        ioctl(fd2, FIONREAD, buf);
        return 0;
}
----------------------------------------

(Q4) What is SHA-1 (only first 10 characters, in lower hexadecimal format) of a commit that fixed the following problem?

Since passing arbitrary arguments to system calls as root user causes legitimate problems (e.g. hang up, reboot), fuzzers are currently forced to blacklist some arguments that legitimately damage the target. In April 2018, syzbot generated a report which confused developers because it was believed that arguments which are known to generate this report are blacklisted. But it turned out that syzbot was by error passing arguments which should have been blacklisted during the fuzz testing.

(Q5) What is SHA-1 (only first 10 characters, in lower hexadecimal format) of a commit that explains the following improvement?

Currently, syzbot might by error generate C reproducer programs using incorrect structure definition (e.g. "struct serial_struct"). Therefore, a utility to validate correctness of structure definition was added.

正解は SECCON{syzkaller.appspot.com+15ff2069cb+966031f340+06c33b3af0+64ca0a3711} です。

1問目は、2問目以降を解いていくためのヒントとなるページへの誘導です。 syzbot でググれば一発でヒットするでしょう。

2問目は、ファジングツールにとって悩みの種であった、カーネルメッセージを読みやすくする改善の話題です。1問目で syzbot というキーワードでググった際に syzkaller.appspot.com を見つけて、逃げるsyzbot、追うカーネル開発者たちをスルーしてしまったチームにとっては、目的のパッチを見つけるまでにちょっと回り道してもらうことになったのではないかと思います。
不具合退治の舞台裏に興味を持ってもらいたくて、出題しました。詳細は The SYZBOT CTF を参照いただければと思います。

3問目は、ファジングツールは、 root ユーザの権限が無くてもシステムをダウンさせてしまうことのある不具合を見つける場合があるということを知ってもらう問題です。発見される不具合の多くは root ユーザの権限が無いと遭遇しないのですが、たまに一般ユーザの権限でも遭遇できてしまう不具合が発見されることがあります。そのため、「このシステムでは管理者権限を与えないから、ファジングテストで見つかった不具合を心配しないで大丈夫」と問題を甘く見ないことが求められます。この問題は、 syzbot が見つけたC言語の再現プログラムを、熊猫が単純化して security@kernel.org に投げて、非公開の議論を経て修正されました。

4問目は、ファジングで使うテストケース作成の難しさについて知ってもらう問題です。 root ユーザの権限があれば不具合を攻撃しなくても合法的にシステムを停止させることができてしまうので、合法的にシステムを停止させてしまうような操作は、テストケースから除外するという対処をしています。この問題ではテストケースから除外しているつもりが除外できていなかったという話題を扱いましたが、実際にはテストケースから除外することは容易ではありません。テストケースから除外することなく対処する方法として、テストケースを root ユーザの権限ではなく一般ユーザの権限で動作させるという方法も提案されていますが、多くの不具合を発見できなくなってしまいます。
そのため、ファジングテストのためのカーネルでは、合法的にシステムを停止させてしまうような操作をカーネル側で拒否できるようにするという提案が現在進行中です。

5問目は、ファジングの凄まじさを知ってもらう問題です。 syzbot は、C言語で記述された再現プログラムを提示してくれるのですが、熊猫が問題を解析しようとして再現プログラムの「読める化(ローカル変数や構造体などを用いて書き直す)」作業をしたところ、構造体を用いると問題が再現しなくなるという不思議な現象に遭遇しました。調査したところ、 syzbot が使用している構造体の定義が間違っている(構造体を間違えた状態のままクラッシュさせることが可能なパラメータの組み合わせを見つけてしまった)という予想外の出来事がありました。構造体のメンバの役割を知らずとも動作できるということなんですね。

出題には至りませんでしたが、12月の出来事として、クラッシュ発生回数トップの座に君臨していた不具合である unregister_netdevice: waiting for DEV to become free (2) が open 状態から fix pending 状態に遷移しました。(注:異なる不具合がこの事象として報告されているため、実際にはまだ終わっていません。)
不具合を修正するパッチには、不具合を報告してくれた人へのクレジット(謝意)として、報告者の名前を含めることが期待されるのですが、パッチの作成者は、必ずしも報告者の名前を含めてくれるとは限りません。その結果、 syzbot が発見した不具合が修正済みなのかどうかを追跡することが難しいという問題があります。この不具合の場合、グーグルさんのボットが見つけた不具合なのに、何故かファーウェイさんのボットが見つけたことにされているパッチに対して「誰?」ってツッコミを入れました。こんなところにも、グーグル対ファーウェイの競争が現れているのでしょうか?(笑)

さて、熊猫が扱っている領域って、CTFの攻防戦には不向きなんですよねぇ。いくつ発見できるか不明な未知の不具合を探したり、どれくらい修正が難しいか予想できない不具合を修正するパッチを書いたりしてもらうという出題にすると、誰も回答不能/出題者側も採点不能という状況に陥りかねません。可視化するためには機械的に採点が可能なフラグ文字列を使わざるを得ないのですが、扱う不具合の内容がプロセスの異常終了/ハングアップ/カーネルパニックなどである以上、フラグ文字列を表示させることや、現在誰が占有しているのかを判断することが非常に困難なのです。その結果、今回はパッチを探すという Jeopardy 問題になりました。CTF競技者にとっては、非常につまらない出題だったかと思いますが、 syzbot の世界は、頭がパニックになりそうなくらいに、予想外の出来事の連続なのです。

posted by 熊猫さくら at 19:24| Comment(0) | TrackBack(0) | Linux
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/187000228
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック