web-dev-qa-db-ja.com

Facebook CTFコンテストでキーの最初の4文字が欠落しているときにテキストを復号化する方法は?

私はサイバーセキュリティの初心者です。現在、私はFacebook Catch the Flagコンテストに参加しています。次のタスクを解決する必要があります:

鍵があります。ただし、キーの最初の4文字が欠落しています。

__ _ _ _ U3xn3Gk9y
_

これはアルゴリズムです:

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

int main()
{
    FILE *fi, *fo, *fk;
    int i, r;
    char key[20], text[100];

    fi = fopen("flag.txt", "r");
    fo = fopen("encrypted.txt", "w");
    fk = fopen("key.txt", "r");

    fscanf(fi, "%s", text);
    fscanf(fk, "%s", key);



    srand(key[0] * key[1] * key[2] * key[3]);
    for(i = 0; i < strlen(text); ++i)
    {
        r = Rand();
        putc(r ^ key[(r % strlen(key))] ^ text[i], fo);
    }

    fclose(fi);
    fclose(fo);
    fclose(fk);
    return 0;
}
_

暗号化されたテキスト:

РY‘ґЊЈZц、…Jщ、PvPw#ѓЗfыbаЁ+dИ?ѕцiЃyЛSBШ“ ¦ЕiЈ; иb—щьХЗ *]ЋOЛ、O™µEкЧи–ББш}

暗号化されたテキストを解読する必要があります。

まず第一に、私は解決策や答えを求めていません。私はいくつかのヒントを求めています:

  1. どこから解決すべきですか:キーまたは乱数の最初の4文字を見つけるには?

  2. Rand()アルゴリズムはどのように機能しますか?

  3. r ^ key[(r % strlen(key))] ^ text[i] = encrypted[i]がtrueの場合、_text[i]=_の式は何になりますか?

  4. この問題を解決する数学的な方法はありますか?ある場合は、名前を付けることができますか?

  5. この問題を解決するためのヒント(解決策ではない)を教えてください。

2
Joe Rakhimov

いくつかのヒント:

  1. キーの文字は、ASCII印刷可能な範囲内にある可能性があります。
  2. デコードされたテキストはおそらくASCII印刷可能な範囲内です。
  3. キースペースを減らすことができれば、32ビットの数値を総当たりにすることはそれほど難しくありません。
4
Polynomial

はい、これはかなり素早くブルートフォースすることができますが、興味がある場合は、このソリューション全体をブルートフォースする必要はありません。数学的なアプローチがあります。これはハッシュアルゴリズムで暗号化アルゴリズムではないようです(つまり、確実に元に戻すことができないため)。

反復可能な暗号化アルゴリズムが乱数生成を使用していることに興味がありますか?これは、ランダムシード(srandを検索)が同じ入力に対して一貫して設定されている場合にのみ機能します。つまり、Rand()を連続して呼び出すと、同じ順序の結果シーケンスが返されます。

Q.この場合、ランダムシードはどのように設定されますか?

A.最初の4文字の文字コードの積で、たまたま欠けているもの。

結果の暗号化されたテキストは、プレーンテキスト入力と同じ長さになることがコードからわかります。また、暗号化された各出力文字は、_(random number generated from the seed at the n'th pass where n is the current index + 1) ^ (that same random number mod the key length of 13 in your example) ^ (the character code at the current index)_のように、インデックスで元の文字によって生成されることも知っています。

それから、出力文字コードとインデックスに基づいて、暗号化の特定のパスでrを見つけるための簡単な数式を導出できます。

無料の公式ソースは見つかりませんでしたが、 here のようないくつかの場所でc Rand関数の実装方法を示しています。

_static unsigned long int next = 1;

int Rand(void) // Rand_MAX assumed to be 32767
{
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

void srand(unsigned int seed)
{
    next = seed;
}
_

数値が生成されるたびにシードが調整されることに注意してください。 Randが出力の5番目の文字(最初の文字)に関連付けられた文字コードを返すときに、nextが可能な値を見つけるために、Rand実装に基づいて別の数式を作成できます知っているキーキャラクターに関連付けられています)。上記のコードとRandの出力をRandの値として使用して暗号化コードに基づいてrを介して後続のパスを実行し、 5番目のパスでnextの有効なオプションが1つだけ残されるまで、出力の次の文字に対して結果が返されます。

それがわかったら、前の文字ごとに1回反転して、rの最初の4つの値を取得します。 rのこれらの値を解決したら、あとはoutput[i] = r ^ key[(r % strlen(key))] ^ text[i]を逆にして_text[i]_を解決するだけです。 _y = a ^ x_の逆関数はy = log base a (x)であることを思い出してください。以前に解決したr値を正しい順序で接続して、暗号化を通過するパスに関連付けられた文字コードを取得します。それらをキーの先頭に追加し、暗号化アルゴリズムを逆にして、暗号化されたテキストを含む新しいキーを渡し、出力に意味があるかどうかを確認して、作業を確認します。そうである場合、ブルートフォースなしでチャレンジを完了しました(おそらくフィルタリングを除きます)。

もちろん、キースペースはブルートフォースに十分なほど小さいので、いつでもそれを行うことができます。

1
S.C.