パスワード認証の暗号化 | はじめてのリバースエンジニアリング#6

ASCII値の合計を比較する簡単な暗号アルゴリズムを用いて、自らリバースエンジニアリングするためのパスワード認証プログラムを作成し直しました。



Introduction

このリバースエンジニアリングシリーズの初回には、単純に入力文字と正規パスワードを比較するパスワード認証プログラムをCで作成しました。

www.bioerrorlog.work

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

int main(int argc, char *argv[]) {
        if(argc==2) {
                printf("Checking Your Pass: %s\n", argv[1]);
                if(strcmp(argv[1], "Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery")==0) {
                        printf("Hello, Master.\n");
                } else {
                        printf("Access Denied.\n");
                }

        } else {
                printf("Access Denied.\n");
        }
        return 0;
}

前回まではこのCコードのバイナリコードを解析してきましたが、コード上に正規パスワードが直接記述されているため、stringsコマンドなどで簡単にパスワードを調べることができてしまいました1

そこで、今回は簡単な暗号アルゴリズムを用いて、パスワード認証プログラムをこれまでより少し破りにくいものに改良します2

Material

Ubuntu18.04.1 LTS を
Windows10の上に、VMwareによって構築した仮想環境で起動しています。
www.bioerrorlog.work


Results

簡単な暗号アルゴリズム

ごく簡単な暗号アルゴリズムとして、パスワードのASCII3値の合計を比較するやり方を使用します。 たとえば、パスワードが"PASS"だった場合、

パスワード: P A S S 合計
ASCII値: 0x50 0x41 0x53 0x53 311

ASCII値の合計は10進数で311となります。 この値を正規パスワードと入力パスワードで比較することで、パスワードの認証を行います。

正規パスワードの合計ASCII値を算出する

それでは、正規パスワードのASCII値の合計を算出します。 上記のパスワード認証プログラムのソースコードでは、正規パスワードが"Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery"となっています。 この正規パスワードのASCII値の合計を算出するために、次のようなCコード"ascii_sum.c"を書きました。

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

int main(int argc, char *argv[]) {
        if(argc==2) {
                int sum = 0;
                for (int i=0; i<strlen(argv[1]); i++) {
                        sum += (int)argv[1][i];
                }
                printf("ASCII sum: %d\n", sum);

        } else {
                printf("Usage: <key>\n");
        }
        return 0;
}

これで、引数に渡した文字列の合計ASCII値が出力されるはずです。 コンパイルしてから、試しに上に示した"PASS"を渡してみると、

$ ./ascii_sum PASS
ASCII sum: 311

正しく合計値311が表示され、プログラムが予想通りに機能することが伺えます。

そこで、正規パスワードのASCII合計値を調べると、

$ ./ascii_sum Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery
ASCII sum: 5345

5345であることが分かりました。

パスワード認証プログラムを作成する

それでは、パスワード認証プログラムを変更して、渡された文字列の合計ASCII値を5345と比較することでアクセス可否を判断するプログラムに書き換えます。

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

int main(int argc, char *argv[]) {
        if(argc==2) {
        printf("Checking Your Pass: %s\n", argv[1]);
        int sum = 0;
                for (int i=0; i<strlen(argv[1]); i++) {
                        sum += (int)argv[1][i];
                }
        if(sum==5345) {
            printf("Hello, Master.\n");
        } else {
                    printf("Access Denied.\n");
            }

    } else {
        printf("Access Denied.\n");
    }
    return 0;
}

これを"your_pass_2.c"とし、コンパイルしてプログラムの挙動を確認します。

まずは間違ったパスワード"WRONG-PASS"を渡して実行します。

$ ./your_pass_2 WRONG-PASS
Checking Your Pass: WRONG-PASS
Access Denied.

予想通りにアクセスが拒否されました。

次に、正規パスワード"Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery"を渡して実行します。

$ ./your_pass_2 Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery
Checking Your Pass: Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery
Hello, Master.

見事、アクセスが承認されました。 これで、ソースコードに直接正規パスワードを記述しない簡単なパスワード認証プログラムができました。


Discussion

今回は、ごく簡単な暗号アルゴリズムを用いて、パスワード認証プログラムを改良しました。

次回は、このバイナリコードをリバースエンジニアリングし、正解パスワードを生成する"Keygen"プログラムを作成します。

それにしても、少し調べてみると暗号アルゴリズムというものは大変奥が深そうです。 今回は可能な限り簡単なやり方をしましたが、現代においても暗号技術は一つの学問として日々研究成果が報告されています。

ハードウェアについてまるで知識がありませんが、たとえば量子コンピュータが飛躍的に高い性能で実現した場合、現在使われている暗号技術が解読可能になったりはしないのでしょうか。 仮に解読可能になった場合、この複雑にシステムが絡み合うIT社会の中で、新しい暗号技術への移行はスムーズに行えるものなのでしょうか。

妄想は膨らみます。


See also

次↓

www.bioerrorlog.work

前↓ www.bioerrorlog.work


  1. ハードコードされたパスワードを読み出す | はじめてのリバースエンジニアリング#4 - 生物系がゼロから始めるIT技術を参照。

  2. LiveOverflow氏の動画Uncrackable Programs? Key validation with Algorithm and creating a Keygen - Part 1/2 - bin 0x07 - YouTubeを参考にしています。

  3. ASCIIとは、最もよく使用される文字コードです。数値と文字が対応したASCIIコードによって、コンピュータによる文字の表示を実現します。ASCIIコードは、ターミナルで$ man asciiとすることで見ることができます。