kimtetの日記

CTFのwriteupとか、勉強したこととか

SECCON 2014 横浜大会 CTF ネットワーク予選 write up 問5

かなり間が空いたけど問5の解説。
解けなかった問題なので改めて書くのがたいへんだった。

このパケットによると、日本時間で今何月何日何時何分何秒?

0000   00 1a a0 89 a3 7f 44 94 fc 7e 1a ba 08 00 45 00  ......D..~....E.
0010   00 4c 00 00 40 00 36 11 11 2c d2 ad a0 1b c0 a8  .L..@.6..,......
0020   00 04 00 7b 00 7b 00 38 6d 96 1c 02 11 e8 00 00  ...{.{.8m.......
0030   06 8b 00 00 02 9e ac 1d 02 32 d7 ad 09 99 d8 db  .........2......
0040   8b 49 d7 ad 0a 44 7a a8 0f 7e d7 ad 0a 46 42 28  .I...Dz..~...FB(
0050   23 a6 d7 ad 0a 46 42 2b 5a b3                    #....FB+Z.

問4と同様、データ部分は問3と同じ。問題文が異なっている。

問題の考え方

データは問3と同じ。 今何時何分何秒なのか、とのことなので、このパケットの保存している時間情報を探して、NTPのプロトコルに従って送受信の間ののネットワーク伝送による誤差を加味して答えればいい。

簡単だと思ってたよ、この時までは。

解法

ntpパケットには時刻情報が4つある。

名称 パケットの中の位置
Reference Timestamp 4行目の11個目-5行目の2個目
Origin Timestamp 5行目の2個目-10個目
Receive Timestamp 5行目の11個目-6行目の2個目
Transmit Timestamp 6行目の2個目-10個目

それぞれ64bitの値であるこれをゴニョゴニョして人間に見られるようにして、計算して回答する。

こっから先は当日はわからなくて時間切れ。
どのTimestampを参照すればいいのかも、
64bitの値をどうやって西暦に直すのかも。

調べた結果

それぞれのタイムスタンプの意味は以下の通り。

名称 意味
参照タイムスタンプ(Reference Timestamp) ローカル時計が最後に設定、修正された時刻
開始タイムスタンプ(Originate Timestamp) クライアントからサーバへリクエストを発信した時間
受信タイムスタンプ(Receive Timestamp) サーバへリクエストが到着した時間
送信タイムスタンプ(Transmit Timestamp) サーバからクライアントに応答が発信された時間

UNIXタイムは32bitで保存されているという話をよく聞くけど、NTPの情報はどう扱ったらいいのかわからない。
64bitの値をどうやって西暦に変換するか。RFCより以下の情報を得た。

NTPタイムスタンプは、64ビット符号無し固定小数点数として表現されており、 このタイムスタンプは、1900年1月1日0時との相対的な差を秒単位で表している。 整数部分は、最初の上位32ビット、小数点以下は、下位32ビットとなっている。 小数部分については、あまり重要でない下位ビットは、0に設定される。

また、同じくRFCより保存形式はビッグエンディアン(上位桁から順に記述)と得られたので、 上位32bitを記述順に扱い、十進数に直す。

d7 ad 09 99 d8 db 8b 49 → 3618441625
d7 ad 0a 44 7a a8 0f 7e → 3618441796
d7 ad 0a 46 42 28 23 a6 → 3618441798
d7 ad 0a 46 42 2b 5a b3 → 3618441798

これが1900年01月01日からの経過秒数になる。 西暦に直すために計算するんだけど、手作業じゃしんどいのでツールを探す。

UNIXタイムスタンプ→西暦のツールはあまたあるけど、 NTPタイムスタンプ→西暦のツールは全然見ない。 で、いろいろ調べていたら、両者の差を書いてあるところがあった。

NTP時刻 - 2208988800秒 = UNIX (POSIX) 時刻

NTP時刻が1900年01月01日~の秒数で、UNIX時刻が1970年01月01日~の秒数だから、 その差を計算すればよい。 両者とも形式的な(うるう秒等を考慮しない)秒数なので、精密な処理は不要。

3618441625 - 2208988800 = 1409452825 = 2014/8/31 11:40:25 JST
3618441796 - 2208988800 = 1409452996 = 2014/8/31 11:43:16 JST
3618441798 - 2208988800 = 1409452998 = 2014/8/31 11:43:18 JST
3618441798 - 2208988800 = 1409452998 = 2014/8/31 11:43:18 JST

で、ここまで出したんだけどこの数字から現在時刻を求める方法がわからない。 いろいろ調べたら、NTPの時刻同期には以下の4つの情報が必要とある。 最初の4つはそのうちの一番最後の「クライアントがサーバのレスポンスを受信した時刻」が このデータからだとわからない。
なにか別の求め方があるのだろうか。教えて詳しい人!

  1. クライアントがリクエストを送信した時刻
  2. サーバがクライアントのリクエストを受信した時刻
  3. サーバがレスポンスを送信した時刻
  4. クライアントがサーバのレスポンスを受信した時刻

参考資料

別解

問1で書いた通りtext2pcapを使用すると時刻情報が一目瞭然なんだけど、 やっぱりここから補正して現在時刻が何時になるのかはわからない。
自分のやった手計算が間違っていなかったことだけ確認できた。
なお、出てくる情報はUTCなので+9:00:00してJSTにしなければならない。

f:id:kimtet:20141123201605p:plain