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