Skip to content

Commit 7cb4320

Browse files
committed
Land rapid7#3561 - unix cmd generic_sh encoder
2 parents 13fd6a3 + 57fe829 commit 7cb4320

File tree

7 files changed

+251
-4
lines changed

7 files changed

+251
-4
lines changed

lib/msf/core/encoder.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ module Type
127127
# Special printf(1) via PHP magic_quotes Command Encoder
128128
#
129129
PrintfPHPMagicQuotes = "printf_php_mq"
130+
#
131+
# perl encoding.
132+
#
133+
CmdUnixPerl = 'perl'
134+
#
135+
# Bourne shell echo encoding.
136+
#
137+
CmdUnixEcho = 'echo'
138+
#
139+
# Bourne shell IFS encoding.
140+
#
141+
CmdUnixIfs = 'ifs'
130142
end
131143

132144
#
@@ -273,6 +285,10 @@ def encode(buf, badchars = nil, state = nil, platform = nil)
273285
# Call encoded_end to do any encoder specific post-processing
274286
encode_end(state)
275287

288+
if arch?(ARCH_CMD)
289+
dlog("#{self.name} result: #{state.encoded}")
290+
end
291+
276292
# Return the encoded buffer to the caller
277293
return state.encoded
278294
end

lib/msf/core/payload_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ def get_encoders
312312
end
313313
encoders.sort_by { |my_encoder| my_encoder.rank }.reverse
314314
elsif badchars.present?
315-
framework.encoders.each_module_ranked('Arch' => [arch]) do |name, mod|
315+
framework.encoders.each_module_ranked('Arch' => [arch], 'Platform' => platform_list) do |name, mod|
316316
encoders << framework.encoders.create(name)
317317
end
318318
encoders.sort_by { |my_encoder| my_encoder.rank }.reverse

modules/encoders/cmd/echo.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
7+
require 'msf/core'
8+
9+
10+
class Metasploit3 < Msf::Encoder
11+
12+
Rank = GoodRanking
13+
14+
def initialize
15+
super(
16+
'Name' => 'Echo Command Encoder',
17+
'Description' => %q{
18+
This encoder uses echo and backlash escapes to avoid commonly restricted characters.
19+
},
20+
'Author' => 'hdm',
21+
'Arch' => ARCH_CMD,
22+
'Platform' => 'unix',
23+
'EncoderType' => Msf::Encoder::Type::CmdUnixEcho)
24+
end
25+
26+
27+
#
28+
# Encodes the payload
29+
#
30+
def encode_block(state, buf)
31+
# Skip encoding for empty badchars
32+
if state.badchars.length == 0
33+
return buf
34+
end
35+
36+
if state.badchars.include?("-")
37+
raise RuntimeError
38+
else
39+
# Without an escape character we can't escape anything, so echo
40+
# won't work.
41+
if state.badchars.include?("\\")
42+
raise RuntimeError
43+
else
44+
buf = encode_block_bash_echo(state,buf)
45+
end
46+
end
47+
48+
return buf
49+
end
50+
51+
#
52+
# Uses bash's echo -ne command to hex encode the command string
53+
#
54+
def encode_block_bash_echo(state, buf)
55+
56+
hex = ''
57+
58+
# Can we use single quotes to enclose the echo arguments?
59+
if state.badchars.include?("'")
60+
hex = buf.unpack('C*').collect { |c| "\\\\\\x%.2x" % c }.join
61+
else
62+
hex = "'" + buf.unpack('C*').collect { |c| "\\x%.2x" % c }.join + "'"
63+
end
64+
65+
# Are pipe characters restricted?
66+
if state.badchars.include?("|")
67+
# How about backticks?
68+
if state.badchars.include?("`")
69+
# Last ditch effort, dollar paren
70+
if state.badchars.include?("$") or state.badchars.include?("(")
71+
raise RuntimeError
72+
else
73+
buf = "$(/bin/echo -ne #{hex})"
74+
end
75+
else
76+
buf = "`/bin/echo -ne #{hex}`"
77+
end
78+
else
79+
buf = "/bin/echo -ne #{hex}|sh"
80+
end
81+
82+
# Remove spaces from the command string
83+
if state.badchars.include?(" ")
84+
buf.gsub!(/\s/, '${IFS}')
85+
end
86+
87+
return buf
88+
end
89+
90+
end

modules/encoders/cmd/generic_sh.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
class Metasploit3 < Msf::Encoder
1111

1212
# Has some issues, but overall it's pretty good
13-
Rank = GoodRanking
13+
Rank = ManualRanking
1414

1515
def initialize
1616
super(

modules/encoders/cmd/ifs.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,25 @@ def initialize
2222
},
2323
'Author' => 'egypt',
2424
'Arch' => ARCH_CMD,
25-
'Platform' => 'unix')
25+
'Platform' => 'unix',
26+
'EncoderType' => Msf::Encoder::Type::CmdUnixIfs)
2627
end
2728

2829

2930
#
3031
# Encodes the payload
3132
#
3233
def encode_block(state, buf)
34+
# Skip encoding for empty badchars
35+
if state.badchars.length == 0
36+
return buf
37+
end
38+
39+
# Skip encoding unless space is a badchar
40+
unless state.badchars.include?(" ")
41+
return buf
42+
end
43+
3344
buf.gsub!(/\s/, '${IFS}')
3445
return buf
3546
end

modules/encoders/cmd/perl.rb

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

modules/exploits/linux/http/nginx_chunked_size.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def initialize(info = {})
3838
'Privileged' => false,
3939
'Payload' =>
4040
{
41-
'BadChars' => "\x0d\x0a",
41+
'BadChars' => "\x0d\x0a"
4242
},
4343
'Arch' => ARCH_CMD,
4444
'Platform' => 'unix',

0 commit comments

Comments
 (0)