ライブハッキング

2019-11-23 東京大学駒場祭 TSG出展企画「TSG LIVE! 4」

@hakatashi

気軽にコメントしてね♪ 

パーソナリティ
紹介①

@hakatashi

  • TSG LIVE! 発起人
  • CTF歴7年
  • 得意ジャンル: Web/Stego

パーソナリティ
紹介②

@JP3BGY

  • CTF歴2年
  • 得意ジャンル: Pwn

ライブハッキング

そもそも
「ハッキング」とは?

(犯罪?)

[ここにスライドを入力]

CTFについて
もっと知りたくなって
きましたね?

この枠では、
TSGが SECCON CTF で
出題した問題の解説や
裏話をします

メモ: ここでコメントを拾う

SECCON CTF 2019 予選で出題された問題

27問!

その1

Tanuki

ジャンル: Misc
配点: 439pt
作問者: @hakatashi

Tanuki 問題文

ご覧ください!

我々は今回のSECCONのために、
超難解かつスーパー安全、
そしてウルトラ解読困難な
新しい暗号を発明しました! 

名付けて、Tanukiです!

+[添付ファイル]

Tanuki 問題文

暗号文1: たたせくたこたたたんた
平文1: せくこん

暗号文2: たSたEたたたたたCCたたたたたOたNたたた
平文2: SECCON

Tanuki暗号のひみつ

実は、文章から「た」を「抜く」だけで
暗号を解読できる!

暗号文1: たたせくたたた
平文1: せくこん

暗号文2: たSEたたたたたCCたたたたたONたたた
平文2: SECCON

Tanuki

当然ですが、これだけなら
何も難しくない⋯⋯

ここで与えられた
添付ファイルを見てみると⋯⋯

tanuki.txt.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz

  • .gzは圧縮ファイルの一種
    • 一言でいうと.zipの亜種
    • つまりtanuki.txtというファイルを
      何度も何度も圧縮したもの
  • このファイル自体は20.0KBだが、
    展開すると⋯⋯

tanuki.txt.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz

  • このファイルを実際に展開すると
    (できたなら) なんと
    2,906,376,313,410,896,280,535,164バイト (=約2.40ヨタバイト)
    のテキストファイルになる

2𥝱9063垓7631京3410兆8962億8053万5164バイト

脱線: ヨタバイトとは

どれくらい大きい?

  • 2019年11月現在、最もバイト単価の安いHDDは
    7580円/4TB。 (kakaku.com調べ)
  • 展開したtanuki.txtを保存するために必要な費用は、
    2,906,376,313,410,896,280,535,164B × (7580円 ÷ 4TiB) = 5,009,117,661,675,580円
    • =5009兆円

Tanuki 解法

  • このサイズだと、ファイルを保存して
    処理するのはおろか、
    ストリーミングで処理することも困難
  • なんとか工夫して処理する必要がある

そもそも

圧縮ファイルって
どうやってデータを圧縮してるか
ご存知ですか?

実は

Zip, GZip, PNG などのファイルでは
同じDeflateという圧縮アルゴリズムが
採用されている

パンダコアラタスマニアタイガーパンダタスマニアデビル

  • パンダ
  •    コアラ
  •       タスマニアタイガー
  •                パンダ (25文字前から3文字コピー)
  •                   タスマニア (12文字前から5文字コピー)
  •                        デビル

パンダコアラタスマニアタイガー(25,3)(12,5)デビル

パンダパンダパンダパンダパンダパンダパンダ

  • パンダ
  •    パンダ (3文字前から3文字コピー)
  •    パンダパンダ (3文字前から6文字コピー)
  •    パンダパンダパンダパンダパンダパンダ (3文字前から18文字コピー)

パンダ(3,18)

パンダ(3,18)

は、「パンダ」を7回繰り返すという意味

→コピー元までの距離を超えてコピーする場合、
Deflate圧縮は実質的にランレングス圧縮と
考えることができる

Tanukiを解くには

  • 「パンダを1000回繰り返した文字列」を
    「パンダパンダパンダパンダ⋯⋯」というデータで
    持っておくのは圧倒的に非効率
  • ランレングス表現をランレングス表現のまま
    「パンダ×1000」のように持っておくことで
    ​効率的にこのようなデータを処理することができる
    • 同じ手法をTanukiにも適用可能!

Tanuki想定解①

  • ランレングス表現のままDeflate展開を処理すると
    ​最終的に、
    • (た×24984550042641701427744)S(た×9475249114589618367172)E(た×15098770148016195475279)C(た×14457375234513681877381)⋯⋯
    • のようなデータが出てくる
  • ここから「た」を「抜」けば、フラグが得られる
    • 解ける!

Tanuki想定解①の問題点

しんどい

他の解法

  • ランレングス表現のまま展開を実装するのは
    非常にしんどい。もっと楽な解き方を考える。
  • 今回の問題文から、最終的なファイルが
    (た×...)S(た×...)E(た×...)C(た×...)C(た×...)⋯⋯
    ​のような形をしていることは明らか
    • 本質部分は間の文字なので、
      繰り返し部分の回数や場所は無視していい
    • 繰り返す必要ないのでは⋯⋯?

Tanuki想定解②

  • ランレングス表現とみなせる部分の
    ​符号を、データ中から完全に取り除いてから
    通常の展開処理を行う
    • これなら既存の実装を使い回せるので
      ​実装はとても楽になる
  • ランレングス表現とみなせない符号を
    ​取り除いてはいけない
    • これを守れば最後までエラー無く
      展開できるように作問されています

デモ

一見ただのお遊びだが⋯⋯

実はけっこう重要なこと

Zip Bomb に対する防御

  • このように「展開すると爆発的に膨れ上がる
    圧縮ファイル」のことを、Zip Bomb などと呼ぶ
  • 一般にアンチマルウェアソフトはZipファイルの
    中身まで見てウイルスファイルの検知を行うので、
    Zip Bomb を用いると展開処理が終わらず
    これらの処理をハングさせることが可能
    • →現在では多くのソフトで対策されている
  • このように圧縮アルゴリズムの中身まで理解して
    ファイルの本質情報を抜き出すことは
    セキュリティの観点からも重要

参考: 「非再帰的ZIP爆弾」は10MBのファイルが281TBに膨らむ - GIGAZINE https://gigazine.net/news/20190705-zip-bomb/

ちなみに⋯⋯

ちなみに

作問者的な観点から言うと、
この前後、類題が多くのCTFで出題されてつらかった

  • SECCON 2019 Online: pngbomb
  • Google CTF 2019 Finals: Stuffed
  • ENCRYPT CTF 2019: Journey to the centre of the file

→圧縮ファイルブーム? (ほんまか)

裏話: Tanuki

Q.どうやって作問したの?

A.気合

Tanuki作問

  • 解法①のしんどい方法の逆をする
    • ランレングス表現のままでできる
      Deflateの圧縮処理を実装
    • 実質zlib相当のコードをRubyで再実装した
  • ここでは解説しないが、Deflateの実際の処理は
    もっと複雑
    • ハフマン符号
    • ハフマン符号のハフマン符号
    • セクション分割
    • CRC

「嘘のない」問題にする

  • 「ランレングス表現を除けば展開できるファイル」という
    ​仕様を満たすだけならもっと簡単に実装できる
  • が、この手の問題において「嘘」はつきたくなかった
    • CRCやデータの中身も含めて、
      ちゃんと (5000兆円あれば) 実際に
      2.4ヨタバイトのデータを得ることができる
      ファイルになってます
  • なおこの時のCRCに関する考察が別の問題の
    作問アイデアになっている

メモ: ここでコメントを拾う

その2

fileserver

ジャンル: Web
配点: 345pt
作問者: @hakatashi

fileserver 問題文

ApacheとかNginXとかよくわからないけど、
要は自分で実装すればいいんでしょ?
ほら、簡単!

Webサイトが与えられます

重要なのはこのあたり

files = Dir.glob(".#{req.path}*")
res['Content-Type'] = 'text/html'
res.body = ERB.new(File.read('index.html.erb')).result(binding)

Dir.globのドキュメントを確認

!?

パスにNULL文字を突っ込むことで
本来読めないはずのファイルを読める

files = Dir.glob(".#{req.path}*")

req.path = '/%00/tmp/flags/'
→ Dir.glob("./%00/tmp/flags/*")

デモ

しかし

  • このままではファイル名しかわからない
  • 中身を読むにはもう一つの脆弱性を
    利用する必要がある

もう一つの脆弱性

def is_bad_path(path)
  bad_char = nil

  %w(* ? [ { \\).each do |char|
    if path.include? char
      bad_char = char
      break
    end
  end

  if bad_char.nil?
    false
  else
    # check if brackets are paired
    if bad_char == ?{
      path[path.index(bad_char)..].include? ?}
    elsif bad_char == ?[
      path[path.index(bad_char)..].include? ?]
    else
      true
    end
  end
end

早期breakの仕様を利用

  • unmatchedな孤立{を含めることで
    []のフィルタを回避することができる

その3

Crazy Repetition

of Codes

ジャンル: Crypto
配点: 326pt
作問者: @hakatashi

本質はこの部分

def crc32(crc, data):
  crc = 0xFFFFFFFF ^ crc
  for c in data:
    crc = crc ^ ord(c)
    for i in range(8):
      crc = (crc >> 1) ^ (0xEDB88320 * (crc & 1))
  return 0xFFFFFFFF ^ crc

crc = 0
for i in range(int("1" * 10000)):
  crc = crc32(crc, "TSG")

int("1" * 10000)回のループ

  • 10000回?
  • ではなく
  • 111111111111⋯(10000個)⋯11111111111回のループ
crc = 0
for i in range(int("1" * 10000)):
  crc = crc32(crc, "TSG")

CRC (巡回冗長検査、
Cyclic Redundancy Check)

  • 主にデータの破損等を検証するために
    計算される数値
  • 数学的にはGF(2)上の多項式環として表現される

問題では

  • 与えられたコードはTSGという文字列を
    ループが回るたびに連結している
  • つまり1111111111⋯(10000文字)⋯1111111111個の
    TSGを連結した文字列のCRCを計算している

数式で表すと⋯⋯

デモ

いかがでしたか?

  • 明日は TSG LIVE! 最終日
  • 今回ご紹介したCTFを、
    今度は生放送で対戦する様子をお届け
  • 視聴者も参加することができます!

おしまい

TSG LIVE! 4 「ライブハッキング」解説スライド

By Koki Takahashi

TSG LIVE! 4 「ライブハッキング」解説スライド

  • 1,353