Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/encoders/cmd/perl.rb
19500 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 = NormalRanking
8
9
def initialize
10
super(
11
'Name' => 'Perl Command Encoder',
12
'Description' => %q{
13
This encoder uses perl to avoid commonly restricted characters.
14
},
15
'Author' => 'hdm',
16
'Arch' => ARCH_CMD,
17
'Platform' => %w[linux unix],
18
'EncoderType' => Msf::Encoder::Type::CmdPosixPerl)
19
end
20
21
#
22
# Encodes the payload
23
#
24
def encode_block(state, buf)
25
# Skip encoding for empty badchars
26
if state.badchars.empty?
27
return buf
28
end
29
30
if state.badchars.include?('-')
31
raise EncodingError
32
else
33
buf = encode_block_perl(state, buf)
34
end
35
36
return buf
37
end
38
39
#
40
# Uses the perl command to hex encode the command string
41
#
42
def encode_block_perl(state, buf)
43
hex = buf.unpack('H*').join
44
cmd = 'perl -e '
45
qot = ',-:.=+!@#$%^&'
46
47
# Convert spaces to IFS...
48
if state.badchars.include?(' ')
49
if state.badchars.match(/[${IFS}]/n)
50
raise EncodingError
51
end
52
53
cmd.gsub!(/\s/, '${IFS}')
54
end
55
56
# Can we use single quotes to enclose the command string?
57
if state.badchars.include?("'")
58
if state.badchars.match(/[()\\]/)
59
cmd << perl_e(state, qot, hex)
60
else
61
# Without quotes, we can use backslash to escape parens so the
62
# shell doesn't try to interpreter them.
63
cmd << "system\\(pack\\(#{perl_qq(state, qot, hex)}\\)\\)"
64
end
65
elsif state.badchars.match(/[()]/n)
66
# Quotes are ok, but we still need parens or spaces
67
if state.badchars.include?(' ')
68
cmd << perl_e(state, qot, hex)
69
else
70
cmd << "'system pack #{perl_qq(state, qot, hex)}'"
71
end
72
else
73
cmd << "'system(pack(#{perl_qq(state, qot, hex)}))'"
74
end
75
76
return cmd
77
end
78
79
def perl_e(state, qot, hex)
80
# We don't have parens, quotes, or backslashes so we have to use
81
# barewords on the commandline for the argument to the pack
82
# function. As a consequence, we can't use things that the shell
83
# would interpret, so $ and & become badchars.
84
qot.delete('$')
85
qot.delete('&')
86
87
# Perl chains -e with newlines, but doesn't automatically add
88
# semicolons, so the following will result in the interpreter
89
# seeing a file like this:
90
# system
91
# pack
92
# qq^H*^,qq^whatever^
93
# Since system and pack require arguments (rather than assuming
94
# $_ when no args are given like many other perl functions),
95
# this works out to do what we need.
96
cmd = "system -e pack -e #{perl_qq(state, qot, hex)}"
97
if state.badchars.include?(' ')
98
# We already tested above to make sure that these chars are ok
99
# if space isn't.
100
cmd.gsub!(' ', '${IFS}')
101
end
102
103
cmd
104
end
105
106
def perl_qq(state, qot, hex)
107
# Find a quoting character to use
108
state.badchars.unpack('C*') { |c| qot.delete(c.chr) }
109
110
# Throw an error if we ran out of quotes
111
raise EncodingError if qot.empty?
112
113
sep = qot[0].chr
114
# Use an explicit length for the H specifier instead of just "H*"
115
# in case * is a badchar for the module, and for the case where this
116
# ends up unquoted so the shell doesn't try to expand a path.
117
"qq#{sep}H#{hex.length}#{sep},qq#{sep}#{hex}#{sep}"
118
end
119
end
120
121