CTF

CTF未経験の僕が30分でバイナリ解析を学び、練習問題を解いた話【備忘録】

最近CTFを勉強し始めたのですが、本日はバイナリ解析の基礎を学んだので備忘録としてまとめておきます。

基本的にはCpawCTFという常設CTFサイトとはりねずみ本を中心に勉強しています。

はりねずみ本は、かなり基礎的な内容から丁寧に書かれているのでとてもおすすめです。
教材に迷ったらこれにして間違いないと思います。

コンピュータセキュリティ技術を競うコンテストCTFで戦うための知識技能を鍛えよう。

もくじ

  1. バイナリ解析とは
  2. バイナリ解析に使うツール
  3. 練習問題にチャレンジ!
  4. 解析してみた
  5. まとめ
  6. 参考

バイナリ解析とは

そもそもバイナリ解析とはなんでしょうか。
なんとなく、「バイナリ」を「解析」することだとわかります。

というわけで、「バイナリ」と「解析」の意味をそれぞれ調べてみました。

バイナリ
バイナリ(またはバイナリー:binary)とは、2進数のこと。
テキスト形式(文字データ)以外のデータ形式全般を指したり、コンピュータが処理・記憶するために2進化されたファイル(バイナリファイル)、またはその内部表現の形式(バイナリデータ、バイナリ形式)のことを指すのに用いられる。

コンピュータはデータを処理するために、全ての情報を「0」と「1」で表現されているデータ形式、つまり2進数に変換しており、コンピュータが解釈するために用意されたデータはすべてバイナリ形式である。
コンピュータが直接解釈して実行できるフォーマットで記述された実行ファイルの形式を特にバイナリコードという。
データがバイナリで記述されているファイルはバイナリファイル、バイナリファイルのデータはバイナリデータと呼ばれ、バイナリファイルの主なものには、音声ファイルや画像ファイル、実行形式のプログラムファイル、圧縮ファイルなどがある。
バイナリデータは、テキストエディタなどで表示・編集することができるが、人間が読んでも、意味を解釈することはきわめて困難である。

https://it-words.jp/w/E38390E382A4E3838AE383AA.html

解析
[名](スル)
1 事物の構成要素を細かく理論的に調べることによって、その本質を明らかにすること。「調査資料を解析する」
2 数学的論法の一。Aの事柄を証明するために、Aが成立するためにはBが成立しなければならないことを示し、Bが成立するためにCが成立しなければならないことを示し、以下順次これを繰り返して既知の事柄に帰着させること。
3 「解析学」の略。

https://kotobank.jp/word/%E8%A7%A3%E6%9E%90-457741

つまりは、「バイナリ解析」とは、『機械語で書かれたソースを細かく調べて、その本質を明らかにすること』であると言えます。

なぜそんなことをするかと言えば、『実行ファイルから、そのプログラムの本質を知るため』です。
もちろんソースコードを読めれば一番ですが、ウイルスを含め、世の中に出回っているプログラムの大半のソースコードは公開されていません。

そこで、逆コンパイルやバイナリ解析などの技法を用いてプログラムの動きを理解することが、ウイルス解析などの作業において非常に重要になるのです。

バイナリ解析に使うツール

バイナリ解析を行うためには、解析に適したツールが必要になります。
なぜなら、バイナリファイルは機械語で書かれているため、人間が読んでも全く理解することができないためです。

バイナリ解析に使用するツールについては、下記リンク先に一通りまとめられています。

バイナリ解析ツール

以下には、今回僕が使用したツールを抜粋してまとめておきます。

・fileコマンド:ファイルの種類などの情報を見られるLinuxのコマンドです。
・ghex:Linux上で動くGUIベースのバイナリエディタです。
・readelf:ELFファイルの情報を表示してくれるLinuxのツールです。

今回は上記の3つのツールを使って、CTFの練習問題を解いていきます。

練習問題にチャレンジ!

今回チャレンジしたのは、CpawCTFの7番の問題です。

問題は、『ファイルを渡されたがクリックしても実行できない!頑張って実行してくれ!』という内容でした。

まずは、渡されたファイルがどんなファイルなのか確認していきます。

Linux環境に課題のファイルをダウンロードして、fileコマンドを実行してみます。

  $ file exec_me
   exec_me: ELF 64-bit LSB executable, x86-64,
   version 1 (SYSV), dynamically linked, interpreter /lib64/l,
   for GNU/Linux 2.6.24, BuildID[sha1]=663a3e0e5a079fddd0de92474688cd6812d3b550,
   not stripped

さて、上記のコマンドを実行した出力結果には、『ELF 64-bit LSB executable』という文言が確認できます。

すなわち、exec_meはELFファイルであることが確認できました。

ELFファイルとは、Linux 上で実行可能なプログラムやそれにリンクされる共有ライブラリなどのバイナリファイルのファイル形式のことです。
ELFファイルは、GUI上でクリックしても実行されず、コンソール上でのみ実行が可能です。

  $ ./exec_me
   cpaw{Do_you_know_ELF_file?}

実際に、上記のコマンドを実行することで、解答が確認できました。
思ったより簡単でしたね!

解析してみた

さて、ここからが本題です。

ELFファイルはバイナリファイルであることがわかりました。
これからこのELFファイルを解析してみます。

先ほど紹介した「ghex」というバイナリエディタで中身を確認してみます。

・・・正直何もわかりませんでした。

次に、ELFファイルの情報を表示してくれるreadelfを使ってみました。

すると、下記のような情報が表示されました。

  ELF ヘッダ:
  マジック: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  クラス: ELF64
  データ: 2 の補数、リトルエンディアン
  バージョン: 1 (current)
  OS/ABI: UNIX - System V
  ABI バージョン: 0
  型: EXEC (実行可能ファイル)
  マシン: Advanced Micro Devices X86-64
  バージョン: 0x1
  エントリポイントアドレス: 0x400440
  プログラムヘッダ始点: 64 (バイト)
  セクションヘッダ始点: 4504 (バイト)
  フラグ: 0x0
  このヘッダのサイズ: 64 (バイト)
  プログラムヘッダサイズ: 56 (バイト)
  プログラムヘッダ数: 9
  セクションヘッダ: 64 (バイト)
  セクションヘッダサイズ: 30
  セクションヘッダ文字列表索引: 27

  セクションヘッダ:
  [番] 名前 タイプ アドレス オフセット
  サイズ EntSize フラグ Link 情報 整列
  [ 0] NULL 0000000000000000 00000000
  0000000000000000 0000000000000000 0 0 0
  [ 1] .interp PROGBITS 0000000000400238 00000238
  000000000000001c 0000000000000000 A 0 0 1
  [ 2] .note.ABI-tag NOTE 0000000000400254 00000254
  0000000000000020 0000000000000000 A 0 0 4
  [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274
  0000000000000024 0000000000000000 A 0 0 4
  [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298
  000000000000001c 0000000000000000 A 5 0 8
  [ 5] .dynsym DYNSYM 00000000004002b8 000002b8
  0000000000000060 0000000000000018 A 6 1 8
  [ 6] .dynstr STRTAB 0000000000400318 00000318
  0000000000000040 0000000000000000 A 0 0 1
  [ 7] .gnu.version VERSYM 0000000000400358 00000358
  0000000000000008 0000000000000002 A 5 0 2
  [ 8] .gnu.version_r VERNEED 0000000000400360 00000360
  0000000000000020 0000000000000000 A 6 1 8
  [ 9] .rela.dyn RELA 0000000000400380 00000380
  0000000000000018 0000000000000018 A 5 0 8
  [10] .rela.plt RELA 0000000000400398 00000398
  0000000000000048 0000000000000018 A 5 12 8
  [11] .init PROGBITS 00000000004003e0 000003e0
  000000000000001a 0000000000000000 AX 0 0 4
  [12] .plt PROGBITS 0000000000400400 00000400
  0000000000000040 0000000000000010 AX 0 0 16
  [13] .text PROGBITS 0000000000400440 00000440
  0000000000000272 0000000000000000 AX 0 0 16
  [14] .fini PROGBITS 00000000004006b4 000006b4
  0000000000000009 0000000000000000 AX 0 0 4
  [15] .rodata PROGBITS 00000000004006c0 000006c0
  0000000000000004 0000000000000004 AM 0 0 4
  [16] .eh_frame_hdr PROGBITS 00000000004006c4 000006c4
  0000000000000034 0000000000000000 A 0 0 4
  [17] .eh_frame PROGBITS 00000000004006f8 000006f8
  00000000000000f4 0000000000000000 A 0 0 8
  [18] .init_array INIT_ARRAY 0000000000600e10 00000e10
  0000000000000008 0000000000000000 WA 0 0 8
  [19] .fini_array FINI_ARRAY 0000000000600e18 00000e18
  0000000000000008 0000000000000000 WA 0 0 8
  [20] .jcr PROGBITS 0000000000600e20 00000e20
  0000000000000008 0000000000000000 WA 0 0 8
  [21] .dynamic DYNAMIC 0000000000600e28 00000e28
  00000000000001d0 0000000000000010 WA 6 0 8
  [22] .got PROGBITS 0000000000600ff8 00000ff8
  0000000000000008 0000000000000008 WA 0 0 8
  [23] .got.plt PROGBITS 0000000000601000 00001000
  0000000000000030 0000000000000008 WA 0 0 8
  [24] .data PROGBITS 0000000000601030 00001030
  0000000000000010 0000000000000000 WA 0 0 8
  [25] .bss NOBITS 0000000000601040 00001040
  0000000000000008 0000000000000000 WA 0 0 1
  [26] .comment PROGBITS 0000000000000000 00001040
  000000000000004d 0000000000000001 MS 0 0 1
  [27] .shstrtab STRTAB 0000000000000000 0000108d
  0000000000000108 0000000000000000 0 0 1
  [28] .symtab SYMTAB 0000000000000000 00001918
  0000000000000618 0000000000000018 29 45 8
  [29] .strtab STRTAB 0000000000000000 00001f30
  000000000000023c 0000000000000000 0 0 1
  Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

  このファイルにはセクショングループがありません。

  プログラムヘッダ:
  タイプ オフセット 仮想Addr 物理Addr
  ファイルサイズ メモリサイズ フラグ 整列
  PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
  0x00000000000001f8 0x00000000000001f8 R E 0x8
  INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
  0x000000000000001c 0x000000000000001c R 0x1
  [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
  0x00000000000007ec 0x00000000000007ec R E 0x200000
  LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
  0x0000000000000230 0x0000000000000238 RW 0x200000
  DYNAMIC 0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
  0x00000000000001d0 0x00000000000001d0 RW 0x8
  NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
  0x0000000000000044 0x0000000000000044 R 0x4
  GNU_EH_FRAME 0x00000000000006c4 0x00000000004006c4 0x00000000004006c4
  0x0000000000000034 0x0000000000000034 R 0x4
  GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
  0x0000000000000000 0x0000000000000000 RW 0x10
  GNU_RELRO 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
  0x00000000000001f0 0x00000000000001f0 R 0x1

  セグメントマッピングへのセクション:
  セグメントセクション…
  00
  01 .interp
  02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
  03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
  04 .dynamic
  05 .note.ABI-tag .note.gnu.build-id
  06 .eh_frame_hdr
  07
  08 .init_array .fini_array .jcr .dynamic .got

  Dynamic section at offset 0xe28 contains 24 entries:
  タグ タイプ 名前/値
  0x0000000000000001 (NEEDED) 共有ライブラリ: [libc.so.6]
  0x000000000000000c (INIT) 0x4003e0
  0x000000000000000d (FINI) 0x4006b4
  0x0000000000000019 (INIT_ARRAY) 0x600e10
  0x000000000000001b (INIT_ARRAYSZ) 8 (バイト)
  0x000000000000001a (FINI_ARRAY) 0x600e18
  0x000000000000001c (FINI_ARRAYSZ) 8 (バイト)
  0x000000006ffffef5 (GNU_HASH) 0x400298
  0x0000000000000005 (STRTAB) 0x400318
  0x0000000000000006 (SYMTAB) 0x4002b8
  0x000000000000000a (STRSZ) 64 (バイト)
  0x000000000000000b (SYMENT) 24 (バイト)
  0x0000000000000015 (DEBUG) 0x0
  0x0000000000000003 (PLTGOT) 0x601000
  0x0000000000000002 (PLTRELSZ) 72 (バイト)
  0x0000000000000014 (PLTREL) RELA
  0x0000000000000017 (JMPREL) 0x400398
  0x0000000000000007 (RELA) 0x400380
  0x0000000000000008 (RELASZ) 24 (バイト)
  0x0000000000000009 (RELAENT) 24 (バイト)
  0x000000006ffffffe (VERNEED) 0x400360
  0x000000006fffffff (VERNEEDNUM) 1
  0x000000006ffffff0 (VERSYM) 0x400358
  0x0000000000000000 (NULL) 0x0

  再配置セクション ‘.rela.dyn’ at offset 0x380 contains 1 entry:
  オフセット 情報 型 シンボル値 シンボル名 + 加数
  000000600ff8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 gmon_start + 0

  再配置セクション ‘.rela.plt’ at offset 0x398 contains 3 entries:
  オフセット 情報 型 シンボル値 シンボル名 + 加数
  000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 putchar@GLIBC_2.2.5 + 0
  000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
  000000601028 000300000007 R_X86_64_JUMP_SLO 0000000000000000 gmon_start + 0

  The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

  Symbol table ‘.dynsym’ contains 4 entries:
  番号: 値 サイズ タイプ Bind Vis 索引名
  0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putchar@GLIBC_2.2.5 (2)
  2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
  3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start

  Symbol table ‘.symtab’ contains 65 entries:
  番号: 値 サイズ タイプ Bind Vis 索引名
  0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  1: 0000000000400238 0 SECTION LOCAL DEFAULT 1
  2: 0000000000400254 0 SECTION LOCAL DEFAULT 2
  3: 0000000000400274 0 SECTION LOCAL DEFAULT 3
  4: 0000000000400298 0 SECTION LOCAL DEFAULT 4
  5: 00000000004002b8 0 SECTION LOCAL DEFAULT 5
  6: 0000000000400318 0 SECTION LOCAL DEFAULT 6
  7: 0000000000400358 0 SECTION LOCAL DEFAULT 7
  8: 0000000000400360 0 SECTION LOCAL DEFAULT 8
  9: 0000000000400380 0 SECTION LOCAL DEFAULT 9
  10: 0000000000400398 0 SECTION LOCAL DEFAULT 10
  11: 00000000004003e0 0 SECTION LOCAL DEFAULT 11
  12: 0000000000400400 0 SECTION LOCAL DEFAULT 12
  13: 0000000000400440 0 SECTION LOCAL DEFAULT 13
  14: 00000000004006b4 0 SECTION LOCAL DEFAULT 14
  15: 00000000004006c0 0 SECTION LOCAL DEFAULT 15
  16: 00000000004006c4 0 SECTION LOCAL DEFAULT 16
  17: 00000000004006f8 0 SECTION LOCAL DEFAULT 17
  18: 0000000000600e10 0 SECTION LOCAL DEFAULT 18
  19: 0000000000600e18 0 SECTION LOCAL DEFAULT 19
  20: 0000000000600e20 0 SECTION LOCAL DEFAULT 20
  21: 0000000000600e28 0 SECTION LOCAL DEFAULT 21
  22: 0000000000600ff8 0 SECTION LOCAL DEFAULT 22
  23: 0000000000601000 0 SECTION LOCAL DEFAULT 23
  24: 0000000000601030 0 SECTION LOCAL DEFAULT 24
  25: 0000000000601040 0 SECTION LOCAL DEFAULT 25
  26: 0000000000000000 0 SECTION LOCAL DEFAULT 26
  27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
  28: 0000000000600e20 0 OBJECT LOCAL DEFAULT 20 JCR_LIST
  29: 0000000000400470 0 FUNC LOCAL DEFAULT 13 deregister_tm_clones
  30: 00000000004004a0 0 FUNC LOCAL DEFAULT 13 register_tm_clones
  31: 00000000004004e0 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
  32: 0000000000601040 1 OBJECT LOCAL DEFAULT 25 completed.6973
  33: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin
  34: 0000000000400500 0 FUNC LOCAL DEFAULT 13 frame_dummy
  35: 0000000000600e10 0 OBJECT LOCAL DEFAULT 18 _frame_dummy_init_array
  36: 0000000000000000 0 FILE LOCAL DEFAULT ABS exec_me.c
  37: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
  38: 00000000004007e8 0 OBJECT LOCAL DEFAULT 17 FRAME_END
  39: 0000000000600e20 0 OBJECT LOCAL DEFAULT 20 JCR_END
  40: 0000000000000000 0 FILE LOCAL DEFAULT ABS
  41: 0000000000600e18 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
  42: 0000000000600e28 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
  43: 0000000000600e10 0 NOTYPE LOCAL DEFAULT 18 __init_array_start
  44: 0000000000601000 0 OBJECT LOCAL DEFAULT 23 GLOBAL_OFFSET_TABLE
  45: 00000000004006b0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
  46: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putchar@@GLIBC_2.2.5
  47: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
  48: 0000000000601030 0 NOTYPE WEAK DEFAULT 24 data_start
  49: 0000000000601040 0 NOTYPE GLOBAL DEFAULT 24 _edata
  50: 00000000004006b4 0 FUNC GLOBAL DEFAULT 14 _fini
  51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _libc_start_main@@GLIBC
  52: 0000000000601030 0 NOTYPE GLOBAL DEFAULT 24 __data_start
  53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start
  54: 0000000000601038 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
  55: 00000000004006c0 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
  56: 0000000000400640 101 FUNC GLOBAL DEFAULT 13 __libc_csu_init
  57: 0000000000601048 0 NOTYPE GLOBAL DEFAULT 25 _end
  58: 0000000000400440 0 FUNC GLOBAL DEFAULT 13 _start
  59: 0000000000601040 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
  60: 000000000040052d 266 FUNC GLOBAL DEFAULT 13 main
  61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
  62: 0000000000601040 0 OBJECT GLOBAL HIDDEN 24 TMC_END
  63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
  64: 00000000004003e0 0 FUNC GLOBAL DEFAULT 11 _init

  Version symbols section ‘.gnu.version’ contains 4 entries:
  アドレス: 0000000000400358 オフセット: 0x000358 リンク: 5 (.dynsym)
  000: 0 (局 所) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (局 所)

  Version needs section ‘.gnu.version_r’ contains 1 entry:
  アドレス: 0x0000000000400360 オフセット: 0x000360 リンク: 6 (.dynstr)
  000000: バージョン: 1 ファイル: libc.so.6 個数: 1
  0x0010: 名前: GLIBC_2.2.5 フラグ: なし バージョン: 2

  Displaying notes found in: .note.ABI-tag
  所有者 データサイズ 説明
  GNU 0x00000010 NT_GNU_ABI_TAG (ABI バージョンタグ)
  OS: Linux, ABI: 2.6.24

  Displaying notes found in: .note.gnu.build-id
  所有者 データサイズ 説明
  GNU 0x00000014 NT_GNU_BUILD_ID (一意なビルドID ビット列)
  ビルドID: 663a3e0e5a079fddd0de92474688cd6812d3b550

うーん、バイナリエディタで見たときよりはなんとなくわかる気がしますが、とはいえ理解とは程遠いですね…。

これは先が長そうです笑

まとめ

今回は初めてCTFの問題に挑戦したので、その内容をまとめてみました。

セキュリティを学ぶにはとにかく広く、そして深い技術への理解が必要なので、非常に難しい反面やりがいもあります。

みなさんもぜひ挑戦してみてはいかがでしょうか?

コンピュータセキュリティ技術を競うコンテストCTFで戦うための知識技能を鍛えよう。

参考

バイナリ解析ツール

セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方

COMMENT

メールアドレスが公開されることはありません。