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 のバイナリモードで編集できる。
変更が終わったら、再度トレースしてみる。
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)のパスワードが判った。
これにて一件落着。
今日はここまで。ばいちゃ。
この記事が気に入ったらサポートをしてみませんか?