rex-encoder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rex/encoder.rb +15 -0
- data/lib/rex/encoder/alpha2.rb +31 -0
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +129 -0
- data/lib/rex/encoder/alpha2/alpha_upper.rb +138 -0
- data/lib/rex/encoder/alpha2/generic.rb +90 -0
- data/lib/rex/encoder/alpha2/unicode_mixed.rb +116 -0
- data/lib/rex/encoder/alpha2/unicode_upper.rb +123 -0
- data/lib/rex/encoder/bloxor/bloxor.rb +327 -0
- data/lib/rex/encoder/ndr.rb +90 -0
- data/lib/rex/encoder/nonalpha.rb +61 -0
- data/lib/rex/encoder/nonupper.rb +64 -0
- data/lib/rex/encoder/version.rb +5 -0
- data/lib/rex/encoder/xdr.rb +108 -0
- data/lib/rex/encoder/xor.rb +69 -0
- data/lib/rex/encoder/xor/dword.rb +13 -0
- data/lib/rex/encoder/xor/dword_additive.rb +13 -0
- data/lib/rex/encoding/xor.rb +20 -0
- data/lib/rex/encoding/xor/byte.rb +15 -0
- data/lib/rex/encoding/xor/dword.rb +21 -0
- data/lib/rex/encoding/xor/dword_additive.rb +92 -0
- data/lib/rex/encoding/xor/exceptions.rb +17 -0
- data/lib/rex/encoding/xor/generic.rb +146 -0
- data/lib/rex/encoding/xor/qword.rb +15 -0
- data/lib/rex/encoding/xor/word.rb +21 -0
- data/lib/rex/poly.rb +134 -0
- data/lib/rex/poly/block.rb +480 -0
- data/lib/rex/poly/machine.rb +13 -0
- data/lib/rex/poly/machine/machine.rb +830 -0
- data/lib/rex/poly/machine/x86.rb +509 -0
- data/lib/rex/poly/register.rb +101 -0
- data/lib/rex/poly/register/x86.rb +41 -0
- data/rex-encoder.gemspec +31 -0
- metadata +248 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require "rex/text"
|
3
|
+
|
4
|
+
module Rex
|
5
|
+
module Encoder
|
6
|
+
module NDR
|
7
|
+
|
8
|
+
# Provide padding to align the string to the 32bit boundary
|
9
|
+
def NDR.align(string)
|
10
|
+
return "\x00" * ((4 - (string.length & 3)) & 3)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Encode a 4 byte long
|
14
|
+
# use to encode:
|
15
|
+
# long element_1;
|
16
|
+
def NDR.long(string)
|
17
|
+
return [string].pack('V')
|
18
|
+
end
|
19
|
+
|
20
|
+
# Encode a 2 byte short
|
21
|
+
# use to encode:
|
22
|
+
# short element_1;
|
23
|
+
def NDR.short(string)
|
24
|
+
return [string].pack('v')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Encode a single byte
|
28
|
+
# use to encode:
|
29
|
+
# byte element_1;
|
30
|
+
def NDR.byte(string)
|
31
|
+
return [string].pack('C')
|
32
|
+
end
|
33
|
+
|
34
|
+
# Encode a byte array
|
35
|
+
# use to encode:
|
36
|
+
# char element_1
|
37
|
+
def NDR.UniConformantArray(string)
|
38
|
+
return long(string.length) + string + align(string)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Encode a string
|
42
|
+
# use to encode:
|
43
|
+
# char *element_1;
|
44
|
+
def NDR.string(string)
|
45
|
+
string << "\x00" # null pad
|
46
|
+
return long(string.length) + long(0) + long(string.length) + string + align(string)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Encode a string
|
50
|
+
# use to encode:
|
51
|
+
# w_char *element_1;
|
52
|
+
def NDR.wstring(string)
|
53
|
+
string = string + "\x00" # null pad
|
54
|
+
return long(string.length) + long(0) + long(string.length) + Rex::Text.to_unicode(string) + align(Rex::Text.to_unicode(string))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Encode a string and make it unique
|
58
|
+
# use to encode:
|
59
|
+
# [unique] w_char *element_1;
|
60
|
+
def NDR.uwstring(string)
|
61
|
+
string = string + "\x00" # null pad
|
62
|
+
return long(rand(0xffffffff))+long(string.length) + long(0) + long(string.length) + Rex::Text.to_unicode(string) + align(Rex::Text.to_unicode(string))
|
63
|
+
end
|
64
|
+
|
65
|
+
# Encode a string that is already unicode encoded
|
66
|
+
# use to encode:
|
67
|
+
# w_char *element_1;
|
68
|
+
def NDR.wstring_prebuilt(string)
|
69
|
+
# if the string len is odd, thats bad!
|
70
|
+
if string.length % 2 > 0
|
71
|
+
string = string + "\x00"
|
72
|
+
end
|
73
|
+
len = string.length / 2;
|
74
|
+
return long(len) + long(0) + long(len) + string + align(string)
|
75
|
+
end
|
76
|
+
|
77
|
+
# alias to wstring, going away soon
|
78
|
+
def NDR.UnicodeConformantVaryingString(string)
|
79
|
+
NDR.wstring(string)
|
80
|
+
end
|
81
|
+
|
82
|
+
# alias to wstring_prebuilt, going away soon
|
83
|
+
def NDR.UnicodeConformantVaryingStringPreBuilt(string)
|
84
|
+
NDR.wstring_prebuilt(string)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/text'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Encoder
|
7
|
+
|
8
|
+
class NonAlpha
|
9
|
+
|
10
|
+
def NonAlpha.gen_decoder
|
11
|
+
decoder =
|
12
|
+
"\x66\xB9\xFF\xFF" +
|
13
|
+
"\xEB\x19" + # Jmp to table
|
14
|
+
"\x5E" + # pop esi
|
15
|
+
"\x8B\xFE" + # mov edi, esi - Get table addr
|
16
|
+
"\x83\xC7" + "A" + # add edi, tablelen - Get shellcode addr
|
17
|
+
"\x8B\xD7" + # mov edx, edi - Hold end of table ptr
|
18
|
+
"\x3B\xF2" + # cmp esi, edx
|
19
|
+
"\x7D\x0B" + # jle to end
|
20
|
+
"\xB0\x7B" + # mov eax, 0x7B - Set up eax with magic
|
21
|
+
"\xF2\xAE" + # repne scasb - Find magic!
|
22
|
+
"\xFF\xCF" + # dec edi - scasb purs us one ahead
|
23
|
+
"\xAC" + # lodsb
|
24
|
+
"\x28\x07" + # subb [edi], al
|
25
|
+
"\xEB\xF1" + # jmp BACK!
|
26
|
+
"\xEB" + "B" + # jmp [shellcode]
|
27
|
+
"\xE8\xE2\xFF\xFF\xFF"
|
28
|
+
end
|
29
|
+
|
30
|
+
def NonAlpha.encode_byte(block, table, tablelen)
|
31
|
+
if tablelen > 255 || block == 0x7B
|
32
|
+
raise RuntimeError, "BadChar"
|
33
|
+
end
|
34
|
+
|
35
|
+
if (block >= 0x41 && block <= 0x5A) || (block >= 0x61 && block <= 0x7A)
|
36
|
+
# gen offset, return magic
|
37
|
+
offset = 0x7b - block
|
38
|
+
table += offset.chr
|
39
|
+
tablelen = tablelen + 1
|
40
|
+
block = 0x7B
|
41
|
+
end
|
42
|
+
|
43
|
+
return [block.chr, table, tablelen]
|
44
|
+
end
|
45
|
+
|
46
|
+
def NonAlpha.encode(buf)
|
47
|
+
table = ""
|
48
|
+
tablelen = 0
|
49
|
+
nonascii = ""
|
50
|
+
encoded = gen_decoder()
|
51
|
+
buf.each_byte { |block|
|
52
|
+
newchar, table, tablelen = encode_byte(block.unpack('C')[0], table, tablelen)
|
53
|
+
nonascii += newchar
|
54
|
+
}
|
55
|
+
encoded.gsub!(/A/, tablelen)
|
56
|
+
encoded.gsub!(/B/, tablelen+5)
|
57
|
+
encoded += table
|
58
|
+
encoded += nonascii
|
59
|
+
end
|
60
|
+
|
61
|
+
end end end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/text'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Encoder
|
7
|
+
|
8
|
+
class NonUpper
|
9
|
+
|
10
|
+
|
11
|
+
def NonUpper.gen_decoder()
|
12
|
+
decoder =
|
13
|
+
"\x66\xB9\xFF\xFF" +
|
14
|
+
"\xEB\x19" + # Jmp to table
|
15
|
+
"\x5E" + # pop esi
|
16
|
+
"\x8B\xFE" + # mov edi, esi - Get table addr
|
17
|
+
"\x83\xC7" + "A" + # add edi, tablelen - Get shellcode addr
|
18
|
+
"\x8B\xD7" + # mov edx, edi - Hold end of table ptr
|
19
|
+
"\x3B\xF2" + # cmp esi, edx
|
20
|
+
"\x7D\x0B" + # jle to end
|
21
|
+
"\xB0\x7B" + # mov eax, 0x7B - Set up eax with magic
|
22
|
+
"\xF2\xAE" + # repne scasb - Find magic!
|
23
|
+
"\xFF\xCF" + # dec edi - scasb purs us one ahead
|
24
|
+
"\xAC" + # lodsb
|
25
|
+
"\x28\x07" + # subb [edi], al
|
26
|
+
"\xEB\xF1" + # jmp BACK!
|
27
|
+
"\xEB" + "B" + # jmp [shellcode]
|
28
|
+
"\xE8\xE2\xFF\xFF\xFF"
|
29
|
+
end
|
30
|
+
|
31
|
+
def NonUpper.encode_byte(badchars, block, table, tablelen)
|
32
|
+
if (tablelen > 255) or (block == 0x40)
|
33
|
+
raise RuntimeError, "BadChar"
|
34
|
+
end
|
35
|
+
|
36
|
+
if (block >= 0x41 and block <= 0x40) or (badchars =~ block)
|
37
|
+
# gen offset, return magic
|
38
|
+
offset = 0x40 - block;
|
39
|
+
table += offset.chr
|
40
|
+
tablelen = tablelen + 1
|
41
|
+
block = 0x40
|
42
|
+
end
|
43
|
+
|
44
|
+
return [block.chr, table, tablelen]
|
45
|
+
end
|
46
|
+
|
47
|
+
def NonUpper.encode(buf)
|
48
|
+
table = ""
|
49
|
+
tablelen = 0
|
50
|
+
nonascii = ""
|
51
|
+
encoded = gen_decoder()
|
52
|
+
buf.each_byte {
|
53
|
+
|block|
|
54
|
+
|
55
|
+
newchar, table, tablelen = encode_byte(block.unpack('C')[0], table, tablelen)
|
56
|
+
nonascii += newchar
|
57
|
+
}
|
58
|
+
encoded.gsub!(/A/, tablelen)
|
59
|
+
encoded.gsub!(/B/, tablelen+5)
|
60
|
+
encoded += table
|
61
|
+
encoded += nonascii
|
62
|
+
end
|
63
|
+
|
64
|
+
end end end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
module Rex
|
3
|
+
module Encoder
|
4
|
+
|
5
|
+
###
|
6
|
+
#
|
7
|
+
# This class implements basic XDR encoding.
|
8
|
+
#
|
9
|
+
###
|
10
|
+
module XDR
|
11
|
+
MAX_ARG = 0xffffffff
|
12
|
+
|
13
|
+
# Also: unsigned int, bool, enum
|
14
|
+
def XDR.encode_int(int)
|
15
|
+
return [int].pack('N')
|
16
|
+
end
|
17
|
+
|
18
|
+
def XDR.decode_int!(data)
|
19
|
+
raise ArgumentError, 'XDR: No Integer data to decode' unless data
|
20
|
+
raise ArgumentError, "XDR: Too little data to decode (#{data.size})" if data.size < 4
|
21
|
+
return data.slice!(0..3).unpack('N')[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def XDR.encode_lchar(char)
|
25
|
+
char |= 0xffffff00 if char & 0x80 != 0
|
26
|
+
return encode_int(char)
|
27
|
+
end
|
28
|
+
|
29
|
+
def XDR.decode_lchar!(data)
|
30
|
+
return (decode_int!(data) & 0xff).chr
|
31
|
+
end
|
32
|
+
|
33
|
+
# Also: Variable length opaque
|
34
|
+
def XDR.encode_string(str, max=MAX_ARG)
|
35
|
+
raise ArgumentError, 'XDR: String too long' if str.length > max
|
36
|
+
len = str.length
|
37
|
+
str << "\x00" * ((4 - (len & 3)) & 3)
|
38
|
+
return encode_int(len) + str
|
39
|
+
end
|
40
|
+
|
41
|
+
def XDR.decode_string!(data)
|
42
|
+
real_len = decode_int!(data)
|
43
|
+
return "" if real_len == 0
|
44
|
+
align_len = (real_len + 3) & ~3
|
45
|
+
return data.slice!(0..align_len-1).slice(0..real_len-1)
|
46
|
+
end
|
47
|
+
|
48
|
+
def XDR.encode_varray(arr, max=MAX_ARG, &block)
|
49
|
+
raise ArgumentError, 'XDR: Too many array elements' if arr.length > max
|
50
|
+
return encode_int(arr.length) + arr.collect(&block).join(nil)
|
51
|
+
end
|
52
|
+
|
53
|
+
def XDR.decode_varray!(data)
|
54
|
+
buf = []
|
55
|
+
1.upto(decode_int!(data)) { buf.push(yield(data)) }
|
56
|
+
return buf
|
57
|
+
end
|
58
|
+
|
59
|
+
# encode(0, [0, 1], "foo", ["bar", 4]) does:
|
60
|
+
# encode_int(0) +
|
61
|
+
# encode_varray([0, 1]) { |i| XDR.encode_int(i) } +
|
62
|
+
# encode_string("foo") +
|
63
|
+
# encode_string("bar", 4)
|
64
|
+
def XDR.encode(*data)
|
65
|
+
data.collect do |var|
|
66
|
+
if var.kind_of?(String)
|
67
|
+
encode_string(var)
|
68
|
+
elsif var.kind_of?(Integer)
|
69
|
+
encode_int(var)
|
70
|
+
elsif var.kind_of?(Array) && var[0].kind_of?(String)
|
71
|
+
raise ArgumentError, 'XDR: Incorrect string array arguments' if var.length != 2
|
72
|
+
encode_string(var[0], var[1])
|
73
|
+
elsif var.kind_of?(Array) && var[0].kind_of?(Integer)
|
74
|
+
encode_varray(var) { |i| XDR.encode_int(i) }
|
75
|
+
# 0 means an empty array index in the case of Integer and an empty string in
|
76
|
+
# the case of String so we get the best of both worlds
|
77
|
+
elsif var.kind_of?(Array) && var[0].nil?
|
78
|
+
encode_int(0)
|
79
|
+
else
|
80
|
+
type = var.class
|
81
|
+
type = var[0].class if var.kind_of?(Array)
|
82
|
+
raise TypeError, "XDR: encode does not support #{type}"
|
83
|
+
end
|
84
|
+
end.join(nil)
|
85
|
+
end
|
86
|
+
|
87
|
+
# decode(buf, Integer, String, [Integer], [String]) does:
|
88
|
+
# [decode_int!(buf), decode_string!(buf),
|
89
|
+
# decode_varray!(buf) { |i| XDR.decode_int!(i) },
|
90
|
+
# decode_varray!(buf) { |s| XDR.decode_string(s) }]
|
91
|
+
def XDR.decode!(buf, *data)
|
92
|
+
return *data.collect do |var|
|
93
|
+
if data.length == 0
|
94
|
+
elsif var.kind_of?(Array) && var[0] == String
|
95
|
+
decode_varray!(buf) { |s| XDR.decode_string!(s) }
|
96
|
+
elsif var.kind_of?(Array) && var[0] == Integer
|
97
|
+
decode_varray!(buf) { |i| XDR.decode_int!(i) }
|
98
|
+
elsif var == String
|
99
|
+
decode_string!(buf)
|
100
|
+
elsif var == Integer
|
101
|
+
decode_int!(buf)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
module Rex
|
4
|
+
module Encoder
|
5
|
+
|
6
|
+
###
|
7
|
+
#
|
8
|
+
# This class performs basic XOR encoding.
|
9
|
+
#
|
10
|
+
###
|
11
|
+
class Xor
|
12
|
+
|
13
|
+
attr_accessor :raw, :encoded, :badchars, :opts, :key, :fkey # :nodoc:
|
14
|
+
|
15
|
+
#
|
16
|
+
# wrap that in a wanna be static class
|
17
|
+
#
|
18
|
+
def self.encode(*args)
|
19
|
+
self.new.encode(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Return the class associated with this encoder.
|
24
|
+
#
|
25
|
+
def encoder()
|
26
|
+
self.class::EncoderKlass
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# This method encodes the supplied data, taking into account the badchar
|
31
|
+
# list, and returns the encoded buffer.
|
32
|
+
#
|
33
|
+
def encode(data, badchars = '', opts = { })
|
34
|
+
self.raw = data
|
35
|
+
self.badchars = badchars
|
36
|
+
self.opts = opts
|
37
|
+
|
38
|
+
# apply any transforms to the plaintext data
|
39
|
+
data = _unencoded_transform(data)
|
40
|
+
|
41
|
+
self.encoded, self.key, self.fkey = encoder().find_key_and_encode(data, badchars)
|
42
|
+
|
43
|
+
# apply any transforms to the encoded data
|
44
|
+
self.encoded = _encoded_transform(encoded)
|
45
|
+
|
46
|
+
return _prepend() + encoded + _append()
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
def _unencoded_transform(data) # :nodoc:
|
51
|
+
data
|
52
|
+
end
|
53
|
+
|
54
|
+
def _encoded_transform(data) # :nodoc:
|
55
|
+
data
|
56
|
+
end
|
57
|
+
|
58
|
+
def _prepend() # :nodoc:
|
59
|
+
""
|
60
|
+
end
|
61
|
+
|
62
|
+
def _append() # :nodoc:
|
63
|
+
""
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end end
|
69
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/encoder/xor'
|
4
|
+
require 'rex/encoding/xor/dword'
|
5
|
+
|
6
|
+
###
|
7
|
+
#
|
8
|
+
# This class wraps the Dword XOR encoder.
|
9
|
+
#
|
10
|
+
###
|
11
|
+
class Rex::Encoder::Xor::Dword < Rex::Encoder::Xor
|
12
|
+
EncoderKlass = Rex::Encoding::Xor::Dword
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/encoder/xor'
|
4
|
+
require 'rex/encoding/xor/dword_additive'
|
5
|
+
|
6
|
+
###
|
7
|
+
#
|
8
|
+
# This class wraps the Dword XOR Additive feedback encoder.
|
9
|
+
#
|
10
|
+
###
|
11
|
+
class Rex::Encoder::Xor::DwordAdditive < Rex::Encoder::Xor
|
12
|
+
EncoderKlass = Rex::Encoding::Xor::DwordAdditive
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# make sure the namespace is created
|
5
|
+
#
|
6
|
+
|
7
|
+
module Rex
|
8
|
+
module Encoding
|
9
|
+
module Xor
|
10
|
+
end end end
|
11
|
+
|
12
|
+
#
|
13
|
+
# include the Xor encodings
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'rex/encoding/xor/generic'
|
17
|
+
require 'rex/encoding/xor/byte'
|
18
|
+
require 'rex/encoding/xor/word'
|
19
|
+
require 'rex/encoding/xor/dword'
|
20
|
+
require 'rex/encoding/xor/qword'
|