SECCON 2016 Online CTF Writeup

https://score-quals.seccon.jp/question/

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

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

# Vigenere (Crypto 100)
[ヴィジュネル暗号 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%B4%E3%82%A3%E3%82%B8%E3%83%A5%E3%83%8D%E3%83%AB%E6%9A%97%E5%8F%B7)

```
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)`で正解か確認できるのがポイント。

```ruby
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パケットを再生して品質を確認](http://www.terilogy.com/momentum/wireshark/wireshark01.html)

"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)
解けなかった。

https://youtu.be/Y6voaURtKlM

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

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

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

# 他の人のWriteup
[SECCON 2016 Online CTFのWrite-upが集まる魔法のスプレッドシート](https://docs.google.com/spreadsheets/d/1ezA4v0qDjB2H7DYdU_NFZv91S6C6YrQmX5gSXAgo3d8)