プロジェクトタイトル
CVE-2021-3156 sudo エクスプロイト生成ツール
インストール
- 依存関係をインストールする ./install.sh
- エクスプロイト生成ツールを実行する: ./run.sh
- システムのsudoバージョンが脆弱である場合、インストールされているバージョン用のエクスプロイトが生成されます。
- エクスプロイトは exploit.c とバイナリ ./exploit に生成されます。
要件
- gdb gcc make python3 python3-distro
- glibc(tcache対応)
- 現時点では、Ubuntu、Debian のオペレーティングシステム。
テスト済み
- Ubuntu 20.04.1
- Ubuntu 20.04.2
- Ubuntu 20.10
- Ubuntu 18.04.5
- Debian 10.7.0
著者
脆弱性
- sudo は main の parse_args 関数でメタ文字をエスケープします。
- その後、set_cmnd でスペースが続かないエスケープ文字が削除されます。
- sudo は parse_args が set_cmnd の前提条件であると想定しています。
- 問題は、各パーサーの条件が異なることです。1つ目はモードが (MODE_RUN && MODE_SHELL) の場合に実行されます。2つ目はモードが (MODE_RUN | MODE_EDIT | MODE_CHECK) かつ (MODE_SHELL|MODE_LOGIN_SHELL) の場合に実行されます。
- 最初のパーサーを実行せずに2番目のパーサーを実行する方法があります: sudoedit -s
- set_cmnd は引数のサイズを計算し、それらを連結するためにヒープにチャンクを作成します。その後、各引数を null バイトが見つかるまでコピーし、次の引数に進みます。入力引数が '\' で終わる場合、set_cmnd はエスケープ文字をスキップし、null バイトをコピーしますが、次の引数を同じ引数としてコピーし続けます。これによりヒープ上でバッファオーバーフローが発生します。
- したがって、最後の引数が '\' で終わる場合、set_cmnd は最初の環境変数の内容でバッファをオーバーフローさせます。この環境変数が '\' で終わる場合、次の変数をコピーし続けます。
エクスプロイト生成ツール
- (https://packetstormsecurity.com/files/161160/Sudo-Heap-Based-Buffer-Overflow.html) で説明されている方法2を使用します。
- sudo はオーバーフロー後に glibc nsswitch を使用して group データベースを読み取ります。
- nsswitch は nsswitch.conf のすべてのデータベースとサービスを保持する service_table データ構造をヒープに作成します。
- group のサービスは struct service_user 型を持ちます。
- 構造体にはサービスの名前を持つ name フィールドがあります。
- nsswitch は、group データベースの各サービスに対して /etc/nsswitch.conf の設定に基づいて libnss_[サービス名]_.so.2 ライブラリを動的にロードします。
- library ポインタはクラッシュを防ぐために NULL に上書きする必要があります。さらに、これによりライブラリがメモリに再ロードされ、今回はシェルコードを含むローカルライブラリがロードされます。
- ヒープグルーミング(feng shui)手法が使用されます。可変サイズの「ローカル」環境変数を作成してヒープにレイアウトを生成し、set_cmnd が引数をコピーするチャンクを目標(group の service_user 構造体)に近づけます。
- set_cmnd の malloc が実行される直前に、ヒープの tcache を調べて、リサイクルされる最初のチャンクとそのサイズを確認します。
- nsswitch のデータベースとサービスを構成するチャンクを並べ替えます。順番に走査し、目標チャンクとその前のチャンクのメモリアドレスを保存します。
- その範囲内のチャンクを tcache bin から探します。
- チャンクの位置とサイズがわかれば、エクスプロイトが生成されます。
- そのチャンクがリサイクルされるように、正確なサイズの '\' で終わる引数と null バイトが使用されます。
- 適切なレイアウトを作成するために、正確な「ローカル」環境変数が作成されます。
- これらの「ローカル」変数の前に、目標構造体に到達するために必要なサイズの環境変数が生成されます。
- エスケープ文字 '\' を含む文字列配列を使用して目標構造体を null バイトで上書きします。これにより、set_cmnd で null バイトが書き込まれます。
- service_user の name を 'x/x' で上書きし、後で 'libnss_x/x.so.2' ライブラリがロードされるようにします。
- ライブラリ内にシェルコードを実行するコンストラクタが作成されます。
- sudo は suid ビットで実行されるため、シェルは root 権限になります。
ライセンス
このプロジェクトは GNU GPL ライセンスの下にあります。