• トップ
  • ブログ一覧
  • 【第2回】セキュリティエンジニアを目指して「CTF」を解く!
  • 【第2回】セキュリティエンジニアを目指して「CTF」を解く!

    広告メディア事業部広告メディア事業部
    2020.06.12

    IT技術

    【第2回】セキュリティエンジニアを目指して「CTF」を解いていく

    セキュリティエンジニアへの需要が高まっているこの時代。

    ネットワーク、サーバ、アプリケーション、OS など、「コンピュータ全般に関する、幅広い分野の知識や技術」が求められています。

    前回の『【第1回】セキュリティエンジニアを目指して「CTF」を解く!』に引き続き、今回も CTF(Capture the flag)を解いていきます。

    前回の記事はこちら

    featureImg2020.06.11【第1回】セキュリティエンジニアを目指して「CTF」を解く!セキュリティエンジニアを目指して「CTF」を解いてくパソコンだけでなく、多くの通信機器がインターネットにつながる時代と...

    注意事項

    1. 前回に引き続き、常設 CTF のCpawCTFを利用します。
    2. 今回のコードは、Docker Official Images の gcc イメージ を使用して動作確認を行っています。
    3. 情報は2020年4月6日現在のものです。

    CpawCTF「Q20.[Crypto]Block Cipher」にチャレンジ!

    こちらは、「Q20.[Crypto]Block Cipher」の問題内容になります。

    与えられたC言語のソースコードを読zみ解いて復号してフラグを手にれましょう。

    暗号文:cpaw{ruoYced_ehpigniriks_i_llrg_stae}

    引用:CpawCTF

    添付されているソースコードは、以下の通りになります。

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <string.h>
    4int main(int argc, char *argv[])
    5{
    6  int i;
    7  int j;
    8  int key = atoi(argv[2]);
    9  const char *flag = argv[1];
    10  printf("cpaw{");
    11  for (i = key - 1; i <= strlen(flag); i += key)
    12  {
    13    for (j = i; j >= i - key + 1; j--)
    14    {
    15      printf("%c", flag[j]);
    16    }
    17  }
    18  printf("}\n");
    19  return 0;
    20}

    「問題文」から傾向を掴む!

    CTF の問題には、問題文に大きなヒントが隠されていることが多くあります

    問題のタイトルには「Crypto(暗号)」というキーワードがあります。

    問題文にも、「復号」、「暗号文」というキーワードがあり、暗号の問題であることがわかります

    また、タイトルは「Block Cipher(ブロック暗号)」というキーワードがあり、ブロック暗号に関する問題であることがわかります

    「ブロック暗号」とは?

    「ブロック暗号」は、データを一定の長さごとに区切って、そのブロックごとに暗号化を行うものです。

    単位ごとに区切っているので、暗号化と復号化が高速で行えるという特徴があります。

    近年、インターネット上で扱われる情報は非常に長いため、そのほとんどがブロック暗号方式で暗号化されています。

    ブロック内のデータ列を、「鍵」と呼ばれる値に基づいて順番を入れ替えます。

    1ビットごとに暗号化するものは、「ストリーム暗号」と呼ばれ、区別されます。

    「ソースコード」を読み解く!

    さて、この問題には以下のようなコードが添付されています。

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <string.h>
    4int main(int argc, char *argv[])
    5{
    6  int i;
    7  int j;
    8  int key = atoi(argv[2]);
    9  const char *flag = argv[1];
    10  printf("cpaw{");
    11  for (i = key - 1; i <= strlen(flag); i += key)
    12  {
    13    for (j = i; j >= i - key + 1; j--)
    14    {
    15      printf("%c", flag[j]);
    16    }
    17  }
    18  printf("}\n");
    19  return 0;
    20}

    問題文には「ソースコードを読み解いて」というセンテンスがあり、ソースコードを読み解くことがポイントとなりそうです。

    「変数名」から読み解く!

    変数の名前は、重要なヒントの1つです。

    argv は、「引数の配列」を表しています。

    const char * flag = argv[1]; の部分から、「コマンドライン引数の1つ目には、フラグに関する文字列を指定する」と推測できます。

    問題文に記されている、暗号文「ruoYced_ehpigniriks_i_llrg_stae」あたりを指定すると良さそうです。

    コード中で使用されている atoi 関数は、「ASCII to Integer」の略で、文字列を整数型に変換する C言語の標準ライブラリ関数です。

    これにより、int key = atoi(argv[2]); の部分から「コマンドライン引数の2つ目には、鍵となる整数文字列を指定する」と推測できます。

    「暗号文」から読み解く!

    暗号文「ruoYced_ehpigniriks_i_llrg_stae」の、4文字目が大文字となっているのが目につきます。

    また、先頭部分「ruoY」を逆から読むと「Your」となります。

    これだけでは何とも言えませんが、「4」をサンプル鍵として、ソースコードの残り部分のループ部分を見ていきたいと思います。

    「コード」から読み解く!

    ループ部分だけを抜粋すると以下の通りです。

    1  for (i = key - 1; i <= strlen(flag); i += key)
    2  {
    3    for (j = i; j >= i - key + 1; j--)
    4    {
    5      printf("%c", flag[j]);
    6    }
    7  }

    「key=4」としてみていくと、「i=3」からループがスタートします。

    2つ目のループでは「j=3」からスタートし、「j=0」となるまで、j が1ずつ減っていきながら、flag[j] の値が出力されます。

    「key=4」の場合、2つ目のループでは、まず、flag[3]、flag[2]、flag[1]、flag[0]と出力され、「Your」となりそうです。

    その後、1つ目のループに戻って、「i=7」、「i=11」、「i=15」...と、順次、同様の処理が実行されるようです。

    以上の内容から、key(今の場合は4)の文字数の単位(もしくはブロック)で、順次、逆から読んでいくというようなプログラムであることがわかります。

    号文「ruoYced_ehpigniriks_i_llrg_stae」の大文字の位置が4番目であることと、プログラムの内容から「key=4」が有力そうです。

    「総当たり」で最終チェック!

    「key=4」が有力ですが、念のため、総当たりで確認しておきます。

    コード

    コードの内容は以下の通りです。

    総当たり用に、元のコードを少し調整しています。

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <string.h>
    4
    5int sub(const char *flag, int key)
    6// int main(int argc, char* argv[]){
    7{
    8  int i;
    9  int j;
    10  // int key = atoi(argv[2]);
    11  // const char *flag = argv[1];
    12  printf("cpaw{");
    13  for (i = key - 1; i <= strlen(flag); i += key)
    14  {
    15    for (j = i; j >= i - key + 1; j--)
    16    {
    17      printf("%c", flag[j]);
    18    }
    19  }
    20  printf("}\n");
    21  return 0;
    22}
    23
    24int main(void)
    25{
    26  int i;
    27  for (i = 0; i < 10; i++)
    28  {
    29    sub("ruoYced_ehpigniriks_i_llrg_stae", i);
    30  }
    31}

    「key=4」で意味のある文章になったのではないでしょうか。

    今回作成したソースコード

    今回作成したソースコードは、以下のリポジトリにまとめてあります。

    【rightcode / ctf-trial】
    https://github.com/rightcode/ctf-trial

    ソースコードや結果を確認する場合は、上記のリポジトリをクローンしてください。

    結果の確認コマンド

    以下のコマンドで、結果を確認できます。

    1# Q20
    2bach check-c.sh 20

    ※結果の確認には Docker と Docker Compose を使用しています。
    Docker をインストールしていない場合は、確認用のコードを環境に合わせて調整してください。

    第3回へつづく!

    いかかでしたでしょうか!

    「CTF」では問題文をしっかり読むことが非常に大事であるということがわかりました。

    実際のセキュリティの世界でも、「ハッカーは自己顕示欲が強く、自分の作ったランサムウェアの解除法などをわかりにくいように隠す行動が見られる」というような報告もあります。

    そのような、攻撃者の性質を見逃さず、細かいところを見て解析することが重要です!

    次回の記事もお楽しみに!

    第3回の記事はこちら

    featureImg2020.06.15【最終回】セキュリティエンジニアを目指して「CTF」を解く!セキュリティエンジニアを目指してまだまだ「CTF」を解いていくセキュリティエンジニアには、「セキュリティ技術をはじめ、...

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...

    featureImg2020.08.04エンジニアの働き方 特集社員としての働き方社員としてのエンジニアの働き方とは?ライトコードのエンジニアはどんな働き方をしてるのか、まとめたいと...

    featureImg2020.07.27IT・コンピューターの歴史特集IT・コンピューターの歴史をまとめていきたいと思います!弊社ブログにある記事のみで構成しているため、まだ「未完成状態」...

    関連記事

    featureImg2020.06.11【第1回】セキュリティエンジニアを目指して「CTF」を解く!セキュリティエンジニアを目指して「CTF」を解いてくパソコンだけでなく、多くの通信機器がインターネットにつながる時代と...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background