Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/encoders/x86/add_sub.rb
19758 views
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::Encoder
7
Rank = ManualRanking
8
9
def initialize
10
super(
11
'Name' => 'Add/Sub Encoder',
12
'Description' => %q{
13
Encodes payload with add or sub instructions. This idea came
14
from (offensive-security) muts' hp nnm 7.5.1 exploit.
15
},
16
'Author' => 'Melih Sarica <ms[at]sevure.com>',
17
'Arch' => ARCH_X86,
18
'License' => MSF_LICENSE,
19
'Decoder' => {
20
'BlockSize' => 4
21
})
22
end
23
24
def add_or_sub(avchars)
25
add = [0x05, 0x50, 0x58, 0x25, 0x54, 0x5C]
26
sub = [0x2D, 0x50, 0x58, 0x25, 0x54, 0x5C]
27
return 1 if add.all? { |ch| avchars.include? ch.chr }
28
return 2 if sub.all? { |ch| avchars.include? ch.chr }
29
30
return 0
31
end
32
33
def write_inst(inst, mcode)
34
@data << inst
35
if mcode != 0
36
for _ in 0...4
37
t = mcode & 0x000000FF
38
@data << t
39
mcode >>= 8
40
end
41
end
42
end
43
44
def rand_with_av_chars
45
t2 = 0
46
for _ in 0...4
47
c = @avchars[rand(@avchars.size)].ord.to_i
48
t2 <<= 8
49
t2 += c
50
end
51
return t2
52
end
53
54
def check_non_av_chars(target)
55
for _ in 0...4
56
t = target & 0x000000FF
57
return true if !@avchars.include? t.chr
58
59
target >>= 8
60
end
61
return false
62
end
63
64
def encode_inst(target)
65
loop do
66
a = rand_with_av_chars
67
b = rand_with_av_chars
68
c = target - a - b if @set == 1
69
c = 0 - target - a - b if @set == 2
70
c %= (0xFFFFFFFF + 1)
71
break unless check_non_av_chars(c) == true
72
end
73
write_inst(@inst['opcode'], a)
74
write_inst(@inst['opcode'], b)
75
write_inst(@inst['opcode'], c)
76
end
77
78
def encode_shellcode(target, z1, z2)
79
write_inst(@inst['and'], z1)
80
write_inst(@inst['and'], z2)
81
encode_inst(target)
82
write_inst(@inst['push'], 0)
83
end
84
85
def decoder_stub(state)
86
buf = ''
87
shellcode = state.buf.split(//)
88
buf << shellcode.pop(4).join until shellcode.empty?
89
state.buf = buf
90
@data = ''
91
@avchars = ''
92
for i in 0..255
93
@avchars += i.chr.to_s if !state.badchars.include? i.chr.to_s
94
end
95
offset = (datastore['BufferOffset'] || 0).to_i
96
@inst = {}
97
@set = add_or_sub(@avchars)
98
if @set == 0
99
raise EncodingError, 'Bad character list includes essential characters.'
100
elsif @set == 1 # add
101
@inst['opcode'] = 0x05
102
else # sub
103
@inst['opcode'] = 0x2d
104
end
105
106
@inst['push'] = 0x50
107
@inst['pop'] = 0x58
108
@inst['and'] = 0x25
109
@inst['push_esp'] = 0x54
110
@inst['pop_esp'] = 0x5c
111
if state.buf.size % 4 != 0
112
raise EncodingError, 'Shellcode size must be divisible by 4, try nop padding.'
113
end
114
115
# init
116
write_inst(@inst['push_esp'], 0)
117
write_inst(@inst['pop'], 0)
118
encode_inst(offset)
119
write_inst(@inst['push'], 0)
120
write_inst(@inst['pop_esp'], 0)
121
# zeroing registers
122
loop do
123
@z1 = rand_with_av_chars
124
@z2 = rand_with_av_chars
125
break unless @z1 & @z2 != 0
126
end
127
decoder = @data
128
return decoder
129
end
130
131
def encode_block(_state, block)
132
# encoding shellcode
133
@data = ''
134
target = block.split(//)
135
return if target.size < 4
136
137
t = 0
138
for i in 0..3
139
t1 = target[3 - i][0].ord.to_i
140
t <<= 8
141
t += t1
142
end
143
encode_shellcode(t, @z1, @z2)
144
encoded = @data
145
return encoded
146
end
147
end
148
149