@@ -10,6 +10,11 @@ module Exploitation
1010
1111class 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
0 commit comments