こんな ASP スクリプトを作って IIS 5.1 で動かしてみたところ、エラーになりました。
IIS 5.0 では動いていたのに・・・
strCmd = "%windir%\system32\cmd.exe /c %windir%\system32\ping.exe localhost > C:\temp\pingtest.txt"
Set oShell = Server.CreateObject("WScript.Shell")
iRet = oShell.Run(strCmd, 0, True)
Response.Write(iRet)
ちなみにエラーは次のものでした。
Microsoft VBScript 実行時エラー (0x800A0046)
書き込みできません。
/test.asp, line 5
"書き込みできません" ってことは本当に書き込みができなかったんですけど、問題はどうして書き込みができなかったんだろう、ってことです。
多分アクセス権が足りなかったんだと思います。(IIS 5.1/6.0 は IIS 5.0 よりもセキュリティが厳しいので)
とりあえず IIS Out-Of-Process Pooled Application として実行されている dllhost.exe に windbg をアタッチして、SetLastError の第一引数に何が渡されているかを見ていきます。
0:023> bp kernel32!setlasterror "dd (esp+0x4) L1;g"
0:023> g
007efee0 00000102
006af0a0 000036b7
006af2bc 00000000
00e8f684 00000002
00e8f684 00000002
00e8ef28 000036b7
00e8e994 00000005
00e8e848 000036b7
(略)
E_ACCESSDENIED (0x5) がセットされているのが見えます。
怪しいのでこの時にブレークして中を見てみます。
0:023> bp kernel32!setlasterror "j poi(esp+0x4)==0x5 'kb1';'dd (esp+0x4) L1;g'"
0:023> g
007efee0 00000102
0076f0a0 000036b7
0076f2bc 00000000
00e8f684 00000002
00e8f684 00000002
00e8ef28 000036b7
(略)
ChildEBP RetAddr Args to Child
00e8e420 7c809392 00000005 7c95043d 00e8e4a0 kernel32!SetLastError
eax=00000005 ebx=c0000022 ecx=7c94fb71 edx=00000015 esi=00000005 edi=00000000
eip=7c8092c0 esp=00e8e424 ebp=00e8e430 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
kernel32!SetLastError:
7c8092c0 8bff mov edi,edi
ブレークしたのでスタックを見てみると、CreateFile でアクセス拒否されてます。
ちょっと前を見てみると、LoadLibraryEx が呼ばれています。
0:013> kb
ChildEBP RetAddr Args to Child
00e8e420 7c809392 00000005 7c95043d 00e8e4a0 kernel32!SetLastError
00e8e430 7c8112b2 c0000022 00e8e74c c0150008 kernel32!BaseSetLastNTError+0x17
00e8e4a0 7c814ade 00000000 80000000 00000005 kernel32!CreateFileW+0x390
00e8e708 7c801d3a 000d3130 00e8e730 00e8e74c kernel32!BasepLoadLibraryAsDataFile+0x125
00e8e76c 77bb13c2 00e8e914 00000000 00000002 kernel32!LoadLibraryExW+0x178
00e8e7bc 77f38c28 00e8e914 00e8e8fc 0014c888 VERSION!GetFileVersionInfoSizeW+0x31
00e8e8d8 77f38e05 00e8e914 00e8e8fc 00005021 SHLWAPI!GetFileVersionInfoSizeWrapW+0x54
00e8eb98 77f38d1d 0014c888 00000000 00000000 SHLWAPI!SHGetFileDescriptionW+0xa8
00e8eddc 77f38499 00e8ee84 00000000 00e8ee04 SHLWAPI!CAssocApplicationElement::_GetAppDisplayName+0xae
00e8edec 7d5e37db 0014c874 02170008 00000000 SHLWAPI!CAssocApplicationElement::QueryString+0x30
00e8ee04 7d5e3779 0014c874 02170008 00000000 SHELL32!_QueryString+0x17
00e8ee30 7d5e37bb 7d5e37c4 0000ffff 02170008 SHELL32!CAssocArray::_QueryElementAny<_FLAGGED_BYTE_BLOB * *>+0xb9
00e8ee50 7d5e3988 000c8a38 0000ffff 02170008 SHELL32!CAssocArray::QueryString+0x20
00e8ee74 77f3b800 000c8a40 00000042 00000004 SHELL32!CAssocArray::GetString+0x61
00e8eea0 7d5f218a 00000042 00000004 001424d4 SHLWAPI!AssocQueryStringW+0x5f
00e8f0f4 7d5f1df3 0013efe8 00000000 00e8f110 SHELL32!CShellExecute::_SetCommand+0x123
00e8f104 7d5f1dc5 0013efe8 00e8f124 7d5f18c4 SHELL32!CShellExecute::_DoExecCommand+0x19
00e8f110 7d5f18c4 00000001 00e8f1cc 0013efe8 SHELL32!CShellExecute::_TryInvokeApplication+0x49
00e8f124 7d5f17f6 000c1f98 00e8f1cc 00e8f164 SHELL32!CShellExecute::ExecuteNormal+0xb1
00e8f138 7d5f1792 00e8f164 0013c3cc 00e8f1cc SHELL32!ShellExecuteNormal+0x30
CreateFile のファイル パスは Null になっていますが、LoadLibraryEx でロードしようとしているモジュールを確認してみると、cmd.exe でした。
0:013> du 00e8e914
00e8e914 "C:\WINDOWS\system32\cmd.exe"
cmd.exe を実行しようとしてアクセス拒否にあっています。CreateFile は一時ファイルか何かなのでしょう。
cmd.exe の ACL をチェックしてみると、IUSR_computername(IIS 6.0 の場合は NETWORK SERVICE)に実行アクセス許可がありませんでした。ちなみにサイトには匿名アクセスを許可しています。
なので cmd.exe と、あわせて ping.exe に IUSR_computername の実行アクセス権を与えます。
そういやファイル出力先パス C:\temp にも IUSR_computername の書き込み許可が必要でしょう。これも許可します。
さらに実行していきます。
0:015> g
00f0d978 00000000
010cf70c 00000000
00f0d8c8 00000000
00f0d8c8 00000000
(略)
ChildEBP RetAddr Args to Child
00f0e98c 7c843606 00000005 00000000 00000000 kernel32!SetLastError
eax=00000005 ebx=00f0e9f0 ecx=7c94fb71 edx=00000015 esi=00000000 edi=00000018
eip=7c8092c0 esp=00f0e990 ebp=00f0e9c8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
kernel32!SetLastError:
7c8092c0 8bff mov edi,edi
またブレークしました。何をしているか見ていきます。
0:015> kb
ChildEBP RetAddr Args to Child
00f0e98c 7c843606 00000005 00000000 00000000 kernel32!SetLastError
00f0e9c8 769bbda2 00000644 00f0e9f0 76971a60 kernel32!ProcessIdToSessionId+0x93
00f0e9e8 769bcadf 00000000 7697ca10 7697c6e0 ole32!AddHydraSessionID+0x54
00f0f190 7698faba 009b3c48 00000000 00000015 ole32!ICoCreateInstanceEx+0x202
00f0f1b8 7698fa89 009b3c48 00000000 00000015 ole32!CComActivator::DoCreateInstance+0x28
00f0f1dc 7698faf7 009b3c48 00000000 00000015 ole32!CoCreateInstanceEx+0x1e
00f0f20c 70e51ebf 009b3c48 00000000 00000015 ole32!CoCreateInstance+0x37
00f0f228 70e21a03 009b3c48 70e17708 009b3c44 asp!ViperCreateInstance+0x18
00f0f24c 70e22060 009b4140 00002000 009b3c28 asp!CComponentObject::TryInstantiate+0x78
00f0f288 70e22124 009b4140 70e59394 7c9410ed asp!CComponentObject::Instantiate+0x26
00f0f2a4 70e4fef7 00000004 00f0f318 00000000 asp!CPageComponentManager::AddScopedUnnamedInstantiated+0x5f
00f0f2ec 70e4288f 0111d698 009b4140 00f0f390 asp!CTypelibCache::CreateComponent+0xc6
00f0f32c 770d73d0 009aaecc 0111d698 00f0f390 asp!CServer::CreateObject+0x66
00f0f34c 770d79e0 009aaecc 00000024 00000004 OLEAUT32!DispCallFunc+0x16a
00f0f3dc 70e43244 00133f1c 009aaecc 00000000 OLEAUT32!CTypeInfo2::Invoke+0x234
00f0f404 7327ae0e 009aaecc 60020002 73254dd0 asp!CDispatchImpl::Invoke+0x4d
00f0f458 7326bb13 0003b880 009aaecc 60020002 vbscript!CatchIDispatchInvoke+0x46
00f0f4a4 732639f6 0003aee0 009aaecc 60020002 vbscript!IDispatchInvoke+0x95
00f0f5b8 73254b01 0003aee0 009aaecc 60020002 vbscript!InvokeDispatch+0x13a
00f0f5dc 7326391f 0003aee0 009aaecc 60020002 vbscript!InvokeByName+0x42
asp!CServer::CreateObject ということは ASP スクリプトの Server.CreateObject の箇所でしょう。
なので文字列の引数を持っているはずです。
ダンプしてみると・・・
0:015> du 0111d698
0111d698 "WScript.Shell"
やっぱりありました。
WScript.Shell の実体はレジストリから C:\WINDOWS\System32\wshom.ocx とわかります。
これにも IUSR_computername の実行アクセス許可を与えます。
そしてさらに続けます。
0:013> g
00e8e848 000036b7
ModLoad: 5cd80000 5cd98000 C:\WINDOWS\System32\wshom.ocx
おっ、読み込まれました。
無事に実行され、C:\temp\pingtest.txt に ping の結果が出力されてました。
このデバッグでは、cmd.exe を実行しようとして拒否されたことがわかったときに同様に ping.exe や c:\temp にアクセス許可を与えなければならないことに気づかないと、ハマります。
この2つに対してのアクセス拒否は cmd.exe プロセス内で発生するので、ASP がホストされるプロセスをいくらデバッグしても何も引っかかってこないためです。
IIS 5.0 では動いていたのに・・・
strCmd = "%windir%\system32\cmd.exe /c %windir%\system32\ping.exe localhost > C:\temp\pingtest.txt"
Set oShell = Server.CreateObject("WScript.Shell")
iRet = oShell.Run(strCmd, 0, True)
Response.Write(iRet)
ちなみにエラーは次のものでした。
Microsoft VBScript 実行時エラー (0x800A0046)
書き込みできません。
/test.asp, line 5
"書き込みできません" ってことは本当に書き込みができなかったんですけど、問題はどうして書き込みができなかったんだろう、ってことです。
多分アクセス権が足りなかったんだと思います。(IIS 5.1/6.0 は IIS 5.0 よりもセキュリティが厳しいので)
とりあえず IIS Out-Of-Process Pooled Application として実行されている dllhost.exe に windbg をアタッチして、SetLastError の第一引数に何が渡されているかを見ていきます。
0:023> bp kernel32!setlasterror "dd (esp+0x4) L1;g"
0:023> g
007efee0 00000102
006af0a0 000036b7
006af2bc 00000000
00e8f684 00000002
00e8f684 00000002
00e8ef28 000036b7
00e8e994 00000005
00e8e848 000036b7
(略)
E_ACCESSDENIED (0x5) がセットされているのが見えます。
怪しいのでこの時にブレークして中を見てみます。
0:023> bp kernel32!setlasterror "j poi(esp+0x4)==0x5 'kb1';'dd (esp+0x4) L1;g'"
0:023> g
007efee0 00000102
0076f0a0 000036b7
0076f2bc 00000000
00e8f684 00000002
00e8f684 00000002
00e8ef28 000036b7
(略)
ChildEBP RetAddr Args to Child
00e8e420 7c809392 00000005 7c95043d 00e8e4a0 kernel32!SetLastError
eax=00000005 ebx=c0000022 ecx=7c94fb71 edx=00000015 esi=00000005 edi=00000000
eip=7c8092c0 esp=00e8e424 ebp=00e8e430 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
kernel32!SetLastError:
7c8092c0 8bff mov edi,edi
ブレークしたのでスタックを見てみると、CreateFile でアクセス拒否されてます。
ちょっと前を見てみると、LoadLibraryEx が呼ばれています。
0:013> kb
ChildEBP RetAddr Args to Child
00e8e420 7c809392 00000005 7c95043d 00e8e4a0 kernel32!SetLastError
00e8e430 7c8112b2 c0000022 00e8e74c c0150008 kernel32!BaseSetLastNTError+0x17
00e8e4a0 7c814ade 00000000 80000000 00000005 kernel32!CreateFileW+0x390
00e8e708 7c801d3a 000d3130 00e8e730 00e8e74c kernel32!BasepLoadLibraryAsDataFile+0x125
00e8e76c 77bb13c2 00e8e914 00000000 00000002 kernel32!LoadLibraryExW+0x178
00e8e7bc 77f38c28 00e8e914 00e8e8fc 0014c888 VERSION!GetFileVersionInfoSizeW+0x31
00e8e8d8 77f38e05 00e8e914 00e8e8fc 00005021 SHLWAPI!GetFileVersionInfoSizeWrapW+0x54
00e8eb98 77f38d1d 0014c888 00000000 00000000 SHLWAPI!SHGetFileDescriptionW+0xa8
00e8eddc 77f38499 00e8ee84 00000000 00e8ee04 SHLWAPI!CAssocApplicationElement::_GetAppDisplayName+0xae
00e8edec 7d5e37db 0014c874 02170008 00000000 SHLWAPI!CAssocApplicationElement::QueryString+0x30
00e8ee04 7d5e3779 0014c874 02170008 00000000 SHELL32!_QueryString+0x17
00e8ee30 7d5e37bb 7d5e37c4 0000ffff 02170008 SHELL32!CAssocArray::_QueryElementAny<_FLAGGED_BYTE_BLOB * *>+0xb9
00e8ee50 7d5e3988 000c8a38 0000ffff 02170008 SHELL32!CAssocArray::QueryString+0x20
00e8ee74 77f3b800 000c8a40 00000042 00000004 SHELL32!CAssocArray::GetString+0x61
00e8eea0 7d5f218a 00000042 00000004 001424d4 SHLWAPI!AssocQueryStringW+0x5f
00e8f0f4 7d5f1df3 0013efe8 00000000 00e8f110 SHELL32!CShellExecute::_SetCommand+0x123
00e8f104 7d5f1dc5 0013efe8 00e8f124 7d5f18c4 SHELL32!CShellExecute::_DoExecCommand+0x19
00e8f110 7d5f18c4 00000001 00e8f1cc 0013efe8 SHELL32!CShellExecute::_TryInvokeApplication+0x49
00e8f124 7d5f17f6 000c1f98 00e8f1cc 00e8f164 SHELL32!CShellExecute::ExecuteNormal+0xb1
00e8f138 7d5f1792 00e8f164 0013c3cc 00e8f1cc SHELL32!ShellExecuteNormal+0x30
CreateFile のファイル パスは Null になっていますが、LoadLibraryEx でロードしようとしているモジュールを確認してみると、cmd.exe でした。
0:013> du 00e8e914
00e8e914 "C:\WINDOWS\system32\cmd.exe"
cmd.exe を実行しようとしてアクセス拒否にあっています。CreateFile は一時ファイルか何かなのでしょう。
cmd.exe の ACL をチェックしてみると、IUSR_computername(IIS 6.0 の場合は NETWORK SERVICE)に実行アクセス許可がありませんでした。ちなみにサイトには匿名アクセスを許可しています。
なので cmd.exe と、あわせて ping.exe に IUSR_computername の実行アクセス権を与えます。
そういやファイル出力先パス C:\temp にも IUSR_computername の書き込み許可が必要でしょう。これも許可します。
さらに実行していきます。
0:015> g
00f0d978 00000000
010cf70c 00000000
00f0d8c8 00000000
00f0d8c8 00000000
(略)
ChildEBP RetAddr Args to Child
00f0e98c 7c843606 00000005 00000000 00000000 kernel32!SetLastError
eax=00000005 ebx=00f0e9f0 ecx=7c94fb71 edx=00000015 esi=00000000 edi=00000018
eip=7c8092c0 esp=00f0e990 ebp=00f0e9c8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
kernel32!SetLastError:
7c8092c0 8bff mov edi,edi
またブレークしました。何をしているか見ていきます。
0:015> kb
ChildEBP RetAddr Args to Child
00f0e98c 7c843606 00000005 00000000 00000000 kernel32!SetLastError
00f0e9c8 769bbda2 00000644 00f0e9f0 76971a60 kernel32!ProcessIdToSessionId+0x93
00f0e9e8 769bcadf 00000000 7697ca10 7697c6e0 ole32!AddHydraSessionID+0x54
00f0f190 7698faba 009b3c48 00000000 00000015 ole32!ICoCreateInstanceEx+0x202
00f0f1b8 7698fa89 009b3c48 00000000 00000015 ole32!CComActivator::DoCreateInstance+0x28
00f0f1dc 7698faf7 009b3c48 00000000 00000015 ole32!CoCreateInstanceEx+0x1e
00f0f20c 70e51ebf 009b3c48 00000000 00000015 ole32!CoCreateInstance+0x37
00f0f228 70e21a03 009b3c48 70e17708 009b3c44 asp!ViperCreateInstance+0x18
00f0f24c 70e22060 009b4140 00002000 009b3c28 asp!CComponentObject::TryInstantiate+0x78
00f0f288 70e22124 009b4140 70e59394 7c9410ed asp!CComponentObject::Instantiate+0x26
00f0f2a4 70e4fef7 00000004 00f0f318 00000000 asp!CPageComponentManager::AddScopedUnnamedInstantiated+0x5f
00f0f2ec 70e4288f 0111d698 009b4140 00f0f390 asp!CTypelibCache::CreateComponent+0xc6
00f0f32c 770d73d0 009aaecc 0111d698 00f0f390 asp!CServer::CreateObject+0x66
00f0f34c 770d79e0 009aaecc 00000024 00000004 OLEAUT32!DispCallFunc+0x16a
00f0f3dc 70e43244 00133f1c 009aaecc 00000000 OLEAUT32!CTypeInfo2::Invoke+0x234
00f0f404 7327ae0e 009aaecc 60020002 73254dd0 asp!CDispatchImpl::Invoke+0x4d
00f0f458 7326bb13 0003b880 009aaecc 60020002 vbscript!CatchIDispatchInvoke+0x46
00f0f4a4 732639f6 0003aee0 009aaecc 60020002 vbscript!IDispatchInvoke+0x95
00f0f5b8 73254b01 0003aee0 009aaecc 60020002 vbscript!InvokeDispatch+0x13a
00f0f5dc 7326391f 0003aee0 009aaecc 60020002 vbscript!InvokeByName+0x42
asp!CServer::CreateObject ということは ASP スクリプトの Server.CreateObject の箇所でしょう。
なので文字列の引数を持っているはずです。
ダンプしてみると・・・
0:015> du 0111d698
0111d698 "WScript.Shell"
やっぱりありました。
WScript.Shell の実体はレジストリから C:\WINDOWS\System32\wshom.ocx とわかります。
これにも IUSR_computername の実行アクセス許可を与えます。
そしてさらに続けます。
0:013> g
00e8e848 000036b7
ModLoad: 5cd80000 5cd98000 C:\WINDOWS\System32\wshom.ocx
おっ、読み込まれました。
無事に実行され、C:\temp\pingtest.txt に ping の結果が出力されてました。
このデバッグでは、cmd.exe を実行しようとして拒否されたことがわかったときに同様に ping.exe や c:\temp にアクセス許可を与えなければならないことに気づかないと、ハマります。
この2つに対してのアクセス拒否は cmd.exe プロセス内で発生するので、ASP がホストされるプロセスをいくらデバッグしても何も引っかかってこないためです。
No comments:
Post a Comment