他人の空似

2019 年 3 月 30 日

/DYNAMICBASE一問一答

Filed under: 解析 — 中の人 @ 5:15 PM

/DYNAMICBASEオプションによるベースアドレスのランダマイズ(以下ASLR)について、わかっているようでわかっていない人も多いかと思ったので細かい挙動についてまとめておきます。

なお以下はすべてWindows10 1809におけるもので、それ以降やそれ以前では異なることがあります。

Q:ASLRってなに?
A:この場で言うASLRは.exeや.dllがメモリ上にマップされるときのアドレスをランダムにしようぜって機能のこと

Q:どういう恩恵があるの?
A:攻撃されたときにアドレスがばれているかどうかは、攻撃者がLv1魔王とLv100魔王ぐらいには変わる、当然隠していた方がよい

Q:.exeはどれぐらいランダムなの?
A:実測したら254通り

Q:.exeのランダムの範囲は?
A:NULLページ(0x00000000のこと)や旧来のデフォルトベースアドレス(0x00400000-0x007F0000)を除いて0x00010000ごとに254か所の中からランダム
/BASEオプションが無指定なら0x00010000から、指定されていた場合そのアドレスから0x00FE0000引いたアドレスからになる

Q:.exeの再ランダマイズされる条件は?
A:OS再起動、またはtouchやコピーで属性が更新されたとき(アンロードや時間経過やリネームなどは含まれず)

Q:.dllはどれぐらいランダムなの?
A:仕様によれば256通りらしいが再起動必須であるため労力の関係から実測は叶わなかった

Q:.dllのランダムの範囲は?
A:以下推測も多く混ざる点に注意
OS起動時に0x7F000000-0x7FFF0000の間を0x00010000ごとに256か所の中からランダムで選ぶ
そこから後ろ詰めで1つでもロードされているDLLのアドレスを埋めていき、全プロセスでアンロードされたDLL部分を開放するを延々繰り返していると思われる

Q:.dllの再ランダマイズされる条件は?
A:OS再起動のみ
アドレス変化自体は全プロセスからアンロードしてから元アドレス付近が埋まるまで他.dllをロードし保持したまま改めてロードしなおせばよい
またはtouchやコピーで属性を更新した別dllを用意して別々に同時ロードするなどでもよい

Q:結局どういうこと?
A:.exeは254通りと少ないがランダマイズされているので比較的安心していい
.dllは.dll全体で1回のランダマイズなのでアドレスが1個でもばれたら全部ばれ得るので注意が必要


2019 年 3 月 26 日

DLLプリロード攻撃のチェッカーをリリース

Filed under: software — 中の人 @ 2:27 PM

前回の記事に関連して、DLLプリロード攻撃が可能なexeかのチェッカーを作りました。

DllPreloadingAttackChecker.zip

使い方はchecker.exeにチェックしたいexeをD&Dするだけ。

といっても所詮はDLLプリロード攻撃なので、NGとか出ても特におびえたりする必要はないです。
(というか誰の環境でも雑にexeなめたら山ほどNG出ると思う)

ただしインストーラーで出たら即開発元に連絡しよう、約束だぞ!

※2019/03/26 18:50頃追記

setup.exeだけ特別扱いしている問題に対応

※2019/03/28 21:10頃追記

DEPENDENTLOADFLAGに対応

2019 年 3 月 24 日

エクスプロイトを書きつつ学ぶWindowsセキュリティー機能 ~DLLプリロード攻撃~

Filed under: 未分類 — 中の人 @ 6:48 PM

前回までとは雰囲気を変えて防御手法ではなく攻撃手法に着目する回。

題材は「DLLプリロード攻撃」、それも特に静的リンクの物に絞ります。

簡単に説明すると、.exeと同じフォルダに細工した.dllファイルを配置するだけで.exe起動時に実行されてしまうよっていう攻撃のことです。

今回はこの攻撃の原理と防御法について一通り解説していきます。

いつものようにサンプルコード DllPreloadingAttack.zip

実演

百聞は一見に如かずということでまず実演してみましょう。

PrintVersion内のPrintVersion.exeを起動してみてください。

これは単にバージョンリソース内のバージョンを標準出力に出すだけの極々一般的なアプリです。

では次にexploit内のversion.dllをPrintVersion.exeと同じディレクトリに配置してからPrintVersion.exeを実行してみてください。

表示が変わりましたね 。

これがDLLプリロード攻撃です。

何が起きたのか

WindowsOSが提供するAPIは.dll形式でアプリに提供されています。

その機構に乗っかってアプリの一部を.dllに分離することもできます。

しかし、どの.dllを使うかはファイル名1つで決められているため、OS提供の物かどうかは.exe視点だと区別がついていません。

※LoadLibrary関数による動的ロードの場合はその限りではない

なのでOS提供の.dllの”一部”は、同名の.dllを特定ディレクトリに配置することで勘違いさせ無理やりロードさせることが可能なのです。

DLLの検索順序は公式に説明されています

この順序で検索して、本物の.dllより前に偽物の.dllを配置することが出来ると攻撃が成立するわけですね。

防御その1、書き込み不能ディレクトリに配置する

検索順序は要するに「.exeと同じディレクトリに同名の.dllがあるとそちらを優先して読んでしまう」です。

※カレントディレクトリの.dllを読んでしまうケースもありますが、そちらはOSの脆弱性として対処される流れのようです。

逆に言えば攻撃者がそこに書き込むことが出来ないならば、いくら脆弱でも問題はないわけです。

例えばProgram Filesがユーザー権限では書き込み不能なのはこのためです。

逆に言うと、Program Files以外に.exeを配置する場合(例:インストーラー)には別の対策が求められます。

防御その2、出来るだけ動的ロードを行う

LoadLibraryのロードでフルパスを指定することでDLLプリロード攻撃はおおよそ防ぐことが出来ます。

※後述しますがLoadLibraryが実装された.dll自体はDLLプリロード攻撃される恐れはありません。

そこでLoadLibraryとGetProcAddressを駆使してフルパスによる動的ロードを徹底することでDLLプリロード攻撃からは堅牢にすることが出来ます。

問題は、その作業がかなりの手間であり、実装コストが跳ね上がることでしょうか。

実際の修正例はPrintVersion_sono2として入れてあります。

実行例:

修正部(※一部):

typedef DWORD (WINAPI *GetFileVersionInfoSizeW_T)(
   _In_ LPCWSTR lptstrFilename,
   _Out_opt_ LPDWORD lpdwHandle
);
...
int main() {
   wchar_t versionPath[MAX_PATH] = { 0 };
   ::GetSystemDirectoryW(versionPath, _countof(versionPath));
   ::wcscat_s(versionPath, L"\\version.dll");
   const HMODULE module = ::LoadLibraryW(versionPath);
   const GetFileVersionInfoSizeW_T GetFileVersionInfoSizeW = reinterpret_cast<GetFileVersionInfoSizeW_T>(::GetProcAddress(module, "GetFileVersionInfoSizeW"));

防御その3、安全なDLLのみを使用する

検索順序で少し説明されていますが、Windowsにおいては絶対にシステムディレクトリから読まれる.dll名というのが存在します。

具体的には

  • NT Object Manager領域に公開されているKnownDLLsに含まれる.dll(レジストリの方じゃないので注意)
  • API Setに含まれる.dll
  • twain_32.dll

の3種類です。

KnownDLLsは以下

advapi32.dllbcrypt.dllbcryptPrimitives.dllcfgmgr32.dll
clbcatq.dllcombase.dllCOMCTL32.dllCOMDLG32.dll
coml2.dllCRYPT32.dllcryptsp.dlldifxapi.dll
gdi32.dllgdi32full.dllgdiplus.dllIMAGEHLP.dll
IMM32.dllkernel.appcore.dllkernel32.dllkernelbase.dll
MSASN1.dllMSCTF.dllmsvcp_win.dllMSVCRT.dll
NORMALIZ.dllNSI.dllntdll.dllole32.dll
OLEAUT32.dllpowrprof.dllprofapi.dllPSAPI.DLL
rpcrt4.dllsechost.dllSetupapi.dllSHCORE.dll
SHELL32.dllSHLWAPI.dllucrtbase.dlluser32.dll
win32u.dllwindows.storage.dllWINTRUST.dllWLDAP32.dll
wow64.dllwow64cpu.dllwow64win.dllWS2_32.dll

※Windows10 Version1809のもの

WinObjを使えばだれでも見れます、
各バージョン別の内容はhttps://windowssucks.wordpress.com/knowndlls/さんとかが追っているようです。

API Setはapi-ms-win-*あるいはext-ms-win-*で始まるdllのこと。

※関連してVirtualDLLの仕組みという記事を過去に書いたこともあります。

twain_32.dllは特例(あるいは過去の遺物)で、プリロードとLoadLibraryAに限って.dllまで省略せずに指定した場合のみシステムディレクトリからロードされる実装になっています。

おそらくは下位互換の都合でしょう。

これは例えばwindows互換OSを目指しているreactOSでも再現されています。

https://doxygen.reactos.org/de/de3/dll_2win32_2kernel32_2client_2loader_8c.html#ab6c0d4229db6159ce0cc96228f87b811

上記までに含まれる.dllのみを静的リンクする分にはDLLプリロード攻撃される心配はないので、その範囲でのみ実装することで堅牢にすることが出来ます。

実際にAPI Setを使用するようOneCore.libでリンクしたPrintVersion_sono3.exeが入れてあります。

※古いWindowsだとリンクエラーで動きません。

※API Set的にはapi-ms-win-core-version-l1-1-0.dllとapi-ms-win-core-version-l1-1-1.dllでリンクされていますが、version.dllをそちらの名前にリネームしても同様に正常動作します

組んだアプリが実際に大丈夫かはMSDNなど公式のドキュメントから得られるdll名と別途突き合わせてください。

防御その4、setup.exeにする

※2019/03/26 18:30頃追記

なんとsetup.exeというファイル名だと常に全.dllがシステムディレクトリから優先してロードされる挙動になる。

なんでもインストーラーがDLLプリロード攻撃される事例が相次いだために例外的対処として入ったとかどうとか……。

本当に最後の手段だが、setup.exeというファイル名を使うという手があることは覚えておいてもよいかもしれない。

防御その5、DEPENDENTLOADFLAGを設定する(Windows10限定)

※2019/03/28 21:00頃追記

VisualStudio C++のリンカオプションに/DEPENDENTLOADFLAG:0x00000800 を指定することでシステムディレクトリ以外の.dllとのリンクを抑止可能。

このオプションはLoadLibraryおよび起動時のリンク処理のデフォルト挙動を変更するオプションで、0x00000800はSystem32からのみ.dllを探索するように変更するもの。

当然ながらアプリケーションディレクトリに.dllを並べるタイプのアプリでは使用できない。

そういう場合は防御その1に書いた通りProgram Filesへ配置してください。

主にインストーラーや.exe単独で動作するアプリ向け。

詳しくはMSDNのDEPENDENTLOADFLAGおよびLoadLibraryExの仕様を参照してください。

ちなみにWindows10 RS1未満だとただ指定無視されて従来と同じ動きになります。

結論

Program Filesに置く以外の対策は非常に面倒かつ難しく、普通のプログラマーではミスなく終えるのはまず無理というのはわかってもらえたかと思います。

のでProgram Filesに置く運用大事。

とはいえMSは公式にアプリケーションディレクトリを介する攻撃について

アプリケーション ディレクトリにおける DLL の植え付けのカテゴリに該当する DLL の植え付けの問題は、多層防御の問題として扱われ、更新プログラムは将来のバージョンについてのみ検討されます。 ~中略~ その攻撃の本質はソーシャル エンジニアリングです。

https://blogs.technet.microsoft.com/jpsecurity/2018/04/10/triaging-a-dll-planting-vulnerability/

と述べており、基本的には脆弱性ではないとする方針のようです。

ちなみに一番問題になるのがインストーラーのケース(ダウンロードフォルダから実行されやすい)、次が特権実行されるアプリのケース(特権昇格に繋がる)です。

これらに該当しない場合、対応しなくても社会通念上許されることがほとんどです。

終わりに

私の作ったものにはこのdllプリロード攻撃を善用しているものが多数含まれています。

そういった関係から溜まった知識をダンプする目的で記述したため、他に比べると有用性は大分低い記事になったかもしれません。

ではまた、次を書く機会があればその時に。

2019/03/26 14:30追記:

脆弱かのチェッカー作ったのでよかったら見て
「DLLプリロード攻撃のチェッカーをリリース

2019 年 3 月 12 日

Mozillaに脆弱性を報告したら3年前から既知だと突っ返された話

Filed under: 未分類 — 中の人 @ 1:38 PM

さすがに3年放置しているとは思わんわ、あと検索機能馬鹿すぎて見つけられなかったのなんとかして。

概略

  • FirefoxとThunderbirdのインストーラーに特権昇格の脆弱性を見つける
  • 報告する
  • https://bugzilla.mozilla.org/show_bug.cgi?id=1269142 と重複と突っ返される
  • 些末にしろ3年放置はやめろ←今ここ

脆弱性詳細

インストーラーはまずユーザー権限で一時フォルダにファイルを展開し、特権を得てからそのファイルを実行したりProgram Filesにコピーしたりする。

当然一時フォルダはユーザー権限で書き換え可能なので、途中で実行される.exeを書きかえれば特権昇格、その他ファイルを書き換えればProgram Filesへの侵入(を経ての特権昇格)が可能。

またこれらへの対策も一切なく、実行.exeの署名検証やProgram Filesへコピーするファイルのホワイトリストなども存在しない。

よって特権昇格が可能である。

https://www.youtube.com/watch?v=DuhyTylF0T0

※C:\直下は特権なしではファイルを書き込めないのに書き込めている

PoC本体は https://resemblances.click3.org/product_list/index.cgi/detail/91 を参照のこと。

回答

2016-04-30 12:38投稿の https://bugzilla.mozilla.org/show_bug.cgi?id=1269142 と内容が重複しているとの回答があった。

見間違えじゃないぞ、2016年のとだ。

比較的些末とはいえ3年近くもの間特権昇格の脆弱性を放置するブラウザ……。

結論

Mozillaのインストーラーはこの調子だと何年でも脆弱なまま放置されそうなので、インストールするときは細心の注意を払おうな!

必要になったときだけインストールして即アンインストール運用は特に危険だぞ!

2018 年 5 月 20 日

cv2converterリリース

Filed under: 未分類 — 中の人 @ 1:18 PM

緋想天/非想天則内部形式の.cv2と.pngの相互変換ツールリリース。
http://wordpress.click3.org/garakuta/cv2converter.zip

単独では何の役にも立たないので適当に何かと組み合わせて下さい。
パレット型pngとか8bitカラーや16bitカラーも対応しようと思ったけど、手元の画像編集ソフトがことごとく非対応で作れなかったからもういいかなって。

touhouSE ver1.25リリース

Filed under: 未分類 — 中の人 @ 12:21 PM

東方系dat展開ツールtouhouSE更新しました。
http://wordpress.click3.org/garakuta/touhouSE.zip

  • 東方憑依華v1.10cに対応
  • ライセンス表記漏れを修正

単にパッチ追加分についてファイル名対応しただけです。
一個だけ不明なままですが、まぁいいかなと。

2018 年 4 月 17 日

touhouSE ver1.24リリース

Filed under: 未分類 — 中の人 @ 6:37 AM

東方系dat展開ツールtouhouSE更新しました。
http://wordpress.click3.org/garakuta/touhouSE.zip

  • コマンドライン引数のselect*/reject*/view-listを追加

以前からたまに発生していた”datから特定のファイル展開だけやらせたい人”がまた観測されたので
いい加減そういった使い方も出来るようにするかと機能追加しました。

具体的には

>touhouSE.exe select-glob *bgm*.ogg reject-glob *_20.ogg #{憑依華datのパス}

みたいにやると20秒版を除いた全BGMファイルだけを展開できます。

view-listつければ展開せずファイル名だけ出力してくれるので、狙った指定ができるまでの試行錯誤も安心!

2018 年 3 月 5 日

touhouSE ver1.23aリリース

Filed under: 未分類 — 中の人 @ 4:40 AM

東方系dat展開ツールtouhouSE更新しました。
http://wordpress.click3.org/garakuta/touhouSE.zip

  • 東方憑依華製品版(Steam/ディスク版)に対応
  • Steins;Gate0 PC版
  • DxArchiveV6に対応
  • nhtex=>dds=>pngといった多段変換に対応
  • コマンドライン引数で動作を変えられるように
  • tfwa形式で24bit形式が変換失敗していたのを修正
  • ファイル名に拡張子以外で.を含むファイルを含むアーカイブを二度連続で展開すると無限ループしていた不具合を修正
  • その他細かな変更色々

東方憑依華対応版です、Steam版と物理ディスク版どちらでも動くのを確認しています。
相変わらずファイル名は一方向ハッシュだったので一週間ほど逆算作業してました、楽しかった。

THxxBGMに東方憑依華製品版(Steam/ディスク)を追加するアプリリリース

Filed under: 未分類 — 中の人 @ 4:35 AM

THxxBGMに憑依華製品版の曲再生機能を足すアプリを作りました(引き続き深秘録と心綺楼も増える)。
http://wordpress.click3.org/garakuta/thxxbgmTh155Patch.zip

使い方は、中のwinmm.dllをTHxxBGM.exeと同じディレクトリに置くだけ。
うまいこと行けばpath設定に憑依華と深秘録と心綺楼が増えて、該当ディレクトリを設定すれば聞けるようになるはず。

2018 年 1 月 18 日

試行錯誤の最小化は本当に正しいのか?

Filed under: 未分類 — 中の人 @ 10:25 PM

駄文、もしくはポエムの類だ、嫌いな人はスルーしてほしい。

以降の記述はすべて”情報科学においては”と装飾されているものとする。
また一個人の考えであり、正しさを保証するものではない。


まず世間においては以下のような考えを主張する人が多くいる。
「ほとんどの問題はすでに解決した人がいるので、試行錯誤したら1時間かかることも探せば10分で答えが見つかる、だから試行錯誤は最低限に抑えるのが上達のこつだ」
これは自分も複数人から実際に聞かされているし、大体の場合は正しいと思う。
しかし自分は正しくないこともあると考えている、それも結構な確率で。

前提として探しても答えが見つからない場合にどうするかを考える。
もちろん組み合わせ爆発的な問題があるので実際試せばわかる程度のものは含めない、もっと根本的にそれが何かすらつかめていないレベルのものだ。
「ほとんどの問題はすでに解決した人がいる」を前提に話している以上は探し方が悪いと言いたいのだろう。
なので「答えを見つけられる探し方を探す」方向に進むか「解決不能な問題である」と諦めるべき、ということだと思う。
以降はこの前提を置いて進める。

では本題として前述の主張に対する欠陥を指摘する。
「ほとんどの問題はすでに解決した人がいる」が事実だとしても「解決しても公開する人は圧倒的少数派である」ことが抜けている。
例を出そう。
「ゲームコントローラーの入力を受けて、フォーカスが当たっているゲームに、任意のキーボードイベントを送りたい」という問題を考える。
これはjoytokeyというアプリで実際に解決されていて、具体的な方法はWin32APIのkeybd_eventの極一部のドキュメントにしか記載がないbScanという隠し機能を使うというものだ。
では、探すだけでこの具体的な方法にたどり着けるだろうか?
2018/01/18のgoogleによれば「joytokey」では260,000件あるが「joytokey keybd_event」では244件で「joytokey keybd_event bScan」は20件、実際に記載があったのは2件で、どちらも無関係な第三者が調べた結果だ。
試行錯誤なしにこの情報にたどり着くのは常人では難しいだろう、少なくとも自分だったら無理だ。
このように明確に解決した人がいても公開しないことは普通なのだ。

公開されないと何が問題かと言えば、誰かが解決済みでも自分は解決できないことが多数発生することだ。
少し考えればわかるだろう、ソース非公開の素晴らしいアプリがあったとしてそれを100%模倣することなど普通は出来ないのだから。
普段探して解決している問題は解決した人がたくさんいるから公開する人も多かっただけに過ぎない。
つまりほとんどの問題は探して解決するなどというのは幻想で、探すだけでは解決しない問題は大量に存在しており、ただそういう問題は直面する確率が低いだけなのだ。
そして1%の事象でも100個集まればそれなりに踏むように、これらの問題のどれかは結構な確率で踏む。
そんな時に毎回諦めるのは本当に良いことだろうか?そうして得られる知識だけで本当に上達したと胸を張れるのだろうか?
自分は違うと思う。

成長とはその技能そのもの以外にも、その技能関連問題をどれぐらい解決できるかも含むと自分は思っている。
なので、誰も教えてくれない知識に自力でたどり着けるようになることも成長だと思う。
もちろんたどり着けるようになる方法そのものを探して身に着けるということは否定しない。
しかしプログラミングなどのように実践しようと思えばいくらでも実践できる分野ではないので、ある程度は都度試行錯誤していくのがベターだと思う。
さすがに毎回探す前に試行錯誤するようでは問題あるとは思うが。

以上、試行錯誤しないと手に入らない知識ばかり気になってここまで来たのに否定されまくったことの愚痴でした。


ちなみに初手試行錯誤も自分は否定しない。
0から試行錯誤した経験はその知識に対して多角的視点を与えてくれる(プログラミング作業では車輪の再発明とも呼ぶ)。
コストが高すぎるので全てで行うことは馬鹿げているが、一切やらない人はそれはそれで愚かだと思う。
なので試行錯誤は用法用量を守って正しく行いましょう、というお話だったとさ。

Older Posts »

Powered by WordPress