SlideShare a Scribd company logo
Microsoft Windows
カーネルのデスノート
Windowsカーネルの内部
$whoami
• @zer0mem
• Tencent KeenLabのWindows
カーネル研究者
• Pwn2Own優勝者(2015/2016)、
wnieにノミネート(2015)
• ファジングで注目するもの:
state
• 武術太極拳拳士
Daniel
• @long123king
• Tencent KeenLabのWindows
カーネル研究者
• Pwn2Own優勝者(2016)
• ファジングで注目するもの:
データ「フォーマット」
• Windbgの専門家
Peter
アジェンダ
sandbox
ntoskrnl
拡張
clfs
内部
Sandbox
• 攻撃対象領域を制限
• バグに対する潜在的景観
• それを悪用するために利用可能なメソッド
• ACL vs さまざまなカーネルオブジェクトへのアクセス
• 非ntos、非w32kドライバー
• さまざまなntosオブジェクト
• w32kフィルタリング
• sandbox化されたアプリが必要とするものに依存
• w32kロックダウン
Sandboxのターゲット
mutex
メモリ
スレッド PE
セクション
パイプ ...
... 他には?
• Nt*トランザクション*
• Nt*エンリストメント*
• Nt*マネージャ*
何だろう?
• カーネル トランザクション マネージャ
• 目的
• カーネルトランザクションマネージャ(KTM)は、トランザクショ
ンを使うアプリケーション開発を可能とする。トランザクションエ
ンジン自体はカーネルの内部にあるが、トランザクションはシ
ングルホスト内または分散ホスト間でカーネルまたはユー
ザーモードトランザクション向けに開発可能。
• KTMは、トランザクションNTFS(TxF)やトランザクションレジス
トリ(TxR)を実装するために使われる。TxFは、NTFSファイル
システム内でトランザクション処理ファイルシステムの操作を
可能とする。TxFは、トランザクション処理レジストリの操作を
可能とする。KTMは、クライアントアプリケーションがトランザク
ションでのファイルシステムやレジストリ操作と連動することを
可能とする。
tm.sys
• シンプルなオブジェクトステート
• わずかなsyscallが利用可能
• それほど多くないコードが含まれている
• しかし面白い方法で相互接続される
• 結果:
• 1回のnullポインターの逆参照
• 1個の悪用可能な脆弱性
tmの回避
• tm.sys
単純目的のドライバー
• しかし、興味深い
モジュールが
バックエンドに含まれる
• CLFS.sys
CLFS.sys
• 目的
• 共通ログファイルシステム(CLFS)APIは、専用クライアントアプリケー
ションが利用できる高パフォーマンスの、汎用的なログファイル・サブ
システムを提供し、複数のクライアントが共有することでログアクセス
を最適化できる。
• ロギングまたはリカバリサポートを必要とするあらゆるユーザーモード
のアプリケーションが、CLFSを使用できる。
• 該当箇所
• データやイベント管理、そしてサーバーや企業アプリケーションを開発
する際にCLFSを使用可能。
• データ管理に対して���、以下とCLFSを使用可能:
• データベースシステム
• ストアアンドフォワードシステムなどのメッセージング
• オンライントランザクション処理(OLTP)システム
• その他トランザクションシステムの類
CLFS.sys
• トランザクションなど色々なものに、かなり統合されて
いる!
• C++コードベース
• 十分な攻撃対象領域を提供
• …しかし、AppContainer/信頼できないレベル、という
わけではない…
• いや、そうなのか?
NtCreateTransactionManager
• CLFSに依存
• 自身のチェックポイント用にCLFSを使う
• それゆえに、以下を暗示する:
• CLFSを開く
• CLFSを*パース*する
• CLFSと相互作用する
• では試してみよう!
CLFS - データファジング I.
• わたしは、カーネルのデータファジングのファンでは
ない
• わたしは、カーネルでデータのパーシングをすることには全くもっ
て強く反対している☺
• 手っ取り早い調査をしてみよう。以下のものならば
わたしもOK:
• ファイルをランダムに変更する
• 結果 = ゼロ
• わたしにとってナイスなもの。というか、わたしはあまり興味がな
い
• 本来のアイディアに立ち戻る!
CLFS - ステートファジング
• アプローチ 1.
• リバース・エンジニアリング:clfs.sys
• ioctl に行く
• ...あぁ、最初からやるのは面倒すぎる...
• アプローチ 2.
• MSDNドキュメントを読み通す
• そのAPI群がどのように動くかを理解する
• 自身または別のAPIを正常に呼び出すために必要なコール
スタック
• Qilin(わたし達の内部ファズツール)にそのロジックを実装する
• Qilinのロジックにほんの少し干渉する
bugz++
• 最初のファズツール試行の15分後、最初のクラッシュ
• …なんてこった
• しかしDDoSのみ
• それを除外
• 別のbugzが出現
• ここで再度考える… 結局、データ・ファジングは本当
にそんなに悪いアイディアなのか?
CLFS - データファジング II.
• リバースエンジニアリング:どこで & どのように
データがパースされるのか
• エントリー・ポイント: ClfsCreateLogFile
• 痛っ… マジック… ダミーのファズ防御
• I. crc
• II. 再配置が必要
CLFS - もっと真剣にファズしよう
• 既存コードの再実装は面倒すぎるが、そもそもそ
れは必要なのか?
CLFS - もっと真剣にファズしよう
• crcの実装と再配置は面倒く
さすぎる
CLFS { ステート、ダミー、強化 }
データ強化されたファズ
27% ++
データダミーファズ
40%
ステートファズ
33%
CLFSファジング戦略 => 結果
CLFSの内部
…その傘下にあるもの…
BLF (ベースログファイル) 形式
コントロールレコード
コントロールレコードシャドウ
ベースログレコード
ベースログレコードシャドウ
情報落ちレコード
情報落ちレコードシャドウ
[2セクター] レイアウト、拡張情報、情報落ちを含む
[2セクター] コントロールレコードのシャドウコピー
[0x3Dセクター] クライアント情報、コンテナ情報を含む。
[0x3Dセクター] ベースログレコードのシャドウコピー。
[1セクター] 情報落ちを含む。
[1セクター] 情報落ちレコードのシャドウコピー。
レコードヘッダー
修正上位バイト
セクター数
予備領域1 チェックサム
フォーマットのバージョン 予備領域2
予備領域3
現在のLSN
次のLSN レコードのオフセット配列(0x10 * DWORD)
固定オフセット
ストリームインデックス
マジック
セクター数
のコピー
コントロールレコード
レコードヘッダー(0x70バイト)
ダンプ数 マジック(0xC1F5C1F5000005F1C)
予備領域1 拡張フェーズ
拡張ブロック
インデックス
拡張ブロック
インデックス
シャドー
拡張後の
ブロックセクター
予備領域2 予備領域3
予備領域4
拡張前の
ファイルセクター
データ
ファイルセクター
情報落ちの種類
情報落ちフィールド
実際のレコード数 予備領域5
レコードパラメータの配列(0x18 * 数)
ベースログレコード
レコードヘッダー(0x70バイト)
ダンプ数 予備領域1 ベースログID(GUID)
クライアント記号のハッシュ配列(0x0B * QWORD)
+配列の終わり
コンテナ記号のハッシュ配列(0x0B * QWORD)
共有セキュリティディスクリプタ記号のハッシュ配列(0x0B * QWORD)
予備領域2
クライアント
数 予備領域3 予備領域4 予備領域5
コンテナ
数
クライアントコンテキストのオフセット配列(0x7C * DWORD)
コンテナコンテキストのオフセット配列(0x400 * DWORD)
予備領域6
更新シーケンス番号
コンテナレコード
レコードヘッダー(0x70バイト)
仮想LSN 補償処理が必要な次のLSN
直前のLSN レコードサイズ 次のレコードサイズ
フラグ レコードタイプ
データ
オフセット
シンボルヘッダー
タイプ(0xC1FDF006) サイズ チェックサム ネームオフセット
予備領域1 予備領域2
予備領域3
ブロックネーム
オフセット
ブロック属性
オフセット
クライアントコンテキスト
タイプ(0xC1FDF007) サイズ
ストリーム
インデックス
予備領域1 フラッシュスレッド
予備領域(0x28バイト)
予備LSN1 ベースLSN
最後にフラッシュされたLSN 最後のLSN
予備LSN2 予備LSN3
予備領域3(0x20バイト)
コンテナコンテキスト
タイプ(0xC1FDF008) サイズ コンテナファイルサイズ 予備領域1
物理コンテナ
インデックス
論理コンテナ
インデックス 予備LSN1
予備領域2フラグストリーム数
CClfsBaseFilePersisted::ReadImage
実際のレコード数
レコードパラメータの配列
コントロールレコード
レコードパラメータ
バッファポインタ サイズ オフセット
CClfsBaseFile::GetBaseLogRecord
CClfsBaseFile::GetBaseLogRecord(CClfsBaseFile* this)
xor eax, eax
cmp ax, [rcx+28h]
jz short locret_1C00335DB
mov rcx, [rcx+30h]
mov rcx, [rcx+30h]
test rcx, rcx
jz short locret_1C00335DB
mov eax, [rcx+28h]
add rax, rcx
locret_1C00335DB:
retn
CClfsBaseFile::AcquireMetadataBlock
Use of AcquireMetadataBlock
CClfsBaseFilePersisted::OpenImage
クライアント記号ハッシュ配列
ベースログレコード
コンテナ記号ハッシュ配列
SD記号ハッシュ配列
シンボルハッシュ関数
__int64 ClfsHashPJW(const struct _UNICODE_STRING *a1)
{
unsigned int v1 = 0, v4 = 0, v6;
PWSTR wchar_buffer = a1->Buffer;
const struct _UNICODE_STRING *v3 = a1;
if ( a1->Length & 0xFFFE ){
do{
int v5 = 0x10 * v1 + RtlUpcaseUnicodeChar(*wchar_buffer);
v6 = v5 & 0xF0000000;
if ( v5 & 0xF0000000 )
v5 ^= v6 >> 0x18;
v1 = v6 ^ v5;
++wchar_buffer;
++v4;
}
while ( v4 < (unsigned int)v3->Length >> 1 );
}
return v1;
}
強化CFLSフォーマットファジング
• ターゲットを熟知している場合、それを上手にファズで
きる。
• 現在わかっていること:
• BLFファイルフォーマット
• コントロールレコード
• ベースログレコード
• 記号ヘッダー
• クライアントコンテキスト
• コンテナコンテキスト
• コンテナレコード
• Clfs.sysは、これらのフォーマットをパースするための
固有のロジックを持っているが、それは十分頑強なの
だろうか?
強化CFLSフォーマットファジング
Select
Deserialize
Mutate
Immune
Serialize
push デシリアライズ
シリアライズ
抗体
強化CFLSフォーマットファジング
class CControlRecord : public CFormatBase<CControlRecord>
{
……
virtual bool serialize(ostream & out) const override;
virtual bool deserialize(istream & in) override;
virtual bool mutate() override;
……
};
class CBaseLogRecord : public CFormatBase<CBaseLogRecord>
{
……
virtual bool serialize(ostream & out) const override;
virtual bool deserialize(istream & in) override;
virtual bool mutate() override;
……
};
……
強化CFLSフォーマットファジング
bool CCLFSFormat::deserialize(istream & in)
{
……
m_controlRecord.deserialize(in);
m_controlRecordShadow.deserialize(in);
m_baseLogRecord.deserialize(in);
m_baseLogRecordShadow.deserialize(in);
m_truncateRecord.deserialize(in);
m_truncateRecordShadow.deserialize(in);
……
}
bool CCLFSFormat::mutate(istream & in)
{ …… }
bool CCLFSFormat::serialize(istream & in)
{ …… }
強化CFLSフォーマットファジング
CCLFSDocument::CCLFSDocument(const string filename)
:m_template_filename(filename)
,m_template_stream(filename, ios::in | ios::binary)
{
/* number: 0 */m_engine.registerFilter(make_unique<CCommonErrorBypass>());
/* number: 1 */m_engine.registerFilter(make_unique<CPOC_XXX_1>());
/* number: 2 */m_engine.registerFilter(make_unique<CPOC_XXX_2>());
/* number: 3 */m_engine.registerFilter(make_unique<CPOC_XXX_3>());
/* number: 4 */m_engine.registerFilter(make_unique<CPOC_XXX_4>());
/* number: 5 */m_engine.registerFilter(make_unique<CPOC_XXX_5>());
……
}
void CCLFSDocument::mutate()
{
m_clfs_format.mutate();
m_engine.triggerFilter(3, m_orginal_clfs_format, m_clfs_format);
}
強化CFLSフォーマットファジング
bool CPOCFilterEngine::triggerFilter(size_t filterIndex,
CCLFSFormat& originalFormat, CCLFSFormat& format)
{
bool b_triggered = false;
for (size_t i = 0; i < m_filters.size(); i++)
{
if (i == filterIndex)
{
m_filters[i]->infect(originalFormat, format);
b_triggered = true;
}
else
m_filters[i]->immune(originalFormat, format);
}
return b_triggered;
}
Q & A
ご清聴ありがとうございました!

More Related Content

[CB16] マイクロソフトウィンドウズカーネルのデスノート by Peter Hlavaty & Jin Long