ログイン
編集不可のページディスカッション情報添付ファイル

2016-04-05 19:23:02時点のリビジョン4

メッセージを消す
Shinkan2016/CTF

MMA

2016年度MMA新歓CTF

CTF(Capture The Flag)は情報セキュリティなどのコンピュータ技術を競う競技のことです。CTFには主に次の2つの形式があります。フラグを見つけ解答するジェパディ形式のものと、他のチームのサーバーに対して攻撃を行いフラグを取る攻防戦形式のものです。

MMAでは2013年より積極的に各種CTFに参加しており、毎年SECCONやDEFCON予選といったコンテストに参加しています。

ルール

  • 問題はウェブサイト(https://wiki.mma.club.uec.ac.jp/Shinkan2016/CTF)及び新歓教室で配布されます。
  • 回答期限は2016/4/19 17:00(JST)です。
  • 回答期限終了までに問題の解法を公開することを禁止します。
  • 問題が解けたら、新歓教室あるいはMMA部室(サークル棟2階)に居るMMA部員に確認してもらってください。解けた問題に応じて賞品があります。
  • 問題の修正がある場合、ウェブサイトにて告知します。

問題

a quiz in floating island

難易度
ジャンル
Misc
出題者
nomeaning

次のCプログラムが、shinkan2016.pwnable.ctf.mma.club.uec.ac.jpのポート2000で動いています。フラグを入手してください。
#include <stdio.h>

int main(int argc, char **argv) {
  float a, b;
  scanf("%f %f", &a, &b);
  if(a == b && *(int*)&a != *(int*)&b) {
    puts("Congratulations. Flag is here.");
    puts(argv[1]);
  } else {
    puts("Wrong");
  }
}

Secure Password Rules

難易度
★(問題1, 問題2)
ジャンル
Programming
出題者
nomeaning

MMA(Modern Mobile Applications)社では、新たなログイン機能を持つアプリケーションを開発するにあたり、安全なパスワードをユーザーに強制させるため次のようなパスワードのルールを定めました。
  • パスワードには半角アルファベット小文字のみを用いることが出来る(記号とか使われるとSQL Injectionとかされるかもしれないのです)。
  • パスワードの長さは1文字以上 N 文字まで(長すぎると容量をたくさん使ってしまいます)。
  • 辞書に含まれている単語が部分文字列として3度以上現れてはならない(辞書攻撃対策です)。 部分文字列は同じ位置にある同じ長さのものを除いて重複して数えます。例えば辞書には"lol", "ol", "lo", "l"の4つが含まれていた場合、"lol"には辞書に含まれている単語が5つ含まれていることになります。

ところが、このルールを定めた後に、辞書が強力すぎるとパスワードに使える文字列が少なくなりすぎてしまうことがあるという指摘が入りました。それに対応する必要があるかを検証するためには、まずパスワード使える文字列の種類を数え上げる必要があります。あなたの仕事はNと辞書が与えられた時に、ルールを満たすパスワードの個数を求めることです。

例えば、N = 3、すなわちパスワードが3文字まであり、辞書には"a", "b", "c"の3つの文字列が含まれているとき、
* 1文字のパスワードは全て条件を満たす(26通り)
* 2文字のパスワードは全て条件を満たす(26^2 通り)
* 3文字のパスワードは"a","b","c"のみからなるものを除いて全て条件を満たす(26^3 - 3 ^ 3通り)

となるので、18251通りのパスワードがありえます。また、N = 5で辞書には"aaa"のみが含まれる時は"aaaaa"以外の全ての5文字以下のパスワードが許容されるため、26 + 26^2 + 26^3+ 26^4 + 26^5 - 1 = 12356629通りのパスワードが考えられます。

例題

  1. N = 6で、辞書ファイルhttps://ctf.mma.club.uec.ac.jp/problems/139/files/sample3.txtに対するパスワードのパターン数は21089426です。
  2. N = 150で、次の辞書ファイルhttps://ctf.mma.club.uec.ac.jp/problems/139/files/sample4.txtに対するパスワードのパターン数を10^9+9で割った余りは275144701です。

問題

  1. N = 5で、次の辞書ファイルhttps://ctf.mma.club.uec.ac.jp/problems/139/files/input1.txtに対するパスワードのパターン数を答えてください。辞書ファイルは1行に1単語が書かれています。パスワードのパターン数の10進表記がそのままフラグになります。
  2. N = 10000で、次の辞書ファイルhttps://ctf.mma.club.uec.ac.jp/problems/139/files/input2.txtに対するパスワードのパターン数を答えてください。ただし、パターン数は非常に大きくなるため10^9+9で割った時の余りを取った数を10進表記したものがフラグになります。

Money Game Returned

難易度
ジャンル
Pwn
出題者
nomeaning

次のCプログラムがサーバーshinkan2016.pwnable.ctf.mma.club.uec.ac.jpのポート27506で動いています。フラグを入手してください。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define N 3
// 各銘柄の値段
int price[N];
// 各銘柄の個数
int count[N];
// 現在の所持金
int money;
// 現在の週
int week;

int check_array_bound(int pos) {
  return pos >= 0 && pos < N;
}

// ゲームを初期化する
void init() {
  int i;
  for(i = 0; i < N; i++) {
    price[i] = 100;
  }
  money = 100;
}

// 現在の状態をユーザに伝える
void show() {
  int i;
  printf("\033[2J");
  if(week == 53) {
    printf("Week #%d(Final Week): \n", week + 1);
  } else {
    printf("Week #%d: \n", week + 1);
  }
  printf("You have %d YEN\n", money);
  for(i = 0; i < N; i++) {
    printf("    Stock #%d: %d YEN (You have %d.)\n", i + 1, price[i], count[i]);
  }
}

// ランダムに銘柄の値段を変化させる
void change() {
  int i;
  for(i = 0; i < N; i++) {
    int d = rand() % 21 - 10;
    price[i] += d;
    if(price[i] < 50) price[i] = 50;
    if(price[i] > 150) price[i] = 150;
  }
}

// 数字入力を受け取る
int get_number() {
  char buf[256] = {};
  int i, ret;

  fgets(buf, 255, stdin);
  if(*buf != '\0') buf[strlen(buf) - 1] = '\0';

  for(i = 0; i < strlen(buf); i++) {
    if(!isdigit(buf[i])) {
      puts("Invalid Number.");
      return get_number();
    }
  }

  ret = atoi(buf);
  return ret;
}

int main() {
  int action, n, m;
 ` srand(time(NULL));
  setvbuf(stdin, NULL, _IONBF, 0);
  setvbuf(stdout, NULL, _IONBF, 0);
  init();
  for(week = 0; week < 54; week++) {
    show();
    printf("Your action (1:Buy, 2:Sell, 3:Rest) : ");
    action = get_number();
    switch(action) {
    case 1:
      // 買う
      printf("Which stock do you want to buy? (%d-%d) : ", 1, N);
      n = get_number() - 1;
      if(!check_array_bound(n)) {
        puts("Invalid stock");
        break;
      }
      printf("How many stocks do you want to buy? (%d-%d): ", 0, money / price[n]);
      m = get_number();
      if(m > money / price[n]) {
        puts("Too much");
        break;
      }
      count[n] += m;
      money -= price[n] * m;
      break;
    case 2:
      // 売る
      printf("Which stock do you want to sell? (%d-%d) : ", 1, N);
      n = get_number() - 1;
      if(!check_array_bound(n)) {
        puts("Invalid stock");
        break;
      }
      printf("How many stocks do you want to sell? (%d-%d): ", 0, count[n]);
      m = get_number();
      if(m > count[n]) {
        puts("Too much");
        break;
      }
      count[n] -= m;
      money += price[n] * m;
      break;
    case 3:
      // 休む
      break;
    default:
      puts("Invalid action");
      break;
    }
    change();
    puts("\n");
  }
  printf("Your final money: %d YEN\n\n", money);
  sleep(1);
  if(money > 1000000) { // Millionaire!
    puts("Congratz! The flag is here.");
    printf("%s\n", getenv("FLAG"));
  } else {
    puts("You have little money to get the flag.");
  }
  return 0;
}

unskipyc
難易度
★★
ジャンル
Forensics
出題者
ytoku

% python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import flag
*CENSORED*

% xxd flag.pyc | tail -n +3
0000020: 0064 0100 6402 0014 6403 0064 0400 6405  .d..d...d..d..d.
0000030: 0085 0300 196a 0000 6406 0064 0700 6404  .....j..d..d..d.
0000040: 0064 0400 6408 0085 0300 1917 8301 0017  .d..d...........
0000050: 4748 6404 0053 2809 0000 0073 0800 0000  GHd..S(....s....
0000060: 466c 6167 2069 7320 731f 0000 000f 39f9  Flag is s.....9.
0000070: 459c 8445 790a c9a9 b900 7310 f129 fdcc  E..Ey.....s..)..
0000080: 65b9 9c8c cece a978 aba9 8933 690a 0000  e......x...3i...
0000090: 0069 1a00 0000 4e69 0900 0000 7401 0000  .i....Ni....t...
00000a0: 007a 7403 0000 0062 696c 69ff ffff ff28  .zt....bili....(
00000b0: 0100 0000 7406 0000 0064 6563 6f64 6528  ....t....decode(
00000c0: 0000 0000 2800 0000 0028 0000 0000 7307  ....(....(....s.
00000d0: 0000 0066 6c61 672e 7079 7408 0000 003c  ...flag.pyt....<
00000e0: 6d6f 6475 6c65 3e03 0000 0073 0000 0000  module>....s....

Ultra Efficient Cipher
難易度
★★
ジャンル
Crypto
出題者
nomeaning

Because XorShift is the efficient random number generator, this cipher is very fast.

Flag format is /^MMA\{[a-z0-9_]+\}$/. flag.txt contains the flag only without any whitespace characters.

#include <stdio.h>

unsigned int s[4];
unsigned int xor_shift() {
  unsigned int t;
  t = s[0] ^ (s[0] << 11);
  s[0] = s[1]; s[1] = s[2]; s[2] = s[3];
  return s[3] = (s[3] ^ (s[3] >> 19)) ^ (t ^ (t >> 8));

}

int main(int argc, char **argv) {
  if(argc != 3) { 
    fprintf(stderr, "Usage: %s key-file input-file\n", argv[0]);
    return 1;
  }
  FILE *fp = fopen(argv[1], "r");
  fread(s, sizeof(unsigned int), 4, fp);
  fclose(fp);

  fp = fopen(argv[2], "r");
  unsigned int buf = 0;
  int i;
  while(fread(&buf, 1, sizeof(buf), fp) > 0) {
    buf ^= xor_shift();
    for(i = 0; i < 4; i++) {
      putchar(buf & 255);
      buf >>= 8;
    }
  }
  fclose(fp);
  return 0;
}
$ ./uec key.dat flag.txt | xxd
00000000: a1e7 05f2 5634 a44f 4732 6ac8 038a 4638  ....V4.OG2j...F8
00000010: 5f0c c880 d669 f3ac 61b5 154a f160 be8d  _....i..a..J.`..
00000020: 7853 764b a605 e09f 5fe3 1a3e 7afe b1b1  xSvK...._..>z...
00000030: 183c de66 1be0 d855                      .<.f...U

各ジャンルの説明

ジャンル名 説明
Crypto 暗号に関する問題が該当します。
Forensics 与えられた情報を分析し、必要な情報を抽出します。例えば、USBメモリーのイメージが与えられて、そこからファイルを抽出するなどが該当します。
Programming 主にプログラミング/アルゴリズムの知識を用いて解く問題が出題されます。
Pwn 与えられたプログラムの脆弱性(プログラムのミスなどによって生じるセキュリティホール)を攻撃し、必要な情報を得る問題が出題されます。
Misc その他の問題が該当します。