
これは、@orange_8361 によって発見され、CsEnox によって PoC が作成された、イベントビューアのデシリアライゼーションを利用した UAC バイパスの Beacon Object File 実装です。

x64 の Win10/Win11 でテスト済み
この UAC バイパスは以下の操作を実行します。これらは OPSEC の観点で考慮する必要があります:
-1. %LOCALAPPDATA%\Microsoft\Event Viewer\RecentViews にバイナリファイルを書き込みます
-2. ShellExecute() を呼び出して mmc.exe / イベントビューアを起動します
--A. イベントビューアが GUI で開きます!
--B. イベントビューアが cmd.exe を呼び出します
---a. cmd.exe は mmc.exe を閉じるために Taskkill を呼び出します
---b. cmd.exe は、ユーザーに何も問題がないと思い込ませるため、時々開いたままになるコンソールウィンドウにエラーメッセージを表示します
---c. cmd.exe はユーザーが指定したその他のコマンドを実行します
-3. %LOCALAPPDATA%\Microsoft\Event Viewer\RecentViews からバイナリファイルが削除されます
オリジナルのデモと CsEnox の PoC に従い、ysoserial を使用して初期ペイロードを作成しました:

ysoserial.exe -o raw -f BinaryFormatter -g TextFormattingRunProperties -c "taskkill /f /im mmc.exe >nul && echo Windows has Recovered from an Unexpected Error. You may Close this Window. &&" > cmd.bin
この UAC バイパスは mmc.exe を起動することで動作します。mmc.exe は画面に表示され、閉じる必要があります。残念ながら、GUI を開かずに mmc.exe を起動する方法は見つかりませんでした。CreateProcess() と CREATE_NO_WINDOW フラグを試しましたが、CreateProcess() は UAC と相性が良くありません。このトピックに関する StackOverflow の投稿では、SW_HIDE フラグ(など)を持つ ShellExecuteA() API が示されましたが、これも有効ではありませんでした。mmc.exe が画面に一瞬表示されるのは避けられないようです。
Ysoserial は cmd.exe /c を呼び出すため、これを使用して taskkill を呼び出し、mmc.exe を閉じます。&& を使用してコマンドを連結し、管理者として実行したいアクションを実行できるようにします。テスト中に、場合によってはそのアクションが mmc.exe によって起動された cmd.exe プロンプトを開いたままにすることがわかりました。これは、デフォルトの Cobalt Strike 実行可能ペイロードのような Local Injector(通常)ペイロードを呼び出す場合に発生します。これに対処するため、taskkill コマンドの出力(以前は開いたままの cmd.exe に表示されていました)を /dev/null に送り、処理済みのエラーに関するメッセージを画面に echo して、この不審な動作が知識のないユーザーに警戒されないようにしようとしました。
プロセスを生成し、そこに注入して終了するペイロードは、cmd.exe ウィンドウを開いたままにしないため、メッセージは不要です。同様に、実行して終了するコマンド(例:net user Administrator newpassword)もウィンドウを開いたままにしません。
この BOF を介して、PowerShell エンコードコマンドを実行できます:



taskkill コマンドとユーザーへのメッセージは、ysoserial コマンドに組み込まれています。この動作を変更したい場合は、独自の ysoserial コマンドを実行し、以下のコード作成のデモに従う必要があります。
カスタムツールを使用して、バイナリファイルを読み込み、16進数で出力しました:

これをメモ帳にコピーし、16進数で '&' を検索すると、目的のバイトが見つかります(このセットは複数ありますが、最後のものが必要です):

ペイロードはこれらのバイトの直後で2つの部分に分割されます:

各部分の長さを計算し、後で使用するために記録します。
ここからが複雑になります。
正直なところ、デシリアライゼーションや ysoserial についてあまり詳しくないのですが、ペイロード内には、ユーザー定義のコマンドを含む「重要な」部分の長さを表すバイト列が存在することがわかりました。これは、ysoserial によって作成された異なるコマンドを含む2つのペイロードの16進ダンプを並べて比較した次のスクリーンショットで確認できます:

説明できない理由ですが、これらのバイトはペイロードの長さを base-128 で反映しています。0x05 は 128 倍されて 640 になります。これに、もう一方のバイト(0xb0 または 0xd4)の値から 128 を引いた値が加算されます。2番目のバイト(0x05)がオーバーフロー(0x06)すると、1番目のバイトは期待される 0x00 ではなく 0x80 から再開されることがわかりました。
このツールで使用されるペイロードは次のようになります:

すべての値を10進数に変換すると、計算は次のようになります:
(6 x 128) + (180-128) = 820
ファイルサイズは 1042 です。テストの結果、この ysoserial のガジェットでは、ファイルサイズとこのバイト列で表される長さの間には常に 222 バイトの差があることがわかりました。この 222 バイトはペイロードの「ヘッダー」であると思われます。
ペイロードの両方の部分が main.c にコピーされ、元の長さ 820 も変数として設定されます。ユーザーコマンドの長さが計算され、この値が元の 820 に加算されます(加えて、挿入する必要のあるスペースの1バイト)。これにより、このバイト列で表す必要のある最終的な値が計算されます。2番目のバイトは LenBytes を 128 で割って計算され、1番目のバイトは LenBytes の余りを求め、128 を加算して(0x80 から始まるように調整)計算されます。

これらのバイトが設定されると、それらは Before バッファ内の適切な場所にコピーされ、ペイロードの長さが内容に応じて適切な値に設定されます。最終的なバッファは次のように組み立てられます:

完成したペイロードはディスクに書き込まれ、mmc.exe が呼び出されて実行されます。その後、ペイロードはクリーンアップされます。
x86_64-w64-mingw32-gcc -o EventViewerUAC.x64.o -Os -c main.c -DBOF
Ysoserial には --rawcmd オプションがあり、cmd.exe とは異なる実行可能ファイルを呼び出すことができますが、引数を指定することはできません。これにより、cmd.exe を呼び出さずにペイロードを直接起動でき、コンソールウィンドウを開いたままにしない可能性があります。ただし、この場合、mmc.exe を閉じるための手段がありません。ペイロードを作成して、自身の親プロセスを特定し、それが mmc.exe であれば、mmc.exe を強制終了してこの UAC バイパスの後始末をすることができます。これは十分可能ですが、私はその手間をかけませんでした。なぜなら、これは数ある UAC バイパスの1つであり、誰もがそのようなカスタムペイロードを作成するわけではないからです。個人的なランナーに組み込むかもしれません。