ハッシュ関数(弊研究室の某課題について考える23日目)

はじめに

この記事は弊研究室の某課題について考えるの23日目の記事です。

今日はハッシュ関数について簡単な解説をします。

ハッシュ関数とは

あるデータが与えられた場合にそのデータを代表する数値を得る操作、または、その様な数値を得るための関数のことを指します。HashMap関数とかSHA1とかに代表されるようなやつらです。

国の識別にJPとか使いますがこれはJapanとわかるので一種のハッシュ値と言えるでしょう

ハッシュ関数の用途

ハッシュの用途としては以下のような感じです

  • ハッシュテーブル
  • キャッシュ
  • 重複レコードの検出
  • 類似レコードの探索
  • 幾何学的ハッシュ
  • 改ざんの検出

この記事では改ざんの検出に扱われるハッシュについて焦点をあて記述していきます

改ざんの検出

ファイルの信頼性を確かめる際に,同じファイルを比較するのは(ファイルにもよりますが)コストが重くなります。そこで元のファイルのハッシュを計算しておき,そのハッシュ値と比較したいファイルのハッシュ値を比較することでファイルの信頼性を保証できます。ハッシュ値を計算するハッシュ関数は高速なためファイル同士を比較するよりも高速に検証可能です。

改ざんの検出を行う際は簡単なハッシュ関数であると,同じハッシュ値を求めることが可能なため,安全なハッシュ関数を用いる必要があります。

ハッシュの特性

ハッシュ関数が安全であるかは以下の特性が守られているかにかかっています。

  • 原像計算困難性
  • 弱衝突耐性(第2原像計算困難性)
  • 強衝突耐性(衝突困難性)

それぞれは原像計算困難 ⊃ 弱衝突耐性 ⊃ 強衝突耐性な関係性です

原像計算困難性

定義:ハッシュ値Hに対してH=h(m)となるmを求められない

これは単純であるハッシュ値がわかったときにそのハッシュ値と同じになるmを求められてはいけないということです。

弱衝突耐性

定義:h(m)からh(m)=h(n)を満たすnを求められない

弱衝突耐性がないと下の画像にある?を求められるということになります。

f:id:kataware8136:20180305150332p:plain

強衝突耐性

定義:h(m)≠h(n)となるmnを求められない

強衝突性がないとmとnを見つけられる。作れるということになります。

f:id:kataware8136:20180305150909p:plain

よく知られているハッシュ関数

このうち推奨暗号なのはsha2だけです。新しくシステム実装する際に使うときには基本的にsha2を使いましょう。

Shattered Attack (蛇足)

蛇足です。去年Googleが公開したSHA1脆弱性の話ですね!

今までさんざん危ない危ない言われてたけど衝突性は破られていなかったSHA1の強衝突耐性が破られたという話です。

これを利用した問題がSECCONで出ました。まぁ仕組みに関しては昔私がLTで話したので読んでね(露骨なアクセス数稼ぎ)

www.slideshare.net

Length Extention Attack

レングスエクステンションアタックとは攻撃者があるハッシュ値を入手した際に元のメッセージに任意のメッセージを付与したハッシュ値を導出可能という攻撃方法です。

ちなみにこの攻撃方法は反復型ハッシュ関数の、H(M||M')H(M)M'から計算できるという性質を利用する攻撃です。

md5sha1,sha2といったMerkle-Damgård構造のハッシュ関数は反復型ハッシュ関数であるため攻撃可能なケースが存在します。

HashPumpというツールがあります。このツールではMD5,SHA1,SHA256,SHA512に対応しています。オリジナルのハッシュ関数は自力で攻撃コードを書く必要があります

Androidの証明書関連のお話(弊研究室の某課題について考える6日目)

はじめに

この記事は弊研究室の某課題について考える6日目の記事です

本来はパーミッションの話をする予定でしたが,学内CTFの問題にならないので変えました

Androidの証明書

Androidのアプリケーションの実体はAPKファイルなのですがこのAPKファイルに署名をしないと端末にインストールすることはできません。

証明書がどのような役割を持っているかですが、APK内にあるファイルが改ざんされていないかを確認することができます。

4日目に書きましたがMETA-INFディレクトリ以下に署名関連のファイルは存在します。その中でも重要となるのはMETA-INF/MANIFEST.MFというファイルです。

以下に私が作成したテストアプリのマニフェストファイルとそのディレクトリ構成を示します。

Manifest-Version: 1.0
Created-By: 1.8.0_161 (Oracle Corporation)

Name: res/drawable-xhdpi-v4/ic_launcher.png
SHA-256-Digest: N32Dm15hayJA533LvqCbKTjB2VKktf8s07k5/GsrcSY=

Name: AndroidManifest.xml
SHA-256-Digest: TZXq3N83t1tAAfKW2Msiqf61rlc52yCRG0xnViSz6qQ=

Name: res/drawable-hdpi-v4/ic_launcher.png
SHA-256-Digest: wFAEDtDl2JOrQllos6kANCnFUUeuQYLRxBxZ4rPQT44=

Name: res/layout/activity_main.xml
SHA-256-Digest: ZfSju9DUI4erELJwRPGT/4quaScbbcc/sNZxzBoDn8U=

Name: resources.arsc
SHA-256-Digest: 5xEbB46maGyhMKqlKNX/E2CcJWus2fp9XE5Pci1b/Ek=

Name: res/drawable-mdpi-v4/ic_launcher.png
SHA-256-Digest: oDeveiogn/RmjjLSWBqGIkEm00m9vvxVI2A4iyG9hq8=

Name: classes.dex
SHA-256-Digest: mwFrI/cqNGVZeSHxWO2kzM7F/Xa/YBpfxRcG8M9OnM4=

Name: res/drawable-xxhdpi-v4/ic_launcher.png
SHA-256-Digest: 9tez3E9oIUiz8dzaZvZBX44SD3jDbVjG7AcunU5NOQ8=

Name: res/menu/main.xml
SHA-256-Digest: JmNDf4y9RNEWeRvzDM9HrKBucRjxYfJ0TQ7zkoB3uzw=
$ tree ./

./
├── AndroidManifest.xml
├── classes.dex
├── res
│   ├── drawable-hdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-mdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-xhdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-xxhdpi-v4
│   │   └── ic_launcher.png
│   ├── layout
│   │   └── activity_main.xml
│   └── menu
│       └── main.xml
└── resources.arsc

APKファイル内の全てのハッシュ値がMANIFEST.MFに記述されています。この値とファイルのハッシュ値を比較すれば改ざんされているかを確認できます。

ファイルのハッシュ値計算方法

ファイルのハッシュ値ですが,ファイルのハッシュダイジェストの20バイトのバイナリ長で返されたものをbase64エンコードしたものとなります。

ハッシュアルゴリズムに関してはMANIFEST.MFに書いてあるのでそれで計算します。今回は上のclasses.dexのハッシュ値を確認します。

phpでのハッシュ確認

$ php -r "echo base64_encode(hash_file('sha256','classes.dex',true));"
mwFrI/cqNGVZeSHxWO2kzM7F/Xa/YBpfxRcG8M9OnM4=%

という感じで計算できているのが確認できます。hash_file関数の最後にtrueを指定しないと16進で値が返ってきてしまいますので結果が変わってしまうので気をつけてください。

pythonでのハッシュ確認

>>> import hashlib
>>> import base64
>>> f = open("./classes.dex","rb")
>>> content = f.read()
>>> print(base64.b64encode(hashlib.sha256(content).digest()))
mwFrI/cqNGVZeSHxWO2kzM7F/Xa/YBpfxRcG8M9OnM4=

こんな感じですね、Pythonのほうが特に気をつけることもなくて楽ですね

おわりに

弊研究室のB4課題の知識としては上のことを知ってれば解けるはず、もっと詳しく知りたい方は参考文献を見る。もしくはAndroid Developerを見に行く等ですね

参考文献

SQLインジェクション(弊研究室の某課題について考える18日目)

はじめに

失踪はしない

弊研究室の某課題について考える18日目の記事です.

SQLインジェクションの簡単な説明です。またこの記事はこのような攻撃手法があるので注意しましょうという目的であり、攻撃を推奨するものではありません。

SQLインジェクション(SQLi)とは

SQLインジェクション(英: SQL Injection)とは、アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。また、その攻撃を可能とする脆弱性のことである。

例えば下のようなphpファイルでsqlにアクセスすることを考えます。(わざと悪い方法を使って書いています)

<?
if(isset($_POST["send"])){
    $id = $_POST["id"];
    //データベース処理
    $dsn = sprintf('mysql: host=%s; dbname=%s; charset=utf8',$db['host'],$db['dbname']);
    try{
        $pdo = new PDO($dsn,$db['user'],$db['pass'],array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
        $query = 'SELECT * FROM list WHERE id = '.$id;
        $stmt = $pdo->prepare($query);
        $stmt->execute();
    }catch(PDOException $e){
        $errorMessage = "データベースエラー";
        echo $e->getMessage();
    }
}
?>

HTMLはこんな感じ

<form method="post">
<label for="id">番号</label><input type="text" id="id" name="id" placeholder="数字を入力してください">
<input type="submit" id="send" name="send" value="送信">
</form>

さて$query = 'SELECT * FROM list WHERE id = '.$id;の部分に脆弱性があります。$idがそのまま文字連結されていますが、この$idはユーザの入力によってどのような入力であってもよい形になっています。

この$id1 or 1=1と入力すると$query = 'SELECT * FROM list WHERE id = 1 or 1=1'となります。するとwhereの中のid = 1 or 1=1trueなのでlistテーブルの全出力が得ることができます。

また例えば$query = 'SELECT * FROM list WHERE id = '.$id.' and passwd = '.$passwdといったqueryがあった際にid1 or 1=1 --とするとクエリが$query = 'SELECT * FROM list WHERE id = 1 or 1 = 1; -- and passwd = '.$passwdとなります.

--sqlコメントアウトなのでpasswdの値がなんであってもこのsqlは正しく通ります。

ブラインドSQLインジェクション

SQLインジェクションを利用すれば様々なクエリを動かすことが可能です。ですがテーブルの情報を消したり更新したりするにはテーブルのカラム名等を知る必要があります。そういうときに使う攻撃方法がブラインドSQLインジェクションになります。

ブラインドSQLインジェクションとはSQLインジェクション脆弱性は存在するがSQLの結果やエラー表示等が見れないときにでも成立する攻撃方法です。SQLインジェクションは存在するのでクエリの実行判定で確認します。

クエリの実行結果が確認できる場合は単純です。一文字ずつ確認していきます。

上の例においてid1 and substr(pass,1,1) = "A" --とすることでpassの一文字目がAであれば実行できます。アルファベット順で試すと時間がかかるので2分木探索をします。

1 and substr(pass,1,1) > "N" --とかこんな感じで定めていくことで効率よくやります。

ではクエリの実行結果が確認できない場合はどうするかというとsleep関数を用います。

クエリが正しく実行された場合はsleep関数によって定められた時間とまるはずなので止まった時間を用いてクエリを判定します。

参考

「ブラインドSQLインジェクションとは何ですか?」への回答 - 徳丸浩のtumblr