Ouavls研究チームは2021年2月3日にsudoから発見された権限を昇格されることが出来る脆弱性CVE-2021-3156を発表した。当該の脆弱性はヒープオーバーフロー(Heap Overflow)を利用し、exploit成功時、管理者権限が獲得できる。
CVE-2021-3156脆弱性のexploitコードはcとpython2つの言語のバージョンでexploit-dbに公開された状態で、exploitコードが公開される前に既にsudoのセキュリティパッチが配布された。現在当該の脆弱性を発見したOuavls研究チームは脆弱性の確認ツールをホームページ( https://qualys-secure.force.com/customer/s/article/000006518 )で提供している。
Part 1では権限を昇格されることが出来る脆弱性の危険性と下記に表示されているsudoの脆弱性を分析後、当該の脆弱性に対して対応方法を提示した。今回Part 2ではsudoから発見された脆弱性の中でつい最近、発見されたCVE-2021-3156のメカニズムをソースコード分析で調べてみよう。
No | CVE | Description |
---|---|---|
1 | CVE-2015-5602 | sudoeitに入力するファイルのパスにワイルドカード文字(*)を使用して上位権限のファイル修正 |
2 | CVE-2016-7076 | wordexp関数に特定の因子を使用する応用プラグラムを実行してnoexec制限オプションが存在するsudoをバイパスして上位権限を獲得 |
3 | CVE-2017-1000367 | SELinuxモジュールが有効化されたシステムから有効性検証不備て制限された権限のsudoerが完全なroot権限を獲得 |
4 | CVE-2019-14287 | -uオプションの入力値の検証が不備な脆弱性を利用してコマンドを実行し、上位権限を獲得 |
5 | CVE-2019-18634 | pwfeedbackオプションが有効化されたsudoプロセスからパスワード入力値にオーバフローを起こして上位権限を獲得 |
6 | CVE-2021-3156 | sudoにバックスラッシュ文字に対するバッファオーバーフローが存在し、これを利用してroot権限を獲得 |
【▲ Part 1でから分析したsudo脆弱性のCVE番号リスト(参考:sudo 脆弱性分析及び対応方法 part.1)】
CVE-2021-3156脆弱性が存在しているsudoのソースコードにはパラメータでバックスラッシュ(¥)の文字列を入力してヒープオーバーフロー脆弱性を発せしさせることができるソースコードが存在する。当該のコードに接するためにはsudo実行時、-eもしくは、-l, -s2つのオプションがの設定が有効になっているべきだが、sudo内部で当該のオプションが同時に設定されないように作られているため、一般的なsudoコマンドでは脆弱性攻撃ができない。
しかし、sudoを「sudo」コマンドではなく「sudoedit」コマンドで実行する場合、プログラム内部で自動的に-eオプションが適用され、「sudoedit -s」コマンドを実行すると「sudo -e -s」オプションを適用したのと同じく実行ができるため脆弱性が存在するルーティンにアクセスできる。
続いて03. sudoソースコード分析のセクションでは下記に紹介されている脆弱なバージョンに該当するsudoのソースコードを分析してsudo脆弱性のメカニズムと一般udoコマンドで脆弱性の攻撃ができない原因、sudoeditコマンドを利用したバイパス方法について説明する。
区分 | 脆弱なバージョン | 危険度 |
---|---|---|
CVE-2021-3156 | sudo 1.8.2 ~ 1.8.31p2 sudo 1.9.0 ~ 1.9.5p1 | High |
【▲ CVE-2021-3156脆弱性があるsudoのバージョン情報】
sudoではコマンド実行時、オプションに従ってプラグを設定する。03. sudoソースコード分析のセクションで説明するプラグとsudo実行時に使用されるオプションのマッピング情報は下記になる。
プラグ | MODE_SHELL | MODE_RUN | MODE_CHECK | MODE_EDIT |
---|---|---|---|---|
オプション | s | – | l | e |
【▲ プラグとsudoオプションのマッピング情報】
sudoコマンド実行後、脆弱性が存在するルーティンに到着するまで2つの条件式を通る。当該の条件式はsudoコマンドを実行時に使用されたオプション(プラグ)設定有無をチェックする。2つの条件式(下記図のsection 1~3)を全て満足する場合ヒープオーバーフロー脆弱性が存在するルーティンにたどり着く。
【▲ sudoコマンド実行後、脆弱性が存在するルーティンにたどり着くまでの過程】
下記の図はsudo 1.8.31バージョンのソースコードのsudoers.cファイルの中にヒープオーバーフロー脆弱性が存在するset_cmnd()関数の内容である。上記の図Section 3に該当するルーティンでヒープオーバーフローが発生する詳細な過程は次になる。
Step1:line 866のバックスラッシュ(¥)エスケイプを解除するロジックにアクセスする際、fromポインター変数が示すバックスラッシュ(¥)文字列の後ろにNULL文字列が位置する。
Step2:line 867からエスケイプを行うためにfrom変数を増減させバックスラッシュ(¥)文字列の後ろに存在するNULL文字列を示すことになり、line 868からfrom変数がもう一回増減されることでNULL文字列の後ろの任意の値を読み込む。
Step3:line 867とline 868のロジックによって増減演算を総2回行い、NULL文字列をスキップすることline 865のwhile文の条件式(from変数がNULL値ではない場合まで実行)を無視する。従って、line 853から計算したヒープメモリのサイズを超える任意の値を続けて入力することができてヒープオーバーフロー脆弱性が発生する。
【▲ set_cmnd()関数の中にヒープオーバーフロー脆弱性が存在するルーティン】
次のソースコードはSection2に該当するルーティンで、当該のルーティンはsudoers.cファイルの中のset_cmnd()関数に存在する。脆弱なコードにアクセスするために2つの条件式を満足しなければならない。MODE_RUN(デフォルト実行プラグ), MODE_EDIT(-e), MODE_CHECK(-l)プラグの中で1つのプラグが設定されるべきで、MODE_SHELL(-s), MODE_LOGIN_SHELLプラグが設定される必要がある。
【▲ 脆弱性が存在するルーティンにたどり着くための条件】
しかし、sudoコマンドでは上記の図からチェックするプラグ(オプション)を同時に設定することができないようになっているため、一般的なsudoコマンドを活用した脆弱性は不可能である。
次の図はparge_args.cファイルの中のparge_args()関数の一部の内容で、sudoコマンドを実行する際に適用したオプションに従ってプラグを設定するルーティンである。脆弱性が存在するルーティンにたどり着くためにはMODE_EDIT(-e)もしくは、MODE_CHECK(-l)プラグとMODE_SHELL(-s)プラグを同時に適用して実行する場合line 532の条件式によってエラーメッセージが出力され、プログラムが終了される。
【▲ -e, -lオプションと-sオプションの同時適用を防ぐルーティン】
MODE_RUN(デフォルト実行プラグ) とMODE_SHELL(-s)プラグが同時に設定される場合でもparge_args.cファイル内にparse_args() 関数のline 571条件式によってline 588のエスケイプルーティンからバックスラッシュ(¥)文字列がエスケイプされ、脆弱性が存在するバックスラッシュ(¥)エスケイプルーティンへの進入が不可能である。
【▲ MODE_RUNプラグとMODE_SHELLプラグを適用時、バックスラッシュ(¥)文字列をエスケイプするルーティン】
しかし、sudoのシンボリックリンクファイルであるsudoeditコマンドでsudoを実行させる場合、基本的にMODE_SHELL(-s)プラグとMODE_EDIT(-e)プラグが設定されるため、脆弱性が存在するルーティンへの進入が可能である。従って、sudoコマンドの代わりにsudoeditコマンドで「sudoedit -s ‘¥’ ‘ 任意の文字列’ 」のようなペイロードを活用したヒープオーバーフロー脆弱性攻撃が可能である。
【▲ sudoeditコマンドでsudo実行時、設定されるプラグ】
現在CVE-2021-3156のexploitコードはOuavls研究チームのBaron SameditとStephen Tongが公開したCとpythonで作成された2つのコードがexploit-dbに公開されており、2つのコードは開発に使用された言語だけ違ってexploit過程は同じである。
exploit-dbに公開されたCVE-2021-3156のexploitコード「Sudo 1.9.5p1 – ‘Baron Samedit’ Heap-Based Buffer Overflow Privilege Escalation (1)」)( https://www.exploit-db.com/exploits/49521 )からは脆弱性攻撃のためのヒープオーバーフロー脆弱性の以外にもtimestamp.cファイル、timestamp_lock()関数に存在するレースコンディション(Race Condition)脆弱性を共に活用する。
exploitコードでは-sourceオプションで対象一般ユーザーのuidとgidの値を0に修正したpasswdファイルをパラメータで受信し、当該asswdファイルの内容を/etc/passwdファイルに上書きすることでroot権限を獲得する。
【▲ 改ざんされたpasswdファイルが攻撃に活用される過程】
exploitコードの中で攻撃のためのプロセスは下記になる。
Step1:-sourceオプションで改ざんされたpasswdファイルを受信した後、当該のファイル内容を環境変数に保存する。
Step2:レースコンディション攻撃に活用されるディレクトリを作成後、当該のディレクトリのシンボリックリンクを作成する。
Step3:-A -sオプションとバックスラッシュ(¥)文字列の後ろにヒープメモリインデックスを当たるための文字列をパラメータで設定後、sudoeditを実行する。この際、環境変数で保存されている改ざんされたpasswdファイルの内容はsudoのステックメモリの保存される。
上記のような過程はレースコンディション攻撃に成功するまで最大5000回まで繰り返して実行される。
【▲ 改ざんされたexploit-dbに公開されたCVE-2021-3156のexploitコード】
exploitコード実行時、実際にsudoeditに送信されるペイロードは下記になる。
【▲ exploitコード実行時、sudoeditに送信されるペイロード】
レースコンディション攻撃実行時、下記のようなランダムの作業ディレクトリが作成される。
【▲ exploitコード実行時、ランダムで作成されるディレクトリ】
レースコンディション攻撃に成功時、timestamp.cファイルのtimestamp_lock()関数の中、line 657によって-sourceオプションで受信されてステックに保存されていたpasswdファイルの内容が/etc/passwdファイルに上書きすることになり、攻撃が成功する。
【▲ sudoのステックメモリに保存された改ざんされたpasswdファイル】
【▲改ざんされたpasswdファイルを/etc/passwdファイルに上書きするルーティン】
攻撃試演環境はexploitコードの開発者がテストしたOSのバージョンとsudoバージョンは同一に構成して行った。
区分 | バージョン |
---|---|
sudo | 1.8.31 |
OS | Ubuntu 20.04.1 |
【▲ PoC試演に使用したsudoのバージョンとOSの種類及びバージジョン】
root権限を獲得する対象である一般ユーザーのuid値を確認する。現在1000に設定していることが確認できる。
【▲ 対象一般ユーザーのuid値】
/etc/passwdファイルをfake_passwdの名前でコピー後、fake_passwdファイルの中のtestユーザーのuidとgidを0に修正する。
【▲ パラメータで送信する改ざんさてたpasswdファイル】
【▲ 対象ユーザーのuid, gidを0に改ざんしたpasswdファイルの内容】
https://www.exploit-db.com/exploits/49521 からCVE-2021-3156 python exploit codeをダウンロード後、修正したfake_passwdファイルを-sourceオプションを使い、python 3.Xバージョンに実行させる。
「success at iteration ・・・」メッセージの後、testユーザーでログインする。ユーザー名とuidがそれぞれrootと0に変更されていることが確認できる。
【▲ exploit成功時、発生するメッセージ】
【▲ exploit成功後、uidが0に変更されてroot権限を獲得した画面】
/etc/passwdファイルの中のtestユーザーのuidが0に変更されたことが確認できる。
【▲ 改ざんされたpasswdファイルの内容で変更された/etc/passwdファイルの内容】
systemtapスクリプトを活用してsudoeditコマンドの実行を遮断することができる。当該のスクリプトを実行すると、sudoeditコマンドは使えなくなり、既存sudoeditの機能はsudo -eコマンドで使える。但し、システムを再起動するとスクリプトをまた実行する手間がかかる。
Step1:必要なsystemtapパッケージ及び依存関係のパッケージインストール
【▲ systemtapパッケージ及び依存関係のパッケージインストール】
RedHat7もしくは、RedHat6, 8ではdebuginfoパッケージを追加でインストールする。
【▲ RedHat7の場合、debuginfoパッケージインストール】
【▲ RedHat6, 8の場合、debuginfoパッケージインストール】
Step2:ファイル名をsudoedit-block.stapに変更し、systemtapスクリプトを作成する。
【▲ sudoedit-block.stapファイルのsystemtapスクリプトの内容】
systemtapスクリプトがバックグラウンドで動作される間、sudoeditコマンドが使えないことが確認できる。
脆弱なバージョンのsudoを使用時、脆弱性が解決された最新バージョンへのアップデートが必要である。
No | 脆弱なバージョン | セキュリティパッチバージョン | パッチ日付 |
---|---|---|---|
1 | 1.8.2 ~1.8.31p2 | 1.8.32 | 2021-02-09 |
2 | 1.9.0 ~ 1.9.5p1 | 1.9.5p2 | 2021-01-26 |
【▲ 脆弱性がパッチされたsudoのバージョン情報】
【▲ sudoバージョン確認】
「sudoedit –s '¥' perl –e 'print "A" x 65536'
」ペイロードで現在、使用しているsudoの脆弱性の存在有無の確認ができる。脆弱性が存在するsudoの場合エラーが発生する。
【▲ 使用中のsudoに脆弱性が存在する時、発生するメッセージ】
脆弱性がパッチされたudoの場合「usage:」のメッセージが発生する。
【▲ 使用中のsudoに脆弱性が存在しない時、発生するメッセージ】
下記は脆弱性がパッチされたsudo 1.8.32のソースコードsudoers.cファイルの中のset_cmnd()関数の内容である。既存脆弱性が存在するルーティンにヒープメモリり割り当てる際に計算したサイズとパラメータに送信された文字列のサイズを計算してヒープオーバーフロー攻撃を防ぐロジックが追加された。
【▲ ヒープオーバーフローの攻撃を防ぐために追加されたロジック】
Part 1では「CVE-2019-14287」と「CVE-2019-18634」、今回のPart 2では「CVE-2021-3156」について調べてみた。sudoユーティリティは管理者権限でプロセスをが実行できるため、悪用された時、システムに大きな被害を及ぼす。特に「CVE-2021-3156」脆弱性の場合は今年、2021年2月に発見された脆弱性であり、今でもハッカーは頻繁に使用されている主要プロセスの脆弱性を探している。そのため、最新バージョン確認も含め、適切なセキュリティ対応が必要である。
[1] CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit)
https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit
[2] Sudo 1.9.5p1 – ‘Baron Samedit ‘ Heap-Based Buffer Overflow Privilege Escalation (1)
https://www.exploit-db.com/exploits/49521
[3] Privilege escalation via command line argument parsing – sudo – (CVE-2021-3156)
https://access.redhat.com/security/vulnerabilities/RHSB-2021-002
[4] Dashboard Toolbox – VMDR DASHBOARD: Baron Samedit | Heap-based buffer overflow Sudo
https://qualys-secure.force.com/customer/s/article/000006518
Written by CYBERFORTRESS, INC.
Tweet