Skip to content

This content is not available in your language yet.

2022/03/30 - アタッシェケースにおける DLL 読み込みに関する脆弱性

JVN#10140834
アタッシェケースにおける DLL 読み込みに関する脆弱性
https://jvn.jp/jp/JVN10140834/

再現手順

「アタッシェケース4」の実行ファイル(AttacheCase.exe)のある場所に、 悪意のある改変された「dwmapi.dll」を置くことで任意のコードが実行される可能性があります。

発生バージョン

ver.4.0.2.7 以前で発生。

回避・対応策

「アタッシェケース4」を最新版へすみやかにアップデートしてください。

具体的には、アタッシェケース4の動作に必要な「dwmapi.dll」を実行ファイル(AttacheCase.exe)のある場所を 検索するのではなく、 「system32」内のみに絞って検索し、読み込むように修正しました。

Program.cs
static class Program
{
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDefaultDllDirectories(uint directoryFlags);
// LOAD_LIBRARY_SEARCH_APPLICATION_DIR : 0x00000200
// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0x00001000
// LOAD_LIBRARY_SEARCH_SYSTEM32 : 0x00000800
// LOAD_LIBRARY_SEARCH_USER_DIRS : 0x00000400
private const uint DllSearchFlags = 0x00000800;
Program.cs
//----------------------------------------------------------------------
// アンマネージドDLLを動的にロードする
// Dynamically load unmanaged DLLs
// ref. https://stackoverflow.com/questions/8836093/how-can-i-specify-a-dllimport-path-at-runtime
// ref. https://anis774.net/codevault/loadlibrary.html
public class UnManagedDll : IDisposable
{
[DllImport("kernel32")]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32")]
static extern bool FreeLibrary(IntPtr hModule);
IntPtr moduleHandle;
public UnManagedDll(string lpFileName)
{
moduleHandle = LoadLibrary(lpFileName);
}
public IntPtr ModuleHandle
{
get
{
return moduleHandle;
}
}
public T GetProcDelegate<T>(string method) where T : class
{
IntPtr methodHandle = GetProcAddress(moduleHandle, method);
T r = Marshal.GetDelegateForFunctionPointer(methodHandle, typeof(T)) as T;
return r;
}
public void Dispose()
{
FreeLibrary(moduleHandle);
}
}

「dwmapi.dll」を読み込むときは、「system32」ディレクトリにあるものを直接ロードします。

Program.cs
//----------------------------------------------------------------------
// アンマネージドDLLを動的にロードする
// Dynamically load unmanaged DLLs
// ref. https://stackoverflow.com/questions/8836093/how-can-i-specify-a-dllimport-path-at-runtime
// ref. https://anis774.net/codevault/loadlibrary.html
public class UnManagedDll : IDisposable
{
[DllImport("kernel32")]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32")]
static extern bool FreeLibrary(IntPtr hModule);
IntPtr moduleHandle;
public UnManagedDll(string lpFileName)
{
moduleHandle = LoadLibrary(lpFileName);
}
public IntPtr ModuleHandle
{
get
{
return moduleHandle;
}
}
public T GetProcDelegate<T>(string method) where T : class
{
IntPtr methodHandle = GetProcAddress(moduleHandle, method);
T r = Marshal.GetDelegateForFunctionPointer(methodHandle, typeof(T)) as T;
return r;
}
public void Dispose()
{
FreeLibrary(moduleHandle);
}
}
Form1.cs
private void ChangeTheme(Control.ControlCollection container, bool fDark)
{
// dwmapi.dll 読み込みに関する脆弱性対策(直接 system32などのディレクトリーを指定する)
// Vulnerability countermeasure for dwmapi.dll loading (specify "system32" etc directory directly)
string dllPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "dwmapi.dll");
using (UnManagedDll dwmapiDll = new UnManagedDll(dllPath))
{
DwmSetWindowAttributeDelegate DwmSetWindowAttribute =
dwmapiDll.GetProcDelegate<DwmSetWindowAttributeDelegate>("DwmSetWindowAttribute");

2022/03/30 - アタッシェケースで作成された⾃⼰実⾏可能形式の暗号化ファイルにおけるDLL読み込みに関する脆弱性

JVN#61502349
アタッシェケースにおける DLL 読み込みに関する脆弱性
https://jvn.jp/jp/JVN61502349/

再現手順

「アタッシェケース#3」「アタッシェケース4」が出力する自己解凍書庫ファイル、 および本体「AttacheCase.exe」のある場所に、 特定のDLLファイルを置くことでDLLハイジャック(DLLプリロード)されることがあります。

以前にも「アタッシェケース#3」で報告されていた2017/07/13の脆弱性ですが、 具体的な対処方法もなく注意喚起に留まっていました。 しかし、前項のDLL読み込みの脆弱性対策を行うことで、この脆弱性も対処することが可能になりました。

発生バージョン

ver.4.0.2.7 以前で発生。
ver.3.1.6.0 以前で発生。

回避・対応策

「アタッシェケース4」「アタッシェケース#3」を最新版へすみやかにアップデートし、 発生バージョンで作成された自己解凍書庫ファイル形式(exe)の暗号化ファイルは、 最新版で作り直してください。

具体的には、前項の脆弱性対策と同じで、実行ファイルのある場所に特定のDLLファイルを読み込みに行くという Windowsのデフォルト仕様に対して、「SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)」で 検索する先を 「system32」に変更、指定することで回避しました。

ただし、Windows7 以降で、 KB2533623セキュリティパッチ のあたったOS上でないと、この脆弱性対策は有効になりません。 つまり Windows7 より前のバージョンではこの脆弱性は残ったままになりますのでご注意ください。

Program.cs
static class Program
{
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDefaultDllDirectories(uint directoryFlags);
// LOAD_LIBRARY_SEARCH_APPLICATION_DIR : 0x00000200
// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0x00001000
// LOAD_LIBRARY_SEARCH_SYSTEM32 : 0x00000800
// LOAD_LIBRARY_SEARCH_USER_DIRS : 0x00000400
private const uint DllSearchFlags = 0x00000800;
Program.cs
[STAThread]
static void Main()
{
// Countermeasure that "Font '?' cannot be found" error
// ref. https://chowdera.com/2022/03/202203241328277504.html
var font = System.Drawing.SystemFonts.DefaultFont; // Load first
// DLLプリロード攻撃対策
// Prevent DLL preloading attacks
try
{
SetDllDirectory("");
SetDefaultDllDirectories(DllSearchFlags);
}
catch
{
// Pre-Windows 7, KB2533623
SetDllDirectory("");
}

2018/08/30 - ディレクトリトラバーサルの脆弱性追加修正

JVN#62121133
アタッシェケースにおける複数のディレクトリトラバーサルの脆弱性
https://jvn.jp/jp/JVN62121133/

※今回の修正は、2018/08/05に入れた修正が不十分だったため、その対処を改めて施したものです。

再現手順

アタッシェケースでは、ATCファイルという独自のフォーマットを用いており、それに直接細工を施します。 オープンソースである「アタッシェケース」の暗号化処理の部分を改ざんし、ビルドしたものから 暗号化ファイルに格納される ファイルリストに不正な文字列を挿入したデータを作成します。

展開するファイルリストに、

”:\Windows\Temp\sample.txt"
": \Windows\Temp\sample.txt"
" :\Windows\Temp\sample.txt"
"z :\Windows\Temp\sample.txt"
" z:\Windows\Temp\sample.txt"
"1:\Windows\Temp\sample.txt"
"hoge:\Windows\Temp\sample.txt”

といったファイルパスを挿入したリストをアタッシェケースで作成し、暗号化した ファイル(*.atc)を展開したところ、 ユーザーの意図しない場所に暗号化ファイルが展開されました。

ただし、これは悪意ある第三者がそうした脆弱性を仕込むアプリケーションを 開発し、当該ファイルを生成しないといけないため、 危険度はやや低めとは思われます。

発生バージョン

ver.3.3.0.0 以前で発生。
ver.2.8.4.0 以前で発生。

回避・対応策

ユーザーはすみやかに最新版へアップデートしてください。

前回の修正では、正規表現を使って不正な文字列が入り込まないように弾くブラックリスト的なアプローチでしたが、 これではどうしてもいろいろと抜け道を作られてしまうため、この脆弱性公表をコーディネートしていただいた、 JPCERT/CC 様の ご提案により、復号時はいったんファイルパスの正規化を行い、 ユーザーが意図する正しい保存先かどうかチェックするホワイトリスト方式で対処しました。この場にてご助言に感謝いたします。

アタッシェケース#3

FileDecrypt3.cs
//-----------------------------------
// ディレクトリ・トラバーサル対策
// Directory traversal countermeasures
// 余計な ":" が含まれている
// Extra ":" is included
if (FilePathSplits.Length > 2)
{
fDirectoryTraversal = true;
InvalidFilePath = OutFilePath;
}
try
{
// ファイルパスを正規化
// Canonicalize file path.
OutFilePath = Path.GetFullPath(OutFilePath);
}
catch
{
fDirectoryTraversal = true;
InvalidFilePath = OutFilePath;
}
// 正規化したパスが保存先と一致するか
// Whether the canonicalized path matches the save destination
if (fDirectoryTraversal == false && OutFilePath.StartsWith(OutDirPath))
{
fd.FilePath = OutFilePath;
}
else
{
fDirectoryTraversal = true;
InvalidFilePath = OutFilePath;
}

アタッシェケース2

TAttacheCaseFileDecrypt2.cpp
// ディレクトリ・トラバーサル対策(ver.2.8.5.0~)
bool fDirectoryTraversal = false;
AnsiString CanonicalizePath = AnsiString(OutDirPath + tsv->Strings[0]);
if (CanonicalizePath.Length() < MAX_PATH) {
// ファイルパスを正規化
if (PathCanonicalize(lpPath, CanonicalizePath.c_str()) == true) {
// 正規化したパスが保存先と一致するか
if (AnsiString(lpPath).Pos(OutDirPath) != 1 ){
fDirectoryTraversal = true;
}
}
else{
fDirectoryTraversal = true;
}
}
else{
fDirectoryTraversal = true;
}

2018/08/30 - 動作設定ファイル(_AtcCase.ini)によって復号時に任意のスクリプトを実⾏可能な脆弱性

JVN#02037158
アタッシェケースにおいて任意のスクリプトを実行される脆弱性
https://jvn.jp/jp/JVN02037158/

再現手順

アタッシェケースには、実行ファイル、またはATCファイルと同⼀フォルダ内に細⼯された設定ファイル(_AtcCase.ini) が存在する場合、 ATCファイルの復号時に任意のスクリプトを実⾏可能な脆弱性が存在します。

発生バージョン

ver.3.3.0.0 以前で発生。 ver.2.8.4.0 以前で発生。

回避・対応策

ユーザーはすみやかに最新版へアップデートしてください。

動作設定ファイル(_AtcCase.ini)が所定の位置にあり、読み込まれるときには、ユーザーに対して読み込んでも 問題ないか? といったダイアログメッセージを出し、注意を促すように修正いたしました。 さらにver.3系では、 その脆弱性を考慮した上で、警告ダイアログメッセージを表示しないという設定も含まれています。

2018/08/05 - 複数のディレクトリトラバーサルの脆弱性

JVN#62121133
アタッシェケースにおける複数のディレクトリトラバーサルの脆弱性
https://jvn.jp/jp/JVN62121133/

※ 今回の脆弱性は、2017/01/16に報告された脆弱性をさらに派生させたものになっています。

再現手順

アタッシェケースでは、ATCファイルという独自のフォーマットを用いており、それに直接細工を施します。 オープンソースである「アタッシェケース」の暗号化処理の部分を改ざんし、ビルドしたものから 暗号化ファイルに格納されるファイルリストに不正な文字列を挿入したデータを作成します。

展開ファイル名に ”..¥” や ”../” を複数、または空白を混ぜたもの、存在しないドライブ名、“¥¥localhost” などを 含むファイルリストを作成し、アタッシェケースでATCファイルを展開したところ、ユーザーの意図しない場所に 暗号化ファイルが展開されました。

ただし、これは悪意ある第三者がそうした脆弱性を仕込むアプリケーションを開発し、 当該ファイルを生成しないといけないため、危険度はやや低めとは思われます。

発生バージョン

ver.3.2.3.0 以前で発生。 ver.2.8.3.0 以前で発生。

回避・対応策

ユーザーはすみやかに最新版へアップデートしてください。

こちらの具体的な修正としては、「復号処理」部分。不正な文字がパスに入ってきたら、この処理を中止するように修正

アタッシェケース#3

FileDecrypt3.cs
//-----------------------------------
// ディレクトリ・トラバーサル対策
// Directory traversal countermeasures
if (Regex.IsMatch(OutputFileData[0], @"^\d+:[a-zA-Z]:|\.\.\s*[\\/]|^\d+:\\\\"))
{
fDirectoryTraversal = true;
InvalidFilePath = OutputFileData[0];
}
FileDecrypt2.cs
// ディレクトリ・トラバーサル対策
// Directory traversal countermeasures
if (Regex.IsMatch(line, @"^\d+:[a-zA-Z]:|\.\.\s*[\\/]|^\d+:\\\\"))
{
e.Result = new FileDecryptReturnVal(INVALID_FILE_PATH, line.Split('\t')[0]);
return (false);
}
else
{
FileList.Add(line);
prefix = 2;
}
FileDecrypt2.cs
// ディレクトリ・トラバーサル対策
// Directory traversal countermeasures
if (Regex.IsMatch(line, @"^\d+:[a-zA-Z]:|\.\.\s*[\\/]|^\d+:\\\\"))
{
e.Result = new FileDecryptReturnVal(INVALID_FILE_PATH, line.Split('\t')[0]);
return (false);
}
else
{
FileList.Add(line);
prefix = 3;
}

アタッシェケース2

TAttacheCaseFileDecrypt2.cpp
// ディレクトリ・トラバーサル対策(ver.2.8.4.0~)
// Directory traversal countermeasures
if (TRegEx::IsMatch(tsv->Strings[0], "^[a-zA-Z]:|\.\.\s*[\\/]|\\\\")){
//'不正なファイルパスです。復号できません。';
MsgText = LoadResourceString(&Msgdecrypt::_MSG_ERROR_INVALID_FILE_PATH);
MsgType = mtError;
MsgButtons = TMsgDlgButtons() << mbOK;
MsgDefaultButton = mbOK;
Synchronize(&PostConfirmMessageForm);
delete DataList;
goto LabelTypeMiss;
}
TAttacheCaseFileDecrypt1.cpp
// ディレクトリトラバーサル対策(ver.2.8.4.0~)
if (TRegEx::IsMatch(tsv->Strings[0], "^[a-zA-Z]:|\.\.\s*[\\/]|\\\\")){
//'不正なファイルパスです。復号できません。';
MsgText = LoadResourceString(&Msgdecrypt::_MSG_ERROR_INVALID_FILE_PATH);
MsgType = mtError;
MsgButtons = TMsgDlgButtons() << mbOK;
MsgDefaultButton = mbOK;
Synchronize(&PostConfirmMessageForm);
delete DataList;
goto LabelTypeMiss;
}

2017/07/13 - 自己実行形式ファイルにおける任意のDLL読み込み(DLLハイジャック、DLLプリロード)

JVN#61502349
アタッシェケースにおける DLL 読み込みに関する脆弱性
https://jvn.jp/jp/JVN61502349/

再現手順

アタッシェケースで作成した自己実行可能形式の暗号化ファイルには、 DLL を読み込む際の検索パスに問題があり、意図しない DLL を 読み込んでしまう脆弱性が存在します。

Windows (32bit / 64bit) で攻撃者の用意したトロイの木馬として偽装した 「DWMAPI.DLL」や「DWrite.dll」などをディレクトリに置きます。 アタッシェケースで暗号化された自己実行可能形式ファイルをそのディレクトリに置きます。 当該EXEを実行すると、意図せずトロイの木馬が読み込まれ、実行されます。

なお、Windows 10 (64bit) で再現したその他ファイル名は次の通りです。

  • WTSAPI32.DLL
  • PROPSYS.DLL
  • MSIMG32.DLL
  • INDOWSCODECS.DLL
  • WINSTA.dll

発生バージョン

ver.4.0.2.7 以前で発生。 ver.3.1.6.0 以前で発生。

回避・対応策

「アタッシェケース4」「アタッシェケース#3」を最新版へすみやかにアップデートし、 発生バージョンで作成された自己解凍書庫ファイル形式(exe)の暗号化ファイルは、 最新版で作り直してください。

具体的には、前項の脆弱性対策と同じで、実行ファイルのある場所に特定のDLLファイルを読み込みに行くという Windowsのデフォルト仕様に対して、「SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)」で 検索する先を「system32」に変更、指定することで回避しました。

Program.cs
static class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDefaultDllDirectories(uint directoryFlags);
// LOAD_LIBRARY_SEARCH_APPLICATION_DIR : 0x00000200
// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0x00001000
// LOAD_LIBRARY_SEARCH_SYSTEM32 : 0x00000800
// LOAD_LIBRARY_SEARCH_USER_DIRS : 0x00000400
private const uint DllSearchFlags = 0x00000800;
Program.cs
static void Main()
{
// DLLプリロード攻撃対策
// Prevent DLL preloading attacks
SetDllDirectory(null);
SetDefaultDllDirectories(DllSearchFlags);

2017/01/16 - ディレクトリトラバーサルの脆弱性

JVN#83917769
アタッシェケースにおけるディレクトリトラバーサルの脆弱性
https://jvn.jp/jp/JVN83917769/

再現手順

アタッシェケースでは、ATCファイルという独自のフォーマットを 用いており、展開ファイル名をATCファイルに保存。

試しに展開ファイル名の先頭に ”..¥” を付け加えたATCファイルを作 成し、アタッシェケースでATCファイルを展開したところ、 展開先ディレクトリの親ディレクトリにファイルが展開された。

ただし、これは悪意ある第三者がそうした脆弱性を仕込むアプリケーションを 開発し、当該ファイルを生成しないといけないため、危険度はやや低めか。

発生バージョン

ver.3.0.1.5 以前で発生。 ver.2.8.2.8 以前で発生。

回避・対応策

ユーザーはすみやかに最新版へアップデートしてください。

アタッシェケース#3

FileDecrypt3.cs
//-----------------------------------
// ディレクトリ・トラバーサル対策
// Directory traversal countermeasures
if (OutputFileData[0].IndexOf(@"..\") >= 0)
{
fDirectoryTraversal = true;
InvalidFilePath = OutputFileData[0];
}
FileDecrypt3.cs
// Directory traversal countermeasures
if (fDirectoryTraversal == true)
{
e.Result = new FileDecryptReturnVal(INVALID_FILE_PATH, InvalidFilePath);
return(false);
}

2010/12/17 - 任意の実行ファイル読み込み(バイナリ・プランティング)

JVN#02175694
アタッシェケースにおける任意の実行ファイル読み込み
https://jvn.jp/jp/JVN02175694/

再現手順

アタッシェケースで、フォルダを復号したあとに、自動でフォルダを開くという動作設定を行う。 任意の圧縮ファイルと「explorer.exe」という名前の任意の実行 ファイルを同じフォルダに保存しておき、 対象ソフトウェアでその圧縮ファイルを展開した場合、同じフォルダにある任意の実行 ファイルが読み込まれてしまう。 USB メモリやネットワーク フォルダを介した攻撃に悪用される恐れがある。

発生バージョン

ver.2.69 以前で発生。

回避・対応策

ユーザーはすみやかに最新版へアップデートしてください。

TAttacheCaseFileDecrypt2.cpp
if ( fOpenFolder == true && fOpenFolderOnce == false ) {
ShellExecuteW(NULL, L"open", L"EXPLORER.EXE", FilePath.c_str(), FilePath.c_str(), SW_NORMAL); //脆弱性対策(ver.2.70)
//ShellExecuteW(NULL, L"explore", FilePath.c_str(), NULL, NULL, SW_NORMAL); //こちらでも正常動作したようだ
fOpenFolderOnce = true;
}

ShellExecute APIの5番目の引数が、NULL になっていたものを、 きちんと既定ディレクトリへ指定してあげることでした。