Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2017-5123 — PoC CVE-2017-5123 - LPE - SMEP/SMAPの回避。KASLRなし | Kitploit
ツール/GitHubGitHub/c3r34lk1ll3r/cve-2017-5123
特権昇格エクスプロイト学習と教育バイナリエクスプロイトラボと実践
GitHubc3r34lk1ll3r/cve-2017-5123

CVE-2017-5123

PoC CVE-2017-5123 - LPE - SMEP/SMAPの回避。KASLRなし

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

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2017-5123

PoC CVE-2017-5123 - LPE - SMEP/SMAP のバイパス。KASLR なし

アップストリームカーネルの waitid 実装では、情報結果をコピーする際のコピー先が制限されていませんでした。これにより、ローカルユーザーが通常は保護されているカーネルメモリに書き込める可能性があり、権限昇格につながる可能性があります。

はじめに

この小さな writeup では、root 権限を取得できるカーネル脆弱性を分析します。

このファイルは4つのパートに分かれています:

  1. VM セットアップ;
  2. 脆弱性の解析;
  3. 悪用;
  4. PoC。

この CVE の悪用方法は他にもたくさんあります(実際、これはカーネル学習用の_PoC_に過ぎず、_実際の攻撃_では使えません)が、この方法論はカーネルエクスプロイトの入門として役立つと思います。

VM セットアップ

カーネルのビルド

この脆弱性は_4c48abe91be0_で導入されたため、そのバージョンのカーネルをビルドする必要があります。

これは古いバージョンであり、コードにパッチを当てる必要があるため、少し厄介かもしれません。 私は、既にパッチ済みのカーネルコードを含むリポジトリと、.configファイルを作成しました。これにより、_クローンしてビルド_することができます。

git clone https://github.com/c3r34lk1ll3r/kernel_mirror.git
cd kernel_mirror
git checkout origin/modified_v4.14
wget https://gist.githubusercontent.com/c3r34lk1ll3r/c9c34ae86140cc7a24d0d90141686ee8/raw/52431b577a71e3fe8f89d6ce355ce9c1c54c53b6/.config
make -j 8 --output-sync=recurse

このカーネルは_virtio_ドライバでビルドされるため、_virtio ディスク_を使ってVMとの間でファイルを共有できます。

Rootfs のセットアップ

次に、初期_rootfs_を作成します:

qemu-img create -f raw hda.raw 10G
# Format the disk to ext4
mkfs.ext4 ./hda.raw 
# Make a mountpoint for the image
mkdir /tmp/mount1
# Mount the disk
sudo mount -o loop ./hda.raw /tmp/mount1

次に、基本的なLinuxディストリビューションをインストールします。例えば、pacstrap や debootstrap を使用します。

sudo pacstrap /tmp/mount1 base base-devel vim

最後に、システムを変更できます:

# Add a 'test' user
echo 'test:x:1000:1000::/home/test:/bin/bash' | sudo tee -a /tmp/mount1/etc/passwd
# without password
echo 'test::14871::::::' | sudo tee -a /tmp/mount1/etc/shadow 
# we can mount a virtio disk in order to share files between host and guest
echo '/transient /home/test/shared 9p trans=virtio,version=9p2000.L,rw,user,exec 0 0' | sudo tee -a /tmp/mount1/etc/fstab
sudo mkdir -p /tmp/mount1/home/test/shared 
# It is usefull to have sudo permission
echo '%wheel ALL=(ALL) NOPASSWD: ALL' | sudo tee -a /tmp/mount1/etc/sudoers
echo 'wheel:x:998:test' | sudo tee -a /tmp/mount1/etc/group

sudo chown -R 1000:1000 /tmp/mount1/home/test
sudo umount /tmp/mount1

すべてが整っていれば、qemu でテストシステムを試すことができます:

qemu-system-x86_64 \
    -kernel ./kernel_mirror/arch/x86_64/boot/bzImage \
    -hda ./hda.raw \
    -m 4G \
    -cpu "Skylake-Client-IBRS,ss=on,vmx=on,hypervisor=on,tsc-adjust=on,clflushopt=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaves=on,pdpe1gb=on,ibpb=on,amd-ssbd=on,skip-l1dfl-vmentry=on,hle=off,rtm=off" \
    -smp 4 \
    -vga virtio \
    -enable-kvm \
    -nographic \
    -machine type=q35,accel=kvm \
    -virtfs "fsdriver=local,id=fs.1,path=./trans_fs,security_model=mapped,writeout=immediate,mount_tag=/transient" \
    -append "root=/dev/sda rw noquiet nokaslr console=ttyS0 loglevel=5" \
    -chardev "vc,id=vc.0,cols=1920,rows=1080" \
    -net "user,hostfwd=tcp::10022-:22" \
    -net "nic" \
    -s

脆弱性

CVE の説明には、waitid システムコール中に無制限の書き込み操作があると記載されています。

kernel/exit.c を開いてコードを見てみましょう:

SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
		infop, int, options, struct rusage __user *, ru)
{
    struct rusage r;
    struct waitid_info info = {.status = 0};
    long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
    int signo = 0;

    if (err > 0) {
        signo = SIGCHLD;
        err = 0;
        if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
            return -EFAULT;
    }
    if (!infop)
        return err;
    user_access_begin();
    unsafe_put_user(signo, &infop->si_signo, Efault);
    unsafe_put_user(0, &infop->si_errno, Efault);
    unsafe_put_user(info.cause, &infop->si_code, Efault);
    unsafe_put_user(info.pid, &infop->si_pid, Efault);
    unsafe_put_user(info.uid, &infop->si_uid, Efault);
    unsafe_put_user(info.status, &infop->si_status, Efault);
    user_access_end();
    return err;
Efault:
    user_access_end();
    return -EFAULT;
}

この関数は非常に単純です。いくつかのチェックの後、unsafe_put_user(...) の呼び出しがいくつかあり、関数は戻ります。

この関数の主要部分は unsafe_put_user(...) 関数で構成されているので、そこに移動しましょう(arch/x86/include/asm/uaccess.h):

/*
 * The "unsafe" user accesses aren't really "unsafe", but the naming
 * is a big fat warning: you have to not only do the access_ok()
 * checking before using them, but you have to surround them with the
 * user_access_begin/end() pair.
 */
#define user_access_begin()	__uaccess_begin()
#define user_access_end()	__uaccess_end()

#define unsafe_put_user(x, ptr, err_label)					\
do {										\
    int __pu_err;								\
    __typeof__(*(ptr)) __pu_val = (x);					\
    __put_user_size(__pu_val, (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);	\
    if (unlikely(__pu_err)) goto err_label;					\
} while (0)

#define unsafe_get_user(x, ptr, err_label)					\
do {										\
    int __gu_err;								\  
    __inttype(*(ptr)) __gu_val;						\
    __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);	\
    (x) = (__force __typeof__(*(ptr)))__gu_val;				\
    if (unlikely(__gu_err)) goto err_label;					\
} while (0)

コメントには重大な警告があります:unsafe_put/get_user を使用したい場合は、最初に access_ok() を呼び出し、それらを user_access_begin/end() で囲む必要があります。

先ほどのコード(waitid)を見ると、access_ok() が呼び出されていないため、このシステムコールはこの_警告_に_違反_しています。

しかし、これらのマクロとは何でしょうか?

SMAP/SMEP

SMAP と SMEP は、エクスプロイトを書きにくくするためにカーネルに導入された2つのセキュリティ機能です。これらの機能はCPUによって強制されることに注意してください。

SMEP は、CPUがスーパーバイザーモードのときにユーザースペースコードを実行することを防ぎます。一方、SMAP はユーザーメモリへの読み取り/書き込みアクセスをブロックします。

カーネルはユーザーメモリとの間でデータの読み書きを行う必要があり、これには2つの方法があります:

  1. カーネル空間でメモリをコピーできる関数(例:copy_from_user)を使用する;
  2. 一時的に SMAP を無効にする

unsafe_put_user の定義にあるように、この関数は ptr が指すメモリに x の値をコピーするだけです(エラーがあれば err_label にジャンプします)。先ほど、カーネルは SMAP のためにユーザースペースにアクセスできないと言いました。そのため、これらの関数は user_access_begin/end() で囲む必要があります。

#define __uaccess_begin() stac()
#define __uaccess_end()   clac()

見ての通り、user_access_begin/end は単に_ASM_命令の stac と clac です。

  • stac: "EFLAGS レジスタの AC フラグビットを設定します。これにより、ユーザーモードのデータアクセスのアライメントチェックが有効になる場合があります。CR4 レジスタで SMAP ビットが設定されている場合でも、スーパーバイザーモードからユーザーモードページへの明示的なデータアクセスが許可されます。"
  • clac: "EFLAGS レジスタの AC フラグビットをクリアします。これにより、ユーザーモードのデータアクセスのアライメントチェックが無効になります。CR4 レジスタで SMAP ビットが設定されている場合、スーパーバイザーモードからユーザーモードページへの明示的なデータアクセスは許可されません。"

基本的に、これらの2つのマクロは SMAP を有効/無効にします。

先ほどの「警告」は access_ok 関数にも言及しています:

/**
 * access_ok: - Checks if a user space pointer is valid
 * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
 *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
 *        to write to a block, it is always safe to read from it.
 * @addr: User space pointer to start of block to check
 * @size: Size of block to check
 *
 * Context: User context only. This function may sleep if pagefaults are
 *          enabled.
 *
 * Checks if a pointer to a block of memory in user space is valid.
 *
 * Returns true (nonzero) if the memory block may be valid, false (zero)
 * if it is definitely invalid.
 *
 * Note that, depending on architecture, this function probably just
 * checks that the pointer is in the user space range - after calling
 * this function, memory access functions may still return -EFAULT.
 */
#define access_ok(type, addr, size)					\
({									\
	WARN_ON_IN_IRQ();						\
	likely(!__range_not_ok(addr, size, user_addr_max()));		\
})

ここのコメントは一目瞭然です。このマクロはポインタが有効なユーザースペースポインタであるかをチェックします。

ツールをダウンロード