見出し画像

OverTheWire:Behemoth5

前回の記事で入手したパスワードで問題のサーバーに接続する。
ssh behemoth5@behemoth.labs.overthewire.org -p 2221

今回取り組むのは /behemoth/behemoth5 になる。
このプログラムを解析して、次レベル(behemoth6)のパスワードを入手することがゴールである。

ehemoth5@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

とりあえず実行してみる。

behemoth5@behemoth:~$ /behemoth/behemoth5
behemoth5@behemoth:~$ 

ありゃ?何も起きない。。
トレースして再度実行してみよう。

behemoth5@behemoth:~$ ltrace /behemoth/behemoth5
__libc_start_main(0x804872b, 1, 0xffffd774, 0x8048920 <unfinished ...>
fopen("/etc/behemoth_pass/behemoth6", "r")       = 0
perror("fopen"fopen: Permission denied
)                                  = <void>
exit(1 <no return ...>
+++ exited (status 1) +++

パスワードファイル(/etc/behemoth_pass/behemoth6) をオープンしようとしてエラーになったようだ。トレース実行ではSUID が無視されるのでファイルの読み取り権限が無かったようだ。

とりあえず、このプログラムを逆アセンブルしてどんなプログラムなのか見てみよう。アセンブラを1行ずつ読むのは面倒なので、どんな関数がコールされているかを眺めてみることにする。

behemoth5@behemoth:~$ objdump -d -M intel /behemoth/behemoth5 | cut -f 3- | grep -A200 '<main>:' | grep @plt
call   80485b0 <fopen@plt>
call   8048550 <perror@plt>
call   8048570 <exit@plt>
call   8048540 <fseek@plt>
call   80485a0 <ftell@plt>
call   8048520 <rewind@plt>
call   8048560 <malloc@plt>
call   8048500 <fgets@plt>
call   8048580 <strlen@plt>
call   8048510 <fclose@plt>
call   8048600 <gethostbyname@plt>
call   8048550 <perror@plt>
call   8048570 <exit@plt>
call   80485f0 <socket@plt>
call   8048550 <perror@plt>
call   8048570 <exit@plt>
call   80485e0 <atoi@plt>
call   8048530 <htons@plt>
call   80485c0 <memset@plt>
call   8048580 <strlen@plt>
call   80485d0 <sendto@plt>
call   8048550 <perror@plt>
call   8048570 <exit@plt>
call   8048610 <close@plt>
call   8048570 <exit@plt>

gethostbyname , socket, sendto という関数が並んでいることが判る。
どうやらファイルを読み込んで、どこかに通信するプログラムのようだ。

このプログラムの動作を把握するために、このプログラムがオープンするファイルのファイル名(/etc/behemoth_pass/behemoth6)を書き換え、権限エラーが起きないようにして、再度実行してみることにする。

まずは、パスワードファイルの代わりになるものを準備する。

ehemoth5@behemoth:/tmp/foo$ echo AAAAAAAAAAAAAAAAAAAAAAAAAA  > hoge
behemoth5@behemoth:/tmp/foo$ ls -l hoge
-rw-r--r-- 1 behemoth5 behemoth5 27 Jul 17 03:03 hoge

次に、このファイルのフルパスが 16進でどんなコードになるかを確認する。

ehemoth5@behemoth:/tmp/foo$ echo /tmp/foo/hoge | hexdump -C
00000000  2f 74 6d 70 2f 66 6f 6f  2f 68 6f 67 65 0a        |/tmp/foo/hoge.|

最後に、問題のプログラム(behemoth5)をコピーして、vi で編集する。
今回のような簡単な変更であれば、vi のバイナリモードで編集できる。

画像1

変更が終わったら、再度トレースしてみる。

behemoth5@behemoth:/tmp/foo$ ltrace ./behemoth5 
__libc_start_main(0x804872b, 1, 0xffffd774, 0x8048920 <unfinished ...>
fopen("/tmp/foo/hoge", "r")                     = 0x804b008
fseek(0x804b008, 0, 2, 0xf7fd2e28)              = 0
ftell(0x804b008, 0, 2, 0xf7fd2e28)              = 27
rewind(0x804b008, 0, 2, 0xf7fd2e28)             = 0xfbad2488
malloc(28)                                      = 0x804c170
fgets("AAAAAAAAAAAAAAAAAAAAAAAAAA\n", 28, 0x804b008) = 0x804c170
strlen("AAAAAAAAAAAAAAAAAAAAAAAAAA\n")          = 27
fclose(0x804b008)                               = 0
gethostbyname("localhost")                      = 0xf7fc7960
socket(2, 2, 0)                                 = 3
atoi(0x80489e4, 2, 0, 0xf7fd2e28)               = 1337
htons(1337, 2, 0, 0xf7fd2e28)                   = 0x3905
memset(0xffffd6a0, '\0', 8)                     = 0xffffd6a0
strlen("AAAAAAAAAAAAAAAAAAAAAAAAAA\n")          = 27
sendto(3, 0x804c170, 27, 0)                     = 27
close(3)                                        = 0
exit(0 <no return ...>
+++ exited (status 0) +++

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

このプログラムはパスワードファイルを読み取り、sendto() を使って内容をlocalhost に送信している。socket(2,2,0 ) となっているので、プロトコルは UDP、ポート番号はおそらくatoi() で変換している 1337 番だろう。

つまり、予め 1337/udp で待ち受けしておいて問題のプログラムを実行すれば良い。

実際にやってみよう。
nc で 1337/udp をバックグラウンドで待ち受け、問題のプログラムを実行し、送信されてきた文字列をチェックする。

behemoth5@behemoth:/tmp/foo$ nc -lu -p 1337 > hoge &
[1] 22107
behemoth5@behemoth:/tmp/foo$ /behemoth/behemoth5
behemoth5@behemoth:/tmp/foo$ cat hoge
mayiroeche

想定通りに動作して、次レベル(behemoth6)のパスワードが判った。

これにて一件落着。
今日はここまで。ばいちゃ。

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