CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/nops/x64/simple.rb
Views: 11778
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Nop
7
8
def initialize
9
super(
10
'Name' => 'Simple',
11
'Alias' => 'x64_simple',
12
'Description' => 'An x64 single/multi byte NOP instruction generator.',
13
'Author' => [ 'sf' ],
14
'License' => MSF_LICENSE,
15
'Arch' => ARCH_X64 )
16
17
register_advanced_options( [ OptBool.new( 'RandomNops', [ false, "Generate a random NOP sled", true ] ) ])
18
register_advanced_options( [ OptBool.new( 'MultiByte', [ false, "Generate a multi byte instruction NOP sled", false ] ) ])
19
end
20
21
# This instruction list is far from complete (Only single byte instructions and some multi byte ADD/MOV instructions are used).
22
# A more complete list might warrant an pseudo assembler (Rex::Arch::X64) instead of hardcoding these.
23
INSTRUCTIONS = [ [ "\x90", 0, "nop" ],
24
[ "\x91", 0, "xchg eax, ecx" ],
25
[ "\x92", 0, "xchg eax, edx" ],
26
[ "\x93", 0, "xchg eax, ebx" ],
27
[ "\x94", 0, "xchg eax, esp" ],
28
[ "\x95", 0, "xchg eax, ebp" ],
29
[ "\x96", 0, "xchg eax, esi" ],
30
[ "\x97", 0, "xchg eax, edi" ],
31
[ "\x98", 0, "cwde" ],
32
[ "\x99", 0, "cdq" ],
33
[ "\x9B", 0, "wait" ],
34
[ "\x9C", 0, "pushfq" ],
35
[ "\x9D", 0, "popfq" ],
36
[ "\x9E", 0, "sahf" ],
37
[ "\x9F", 0, "lahf" ],
38
[ "\xFC", 0, "cld" ],
39
[ "\xFD", 0, "std" ],
40
[ "\xF8", 0, "clc" ],
41
[ "\xF9", 0, "cmc" ],
42
[ "\x50", 0, "push rax" ],
43
[ "\x51", 0, "push rcx" ],
44
[ "\x52", 0, "push rdx" ],
45
[ "\x53", 0, "push rbx" ],
46
[ "\x54", 0, "push rsp" ],
47
[ "\x55", 0, "push rbp" ],
48
[ "\x56", 0, "push rsi" ],
49
[ "\x57", 0, "push rdi" ],
50
[ "\x58", 0, "pop rax" ],
51
[ "\x59", 0, "pop rcx" ],
52
[ "\x5A", 0, "pop rdx" ],
53
[ "\x5B", 0, "pop rbx" ],
54
[ "\x5C", 0, "pop rsp" ],
55
[ "\x5D", 0, "pop rbp" ],
56
[ "\x5E", 0, "pop rsi" ],
57
[ "\x5F", 0, "pop rdi" ],
58
[ "\x04", 1, "add al, 0x??" ],
59
[ "\x80\xC3", 1, "add bl, 0x??" ],
60
[ "\x80\xC1", 1, "add cl, 0x??" ],
61
[ "\x80\xC2", 1, "add dl, 0x??" ],
62
[ "\x80\xC4", 1, "add ah, 0x??" ],
63
[ "\x80\xC7", 1, "add bh, 0x??" ],
64
[ "\x80\xC5", 1, "add ch, 0x??" ],
65
[ "\x80\xC6", 1, "add dh, 0x??" ],
66
[ "\x66\x05", 2, "add ax, 0x????" ],
67
[ "\x66\x81\xC3", 2, "add bx, 0x????" ],
68
[ "\x66\x81\xC1", 2, "add cx, 0x????" ],
69
[ "\x66\x81\xC2", 2, "add dx, 0x????" ],
70
[ "\x66\x81\xC6", 2, "add si, 0x????" ],
71
[ "\x66\x81\xC7", 2, "add di, 0x????" ],
72
[ "\x66\x41\x81\xC0", 2, "add r8w, 0x????" ],
73
[ "\x66\x41\x81\xC1", 2, "add r9w, 0x????" ],
74
[ "\x66\x41\x81\xC2", 2, "add r10w, 0x????" ],
75
[ "\x66\x41\x81\xC3", 2, "add r11w, 0x????" ],
76
[ "\x66\x41\x81\xC4", 2, "add r12w, 0x????" ],
77
[ "\x66\x41\x81\xC5", 2, "add r13w, 0x????" ],
78
[ "\x66\x41\x81\xC6", 2, "add r14w, 0x????" ],
79
[ "\x66\x41\x81\xC7", 2, "add r15w, 0x????" ],
80
[ "\x05", 4, "add eax, 0x????????" ],
81
[ "\x81\xC3", 4, "add ebx, 0x????????" ],
82
[ "\x81\xC1", 4, "add ecx, 0x????????" ],
83
[ "\x81\xC2", 4, "add edx, 0x????????" ],
84
[ "\x81\xC6", 4, "add esi, 0x????????" ],
85
[ "\x81\xC7", 4, "add edi, 0x????????" ],
86
[ "\x41\x81\xC0", 4, "add r8d, 0x????????" ],
87
[ "\x41\x81\xC1", 4, "add r9d, 0x????????" ],
88
[ "\x41\x81\xC2", 4, "add r10d, 0x????????" ],
89
[ "\x41\x81\xC3", 4, "add r11d, 0x????????" ],
90
[ "\x41\x81\xC4", 4, "add r12d, 0x????????" ],
91
[ "\x41\x81\xC5", 4, "add r13d, 0x????????" ],
92
[ "\x41\x81\xC6", 4, "add r14d, 0x????????" ],
93
[ "\x41\x81\xC7", 4, "add r15d, 0x????????" ],
94
[ "\x48\xB8", 8, "mov rax, 0x????????????????" ],
95
[ "\x48\xBB", 8, "mov rbx, 0x????????????????" ],
96
[ "\x48\xB9", 8, "mov rcx, 0x????????????????" ],
97
[ "\x48\xBA", 8, "mov rdx, 0x????????????????" ],
98
[ "\x48\xBE", 8, "mov rsi, 0x????????????????" ],
99
[ "\x48\xBF", 8, "mov rdi, 0x????????????????" ],
100
[ "\x49\xB8", 8, "mov r8, 0x????????????????" ],
101
[ "\x49\xB9", 8, "mov r8, 0x????????????????" ],
102
[ "\x49\xBA", 8, "mov r10, 0x????????????????" ],
103
[ "\x49\xBB", 8, "mov r11, 0x????????????????" ],
104
[ "\x49\xBC", 8, "mov r12, 0x????????????????" ],
105
[ "\x49\xBD", 8, "mov r13, 0x????????????????" ],
106
[ "\x49\xBE", 8, "mov r14, 0x????????????????" ],
107
[ "\x49\xBF", 8, "mov r15, 0x????????????????" ],
108
]
109
110
I_OP = 0
111
I_SIZE = 1
112
I_TEXT = 2
113
114
REGISTERS = [ [ "rsp", "esp", "sp" ],
115
[ "rbp", "ebp", "bp" ],
116
[ "rax", "eax", "ax", "al", "ah" ],
117
[ "rbx", "ebx", "bx", "bl", "bh" ],
118
[ "rcx", "ecx", "cx", "cl", "ch" ],
119
[ "rdx", "edx", "dx", "dl", "dh" ],
120
[ "rsi", "esi", "si" ],
121
[ "rdi", "edi", "di" ],
122
[ "r8", "r8d", "r8w", "r8b" ],
123
[ "r9", "r9d", "r9w", "r9b" ],
124
[ "r10", "r10d", "r10w", "r10b" ],
125
[ "r11", "r11d", "r11w", "r11b" ],
126
[ "r12", "r12d", "r12w", "r12b" ],
127
[ "r13", "r13d", "r13w", "r13b" ],
128
[ "r14", "r14d", "r14w", "r14b" ],
129
[ "r15", "r15d", "r15w", "r15b" ],
130
]
131
132
def generate_random_sled( length, instructions, badchars, badregs )
133
opcodes_stack = []
134
total_size = 0
135
sled = ''
136
try_count = 0
137
good_bytes = []
138
139
# Fixup SaveRegisters so for example, if we wish to preserve RSP we also should also preserve ESP and SP
140
REGISTERS.each { | reg | reg.each { |x| badregs += reg if badregs.include?( x ) } }
141
badregs = badregs.uniq()
142
143
# If we are preserving RSP we should avoid all PUSH/POP instructions...
144
if badregs.include?( "rsp" )
145
badregs.push( 'push' )
146
badregs.push( 'pop' )
147
end
148
149
# Loop while we still have bytes to fill in the sled...
150
while true
151
# Pick a random instruction and see if we can use it...
152
instruction = instructions[ rand(instructions.length) ]
153
154
# Avoid using any bad mnemonics/registers...
155
try_another = false
156
badregs.each do | bad |
157
try_another = true if instruction[I_TEXT].include?( bad.downcase() )
158
break if try_another
159
end
160
next if try_another
161
162
# Get the first bytes of the chosen instructions opcodes...
163
opcodes = instruction[I_OP]
164
165
# If their are additional bytes to append, do it now...
166
1.upto( instruction[I_SIZE] ) do | i |
167
opcodes += Rex::Text.rand_char( badchars )
168
end
169
170
# If we have gone over the requested sled length, try again.
171
if total_size + opcodes.length > length
172
try_count -= 1
173
174
# If we have tried unsuccessfully 32 times we start unwinding the chosen opcode_stack to speed things up
175
if try_count == 0
176
pop_count = 4
177
while opcodes_stack.length and pop_count
178
total_size -= opcodes_stack.pop().length
179
pop_count -= 1
180
end
181
end
182
next
183
end
184
185
# Reset the try_count for the next iteration.
186
try_count = 32
187
188
# save the opcodes we just generated.
189
opcodes_stack.push( opcodes )
190
191
# Increment the total size appropriately.
192
total_size += opcodes.length
193
194
# Once we have generated the requested amount of bytes we can finish.
195
break if total_size == length
196
end
197
198
# Now that we have chosen all the instructions to use we must generate the actual sled.
199
opcodes_stack.each do | opcodes_ |
200
sled += opcodes_
201
end
202
203
return sled
204
end
205
206
def generate_sled( length, opts )
207
badchars = opts['BadChars'] || ''
208
random = opts['Random'] || datastore['RandomNops']
209
badregs = opts['SaveRegisters'] || []
210
good_instructions = []
211
sled = ''
212
213
# Weed out any instructions which will contain a bad char/instruction...
214
INSTRUCTIONS.each do | instruction |
215
good = true;
216
# If the instruction contains some bad chars we wont use it...
217
badchars.each_char do | bc |
218
if instruction[I_OP].include?( bc )
219
good = false
220
break
221
end
222
end
223
# if we are only to generate single byte instructions, weed out the multi byte ones...
224
good = false if instruction[I_SIZE] > 0 and not datastore['MultiByte']
225
226
good_instructions.push( instruction ) if good
227
end
228
229
# After we have pruned the instruction list we can proceed to generate a sled...
230
if good_instructions.empty?
231
# If we are left with no valid instructions to use we simple can't generate a sled.
232
sled = nil
233
elsif not random
234
if not badchars.include?( "\x90" )
235
sled += "\x90" * length
236
else
237
sled = nil
238
end
239
else
240
sled += generate_random_sled( length, good_instructions, badchars, badregs )
241
end
242
243
return sled
244
end
245
end
246
247