セキュリティ・ミニキャンプ in 秋田 2018 に参加しました

はじめに

f:id:Szarny:20181217202547p:plain
読んで字のごとく,2018年12月15日に秋田大学で開催されたセキュリティ・ミニキャンプ in 秋田 2018に参加しました.
セキュリティ・ミニキャンプ in 秋田 2018

本記事では,その時のことを書きたいと思います.

会場に着くまで

私は岩手県の盛岡あたりに住んでいるので,少し前までは当日の早朝に新幹線で行こうかな〜くらいに思っていました.
が,始発の新幹線に乗っても開始時刻に間に合わないことが発覚し,急遽ネカフェ難民が決定.
当日の午前4時くらいに盛岡のネカフェを出て,5時20分の電車に乗車し,
一回の乗り継ぎを経て8時前くらいに秋田駅に到着しました. f:id:Szarny:20181217195214p:plain:w300 f:id:Szarny:20181217195256p:plain:w300 f:id:Szarny:20181217195307p:plain:w300

専門講義1 「バイナリエクスプロイト」

午前の専門講義は天津 健氏による「バイナリエクスプロイト」でした.
具体的に学んだ事柄は以下の通りです.

  • 基礎知識

  • 脆弱性のエクスプロイト

    • 脆弱な型キャスト
    • 想定しない配列範囲外へのアクセス
    • 変数の上書き
    • リターンアドレスの上書き

脆弱な型キャスト

型キャストによって正負が入れ替わったり,一部の情報が欠落したりすることによって生じる不具合を利用した脆弱性です.
例えば,以下のようなCプログラムがあります.

#include <stdio.h>
int valueIsTen(char value){
    if(value == 10){
        return 1;
    }else{
        return 0;
    }
}

int main(void){
    int value;
    
    printf("input value >> ");
    scanf("%d", &value);
    
    if(value > 1000 && valueIsTen(value)){
        printf("Correct!\n");
    }else{
        printf("Incorrect...\n");
    }
}

ユーザの入力した値(value)が,1000より大きい かつ 10である 時に Correct! を表示します.
一見無理そうに見えますが,valueIsTen関数の引数の型がcharに設定されています.
そのため,0xff以上の値が引数に設定されると,上位ビットの値の情報は欠落してしまいます.
そのため,value0xff0aのような値を与えると,両方の条件式を同時に満たすことができます.

$ python -q
>>> 0xff0a
65290
>>> quit()

$ ./a.out 
input value >> 65290
Correct!

想定しない配列範囲外へのアクセス

C言語では配列アクセス時に,アクセスするアドレスが正当であるかチェックを行わないため,本来配列が参照すべき範囲を超えたアクセスを行うことが可能です.
本項は,この特徴を利用したエクスプロイトです.

#include <stdio.h>

int main(void){
    int int_array[] = {1,2,3};
    int secret_value = 4649;

    int idx;
    
    printf("input idx >> ");
    scanf("%d", &idx);
    
    printf("%d\n", int_array[idx]);
}

int_array[ユーザが指定した添字]を表示するプログラムです.
本来secret_valueを参照することはできませんが,添字に想定外の値を与えることでその値をリークさせることが可能です.

tsubasa:tmp $ ./a.out 
input idx >> 0
1
tsubasa:tmp $ ./a.out 
input idx >> 1
2
tsubasa:tmp $ ./a.out 
input idx >> 2
3
tsubasa:tmp $ ./a.out 
input idx >> -1
4649

変数の上書き

getsscanfなどの,文字列長をチェックしない関数に対して,対象の変数が持つサイズをオーバーさせるような値を入力すると,そのほかの変数の値を書き換えることが可能です.

#include <stdio.h>

typedef struct {
    char name[100];
    int is_admin;
} User;

int main() {
    User user = {0, 0};

    printf("name >> ");
    scanf("%s", user.name);

    if (user.is_admin) {
        printf("Admin!\n");
    } else {
        printf("Not admin.\n");
    }
}

上記のプログラムにおいて,本来User.is_adminの値を書き換えることができませんが,scanfを用いている部分にUser.nameが確保している容量以上の値を入力させることで,変数をオーバーフローさせることができます.

$ ./a.out 
name >> tsubasa
Not admin.

$ python -c "print('A'*101)" | ./a.out 
name >> Admin!

リターンアドレスの上書き

これも原因は上記と同様です.
先ほどは特定の変数の値を上書きさせることが目的でしたが,本攻撃ではスタックフレームに積まれたリターンアドレスを書き換えることを目的としています.
そうすることで,プログラムの実行位置(ripのアドレス)を任意に操作可能になります.

専門講義2 「産業制御システム攻防演習」

午前の専門講義は目黒 有輝氏による「産業制御システム攻防演習」でした.

具体的な講義内容は大人の事情で書けませんが,主に以下のようなことについて学びました.

  • 情報システムセキュリティと制御システムセキュリティの違い
  • 制御システムセキュリティの難しさ
  • 制御プロトコルの解析
  • 制御プロトコルを用いた攻撃
  • 上記の攻撃を防ぐ手法

制御システムについては普段学べるような分野ではないので,とても興味深い体験をすることができました.
昨年のセキュリティ・ミニキャンプ in 東北 2017 (盛岡) で学んだことも生かせたのでとても良かったです!

実際の制御システムを用いて制御システムセキュリティを学ぶといったことは難しそうですが,そこで用いられているプロトコルやそれらに対する攻撃といった事項は一般的な情報システム上で用いられているテクニックが応用できることがあるため,普段から様々な方面で情報収集を行っておかなければという気持ちになりました.

おわりに

午前・午後ともにとても楽しく充実した講義でした!
講師ならびに関係者の方々,ありがとうございました!🙇‍♂️

次はセキュリティキャンプ全国大会で!!!

f:id:Szarny:20181217202524p:plain:w300 f:id:Szarny:20181217202724p:plain:w300