ユーザーインターフェイス特権の分離 (英語: User Interface Privilege Isolation, UIPI)[1] とは、Windows Server 2008/Vista以降に、シャッターアタック(Shatter Attack、壊滅的攻撃)を防ぐために導入されたセキュリティ機能である。Windows NT 4.0以降、Object Managerを介して生成されるオブジェクトにはセキュリティ記述子が与えられ、そうしたオブジェクトへのアクセス制御は可能であったが、ウィンドウオブジェクトにはセキュリティ記述子は与えられず、ウィンドウ自体へのセキュリティ制御はできなかった。
UIPIと必須整合性制御により、同じ対話型デスクトップ内において、低い整合性で実行されているプロセスは、より高い整合性で実行されているプロセスに対して、DLLインジェクションやウィンドウメッセージAPI(SendMessage
/PostMessage
等)など、任意のコードを他プロセスに実行させることのできる操作を実行できない。
Windowsでは、任意のウィンドウオブジェクトを取得してそのオブジェクトに対してデータを送信する(WM_SETTEXT
)ことができるが、言い換えれば、悪意のあるデータを送りつけることが可能である。次の例において、もしメモ帳のプロセスが高い整合性レベルで実行されている場合、UIPIはこうした書き込みをブロックする[2]。
// ウインドウクラスを元に、メモ帳のウインドウを検索
HWND hwndNotepad = FindWindow(L"notepad", NULL);
// メモ帳のウインドウからエディトコントロールを取得
HWND hWndEdit;
EnumChildWindows(hWndEdit, EnumChildProc, (LPARAM)&hWndEdit);
// エディトコントロールに任意のテキストを設定
BOOL bResult = SendMessage(hWndEdit, WM_SETTEXT, 0, (LPARAM)L"text");
ただし、WM_NULL
、WM_MOVE
、WM_SIZE
、WM_GETTEXT
、WM_GETTEXTLENGTH
、WM_GETHOTKEY
、WM_GETICON
、WM_RENDERFORMAT
、WM_DRAWCLIPBOARD
、WM_CHANGECBCHAIN
、WM_THEMECHANGED
はUIPIのブロックする対象ではない[2]。特に、WM_GETTEXT
がブロックされないということは、高ILで実行されているプロセスのウィンドウオブジェクトのデータを読み取ることはできるということである[2]。
WCHAR wszBuffer[1024];
bResult = SendMessage(hWndEdit, WM_GETTEXT, sizeof(wszBuffer) / sizeof(WCHAR), (LPARAM)wszBuffer);
シャッター攻撃において、バッファーフローを引き起こせるメッセージはWM_COPYDATA
とWM_DROPFILES
などがある。例えば、送信側はWM_COPYDATA
の自身のサイズ(cbData
)を自由に設定できるため、もし受信側が受け取るサイズを静的に定義しているとオーバーフローが起こる可能性がある。当然、UIPIはこれを防ぐため導入されたため、このようなメッセージを低ILプロセスから高ILプロセスに送ることはできない[2]。
WCHAR wszData[] = L"message";
COPYDATASTRUCT data = { 0 };
data.cbData = sizeof(wszData); // 0xFFFFFFFFでもよい。
data.lpData = wszData;
SendMessage(hWndTarget, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&data);
整合性レベル「中(Medium)」以上のプロセスは、ChangeWindowMessageFilterEx
を使用して、特定の種類のメッセージを許可することができる[2]。
例えば、osk.exe
は画面にキーボードUIを表示し、 ユーザーがキーをクリックすると、その入力を背後のウインドウに送信する。 もし、背後のウインドウが昇格したプロセスによって作成されていても、UIPIによってブロックされるべきではない[2]。
こうしたUIアクセシビリティソフトウェアのような、他のソフトウェアのUIにアクセスするソフトウェアはUIPIが障壁となる。そのため、Windowsは以下の条件を満たしている場合に限り、UIPIの無効化を提供する[2]。
%SystemRoot%
もしくは%ProgramFiles%
にインストールされている。uiAccess
値がtrue
である。<requestedExecutionLevel level="..." uiAccess="true" />