LoginSignup
3

More than 5 years have passed since last update.

posted at

updated at

SECCON 2016 Online CTF Writeup

チームnicklegrで個人参加。
300点で305位(930チーム中)でした。

今年は難しくてさっぱり。本格的なCTFになってました。
いいことだけど、雑魚としてはプログラミング問題も少しほしかったなぁ。

Vigenere (Crypto 100)

ヴィジュネル暗号 - Wikipedia

k: ????????????
p: SECCON{???????????????????????????????????}
c: LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ

k=key, p=plain, c=cipher, md5(p)=f528a6ab914c1ecf856a1d93103948fe


 |ABCDEFGHIJKLMNOPQRSTUVWXYZ{}
-+----------------------------
A|ABCDEFGHIJKLMNOPQRSTUVWXYZ{}
B|BCDEFGHIJKLMNOPQRSTUVWXYZ{}A
C|CDEFGHIJKLMNOPQRSTUVWXYZ{}AB
D|DEFGHIJKLMNOPQRSTUVWXYZ{}ABC
E|EFGHIJKLMNOPQRSTUVWXYZ{}ABCD
F|FGHIJKLMNOPQRSTUVWXYZ{}ABCDE
G|GHIJKLMNOPQRSTUVWXYZ{}ABCDEF
H|HIJKLMNOPQRSTUVWXYZ{}ABCDEFG
I|IJKLMNOPQRSTUVWXYZ{}ABCDEFGH
J|JKLMNOPQRSTUVWXYZ{}ABCDEFGHI
K|KLMNOPQRSTUVWXYZ{}ABCDEFGHIJ
L|LMNOPQRSTUVWXYZ{}ABCDEFGHIJK
M|MNOPQRSTUVWXYZ{}ABCDEFGHIJKL
N|NOPQRSTUVWXYZ{}ABCDEFGHIJKLM
O|OPQRSTUVWXYZ{}ABCDEFGHIJKLMN
P|PQRSTUVWXYZ{}ABCDEFGHIJKLMNO
Q|QRSTUVWXYZ{}ABCDEFGHIJKLMNOP
R|RSTUVWXYZ{}ABCDEFGHIJKLMNOPQ
S|STUVWXYZ{}ABCDEFGHIJKLMNOPQR
T|TUVWXYZ{}ABCDEFGHIJKLMNOPQRS
U|UVWXYZ{}ABCDEFGHIJKLMNOPQRST
V|VWXYZ{}ABCDEFGHIJKLMNOPQRSTU
W|WXYZ{}ABCDEFGHIJKLMNOPQRSTUV
X|XYZ{}ABCDEFGHIJKLMNOPQRSTUVW
Y|YZ{}ABCDEFGHIJKLMNOPQRSTUVWX
Z|Z{}ABCDEFGHIJKLMNOPQRSTUVWXY
{|{}ABCDEFGHIJKLMNOPQRSTUVWXYZ
}|}ABCDEFGHIJKLMNOPQRSTUVWXYZ{

ヴィジュネル暗号は平文と暗号文の各文字が分かれば鍵が求まるので、まずはSECCON{の部分。手作業でテーブルを引いてみた。

k: VIGENER?????
p: SECCON{???????????????????????????????????}
c: LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ

なら次の文字はEでしょう。

k: VIGENERE????

残り4文字なら、 28^4 = 614656 なので総当たりできる。md5(p)で正解か確認できるのがポイント。

require "pp"
require "digest/md5"

CIPHER = "LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ"
CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}"

def to_index(c)
  if "A".ord <= c.ord && c.ord <= "Z".ord
    c.ord - "A".ord
  else
    return 26 if c == "{"
    return 27 if c == "}"
    raise
  end
end

def make_table
  table = Array.new(28) do
    Array.new(28)
  end

  CHARS.each_char do |c|
    CHARS.each_char do |k|
      i = CHARS.index(c)
      i -= to_index(k)
      i += 28 if i < 0

      raise if !CHARS[i]
      table[to_index(k)][to_index(c)] = CHARS[i]
    end
  end

  table
end

def decode(cipher, key, table)
  ret = ""
  key_index = 0
  cipher.each_char do |c|
    ret += table[to_index(key[key_index])][to_index(c)]
    key_index += 1
    key_index %= key.size
  end
  ret
end

table = make_table()

CHARS.each_char do |c1|
  puts c1
  CHARS.each_char do |c2|
    CHARS.each_char do |c3|
      CHARS.each_char do |c4|
        key = "VIGENERE" + c1 + c2 + c3 + c4
        plain = decode(CIPHER, key, table)
        if Digest::MD5.hexdigest(plain) == "f528a6ab914c1ecf856a1d93103948fe"
          puts "found!: #{key} #{plain}"
          exit
        end
      end
    end
  end
end
A
B
C
found!: VIGENERECODE SECCON{ABABABCDEDEFGHIJJKLMNOPQRSTTUVWXYYZ}

鍵はVIGENERECODE。これくらいならエスパーした人もいるかも。

VoIP (Forensics 100)

Wiresharkに投げたらフラグを読み上げてくれた。
Wiresharkのコアな使い方|VoIPパケットを再生して品質を確認

"nine"が聞き取りずらかった。

SECCON{9001IVR}

Anti-Debugging (Binary 100)

Windowsバイナリ。パスワードチェック + アンチデバッグ。
WindowsはOllydbgが使えるので楽。

ご丁寧に、チェックに引っかかったらエラーメッセージを出してくれる。

ASCII "password is wrong."
ASCII "But detected debugger!"
ASCII "But detected Ollydbg."

これらの文字列の参照箇所にチェックルーチンがまとまってた。全部スキップするようにパッチを当てた。

Patches, item 0
  Address = 004013A3
  Module = bin
  Size = 6.
  Status = Applied
  Modified command = JMP 00401663
  Original command = JNE 0040174F
  Comments =

実行したらフラグ。なぜかこれだけメッセージボックスで出てきた。

SECCON{check_Ascii85}

PNG over Telegraph (Crypto 300)

解けなかった。

見た瞬間吹いた。なんだこれw

カメラアングルがほぼ固定なので、各ポーズのリファレンス画像を用意して差分を取ればいける気がするけど、だいぶ泥臭い作業になりそう。

あと文字が21種類しかないので、どうやってデコードするんだろ。Base64とかではなさそう。

他の人のWriteup

SECCON 2016 Online CTFのWrite-upが集まる魔法のスプレッドシート

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3