セキュリティ・キャンプ2021 Cトラック通った

Seccamp2021の選考通過した

今回、初応募でした。まさか通ると思ってなくて、来年もう一回やるかと考えてました。課題でも書いたのですが先輩からの話で2年生のときからseccampの存在は知っていましたが、技量がたらないと思って申し込んでませんでした。今回、たまたま応募開始のページを見て申し込もうと決めた次第です。同じCトラックの方々より、明らかに技術足りていませんが、頑張っていきたいと思います。(インターン、教習とかぶっていくのですごいタスクの量になりそう)

過去の偉大なる方々の応募課題を参考?にしたり、読んでほえーって思ったりしたので、自分のクソ雑魚回答も残しておけば誰かの役に立つかなと思ったのでまとめたいと思います。

題名にも書いていますが、自分はCトラックです。

問1 

あなたがセキュリティ・キャンプ全国大会に応募する理由を教えてください。受講生や講師とのコミュニケーション、受講したい講義、なりたい自分など、何でも構いません。

僕は2年生になったころから、セキュリティ分野に興味を持ち始め、自身の周りに関係するセキュリティ分野での意識が高くなりました。
このころから、学内の部活や個人でCTFに参加し始め、実際に問題を解いて勉強を始めました。CTFの多数ある分野の中でも特に"Reversing"で強くなりたいと思ってやってきました。
しかしながら、実際のセキュリティ分野での知識をつけるにはCTFだけでは偏ってしまうと思い、去年の末頃から春休みに書けてマルウェア解析について勉強を始めましたが、自分一人の力では限界があり勉強が進まなくなりました。
そこで、今回のCトラックの内容を見つけ参加したいと思いました。
このキャンプに参加するにあたって、講義を受けるというのが一番の目的ですが、その他にも同年代の同じ分野について興味がある人と会話がしたい、関係性を広げたいという気持ちもあります。学校内でもセキュリティという分野について会話をすることがあまりありません。同じ分野に興味をもってる他の人の意見とか、体験、技術を聞いて自分の中に取り込んで知識にしたいです。なのでは初日のプログラムに用意されているグループワークはとても楽しみです。セキュリティにこだわらずコミュニケーションが取りたいなと思います。
プログラムを見てグループワーク同様、受けたいと思ったトラック外の講義はもう一つあります。それは倫理の特別講習です。特に解析系では法律が関係してくるなと感じていましたし、そう学んできました。しかし、今までCTF・それ以外の個人的な解析をしてきたなかで、法律に触れなかったというよりも法律に触れそうなレベルのことをしたことがありません。でも、解析の対象を広げたり仕事にするとなると必ず必要な知識だと思います。社会でこの分野を武器にして働いてる方々の授業を聞くことでどのように意識することが大切なのかを学びたいです。

セキュリティキャンプの存在は2年生のころから知っていました。しかし、今までは自分の技術が足りないと思い応募をしませんでした。
今年になって参加しようと思った1つ目の理由は自分がやりたいことが決まってきたからです。自分は解析の中でもマルウェアなどの解析をしたいと思っています。また、これに関することを職にしたいと思いました。そう思う中で自分の力だけでは見ている場所が狭くなっているし、ステップアップが難しくなってきたというのを感じたからです。
2つ目の理由は先日の大阪のミニキャンプに参加したことです。まず、アバウトですがとても雰囲気がよかったです。ミニキャンプでこの雰囲気ならキャンプに参加すればどれだけ楽しいだろうと思いました。また、ディスカッションを聞いていていろんな考え方があるのだと実感しました。この会話をするには、同じ分野に興味を持っている人と関わることが第一歩です。それを実現するために、このセキュリティキャンプはとても身近なものだと気づきました。途中の修了生による、キャンプの紹介もとてもためになりました。

今回、応募するトラックの中でもCトラックに決めた理由は講義がとてもおもしろそうと感じたからというのと、自分がやりたいことにとても近いと感じたからです。特に"C3-1,C3-2:Zero to Malware Analyst Part1/Part2"、"C4:UEFI BIOSセキュリティ"が興味を惹かれた講義名でした。
・C3
この講義は自分がやりたいと思っていることに一番近いと感じました。また、実際に手を動かすので自分のスキルがあるところ(あるかわからないけど)、ないところがはっきり分かると思うし、新しい解析の方法を得ることができると思います。講義紹介の中にあった、スクリプトによる解析の自動化については触れたことがなかったのでどんなものだろうという気持ちです。

・C4
まずUEFI BIOSセキュリティって何だ?となりました。実際ここに脆弱性があるなんて考えたことがなかったです。そもそもUEFIを使うことはデュアルブートなどの設定をするときだけです。なので、ここが狙われるということ自体驚きでした。
UEFIに限らず、他の部分に目を向けるというのも講義紹介にある発見・対応だと思いました。その練習をこの講義でしたいです。

また、実際にこの分野で働いている先生方の授業を受けれるので就職を考えてる身としては、その話をお聞きすることができたらいいなと考えています。この2つの講義だけでなく、Cトラックはすべて受けたい気持ちでいっぱいです。もし、可能で時間があれば他のトラックの講義も受けてみたいなと思っています。

多数あるセキュリティの分野の中でもrev、解析がやりたいのはそのソフトウェアの挙動を知るのが楽しいと思ったからです。まだ経験も浅く偉そうなことは言えませんが、CTFなどの問題を解く際にそいつが何をするのかということを把握して、解けた時はとても楽しいです。

まだ知識も技術も少ないので応募するか悩みましたが、やってみないと始まらないのでやってみようと思いました。つたない文章ですが読んでくださってありがとうございました。

問2 

今までに解析したことのあるソフトウェアやハードウェアにはどのようなものがありますか?解析の目的や解析方法、結果として得られた知見などを含めて教えてください。

1.ewfの解析
これはCTFの問題でforensicsに分類されるものだった。問題内容は、passwordを探すでした。
解析方法として、個人ではFTK imagerを利用したが、このファイルがバックアップだったので量が多く目で探すことはできず諦めました。
CTF終了後ヒントをもらってewf-toolsを使用して解析した。FTK imagerを利用して解析していたときから気づいていたが、OSはwindowsであった。理由としては、iniファイルがあったこと、ファイル構造がAppdataなどwindowsで見かけたフォルダが存在していたからである。
CTFだからフラグを得る方法はほぼ確定しており、今回はlsass.DMPからhashを得てデコードするという方法だった。
ここまでに至る経緯として、SAMとSYSTEMのファイルを用いてhashを抽出しようとしたが、SYSTEMが0で埋め尽くされていたためできなかった。次にlsass.exeというものを知り探したがなかった(C:\Windows\system32\lsass.exe)。ここでlsass.DMPという存在をヒントとしてもらい、ここからhashをpypykatzを使って抽出しオンラインツールを使用してデコードした。
CTFの問題を解く中で得られた結果は
windowsではパスワードはSAMデータベースで保存される(C:\Windows\System32\config\SAM)
・また保存前に暗号化されるがこれはNTML hashという暗号化方式が取られている
・lsass.exeにはイベントログが記録されているので、ここに打ったパスワードとかも保存されている(?)
lsass.exeに対しての理解が完全にできていないので少しもやっとした部分が残っている。
CTFとしてはここで終わりだが、フラグ以外にも気になったことがあったので解析・調査を続けることにした。
まず、問題なのでいろいろなファイルが削除されていることが分かった。
そこで、$RECYCLE.BIN(ゴミ箱)を見たが、desktop.iniのみで他のファイルはなかった。
他にもこのバックアップには二人のユーザーの情報があることが分かった。これは二人の名前がUsersの中にあったことと、Publicフォルダがあったことから分かった情報である。

この経験で得られた知識はwindowsの簡単な内部ファイルの構成。ubuntuではよく深いディレクトリ情報を見るけれどwindowsではあまりしないので知らないことだらけでした。ewfの解析も初めてだったので、解析方法の手段が広がりました。
このようにWindowsの構造を理解するのもマルウェアが狙うところを理解することに繋がるのかなと感じた問題だったので、この問題はCTFの中でも記憶に残っています。

2.正式名称を出していいのか分からないので伏せますが、某パズルゲームを解析しました。
調査方法
1.bytecode-viewerを用いて逆アセンブリしてコードを眺める
このとき解析するアプリは2個用意しました。一つは実際にプレイをしたことがあるもの、もう一つはダウンロードしただけでまっさらな状態なもの
2.mitomproxyを用いて通信を眺める

1.
まず、2つのapkを用意した理由はユーザーのデータでなにかしら変わっているものがあると考えたからでした。しかし、結果は新しいプログラムファイルもできておらず変わる点は見つけられませんでした。
resフォルダからたくさんの写真が手に入りましたが、これらは特にゲームと関係するものではありませんでした。おそらくですが、googlefacebookに関連するものだと思います。
実際の中身のコードですが、apkを解析した経験が少ないのとjavaを読み慣れていないというので全てを理解することはできませんでした。
comフォルダには4つのフォルダがありました。フォルダは"appsflyer"、"facebook"、"google"、"linecorp"の4つです。このアプリが連携しているものがあるのかなと考えます。
jpフォルダではメールの送信を構成するプログラムがありました。文字の色やサイズを指定しており、実機で確認するとこの通りでした。ここでの文字コードUTF-8に統一されていました。
この他にも画面のサイズを取得しているプログラムもありました。このゲームは画面のサイズに合わせて配置なども変わるのでそのためだと考えられました。
android/supportフォルダに存在するプログラムはosかanimationに関連するモジュールが書いてあったので、ここで大部分のデザインを構成しているのではないかと考えました。

2.
アプリにログインする時と、ダンジョンに潜入するときどこと通信しているのかを見ることを目的にして行った。
スマートフォンの通信をmitmproxyでキャッチした。
まずログイン時の接続先は5つあった。
公式サイト×2、モバイルアプリ広告の効果測定プラットフォーム、facebookの連携みたいなもの、analytics.js。
次にresponseを全て手元に持ってきた。このときに使った命令は"cut.save @focus response.content <file>"です。
10個あったが、興味を惹かれたものだけを結果としてまとめておく。
2個目のurl(json)にはgatekeeperの情報が書かれていた。gatekeeperと言ってもfacebookのもの(かつios独自のもの)だった。
7個目のurl(json)にはEULAの情報が書かれていた。
9、10個目のurl(json)には自分のアカウント状態(box、メール、フレンドの情報など)が見れた。
requestの情報も手に入れてみたが、何も得られるものはなかった。これは、自分が向こうのサーバーにアクセスしているためなので見れなくて当たり前かなと考えている。
次にダンジョン潜入では勝った時と、負けた時の2つの接続先をみた。しかし、クリア後の報酬をもらうところ以外は違いはなく、またログイン時との違いもあまり見られなかったためここでは割愛する。
ログイン時と同じく、responseについて調べた。
1個目のurl(json)はダンジョンの情報を取得していそうだった。ここではfmeというデータ変換エンジンを使用していることが分かった。
5個目のurl(ファイル形式がよくわからない)にはgzipがあった。threatListUpdates_fetch.datという名前だったが、これが何なのか突き止めることはできなかった。

この経験で得たものはapkファイルの構成と、それぞれのフォルダの特性です。
これまでapkを解析したことはありませんでした。apkというファイルフォーマットになっているものの、ヘッダがzip形式であったことは驚きました。しかしながら、apkが様々なフォルダで構成されていることを考えると納得しました。
また、それぞれのフォルダに役割がしっかりあり綺麗に整理されているのを見るのはとても気持ちよかったです。
余談ですが、証明書を抜き出したのですが秘密鍵が秘匿されていることが確認できたのもよかったです。
通信内容ではEULAが一番おどろいた情報でした。このような形で利用規約が残っているということを知れたのはいい機会でした。ゲームを始めるさいに適当に利用規約をokにしがちですが少し、規約を読もうと思いました。
また、ユーザーのデータはapkに全く保存されない(プログラムとして含まれない)ことも理解できました。Android OSであれば、マイクロSDや内蔵メモリ上に、iosであればicloudに保存されることを再確認できたのはよかったです。
反省点としては、もっとソースコードについての理解を深めたかったです。

3.解析に入るか怪しい部分がありますが、以前HDDの調査をしました。
簡単な経緯
このときのパソコンはThinkPad E580
ある日、立ち上げると"2100 : Detection on HDD0"のエラーが吐かれOSの起動ができなくなった。
この時、PCのHDDがありそうな部分から"カタカタ"と音がしていた。
いろいろ調べて直せず、性能も低く古いPCだったこともあり分解して調べてみることにした。

調査方法
PCからHDDの取り出しを行った。そこからHDDの分解を始めた。分解は、蓋を開き磁気ディスクやアクチュエータを取るところまで行った。
異音がしていたのは、アクチュエータに原因があると思っており、この部品を取る前に動作を確認したが特に部品の動きに悪いところはなさそうだった。
この時、PCにつけて動かしはせず自分で部品を動かしてみたりする程度に留めた。
ここで、実際に手を動かす調査は終了した。
その後、ネット上で情報を探すことにした。
まず、エラー文について調べるとこのエラーはThinkPad独特なものであることが分かった。
それに関する情報では、このエラーが出たからといってHDDが壊れているわけではないという情報を見たが、ある程度の回復作業を試みても回復しなかったこと、異音がしていたことからこの可能性は低いと判断した。
次に同じような異音について調査したところ、同じ症状を見つけた。ここでほとんどの情報が得られた。

調査結果
これらの調査から得られた結果は
・自分の手では直すことがほぼ不可能だったこと
・異音の正体はヘッドがシークを繰り返していたこと
・この異音が起こる原因がヘッドが磁気データを読みに行くがトラック0領域を正常に読み出せないため
・トラック0がHDD0にあたるため、上記のエラーがでたこと
この4つです。

この経験で得た知識はHDDの内部構成についてです。自分の想像していたデータを取り出すイメージも正確なものになりました。他の情報で、ヘリウムが充填されているHDDがあることも初めて知りました(高価なようですが)。
また、教訓は自分の大切なデータはcloudなどに上げておこうということでした。

問3 

今までに作成したソフトウェアやハードウェアにはどのようなものがありますか?
どんな言語やライブラリ、パーツを使って作ったのか、どこにこだわって作ったのか、などたくさん自慢してください。

1.高専祭でバーサライタを作成
Neopixelの光をC言語(Arduinoの特殊な部分を含めて)を用いて制御。現在時刻を取得するため、wifiでの通信が可能なESP32を使用。
モータで光る棒を回して、光の残像を利用し時計が浮き出るようなものを制作した。全長は16インチのPCぐらい。工夫点1は、LEDを光らせるための電気はモーターと回る棒の間に挟んだ給電モジュールを使用した。給電モジュールは電磁誘導で電気を発生させるようなもので、これを使用することによって電源はモータにおくる一個に抑えることができた。
自分を含めた4人で制作した。
ハードウェア面で工夫したこと2は、先程書いた全ての器具をコンパクトにまとめたことである。これらをバラバラに設置していると、光やモータの回転を遮ってしまったり、コードが絡まるためである。また、モータは力のあるモータを使用した。当初の計画では音が小さい三相交流のブラシレスモータを使用しようとしていたがパワーが足りずこちらを使用した。
遠心力が大きかったため、これを固定する土台も一から制作した。
棒は3Dプリンタを使用して作成した。足場は金属製のものを用いて組み立てた。
コードを書く上で特殊なライブラリを使ってはいない。Adafruit_NeoPixel.h、Wi-Fi.h、そしてtime.hを使用した。
ブラシレスモータの制御をしている時は、Utility.hを使用した。三相交流を制御するので三角関数を使用して各場所に対して電流を流す、吐く、流さないを制御した。
回転数と光のパターンの合わせ方は、実際にバーサライタを動かして、コードの処理速度を確認し電圧を調整して回転数を合わせるという方法。
これは回転数と光の移り方を完全に一致させることができずに得られた副産物として、時刻が移動してしまう(時刻を表示しながら回っている)現象がある。ミスではあるので直そうとしたが、実際に光らせていると綺麗だったのでそのままにしました。
僕自身技術不足を痛感しており、チームメイトの助けを得ながら作り上げた初めてのものだったのでとても楽しかったです。実際に見にこられた方にもいい評判で、学内で賞も取れたのでよかったです。

2.予約の空き状況を確認するbotを作成
python3でdiscordのbotを制作し、heroku上で動かしています。(現在も稼働中)
ここでは3つのそれぞれの役割を持ったプログラムを作りました。1つ目はdiscordのログインと、予約状況の送信を兼ねたプログラム。2つ目はサイトに自動ログインをし、目的のurlまで進むプログラム。また、このプログラムは3つ目のプログラムの結果を見る役割も持っています。空いているときにしか通知は来てほしくないので、それを見るという目的です。3つ目はhtmlを読んで予約表のテーブル状況をoかxで取得する役割を持っています。
工夫した点は、まずherokuを使うというところです。自分の手元ではずっと動かせないので困っていたところこれを見つけて使うことができました。
次に、自動ログインです。目標としているサイトは記事などにあるサイトと少し違っており、ボタンのクリックや実際にパスワードを入れる欄を見つけさせるのが難しかったです。3つ目のプログラムは簡単なスクレイピングをしているだけなので、そんなに難しいことではなかったはずですが、知識がないためここにも時間をかけました。
全体を通して、使ったpython3のライブラリは"discord"、"selenium"、"beautifulsoup4"、"lxml"、"time"です。また、herokuや手元での実行時にchromedriverを利用しました。

問4 

ここ数年に発表された、以下のキーワードに関連するニュースや記事や学術論文から1つ選び、それに関して調べた内容を記述してください。内容には、1.選んだ理由、2.技術的詳細、3.被害規模または影響範囲、4.対策、の4点を必ず含めてください。なお、対策は今ある技術のみに捕われず、将来的な技術や法律など、自由な発想で書いてください。

キーワード:
- サイバーセキュリティインシデント
- マルウェア
- 攻撃キャンペーン
- 脆弱性
- 新たな攻撃手法
- 未知の脅威
- 組み込みシステム

2020年6月中旬に米国の企業CloudflareでおきたDDoS攻撃の事例についてまとめます。

キーワードは新しい攻撃手段です。

1.選んだ理由
キーワード通りの新しい攻撃手段として何があるのかを知りたかった。そこでこのキーワードで調べるとDoS攻撃が引っかかり、「どこが新しい手段やねん」と思いながら見てみると、古くて新しいDoS攻撃という題名があった。
この言葉に興味を惹かれDoS攻撃について調べているうちに、上記の事例が引っかかった。この企業はセキュリティ関連の企業だったので、実際にこのような企業でも攻撃を受けるのかと感じた。内容を見ていると、攻撃は受けたものの最小限の被害に留めたとあったので、対策やその後の動向も気になってこのニュースを調べることに決めた。

2.技術的詳細
DoS攻撃の中でも発展形であるDDoS攻撃の対象となった。
まず、DoS攻撃は第三者によってサーバが攻撃されること。具体的な攻撃方法は主に2種類あり、1つはwebサイトやwebサービスに大量のデータを送りつけ、何らかのデータ処理を永遠に繰り返させる"フラッド攻撃"と呼ばれる方法。2つ目はwebサイトやwebサービスのシステムの脆弱性をついてシステムをダウンさせたり、使えなくさせる方法。
次に、DDoS攻撃マルウェアなどで不正に乗っ取った複数のコンピュータのIPを利用してDoS攻撃を行う。複数なので、攻撃元のIPアドレスを特定しブロックするということが非常に難しい。また、攻撃者本人のIPアドレスではないので攻撃者の身元が割り出せない。この2つが進化系となる所以である。
また、DDoS攻撃も変化を続けており様々な攻撃手法が取られている。
Cloudflareが受けた実際に受けた攻撃内容は、316,000個以上のIPアドレスからの攻撃トラフィックが1つのIPアドレスをターゲットにしていた。攻撃目標となったIPアドレスは、Cloudflareの無料プラン利用者が主に使っていたアドレスだった。この攻撃はTCPプロトコル経由で"SYNフラッド"、"ACKフラッド"、"SYN-ACKフラッド"という3つの攻撃ベクトルが組み合わされていた。攻撃時の様子としては、毎秒4〜6億ppsを上回る攻撃が何時間も続いた。最大値は7億5400万ppsと報告している。この攻撃の期間は6/18〜21までの4日間。
このことから、受けた攻撃の種類はDDoSの中でも帯域幅消費型DDoS攻撃だと分かります。
また、3つの攻撃ベクトルということから"SYNフラッド攻撃"、"SYN-ACKフラッド攻撃"、"ACKフラッド攻撃"の組み合わせなのでこの3つのまとめもしていく。

SYNフラッド攻撃(ハーフオープン攻撃)
この攻撃は利用可能な全てのサーバーリソースを消費することによって、正当なトラフィックがサーバーを利用できないようにすることを目的としている。攻撃者は最初の接続要求パケットを繰り返し送信することで正当なトラフィックに応答するのを全く反応しない。あるいは非常に遅いという状態にすることができる。
まず、攻撃者は乗っ取ったPCのIPを用いて大量のSYNパケットを標的となるサーバーに送る。サーバーは各接続リクエストに応答し、応答を受け取れるようにポートを開いた状態になる。サーバーはACKパケットを待つけれど、これを攻撃者は送らないため、接続は完了しない。それどころか新たなSYNパケットを送るのでサーバーは正常に機能できなくなる。

・ACKフラッド攻撃
この攻撃は受信するすべてのパケットを処理する必要があるデバイスを標的にする。ファイアウォールとサーバーはこの攻撃の対象になりやすい。逆にルーターなどはこの攻撃の影響を受けない。
基本はSYNフラッド攻撃と同じで、攻撃者がTCPヘッダーにACKフラグを含めた不正なACKパケットを大量に送る。
またこの攻撃ではいきなりACKパケットを送信しているが、これはTCPの接続の3ステップの1ステップ目をすっ飛ばしている。よって、クライアントとサーバーの間にアクティブなTCP接続はありません。なので、サーバーはパケットを廃棄して接続拒否をします。これらの理由から、サーバーは正常に機能できなくなります。
この攻撃では正当なACKパケットと不正なACKパケットの見分けが難しいので、阻止するのが困難となる。また、この攻撃は別の攻撃のカモフラージュとして使われている可能性が大きい。


・SYN-ACKフラッド攻撃
通常、TCPで接続を確立する際、2ステップ目でサーバーはクライアントデバイスにSYN-ACKパケットを送信します。
しかし、この攻撃では攻撃者がSYN-ACKパケットを大量にサーバーに送りつけます。このパケットはTCPの接続の確立で使うパケットではないので、サーバーが正常に機能しなくなります。

3.被害規模・影響範囲
この4日間で、サーバーがダウンしたりサービスが低下することはなかった。Cloudflareのシステムが攻撃への自動対応したからであった。このシステム名は"Gatebot"。なので、人間は全く関与せずして防御が成った。
影響範囲としては、今までCloudflareを使ってなかった人にいったと思います。いい意味でです。

4.対策
既存のDoS攻撃への対策は、同IPのアクセス制御があります。これによって、1つのIPアドレスからたくさんのパケットを送られることがなくなります。また、サービス対象者が国内のみの場合海外からのアクセスを制限する。日本は海外からの攻撃が多いことから国内でのサービスならこの手段が攻撃を減らします。これに加えて近年ではWAFを導入することも対策の一つとして有効です。
ここからは自分の考えです。実用性はあまり考えないことにします。大量のパケットを送信されることで、動作が遅くなり最悪動作しなくなるのであれば、それに耐えられるサーバーの大きさ(ネットワーク)を用意すればいいと考えます。TCP接続は別で処理させることができるのであればその処理をするものを何個もストックさせておいて、攻撃を受けてもう処理できないとなれば別のやつと換装する。
通信を可視化して、おかしい通信は赤色みたいな表示にして早期発見ができるようにする。
知識が少ないため、不可能というか意味が分からないことを書いているかもしれませんがご了承下さい。

問5 

ブログや GitHub など、技術情報を公開している URL があれば教えてください。またその内容についてアピールすべきポイントがあれば記載してください。

ブログ1 : https://bigdrea6.hatenablog.com
ブログ2 : https://scrapbox.io/bigdrea6
Github : https://github.com/Bigdrea6

問6 

配布した6_decode.binは PE形式のプログラムであり、実行すると内部に保持したエンコードされたデータをデコードして表示します。6_decode.binを解析し、挙動などわかったことをまとめて解析レポートを作成してください。また、エンコードアルゴリズムを特定して、デコードスクリプトを作成し、次のデータを復号して回答してください。

"\x8d\x93\x13\x8a\x43\xb6\x59\x4d\x41\x80\x1b\x53\x02\x86\xf2\xed\x55\x55\x78\x59\x8b\x77\x35\x17\x56"

解析が最後までできたとしても、できなかったとしても、解析の手順、解析にあたり学習したこと、解析の過程で判明したことを文字数制限の範囲で自由に記述してください。

解析レポートという形に添えているかわかりませんが、このプログラムの流れをmain関数を中心に流れを書いていきたいと思います。その前に、解析の手順・方法を示します。

今回、解析をする前に実行結果を見ました。実行ではwineを使用しました。実行すると、"Decode!!"という題名がついたウィンドウが立ち上がり中には"This_is_decoded_text"と書かれ、"OK"のボタンも表示されます。
この"This_is_decoded_text"がデコードされたデータなのだと予想しながら解析を進めていきます。
解析にはghidraを使用しました。ところどころ変数や関数名をいじったので、まっさらなデコンパイル状態とは少し違います。

main(entry)の流れ
まずsecurity_init_cookie()が呼ばれます。調べたところ、これはバッファーのセキュリティを見ているようです。関数を開始するさいに、クッキーをスタックに配置し関数が終了するさいにこのスタックの値とクッキーを比較してバッファオーバーランが起きたかを確認しています。という説明を見ましたが、最後にこの関数が呼ばれていないので、よくわからないままになっています。実際にこの中身を見ます。
security_init_cookie(){
if (DAT_140003008==0x2b992ddfa232)
この一文目が上記の説明におけるクッキーの値とスタックに配置した値を比べている場所だと思います。
この行以降、いろいろなことをしていますが、明確な値がわからないこともあり飛ばします。最後に、_DAT_140003000にビット反転を代入しています。メモリの情報を見ると、値は0xd466d2205dcdです。この値は、0x2b992ddfa232の反転の値ではありません。なので、この行より上のコードによってDAT_140003008は0x2b992ddfa232以外の値になったことがわかります。多分ですが、0xd466d2205dceになったと考えられます。
}

このコードが終わると次にuVar3にscrt_initialize_crt(1)の値が入ります。
scrt_initialize_crt(param1){
if(param1==0)は通過しません。isa_available_init()が呼び出されます。
isa_available_init()で更新される値は次のです。
_DAT_140003020、DAT_140003640、_DAT_140003018、_DAT14000301cの4つです。しかし、これらの値はこの関数以外で使用されません。なので、ここでの処理は詳しく書かないことにしました。
その後、uVar1に1が入ります。これによって、この関数がreturnする値が決まります。
return uVar1 & 0xffffffffffffff00 | 1より1がreturnされます。
}

uVar3=1なので、if(uVar3=='\0')は通りません。boolの値がfalseに更新され、uVar3の値が新たに入ります。この際に呼ばれた関数はscrt_acquire_startup_lock()です。
scrt_acquire_startup_lock{
bVar1に値が入ります。この際に呼ばれる関数はscrt_is_ucrt_dll_in_use()です。この関数では_DAT_140003030 != 0かどうかがreturnの値になっています。メモリを見たところ、0ではなかったので、return trueとなります。
よって、bVar1=trueです。これはboolなので、trueを持てます。intだと1です。これ以降のコードについて完全に理解ができていません。
しかし、これらのよくわからないコードは読まなくて良くて本質はdo-while文にあるのではないかと思います。 この中身を読んでいると、興味深い一文を見つけました。uVar3=!bVar2*upate_numです。!bVar2は0です。0に何かけても0です。ここの文には絶対にたどりつくので、このことからuVar3は0になることがわかり、return uVar3はreturn 0になります。
}

uVar3=0になりました。わからない値がありますが、これ以降の流れに直接関わってこないので無視します。この直後にある条件分岐の流れにより、boolの値がtrueになります。そして、scrt_release_startup_lock(uVar&0xff)が呼び出されます。uVar3&0xffは0です。この関数で興味深い挙動はありませんでした。次に進みます。ppcVar4に値が入ります。関数が呼び出されますが、returnがアドレスを返しているだけなのでそのアドレスが入ります。これと同じようなことがplVar5にも行われます。

ここからがこのプログラムの一番の役目を持つところになってきます。これを実行したあとにもいろいろなことが書いてありますが、結局のところexitに向かっていくだけなので、mainの流れというのは以上にしたいと思います。実際に、ウィンドウを作成しているところ、デコードしているところというのはこのmainと分けて書きたいと思います。

ウィンドウ生成・デコードの流れ
scrt_get_show_window_mode()
get_wide_winmain_comand_line()
この2つの関数が最初に呼び出されます。多分独自の関数(windowsの)なので、関数の内容を確認することはできませんでしたが関数名から察するにウィンドウを生成する準備なのだろうと思います。その後decode_windowが呼び出されます。この関数名は自分がつけたものです。アドレスは0x140001150です。
decode_window{
5つの変数が宣言されています。hResInfo、DVar1、hResData、pCVar2、lptextです。これら5つの値、それぞれ特殊なものが代入されています。調べましたが完全に理解できませんでした。なので、検索結果と関数の流れからの予測が入ります。まず、hResInfo〜pCVar2までは、問題分にあるようなプログラム内に格納されているエンコードされたデータを取り出すための準備をしていると思います。実際に格納されているアドレスを持ったり、データ型・識別子を持ったりしているので、このように考えました。そして、lptextにエンコードされたデータが代入されます。代入といっても、実際にデータを持つのではなくエンコードされたデータが入っているアドレスを持つ感じになってそうでした。ポインタだったので。これによって他の関数にlptextを渡し、アドレスの先のデータが更新されデコードできるのだと思います。
この後デコードを担当する関数を呼び出します。この関数をdecode_partとしました。
decode_part(lptext,Dvar1,DAT_140003038,s_SECCAMP2021_140003040.0xb)
まず、これらの値について書いて置きたいと思います。
lptext : エンコードされたデータがあるアドレス
Dvar1 : エンコードされたデータの長さ
DAT_140003008 : 0x89192712
s_SECCAMP2021_140003040 : SECCAMP2021
0xb : 11ですがこれはSECCAMP2021の長さだと思います。

また、このdecode_partの関数は実際に問題を解く上で使用しました。そこで、自分はpython3を使ったので少しpython形式にした状態で書きたいと思います。
decode_part (decode.py)
param1 = #エンコードされたデータ

param4 = "SECCAMP2021"
param5 = 0xb

local_res18 = 0x89192712

for i in range(len(param1)):
lVar1 = local_res18*5 + 0x2365f703

if (0xa0 < param1[i]):
param1[i] -= 1

param1[i] ^= lVar1

local_res18 = (lVar1>>2) -0x1ca9

param1[i] = param1[i] ^ ord(param4[i % param5]) + ord(param4[i % param5]) + local_res18

結構デコンパイル状態から削りながら書きましたがやっていることはこれと同じです。
}

このようにデコードされたデータをMessageBoxAでウィンドウを生成して表示します。
MessageBoxA(null,lptetx,"Decode!!",0)
実際にこの形式でウィンドウは立ち上がっていました。

以上でこのプログラムの解析は終わりです。ここから、このコードを解析していて気になったというかこのコードについての見解、そしてデコードせよという問題に対しての回答をしたいと思います。

解析していくなかで、このプログラムとは全く関係ない関数がたくさんありました。冒頭のsecurity_init_cookieなどです。これらの関数について調べていると、このコードは"Microsoft Visual C++"で書かれたC++のプログラムなのではという結論にいたりました。正確にはどうなのかわかりませんが、これらの関数はこれのコンパイル時に自動的に生成されるということを知りました。解析とは関係ありませんが、書いておきたいと思います。
次に、実際に与えられたデータのデコードです。二回目になりますが、使用したコードと実行結果を示します。

param1 = [0x8d,0x93,0x13,0x8a,0x43,0xb6,0x59,0x4d,0x41,0x80,0x1b,0x53,0x02,0x86,0xf2,0xed,0x55,0x55,0x78,0x59,0x8b,0x77,0x35,0x17,0x56]

param4 = "SECCAMP2021"
param5 = 0xb

local_res18 = 0x89192712

for i in range(len(param1)):
lVar1 = local_res18*5 + 0x2365f703

if (0xa0 < param1[i]):
param1[i] -= 1

param1[i] ^= lVar1

local_res18 = (lVar1>>2) -0x1ca9

param1[i] = param1[i] ^ ord(param4[i % param5]) + ord(param4[i % param5]) + local_res18


for c in param1:
print(chr(c%256),end='')

実行結果 : D1d_y0u_$01v3_C0s70m_X0r?

以上です。

問7

 配布ファイル内の7_sc_spreadsheets.001は、NTFSボリュームのddイメージファイルです。イメージファイル内には複数のExcel形式のファイルが存在します。以下の問題について、必要であれば解析結果から得られる見解も含めて回答してください。

問7-1

これらはあるファイルが起点となり、変更が加えられたファイルです。起点となったファイルの入手元を回答してください。

自分が捉えた起点の意味ではBook10.xlsのことだと考えました。
このファイルはfls -> icatの抽出では38-128-3から取ったものである。

問7-2

復元可能なファイルを含めて、全てのExcelファイルのSHA-256ハッシュ値を回答してください。

15702c89d64e3f7da51d2bd7376b05bf5ecc8e477a2d14221fde6da67c714140 Book10.xls
12094ea2678d9750e482cd9b3bd2fa924647c4101f7b280a3f9ac0e9a38d7b47 Book10m.xls
921e84d44ac6ac57f49c9a25b9e6ad60acf6698643e7167a29970b290f809427 Book10p.xls
これらのファイルはfls -> icatの解析で得られたものですが、違う手法で解析したところ違うファイルが得られました。
名前がないので、hoge.xls、huga.xlsとしておきます。
020b9e009135573ef32433135457292f5c9c706cca22b3785ac73a20707af473 hoge.xls
1493c193a7fd11a40f65cfb7fd5ab1bf07c27418e438e9e3f90b22c7214a6907 huga.xls

問7-3

これらのファイルはどのような順番で、どのような変更が加えられたかを、できるだけ具体的に示してください。

ファイルが変更された順番はBook10.xls -> Book10m.xls -> Book10p.xlsとなると考えられます。なので、最後に変更を加えられたのはBook10p.xlsとなります。以下示す時間はNTFSの都合上UTCの時間になります。

それぞれ変更された点について書きたいと思います。

・Book10.xls
このファイルは"test"が作成し、"test"が最後の変更をしています。
create_timeとlast_saved_timeはそれぞれ"2021-03-21 11:44:12"と"2021-03-21 11:48:01"です。この時間差から、変更内容はセル2つに渡って書かれた"This is a sample file"だと考えます。

・Book10m.xls
ファイルの作成者はBook10.xlsと同じです。最後の変更を行ったのは"forensics"です。create_timeはBook10.xlsと同じなので、これは次のURLから保存されたものではないかと考えます。
"https://www.kazamiya.net/files/ccba209a4d0c139e1437781932409ccf/"
last_saved_timeは"2021-03-26 16:06:17"です。具体的な変更内容はmacroの追加です。また、このファイルは削除されていました。
macroのファイル名は"xlm_macro.txt"です。以下にmacroの内容を書きます。

Macro1,A1,"IF(GET.WORKSPACE(19),,CLOSE(TRUE))",""
Macro1,A2,"IF(ALERT("XLM/V"&"elvetS"&"weats"&"hop",1),,CLOSE(TRUE))",""
Macro1,A3,HALT(),""

実際にこのファイルを開くとA2に記されているような言葉が書かれたポップアップが出てきました。
また、このファイルは削除されていました。

・Book10p.xls
このファイルのもとは、Book10m.xlsの複製だと考えます。理由は、create_timeがBook10m.xlsのlast_saved_timeから1秒も経っていないこと、それとこのファイルだけ秒以下(ミリ秒みたいな)ところまで時間を持っていたからです。また、作成者と最後の変更を行った人は記載されていませんでした。記載されていない理由は後述します。last_saved_timeは"2021-03-26 16:07:36"です。具体的な変更内容は何かしらの情報を秘匿したことです。それによって、作成者と最後の変更を行った人の名前を表示(保持)していないと考えます。macroがあるということも隠されていました。

以上が最初に示した流れとなると考えます。ここで、7-2で回答したhoge.xlsとhuga.xlsについて触れたいと思います。huga.xlsはsha256が違うものの、タイムスタンプ・ファイルの中身はBook10m.xlsと同じでした。hoge.xlsは少し違うかったです。違う点は、macroの書かれたシートがむき出しになっていること、last_saved_timeが"2021-03-26 16:06:08"だったことです。9秒だけBook10m.xlsとずれています。
また、これらのファイルはFTK Imagerのunalocated spaceから取り出したのですが、なぜこの2つのファイルが未定義領域にあったのか謎です。

ここまでの説明はoletoolsや、実際にwindowsでのプロパティなどを確認して得た結果です(主に時間の話)。ファイル内容自体はこれであっていると思いますが、このタイムスタンプは改ざんされている可能性が高いと考えました。なので、いままでの説明は流れ1として、別のツールでの解析を流れ2として示したいと思います。実際にタイムスタンプが結構違っており、どちらを信じればよいかわからなかったのでこのような結果となりました。

結果としては、流れ1と異なりました。このときに使ったツールは主にftsなどの実際のNTFSファイルから情報を見るものです。
NTFSに記録されているタイムスタンプすら改ざんされていたらもうわからないです。

SI、FNのMACtime+crtimeのBook10.xls(n)、m、pの順番を示したいと思います。
まず、SIにおいてのMACtime+crtimeの時間の順番はn=pその次にmでした。
以下に、具体的な時間を示します。
mtime : 3/26 16:02:55(n=p) -> 3/26 16:06:17(m)
atime : 3/26 16:04:17 -> 3/26 16:07:36
ctime : 3/26 16:02:55 -> 3/26 16:07:36
crtime : 3/26 16:02:54 -> 3/26 16:04:17

この情報だけ見ると流れ1のBook10m.xlsがダウンロードされたファイルというのには無理があるように思います。
また、Book10mではなくBook10pが同じ時間であることからこちらのほうがダウンロードされたファイルであり、流れ1に示したようなBook10mの複製ではなくなると思いました。
ただ、Book10pはBook10、Book10mと作成方法(生成のされ方)は違うと思います。なぜなら、この2つは<file name>:Zone.Identifierというファイルを持っていましたがBook10pにはそれがなかったからです。

次に、FNにおいてのMACtime+crtimeの時間の順番はn -> m -> pでした。
以下に、具体的な時間を示します。
mtime : 3:26 16:02:54(n) -> 3/26 16:04:17(m) -> 3/26 16:07:36(p)
atime、ctime、crtimeはミリ秒は違うもののすべてmtimeと同じ時間でした。

この情報だけ見ると、流れ1の流れ自体は成り立っているように見えます。また、Book10.xlsとBook10p.xlsの時間も同じです。

調べたところプロパティで表示されるのはSIのタイムスタンプであることが分かりました。なので流れ1は改ざんされた情報になるのかなと考えています。
また、ファイルの移動・名前の変更を行うと、FNのタイムスタンプはSIのタイムスタンプで上書きされることを知りました。ということはコピーもダウンロードもタイムスタンプを見ていると不可能な作業なのかもしれないと思いました。ただ、Book10mは先述した通り削除されているのでSIとFNのタイムスタンプが一致しているように見えます。

流れ1と流れ2を踏まえて変更された順番はBook10.xls -> Book10m.xls -> Book10p.xlsではないかと思いますが、流れ1で記述したような変更内容・方法になっているかは分かりません。しかし、それ以上の結果・考察をすることができなかったのでこれを回答としたいと思います。

問8

ファジングは大量の入力を生成してプログラムを実行、結果を観測しプログラムがクラッシュしたり正常終了しなくなるような入力を発見する手法です。

しかしプログラムが異常な動作をする度に全ての入力を保存しているとキリがありません。例えば「開き括弧"("に対応する閉じ括弧")"が無い場合にクラッシュする」ようなバグの場合、
ファザーは"(", "((", "(()".... 等の膨大な数の入力をクラッシュ入力として保存してしまいます。発見された入力が数万個もあるのに蓋を開ければ全て同じ単一のバグを引いていたようでは解析も徒労に終わってしまいます。

そこでAmerican Fuzzy Lop (AFL)というファザーは独自のアルゴリズムを用いて、同一のバグに対するクラッシュ入力は1つしか保存しないようにしています。

https://github.com/google/AFL/blob/fab1ca5ed7e3552833a18fc2116d33a9241699bc/afl-fuzz.c#L3302

AFLのソースコードを読解し、当該アルゴリズムの概要を「afl-gcc」「エッジカバレッジ」「ビットマップ」という用語を用いて説明してください。

今回、読解していく中ですべてを正しく読むことはできなかった。また、今回はファジング処理について深い読解はしていません。クラッシュの処理を見る関係でファジング部分を読解したのみです。

まず、afl-gcc.cにてファジング対象とするプログラムのコンパイルを行う。
ここでのコンパイル時にカバレッジ計算のコードを挿入する。ここでの挿入の仕方がエッジカバレッジとなる所以でとなる。エッジカバレッジでは条件付き分岐を区切りとしたコードをまとまりと見てカバレッジを計算するので、それが可能となるようにカバレッジ計算のコードを挿入する。具体例を上げると次のようになる。
"カバレッジのためのコード"
if(){
"カバレッジのためのコード"
}
"カバレッジのためのコード" #次の条件付き分岐が来るまで新しいコードは挿入しない。

このような準備をしてから本体である、afl-fuzz.cに入っていく。
このプログラムでは、対象のプログラムの情報をstruct queue_entry{};で管理している。ここで管理する情報はファイル名などのファイル情報に始まり、ファジングに関する情報のことまで入る。この構造体はあらゆるところで使用される。
main関数から読み進めていくことにした。
結果main関数では大まかに分けると2つのパートに分けることができると考えた。1つ目はオプションの確認やあらゆるものの初期化、初期化処理のパート。2つ目はファジングの処理のパート。
初期化処理のはじめのほうではcpuの動作などの調整を行っています。
setup_shm()
ここではカバレッジの計算で使用する共有メモリとvirgin_bitsを作成する。
virgin_bitsをまず初期化します。そして共有メモリの宣言と、場所の確保を行います。これの大きさは65536です。そして、共有メモリの最初のバイトのポインタをtrace_bitsにいれる。なので、trace_bitsが共有メモリになる。

setup_dirs_fds()では、ファジング結果のファイルの保存先の設定を行う。
read_testcases()でテストケースを読み込む。ここで、先程記述した構造体が使用される。

perform_dry_run()
ここで、対象のプログラムを実行します。ここではコンパイル時に分割したコードごとに実行されていく。これをする理由は調べたところ、対象のプログラムのカバレッジ情報を取得するという目的と、実行するコードのまとまり(テストケース)にクラッシュするようなものがないかを見る目的があるそうです。
使用するメモリの確保をします。(use_mem)そしてここにファイルの内容が入ります。テストケースの結果はcalibrate_case()で見ます。そのあとメモリを開放します。
calibrate_case()
まずforkserverというものを初期化しています。その後、何回かfor文にてrun_target()されています。
このforkserverは何なのかわからなかったので飛ばします。run_target()が実際にコードを実行する場所です。
run_target()
まずtrace_bitsをクリアします。0に。しかし、このあとforkserverが関わってきたので何をしているかよくわかっていないです。ただ、caliabrate_case()で何回もこの関数を実行していてtrace_bitsをこの関数で初期化していることから実行結果をtrace_bitsに入れているのだろうと推測します。

calibrate_caseに戻ります。run_target()を呼び出したあと、cksmでカバレッジのビットマップ(trace_bits)のハッシュ値の比較をしています。このあとこのハッシュ値の比較の結果をいろいろなif文で見ています。
まず、q -> exec_cksum != cksum。has_new_bits(virigin_bits)します。このif文は理解できていません。
次のq -> exec_cksumでは、最初かどうかを確認しています。先にelseの処理になりますが、もし最初の実行結果の場合、trace_bitsはfirst_traceに保存されます。最初じゃない場合は、最初の実行結果と異なるビットマップがあるかを見ています。異なるビットマップがあった場合はその場所をマークします。
その後、時間の取得を行っています。ここでの時間は経過時間だと思います。また、計算したあとのtrace_bitsの情報を持ちます。その後、ビットマップの処理を行います。

perform_dry_runに戻ります。calibrate_case()の返り値はresに入ります。switch文にてresを見ます。
ケースは全部で6つです。すべてのケースに"FAULT"という言葉がついています。これを実行する目的を話したのはここで生きてきて、このFAULT判定を受けたものはここで実行するコードから除外される。

ここからまだいろいろなことが実行されますが、飛ばしてファジング処理に進みます。

fuzz_one()がファジング処理の親分です。まず、calibrate_case()をします。実行するので、当たり前といえば当たり前です。これをしたあとおそらくファジングの前処理のようなものが実行されていきます。そして、common_fuzz_stuff()が呼び出されます。ここでもう一度run_target()を呼び出します。返り値はfaultに入ります。そして、faultについて見ます。その後、save_if_interesting()を呼び出します。個人的にここはcrash_modeと正しいか見ていることから、クラッシュの処理をしている部分だと思います。ここで、run_target()の返り値faultについて見ます。trace_bitsを見てから、またcalibrate_case()を呼び出しています。ここで、返り値resがFAULT_ERRORかどうかを見ます。もしFAULT_ERRORなら実行しないということにする。
その後、faultについてswitchで見ていく。caseは全部で3つ。
これ以降をすべて読解することはできませんでしたが、興味深い名前を見つけました。それはkeep_as_crashです。これはgoto文でした。これより、結局FAULT_TMOUTに進んでもなんらかの処理でFAULT_CRASHに進むことがわかりました。
FAULT_CRASHに進むとまず、total_crashの値が加算されます。その後、unique_crashとKEEP_UNIQUE_CRASHを比べています。多分、このクラッシュ(unique_crash)が記録されているクラッシュ(KEEP_UNIQUE_CRASH)にあるかを調べているのだと思います。もし、記録されていないクラッシュならwrite_crash_readme()にて記録するのだと考えられます。
なので、すべてをきれいに読解することはできませんでしたが問題分にあるように同じクラッシュを1つのクラッシュ出力にする方法はこの部分にあると思います。ここの仕組み自体完全に理解できていませんが多分、比べる方法はtrace_bitsにて、カバレッジ計算の結果がビットマップで記録されているので、ビットを見ることによって結果を得ているのだと思う。xorを取ったときに同じ値だと0を返すのでそれをkeepingに入れて見ているのかなと考えます。
以上です。

 

解いたときの感触とかいろいろ

演習課題以外(1~5)は置いといて、6~8で一番難しかったのが8。もうちょっと詰めたかったけどちょっと都合が合わなかった。演習課題で満点が取れないから、1~5で自分の気持ちをいっぱい書いたつもり。実際に回答したように考えているしここを評価されたりしたら嬉しいかな。最初の"以下の問1〜問8について、それぞれ5,000文字以内で回答してください"が正直めっちゃ怖かった。5000字書いたほうがいいのかなと思ったりして、問3なんか自分が雑魚過ぎて書くことなさすぎて萎えてた。

 

結局提出したのは締切の1週間とちょい前。課題に取り組んだのは1ヶ月くらい。

結果来るまで結構、不安だった。そろそろ結果の通知来るだろうなってときにインターンの結果、試験の結果とかいろいろ重なり過ぎてやばかった。

 だから通ったらこうなったし、家でずっと叫んでた。

 

最後に。一緒にCトラック受ける方々よろしくお願いします。後、一緒にこれ勉強しないってことがあれば誘っていただけると嬉しいです。頑張ってついて行きます。

またキャンプ終わったら感想とか書こう。