phoenixが送るBeginners CTF 2019 OneLine(Pwn)の解説

はじめまして、チームfalconのヒーローことphoenixです。

本日より、Beginners CTF 2019のWriteUpを書い参ります。

待望の1回目は、OneLine(Pwn)です。

まず、Pwnのことを知らない人がいると思うので簡単に説明しておくと、 Pwnはサーバ上で動作しているプログラムの脆弱性を突いてflagをゲットする問題です。

例えば今回の問題では、 サーバが 153.120.129.186:10000(IPアドレス:ポート番号)であり、そのサーバにつないだ際に動作しているプログラムの脆弱性を突くことになります。 以下は、実際にサーバにつないだ際のプログラムの反応です。

$ nc 153.120.129.186 10000
You can input text here!
>>

今回はサーバプログラム(oneline)とそのプログラムが使う共有ライブラリ(libc-2.27.so)が用意されているため、それらをダウンロードしてローカル環境で脆弱性の解析を行います。

まずは、fileコマンドとchecksecを用いてonelineについての情報(ファイルタイプ,セキュリティ機構の有無)を調べます。

$ file oneline
oneline: ELF 64-bit LSB  shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, BuildID[sha1]=34fd51e025f282f2e06259d36a690436147b04f3, not stripped

$checksec --file oneline
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   oneline

これより,onelineがx86_64環境で動作する実行ファイルであり,Full RELRO・PIE・NX bitのセキュリティ機構が施されているこが確認できます。

今回の問題においては,Full RELROとNX bitについて特に気にする必要はないのですが,PIEについては注意が必要です。 PIEは,実行ファイルを物理メモリ上にロードするときにランダムな位置に配置可能にするために,アドレス参照をすべて相対アドレスにするというものです。(以下の図を参考)

PIEが施されることによって,実行ファイル内の任意のアドレスの命令を実行させることの難易度が高くなってしまいます。(アドレスのリークを行い,相対アドレスから実行させたい命令のアドレスを求めるといった作業が必要になるため)

$objdump -d -M intel oneline
000000000000086d <main>:
 86d:   55                      push   rbp
 86e:   48 89 e5                mov    rbp,rsp
 871:   48 83 ec 10             sub    rsp,0x10
 875:   be 01 00 00 00          mov    esi,0x1
 87a:   bf 28 00 00 00          mov    edi,0x28
 87f:   e8 7c fe ff ff          call   700 <calloc@plt>
 884:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
     :

いきなり難しいことを考えても仕方がないので,とりあえず実行してみることにしましょう。

$ nc 153.120.129.186 10000
You can input text here!
>> A
A
                              @a  Once more again!
>> A
A

入力を2回求められたので,とりあえず2回とも'A'と入力してみました。 すると,1回目の'A'を入力したあとには,Once more again!という返事があり,2回目の'A'を入力した後には何も返事はなくプルグラムが終了してしまいました。

。。。 ちょっと1回目の返事に着目してみましょう。先ほどOnce more again!という返事があったと書きましたが,何やらその前に空白と@aという文字あることにお気づきでしょうか?

それでは,もう一度同じようにサーバにつないで'A'を入力してみましょう。

$ nc 153.120.129.186 10000
You can input text here!
>> A
A
                              @k'  Once more again!
>> A
A

.。。。 なんと,同じ入力にも関わらず今度は@aではなく@k'という返事がOnce more again!の前について返ってきたのです。

これらが何を表しているのかを調べるためhexdumpで出力した結果が次です。

$ echo A | ./oneline | hexdump -C
00000000  59 6f 75 20 63 61 6e 20  69 6e 70 75 74 20 74 65  |You can input te|
00000010  78 74 20 68 65 72 65 21  0a 3e 3e 20 41 0a 00 00  |xt here!.>> A...|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 b0 23 e2 b4  |.............#..|
00000040  ca 7f 00 00 4f 6e 63 65  20 6d 6f 72 65 20 61 67  |....Once more ag|
00000050  61 69 6e 21 0a 3e 3e 20                           |ain!.>> |
00000058

$ echo A | ./oneline | hexdump -C
00000000  59 6f 75 20 63 61 6e 20  69 6e 70 75 74 20 74 65  |You can input te|
00000010  78 74 20 68 65 72 65 21  0a 3e 3e 20 41 0a 00 00  |xt here!.>> A...|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 b0 d3 39 53  |..............9S|
00000040  59 7f 00 00 4f 6e 63 65  20 6d 6f 72 65 20 61 67  |Y...Once more ag|
00000050  61 69 6e 21 0a 3e 3e 20                           |ain!.>> |
00000058

Once more again の前の内容を確認すると,

b0 23 e2 b4 ca 7f

b0 d3 39 53 59 7f

勘の良い人はこれを逆から読んで,共有ライブラリの何かの関数のアドレスを示していることに気づくと思います。

実際にこのアドレスが何かを調べるために,ローカル環境のASLRを無効にし,gdbで調べてみます。

$ sudo sysctl kernel.randomize_va_space=0

$ echo A | ./oneline | hexdump -C
00000000  59 6f 75 20 63 61 6e 20  69 6e 70 75 74 20 74 65  |You can input te|
00000010  78 74 20 68 65 72 65 21  0a 3e 3e 20 41 0a 00 00  |xt here!.>> A...|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 b0 03 b0 f7  |................|
00000040  ff 7f 00 00 4f 6e 63 65  20 6d 6f 72 65 20 61 67  |....Once more ag|
00000050  61 69 6e 21 0a 3e 3e 20                           |ain!.>> |
00000058

$ gdb -q ./oneline
gdb-peda$ b main
gdb-peda$ r 
gdb-peda$ info  symbol 0x7ffff7b003b0
write in section .text of /lib/x86_64-linux-gnu/libc.so.6

どうやらwriteのアドレスがリークしているようですね。

(続く)