Module: Rex::Text

Defined in:
lib/rex/text.rb,
lib/rex/text/hex.rb,
lib/rex/text/xor.rb,
lib/rex/text/hash.rb,
lib/rex/text/lang.rb,
lib/rex/text/rand.rb,
lib/rex/text/color.rb,
lib/rex/text/silly.rb,
lib/rex/text/table.rb,
lib/rex/text/base32.rb,
lib/rex/text/base64.rb,
lib/rex/text/ebcdic.rb,
lib/rex/text/encode.rb,
lib/rex/text/pattern.rb,
lib/rex/text/unicode.rb,
lib/rex/text/version.rb,
lib/rex/text/badchars.rb,
lib/rex/text/checksum.rb,
lib/rex/text/compress.rb,
lib/rex/text/block_api.rb,
lib/rex/text/randomize.rb,
lib/rex/text/wrapped_table.rb,
lib/rex/text/illegal_sequence.rb,
lib/rex/text/binary_manipulation.rb

Overview

This class formats text in various fashions and also provides a mechanism for wrapping text at a given column.

Defined Under Namespace

Modules: Color Classes: IllegalSequence, Table, WrappedTable

Constant Summary collapse

UpperAlpha =

Constants

"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LowerAlpha =
"abcdefghijklmnopqrstuvwxyz"
Numerals =
"0123456789"
Base32 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
Base64 =
UpperAlpha + LowerAlpha + Numerals + '+/'
Base64Url =
UpperAlpha + LowerAlpha + Numerals + '-_'
Alpha =
UpperAlpha + LowerAlpha
AlphaNumeric =
Alpha + Numerals
HighAscii =
[*(0x80 .. 0xff)].pack("C*")
LowAscii =
[*(0x00 .. 0x1f)].pack("C*")
DefaultWrap =
60
AllChars =
[*(0x00 .. 0xff)].pack("C*")
Punctuation =
( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*(0x7b .. 0x7e)] ).flatten.pack("C*")
DefaultPatternSets =
[ Rex::Text::UpperAlpha, Rex::Text::LowerAlpha, Rex::Text::Numerals ]
TLDs =
['com', 'net', 'org', 'gov', 'biz', 'edu']
States =
["AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DE", "FL", "GA", "HI",
"IA", "ID", "IL", "IN", "KS", "KY", "LA", "MA", "MD", "ME", "MI", "MN",
"MO", "MS", "MT", "NC", "ND", "NE", "NH", "NJ", "NM", "NV", "NY", "OH",
"OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA",
"WI", "WV", "WY"]
Countries =
["AF", "AX", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM",
"AW", "AC", "AU", "AT", "AZ", "BS", "BH", "BB", "BD", "BY", "BE", "BZ",
"BJ", "BM", "BT", "BW", "BO", "BA", "BV", "BR", "IO", "BN", "BG", "BF",
"BI", "KH", "CM", "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC",
"CO", "KM", "CG", "CD", "CK", "CR", "CI", "HR", "CU", "CY", "CZ", "CS",
"DK", "DJ", "DM", "DO", "TP", "EC", "EG", "SV", "GQ", "ER", "EE", "ET",
"FK", "FO", "FJ", "FI", "FR", "FX", "GF", "PF", "TF", "MK", "GA", "GM",
"GE", "DE", "GH", "GI", "GB", "GR", "GL", "GD", "GP", "GU", "GT", "GN",
"GY", "HT", "HM", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IQ", "IE",
"IL", "IM", "IT", "JE", "JM", "JP", "JO", "KZ", "KE", "KI", "KP", "KR",
"KW", "KG", "LA", "LV", "LB", "LI", "LR", "LY", "LS", "LT", "LU", "MO",
"MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", "MR", "MU", "YT", "MX",
"FM", "MD", "MC", "ME", "MS", "MA", "MZ", "MM", "NA", "NR", "NP", "NL",
"AN", "NT", "NC", "NZ", "NI", "NE", "NG", "NU", "NF", "MP", "NO", "OM",
"PK", "PW", "PS", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR",
"QA", "RE", "RO", "RU", "RW", "GS", "KN", "LC", "VC", "WS", "SM", "ST",
"SA", "SN", "RS", "SC", "SL", "SG", "SI", "SK", "SB", "SO", "ZA", "ES",
"LK", "SH", "PM", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ",
"TZ", "TH", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG",
"UA", "AE", "UK", "US", "UM", "UY", "SU", "UZ", "VU", "VA", "VE", "VN",
"VG", "VI", "WF", "EH", "YE", "YU", "ZM", "ZW"]
Surnames =

Most 100 common surnames, male/female names in the U.S. (names.mongabay.com/)

[
  "adams", "alexander", "allen", "anderson", "bailey", "baker", "barnes",
  "bell", "bennett", "brooks", "brown", "bryant", "butler", "campbell",
  "carter", "clark", "coleman", "collins", "cook", "cooper", "cox",
  "davis", "diaz", "edwards", "evans", "flores", "foster", "garcia",
  "gonzales", "gonzalez", "gray", "green", "griffin", "hall", "harris",
  "hayes", "henderson", "hernandez", "hill", "howard", "hughes", "jackson",
  "james", "jenkins", "johnson", "jones", "kelly", "king", "lee", "lewis",
  "long", "lopez", "martin", "martinez", "miller", "mitchell", "moore",
  "morgan", "morris", "murphy", "nelson", "parker", "patterson", "perez",
  "perry", "peterson", "phillips", "powell", "price", "ramirez", "reed",
  "richardson", "rivera", "roberts", "robinson", "rodriguez", "rogers",
  "ross", "russell", "sanchez", "sanders", "scott", "simmons", "smith",
  "stewart", "taylor", "thomas", "thompson", "torres", "turner", "walker",
  "ward", "washington", "watson", "white", "williams", "wilson", "wood",
  "wright", "young"
]
Names_Male =
[
  "aaron", "adam", "alan", "albert", "andrew", "anthony", "antonio",
  "arthur", "benjamin", "billy", "bobby", "brandon", "brian", "bruce",
  "carl", "carlos", "charles", "chris", "christopher", "clarence", "craig",
  "daniel", "david", "dennis", "donald", "douglas", "earl", "edward",
  "eric", "ernest", "eugene", "frank", "fred", "gary", "george", "gerald",
  "gregory", "harold", "harry", "henry", "howard", "jack", "james", "jason",
  "jeffrey", "jeremy", "jerry", "jesse", "jimmy", "joe", "john", "johnny",
  "jonathan", "jose", "joseph", "joshua", "juan", "justin", "keith",
  "kenneth", "kevin", "larry", "lawrence", "louis", "mark", "martin",
  "matthew", "michael", "nicholas", "patrick", "paul", "peter", "philip",
  "phillip", "ralph", "randy", "raymond", "richard", "robert", "roger",
  "ronald", "roy", "russell", "ryan", "samuel", "scott", "sean", "shawn",
  "stephen", "steve", "steven", "terry", "thomas", "timothy", "todd",
  "victor", "walter", "wayne", "william", "willie"
]
Names_Female =
[
  "alice", "amanda", "amy", "andrea", "angela", "ann", "anna", "anne",
  "annie", "ashley", "barbara", "betty", "beverly", "bonnie", "brenda",
  "carol", "carolyn", "catherine", "cheryl", "christina", "christine",
  "cynthia", "deborah", "debra", "denise", "diana", "diane", "donna",
  "doris", "dorothy", "elizabeth", "emily", "evelyn", "frances", "gloria",
  "heather", "helen", "irene", "jacqueline", "jane", "janet", "janice",
  "jean", "jennifer", "jessica", "joan", "joyce", "judith", "judy", "julia",
  "julie", "karen", "katherine", "kathleen", "kathryn", "kathy", "kelly",
  "kimberly", "laura", "lillian", "linda", "lisa", "lois", "lori", "louise",
  "margaret", "maria", "marie", "marilyn", "martha", "mary", "melissa",
  "michelle", "mildred", "nancy", "nicole", "norma", "pamela", "patricia",
  "paula", "phyllis", "rachel", "rebecca", "robin", "rose", "ruby", "ruth",
  "sandra", "sara", "sarah", "sharon", "shirley", "stephanie", "susan",
  "tammy", "teresa", "theresa", "tina", "virginia", "wanda"
]
Iconv_IBM1047 =

The Iconv translation table for IBM’s mainframe / System Z (z/os, s390, mvs, etc) - This is a different implementation of EBCDIC than the Iconv_EBCDIC below. It is technically referred to as Code Page IBM1047. This will be net new (until Ruby supports 1047 code page) for all Mainframe / SystemZ based modules that need to convert ASCII to EBCDIC

The bytes are indexed by ASCII conversion number e.g. Iconv_IBM1047 == xc1 for letter “A”

Note the characters CANNOT be assumed to be in any logical order. Nor are the tables reversible. Lookups must be for each byte gist.github.com/bigendiansmalls/b08483ecedff52cc8fa3

[
  "\x00","\x01","\x02","\x03","\x37","\x2d","\x2e","\x2f",
  "\x16","\x05","\x15","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
  "\x11","\x12","\x13","\x3c","\x3d","\x32","\x26","\x18","\x19",
  "\x3f","\x27","\x1c","\x1d","\x1e","\x1f","\x40","\x5a","\x7f",
  "\x7b","\x5b","\x6c","\x50","\x7d","\x4d","\x5d","\x5c","\x4e",
  "\x6b","\x60","\x4b","\x61","\xf0","\xf1","\xf2","\xf3","\xf4",
  "\xf5","\xf6","\xf7","\xf8","\xf9","\x7a","\x5e","\x4c","\x7e",
  "\x6e","\x6f","\x7c","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6",
  "\xc7","\xc8","\xc9","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6",
  "\xd7","\xd8","\xd9","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7",
  "\xe8","\xe9","\xad","\xe0","\xbd","\x5f","\x6d","\x79","\x81",
  "\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x91",
  "\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\xa2",
  "\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xc0","\x4f",
  "\xd0","\xa1","\x07","\x20","\x21","\x22","\x23","\x24","\x25",
  "\x06","\x17","\x28","\x29","\x2a","\x2b","\x2c","\x09","\x0a",
  "\x1b","\x30","\x31","\x1a","\x33","\x34","\x35","\x36","\x08",
  "\x38","\x39","\x3a","\x3b","\x04","\x14","\x3e","\xff","\x41",
  "\xaa","\x4a","\xb1","\x9f","\xb2","\x6a","\xb5","\xbb","\xb4",
  "\x9a","\x8a","\xb0","\xca","\xaf","\xbc","\x90","\x8f","\xea",
  "\xfa","\xbe","\xa0","\xb6","\xb3","\x9d","\xda","\x9b","\x8b",
  "\xb7","\xb8","\xb9","\xab","\x64","\x65","\x62","\x66","\x63",
  "\x67","\x9e","\x68","\x74","\x71","\x72","\x73","\x78","\x75",
  "\x76","\x77","\xac","\x69","\xed","\xee","\xeb","\xef","\xec",
  "\xbf","\x80","\xfd","\xfe","\xfb","\xfc","\xba","\xae","\x59",
  "\x44","\x45","\x42","\x46","\x43","\x47","\x9c","\x48","\x54",
  "\x51","\x52","\x53","\x58","\x55","\x56","\x57","\x8c","\x49",
  "\xcd","\xce","\xcb","\xcf","\xcc","\xe1","\x70","\xdd","\xde",
  "\xdb","\xdc","\x8d","\x8e","\xdf"
]
Iconv_ISO8859_1 =

This is the reverse of the above, converts EBCDIC -> ASCII The bytes are indexed by IBM1047(EBCDIC) conversion number e.g. Iconv_ISO8859_1 = x41 for letter “A”

Note the characters CANNOT be assumed to be in any logical (e.g. sequential) order. Nor are the tables reversible. Lookups must be done byte by byte

[
  "\x00","\x01","\x02","\x03","\x9c","\x09","\x86","\x7f",
  "\x97","\x8d","\x8e","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
  "\x11","\x12","\x13","\x9d","\x0a","\x08","\x87","\x18","\x19",
  "\x92","\x8f","\x1c","\x1d","\x1e","\x1f","\x80","\x81","\x82",
  "\x83","\x84","\x85","\x17","\x1b","\x88","\x89","\x8a","\x8b",
  "\x8c","\x05","\x06","\x07","\x90","\x91","\x16","\x93","\x94",
  "\x95","\x96","\x04","\x98","\x99","\x9a","\x9b","\x14","\x15",
  "\x9e","\x1a","\x20","\xa0","\xe2","\xe4","\xe0","\xe1","\xe3",
  "\xe5","\xe7","\xf1","\xa2","\x2e","\x3c","\x28","\x2b","\x7c",
  "\x26","\xe9","\xea","\xeb","\xe8","\xed","\xee","\xef","\xec",
  "\xdf","\x21","\x24","\x2a","\x29","\x3b","\x5e","\x2d","\x2f",
  "\xc2","\xc4","\xc0","\xc1","\xc3","\xc5","\xc7","\xd1","\xa6",
  "\x2c","\x25","\x5f","\x3e","\x3f","\xf8","\xc9","\xca","\xcb",
  "\xc8","\xcd","\xce","\xcf","\xcc","\x60","\x3a","\x23","\x40",
  "\x27","\x3d","\x22","\xd8","\x61","\x62","\x63","\x64","\x65",
  "\x66","\x67","\x68","\x69","\xab","\xbb","\xf0","\xfd","\xfe",
  "\xb1","\xb0","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f","\x70",
  "\x71","\x72","\xaa","\xba","\xe6","\xb8","\xc6","\xa4","\xb5",
  "\x7e","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a",
  "\xa1","\xbf","\xd0","\x5b","\xde","\xae","\xac","\xa3","\xa5",
  "\xb7","\xa9","\xa7","\xb6","\xbc","\xbd","\xbe","\xdd","\xa8",
  "\xaf","\x5d","\xb4","\xd7","\x7b","\x41","\x42","\x43","\x44",
  "\x45","\x46","\x47","\x48","\x49","\xad","\xf4","\xf6","\xf2",
  "\xf3","\xf5","\x7d","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
  "\x50","\x51","\x52","\xb9","\xfb","\xfc","\xf9","\xfa","\xff",
  "\x5c","\xf7","\x53","\x54","\x55","\x56","\x57","\x58","\x59",
  "\x5a","\xb2","\xd4","\xd6","\xd2","\xd3","\xd5","\x30","\x31",
  "\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\xb3",
  "\xdb","\xdc","\xd9","\xda","\x9f"
]
Iconv_EBCDIC =

The Iconv translation table. The Iconv gem is deprecated in favor of String#encode, yet there is no encoding for EBCDIC. See #4525

[
  "\x00", "\x01", "\x02", "\x03", "7", "-", ".", "/", "\x16", "\x05",
  "%", "\v", "\f", "\r", "\x0E", "\x0F", "\x10", "\x11", "\x12", "\x13",
  "<", "=", "2", "&", "\x18", "\x19", "?", "'", "\x1C", "\x1D", "\x1E",
  "\x1F", "@", "Z", "\x7F", "{", "[", "l", "P", "}", "M", "]", "\\",
  "N", "k", "`", "K", "a", "\xF0", "\xF1", "\xF2", "\xF3", "\xF4",
  "\xF5", "\xF6", "\xF7", "\xF8", "\xF9", "z", "^", "L", "~", "n", "o",
  "|", "\xC1", "\xC2", "\xC3", "\xC4", "\xC5", "\xC6", "\xC7", "\xC8",
  "\xC9", "\xD1", "\xD2", "\xD3", "\xD4", "\xD5", "\xD6", "\xD7",
  "\xD8", "\xD9", "\xE2", "\xE3", "\xE4", "\xE5", "\xE6", "\xE7",
  "\xE8", "\xE9", nil, "\xE0", nil, nil, "m", "y", "\x81", "\x82",
  "\x83", "\x84", "\x85", "\x86", "\x87", "\x88", "\x89", "\x91",
  "\x92", "\x93", "\x94", "\x95", "\x96", "\x97", "\x98", "\x99",
  "\xA2", "\xA3", "\xA4", "\xA5", "\xA6", "\xA7", "\xA8", "\xA9",
  "\xC0", "O", "\xD0", "\xA1", "\a", nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil
]
Iconv_ASCII =
[
  "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\a", "\b",
  "\t", "\n", "\v", "\f", "\r", "\x0E", "\x0F", "\x10", "\x11", "\x12",
  "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1A", "\e",
  "\x1C", "\x1D", "\x1E", "\x1F", " ", "!", "\"", "#", "$", "%", "&",
  "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4",
  "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B",
  "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", nil, "\\", nil,
  nil, "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
  "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
  "z", "{", "|", "}", "~", "\x7F", nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil
]
VERSION =
"0.2.28"
@@codepage_map_cache =
nil

Class Method Summary collapse

Class Method Details

.ascii_safe_hex(str, whitespace = false) ⇒ Object

Turn non-printable chars into hex representations, leaving others alone

If whitespace is true, converts whitespace (0x20, 0x09, etc) to hex as well.



113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rex/text/hex.rb', line 113

def self.ascii_safe_hex(str, whitespace=false)
  # This sanitization is terrible and breaks everything if it finds unicode.
  # ~4 Billion can't be wrong; long-term, this should be removed.
  if str.encoding == (::Encoding::UTF_8)
    return str
  end
  if whitespace
    str.gsub(/([\x00-\x20\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] }
  else
    str.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
  end
end

.b32decode(bytes_in) ⇒ Object

Base32 decoder



64
65
66
67
68
69
70
# File 'lib/rex/text/base32.rb', line 64

def self.b32decode(bytes_in)
  bytes = bytes_in.take_while {|c| c != 61} # strip padding
  n = (bytes.length * 5.0 / 8.0).floor
  p = bytes.length < 8 ? 5 - (n * 8) % 5 : 0
  c = bytes.inject(0) {|m,o| (m << 5) + Base32.index(o.chr)} >> p
  (0..n-1).to_a.reverse.collect {|i| ((c >> i * 8) & 0xff).chr}
end

.b32encode(bytes_in) ⇒ Object

Base32 encoder



39
40
41
42
43
44
45
# File 'lib/rex/text/base32.rb', line 39

def self.b32encode(bytes_in)
  n = (bytes_in.length * 8.0 / 5.0).ceil
  p = n < 8 ? 5 - (bytes_in.length * 8) % 5 : 0
  c = bytes_in.inject(0) {|m,o| (m << 8) + o} << p
  [(0..n-1).to_a.reverse.collect {|i| Base32[(c >> i * 5) & 0x1f].chr},
   ("=" * (8-n))]
end

.badchar_index(data, badchars = '') ⇒ Integer?

Return the index of the first badchar in data, otherwise return nil if there wasn’t any badchar occurences.

Parameters:

  • data (String)

    The string to check for bad characters

  • badchars (String) (defaults to: '')

    A list of characters considered to be bad

Returns:

  • (Integer)

    Index of the first bad character if any exist in data

  • (nil)

    If data contains no bad characters



17
18
19
20
21
22
23
# File 'lib/rex/text/badchars.rb', line 17

def self.badchar_index(data, badchars = '')
  badchars.unpack("C*").each { |badchar|
    pos = data.index(badchar.chr)
    return pos if pos
  }
  return nil
end

.block_api_hash(mod, func) ⇒ String

Calculate the block API hash for the given module/function

Parameters:

  • mod (String)

    The name of the module containing the target function.

  • fun (String)

    The name of the function.

Returns:

  • (String)

    The hash of the mod/fun pair in string format



16
17
18
19
20
21
# File 'lib/rex/text/block_api.rb', line 16

def self.block_api_hash(mod, func)
  unicode_mod = (mod.upcase + "\x00").unpack('C*').pack('v*')
  mod_hash = self.ror13_hash(unicode_mod)
  fun_hash = self.ror13_hash(func + "\x00")
  "0x#{(mod_hash + fun_hash & 0xFFFFFFFF).to_s(16)}"
end

.charset_exclude(keepers) ⇒ String

Returns all chars that are not in the supplied set

Parameters:

  • keepers (String)

Returns:

  • (String)

    All characters not contained in keepers



44
45
46
47
# File 'lib/rex/text/badchars.rb', line 44

def self.charset_exclude(keepers)
  excluded_bytes = [*(0..255)] - keepers.unpack("C*")
  excluded_bytes.pack("C*")
end

.checksum16_be(str) ⇒ Integer

Returns 16-bit checksum.

Parameters:

  • str (String)

    Big-endian data to checksum

Returns:

  • (Integer)

    16-bit checksum



23
24
25
# File 'lib/rex/text/checksum.rb', line 23

def self.checksum16_be(str)
  (str.unpack("n*").inject(:+) || 0) % 0x10000
end

.checksum16_le(str) ⇒ Integer

Returns 16-bit checksum.

Parameters:

  • str (String)

    Little-endian data to checksum

Returns:

  • (Integer)

    16-bit checksum



17
18
19
# File 'lib/rex/text/checksum.rb', line 17

def self.checksum16_le(str)
  (str.unpack("v*").inject(:+) || 0) % 0x10000
end

.checksum32_be(str) ⇒ Integer

Returns 32-bit checksum.

Parameters:

  • str (String)

    Big-endian data to checksum

Returns:

  • (Integer)

    32-bit checksum



35
36
37
# File 'lib/rex/text/checksum.rb', line 35

def self.checksum32_be(str)
  (str.unpack("N*").inject(:+) || 0) % 0x100000000
end

.checksum32_le(str) ⇒ Integer

Returns 32-bit checksum.

Parameters:

  • str (String)

    Little-endian data to checksum

Returns:

  • (Integer)

    32-bit checksum



29
30
31
# File 'lib/rex/text/checksum.rb', line 29

def self.checksum32_le(str)
  (str.unpack("V*").inject(:+) || 0) % 0x100000000
end

.checksum8(str) ⇒ Integer

Returns 8-bit checksum.

Parameters:

  • str (String)

    Data to checksum

Returns:

  • (Integer)

    8-bit checksum



11
12
13
# File 'lib/rex/text/checksum.rb', line 11

def self.checksum8(str)
  (str.unpack("C*").inject(:+) || 0) % 0x100
end

.compress(str) ⇒ String

Compresses a string, eliminating all superfluous whitespace before and after lines and eliminating all lines.

Parameters:

  • str (String)

    The string in which to crunch whitespace

Returns:

  • (String)

    Just like str, but with repeated whitespace characters trimmed down to a single space



16
17
18
# File 'lib/rex/text/compress.rb', line 16

def self.compress(str)
  str.gsub(/\n/m, ' ').gsub(/\s+/, ' ').gsub(/^\s+/, '').gsub(/\s+$/, '')
end

.cowsay(text, width = 39) ⇒ Object

Converts a string to one similar to what would be used by cowsay(1), a UNIX utility for displaying text as if it was coming from an ASCII-cow’s mouth:

 __________________
< the cow says moo >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Parameters:

  • text (String)

    The string to cowsay

  • width (Integer) (defaults to: 39)

    Width of the cow's cloud. Default's to cowsay(1)'s default, 39.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rex/text/silly.rb', line 24

def self.cowsay(text, width=39)
  # cowsay(1) chunks a message up into 39-byte chunks and wraps it in '| ' and ' |'
  # Rex::Text.wordwrap(text, 0, 39, ' |', '| ') almost does this, but won't
  # split a word that has > 39 characters in it which results in oddly formed
  # text in the cowsay banner, so just do it by hand.  This big mess wraps
  # the provided text in an ASCII-cloud and then makes it look like the cloud
  # is a thought/word coming from the ASCII-cow.  Each line in the
  # ASCII-cloud is no more than the specified number-characters long, and the
  # cloud corners are made to look rounded
  text_lines = text.scan(Regexp.new(".{1,#{width-4}}"))
  max_length = text_lines.map(&:size).sort.last
  cloud_parts = []
  cloud_parts << " #{'_' * (max_length + 2)}"
  if text_lines.size == 1
    cloud_parts << "< #{text} >"
  else
    cloud_parts << "/ #{text_lines.first.ljust(max_length, ' ')} \\"
    if text_lines.size > 2
      text_lines[1, text_lines.length - 2].each do |line|
        cloud_parts << "| #{line.ljust(max_length, ' ')} |"
      end
    end
    cloud_parts << "\\ #{text_lines.last.ljust(max_length, ' ')} /"
  end
  cloud_parts << " #{'-' * (max_length + 2)}"
  cloud_parts << <<EOS
   \\   ,__,
    \\  (oo)____
       (__)    )\\
          ||--|| *
EOS
  cloud_parts.join("\n")
end

.decode_base32(str) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rex/text/base32.rb', line 72

def self.decode_base32(str)
  bytes = str.bytes
  result = ''
  size= 8
  while bytes.any? do
    bytes.each_slice(size) do |a|
      bytes_out = b32decode(a).flatten.join
      result << bytes_out
      bytes = bytes.drop(size)
    end
  end
  return result
end

.decode_base64(str) ⇒ Object

Base64 decoder



24
25
26
# File 'lib/rex/text/base64.rb', line 24

def self.decode_base64(str)
  str.to_s.unpack("m")[0]
end

.decode_base64url(str) ⇒ Object

Base64 decoder (URL-safe RFC6920, ignores invalid characters)



40
41
42
43
44
# File 'lib/rex/text/base64.rb', line 40

def self.decode_base64url(str)
  decode_base64(
    str.gsub(/[^a-zA-Z0-9_\-]/, '').
      tr('-_', '+/'))
end

.dehex(str) ⇒ Object

Convert hex-encoded characters to literals.

Examples:

Rex::Text.dehex("AA\\x42CC") # => "AABCC"

Parameters:

  • str (String)

See Also:



185
186
187
188
189
190
191
192
193
194
# File 'lib/rex/text/hex.rb', line 185

def self.dehex(str)
  return str unless str.respond_to? :match
  return str unless str.respond_to? :gsub
  regex = /\x5cx[0-9a-f]{2}/nmi
  if str.match(regex)
    str.gsub(regex) { |x| x[2,2].to_i(16).chr }
  else
    str
  end
end

.dehex!(str) ⇒ Object

Convert and replace hex-encoded characters to literals.

Parameters:

  • str (String)


200
201
202
203
204
205
# File 'lib/rex/text/hex.rb', line 200

def self.dehex!(str)
  return str unless str.respond_to? :match
  return str unless str.respond_to? :gsub
  regex = /\x5cx[0-9a-f]{2}/nmi
  str.gsub!(regex) { |x| x[2,2].to_i(16).chr }
end

.encode_base32(str) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rex/text/base32.rb', line 47

def self.encode_base32(str)
  bytes = str.bytes
  result = ''
  size= 5
  while bytes.any? do
    bytes.each_slice(size) do |a|
      bytes_out = b32encode(a).flatten.join
      result << bytes_out
      bytes = bytes.drop(size)
    end
  end
  return result
end

.encode_base64(str, delim = nil) ⇒ Object

Base64 encoder



13
14
15
16
17
18
19
# File 'lib/rex/text/base64.rb', line 13

def self.encode_base64(str, delim=nil)
  if delim
    [str.to_s].pack("m").gsub(/\s+/, delim)
  else
    [str.to_s].pack("m0")
  end
end

.encode_base64url(str, delim = nil) ⇒ Object

Base64 encoder (URL-safe RFC6920)



31
32
33
34
35
# File 'lib/rex/text/base64.rb', line 31

def self.encode_base64url(str, delim=nil)
  encode_base64(str, delim).
    tr('+/', '-_').
    gsub('=', '')
end

.from_ebcdic(str) ⇒ String

Note:

This method will raise in the event of invalid characters

A native implementation of the EBCDIC to ASCII conversion table, since EBCDIC isn’t available to String#encode as of Ruby 2.1

Parameters:

  • str (String)

    an EBCDIC encoded string

Returns:

  • (String)

    An encodable ASCII string



173
174
175
176
177
178
179
180
181
182
183
# File 'lib/rex/text/ebcdic.rb', line 173

def self.from_ebcdic(str)
  new_str = []
  str.each_byte do |x|
    if Iconv_EBCDIC.index(x.chr)
      new_str << Iconv_ASCII[Iconv_EBCDIC.index(x.chr)]
    else
      raise Rex::Text::IllegalSequence, ("\\x%x" % x)
    end
  end
  new_str.join
end

.from_ibm1047(str) ⇒ Object

The next two are the same as the above, except strictly for z/os conversions

strictly for ISO8859-1 -> IBM1047

A native implementation of the ISO8859-1(ASCII) -> IBM1047(EBCDIC) conversion table, since EBCDIC isn’t available to String#encode as of Ruby 2.1



209
210
211
212
213
214
215
216
# File 'lib/rex/text/ebcdic.rb', line 209

def self.from_ibm1047(str)
  return str if str.nil?
  new_str = []
  str.each_byte do |x|
    new_str << Iconv_ISO8859_1[x.ord]
  end
  new_str.join
end

.gzip(str, level = 9) ⇒ String

Compresses a string using gzip

Parameters:

  • level (Integer) (defaults to: 9)

    Compression level, 1 (fast) to 9 (best)

  • str (String)

    The string to be compressed

Returns:

  • (String)

    The compressed version of str

Raises:

  • (RuntimeError)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rex/text/compress.rb', line 77

def self.gzip(str, level = 9)
  raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
  raise RuntimeError, "Invalid gzip compression level" if (level < 1 or level > 9)

  s = ""
  s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
  gz = Zlib::GzipWriter.new(StringIO.new(s, 'wb'), level)
  gz << str
  gz.close
  return s
end

.gzip_present?Boolean

backwards compat for just a bit…

Returns:

  • (Boolean)


33
34
35
# File 'lib/rex/text/compress.rb', line 33

def self.gzip_present?
  self.zlib_present?
end

.hex_to_raw(str) ⇒ Object

Converts a hex string to a raw string

Examples:

Rex::Text.hex_to_raw("\\x41\\x7f\\x42") # => "A\x7fB"


100
101
102
# File 'lib/rex/text/hex.rb', line 100

def self.hex_to_raw(str)
  [ str.downcase.gsub(/'/,'').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack("H*")
end

.hexify(str, col = DefaultWrap, line_start = '', line_end = '', buf_start = '', buf_end = '') ⇒ Object

Converts a string to a hex version with wrapping support



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rex/text/hex.rb', line 129

def self.hexify(str, col = DefaultWrap, line_start = '', line_end = '', buf_start = '', buf_end = '')
  output	 = buf_start
  cur	 = 0
  count	 = 0
  new_line = true

  # Go through each byte in the string
  str.each_byte { |byte|
    count  += 1
    append	= ''

    # If this is a new line, prepend with the
    # line start text
    if (new_line == true)
      append	 << line_start
      new_line  = false
    end

    # Append the hexified version of the byte
    append << sprintf("\\x%.2x", byte)
    cur    += append.length

    # If we're about to hit the column or have gone past it,
    # time to finish up this line
    if ((cur + line_end.length >= col) or (cur + buf_end.length  >= col))
      new_line  = true
      cur	  = 0

      # If this is the last byte, use the buf_end instead of
      # line_end
      if (count == str.length)
        append << buf_end + "\n"
      else
        append << line_end + "\n"
      end
    end

    output << append
  }

  # If we were in the middle of a line, finish the buffer at this point
  if (new_line == false)
    output << buf_end + "\n"
  end

  return output
end

.html_decode(str) ⇒ Object

Decode a string that’s html encoded



85
86
87
88
# File 'lib/rex/text/encode.rb', line 85

def self.html_decode(str)
  decoded_str = CGI.unescapeHTML(str)
  return decoded_str
end

.html_encode(str, mode = 'hex') ⇒ String

Encode a string in a manner useful for HTTP URIs and URI Parameters.

Parameters:

  • str (String)

    The string to be encoded

  • mode ("hex", "int", "int-wide") (defaults to: 'hex')

Returns:

  • (String)

Raises:

  • (TypeError)

    if mode is not one of the three available modes



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rex/text/encode.rb', line 69

def self.html_encode(str, mode = 'hex')
  case mode
    when 'hex'
      return str.unpack('C*').collect{ |i| "&#x" + ("%.2x" % i) + ";"}.join
    when 'int'
      return str.unpack('C*').collect{ |i| "&#" + i.to_s + ";"}.join
    when 'int-wide'
      return str.unpack('C*').collect{ |i| "&#" + ("0" * (7 - i.to_s.length)) + i.to_s + ";" }.join
    else
      raise TypeError, 'invalid mode'
  end
end

.md5(str) ⇒ Object

Hexidecimal MD5 digest of the supplied string



19
20
21
# File 'lib/rex/text/hash.rb', line 19

def self.md5(str)
  Digest::MD5.hexdigest(str)
end

.md5_raw(str) ⇒ Object

Raw MD5 digest of the supplied string



12
13
14
# File 'lib/rex/text/hash.rb', line 12

def self.md5_raw(str)
  Digest::MD5.digest(str)
end

.pack_int64le(val) ⇒ Object

Pack a value as 64 bit litle endian; does not exist for Array.pack



67
68
69
# File 'lib/rex/text/binary_manipulation.rb', line 67

def self.pack_int64le(val)
  [val & 0x00000000ffffffff, val >> 32].pack("V2")
end

.patt2(len, sets = nil) ⇒ Object

Step through an arbitrary number of sets of bytes to build up a findable pattern. This is mostly useful for experimentially determining offset lengths into memory structures. Note that the supplied sets should never contain duplicate bytes, or else it can become impossible to measure the offset accurately.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rex/text/pattern.rb', line 46

def self.patt2(len, sets = nil)
  buf = ""
  counter = []
  sets ||= [ UpperAlpha, LowerAlpha, Numerals ]
  len ||= len.to_i
  return "" if len.zero?

  sets = sets.map {|a| a.split(//)}
  sets.size.times { counter << 0}
  0.upto(len-1) do |i|
    setnum = i % sets.size

    #puts counter.inspect
  end

  return buf
end

.pattern_create(length, sets = nil) ⇒ String

Creates a pattern that can be used for offset calculation purposes. This routine is capable of generating patterns using a supplied set and a supplied number of identifiable characters (slots). The supplied sets should not contain any duplicate characters or the logic will fail.

Parameters:

  • length (Integer)
  • sets (Array<(String,String,String)>) (defaults to: nil)

    The character sets to choose from. Should have 3 elements, each of which must be a string containing no characters contained in the other sets.

Returns:

  • (String)

    A pattern of length bytes, in which any 4-byte chunk is unique

See Also:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rex/text/pattern.rb', line 22

def self.pattern_create(length, sets = nil)
  buf = ''
  offsets = []

  # Make sure there's something in sets even if we were given an explicit nil
  sets ||= [ UpperAlpha, LowerAlpha, Numerals ]

  # Return stupid uses
  return "" if length.to_i < 1
  return sets[0][0].chr * length if sets.size == 1 and sets[0].size == 1

  sets.length.times { offsets << 0 }

  until buf.length >= length
      buf << converge_sets(sets, 0, offsets, length)
  end

  buf[0,length]
end

.pattern_offset(pattern, value, start = 0) ⇒ Integer?

Calculate the offset to a pattern

Parameters:

  • pattern (String)

    The pattern to search. Usually the return value from pattern_create

  • value (String, Integer)

Returns:

  • (Integer)

    Index of the given value within pattern, if it exists

  • (nil)

    if pattern does not contain value

See Also:



73
74
75
76
77
78
79
80
81
# File 'lib/rex/text/pattern.rb', line 73

def self.pattern_offset(pattern, value, start=0)
  if value.kind_of?(String)
    pattern.index(value, start)
  elsif value.kind_of?(Integer)
    pattern.index([ value ].pack('V'), start)
  else
    raise ::ArgumentError, "Invalid class for value: #{value.class}"
  end
end

.permute_case(word, idx = 0) ⇒ Object

Permute the case of a word



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rex/text/randomize.rb', line 86

def self.permute_case(word, idx=0)
  res = []

  if( (UpperAlpha+LowerAlpha).index(word[idx,1]))

    word_ucase = word.dup
    word_ucase[idx, 1] = word[idx, 1].upcase

    word_lcase = word.dup
    word_lcase[idx, 1] = word[idx, 1].downcase

    if (idx == word.length)
      return [word]
    else
      res << permute_case(word_ucase, idx+1)
      res << permute_case(word_lcase, idx+1)
    end
  else
    res << permute_case(word, idx+1)
  end

  res.flatten
end

.rand_4byte_utf8String

Generate a valid random 4 byte UTF-8 character valid codepoints for 4byte UTF-8 chars: U+010000 - U+10FFFF

Examples:

Rex::Text.rand_4byte_utf8 # => "\u{108CF3}"

Returns:

  • (String)


202
203
204
# File 'lib/rex/text/rand.rb', line 202

def self.rand_4byte_utf8
  [rand(0x10000..0x10ffff)].pack('U*')
end

.rand_base(len, bad, *foo) ⇒ Object

Base text generator method



102
103
104
105
106
107
108
109
# File 'lib/rex/text/rand.rb', line 102

def self.rand_base(len, bad, *foo)
  cset = (foo.join.unpack("C*") - bad.to_s.unpack("C*")).uniq
  return "" if cset.length == 0
  outp = []
  (len = rand(len)) if len.kind_of?(Range)
  len.times { outp << cset[rand(cset.length)] }
  outp.pack("C*")
end

.rand_char(bad, chars = AllChars) ⇒ Object

Generates a random character.



97
98
99
# File 'lib/rex/text/rand.rb', line 97

def self.rand_char(bad, chars = AllChars)
  rand_text(1, bad, chars)
end

.rand_countryObject

Generate a country code



219
220
221
# File 'lib/rex/text/rand.rb', line 219

def self.rand_country
  Countries.sample
end

.rand_guidString

Generate a random GUID

Examples:

Rex::Text.rand_guid # => "{ca776ced-4ab8-2ed6-6510-aa71e5e2508e}"

Returns:

  • (String)


190
191
192
# File 'lib/rex/text/rand.rb', line 190

def self.rand_guid
  "{#{[8,4,4,4,12].map {|a| rand_text_hex(a) }.join("-")}}"
end

.rand_hostnameString

Generate a random hostname

Returns:

  • (String)

    A random string conforming to the rules of FQDNs



209
210
211
212
213
214
215
216
# File 'lib/rex/text/rand.rb', line 209

def self.rand_hostname
  host = []
  (rand(5) + 1).times {
    host.push(Rex::Text.rand_text_alphanumeric(rand(10) + 1))
  }
  host.push(TLDs.sample)
  host.join('.').downcase
end

.rand_mail_addressObject

Generate a random mail address



253
254
255
256
257
258
259
260
# File 'lib/rex/text/rand.rb', line 253

def self.rand_mail_address
  mail_address = ''
  mail_address << Rex::Text.rand_name
  mail_address << '.'
  mail_address << Rex::Text.rand_surname
  mail_address << '@'
  mail_address << Rex::Text.rand_hostname
end

.rand_nameObject

Generate a name



234
235
236
237
238
239
240
# File 'lib/rex/text/rand.rb', line 234

def self.rand_name
  if rand(10) % 2 == 0
    Names_Male.sample
  else
    Names_Female.sample
  end
end

.rand_name_femaleObject

Generate a female name



248
249
250
# File 'lib/rex/text/rand.rb', line 248

def self.rand_name_female
  Names_Female.sample
end

.rand_name_maleObject

Generate a male name



243
244
245
# File 'lib/rex/text/rand.rb', line 243

def self.rand_name_male
  Names_Male.sample
end

.rand_stateObject

Generate a state



224
225
226
# File 'lib/rex/text/rand.rb', line 224

def self.rand_state()
  States.sample
end

.rand_surnameObject

Generate a surname



229
230
231
# File 'lib/rex/text/rand.rb', line 229

def self.rand_surname
  Surnames.sample
end

.rand_text(len, bad = '', chars = AllChars) ⇒ Object

Generate random bytes of data



112
113
114
115
# File 'lib/rex/text/rand.rb', line 112

def self.rand_text(len, bad='', chars = AllChars)
  foo = chars.split('')
  rand_base(len, bad, *foo)
end

.rand_text_alpha(len, bad = '') ⇒ Object

Generate random bytes of alpha data



118
119
120
121
122
123
# File 'lib/rex/text/rand.rb', line 118

def self.rand_text_alpha(len, bad='')
  foo = []
  foo += ('A' .. 'Z').to_a
  foo += ('a' .. 'z').to_a
  rand_base(len, bad, *foo )
end

.rand_text_alpha_lower(len, bad = '') ⇒ Object

Generate random bytes of lowercase alpha data



126
127
128
# File 'lib/rex/text/rand.rb', line 126

def self.rand_text_alpha_lower(len, bad='')
  rand_base(len, bad, *('a' .. 'z').to_a)
end

.rand_text_alpha_upper(len, bad = '') ⇒ Object

Generate random bytes of uppercase alpha data



131
132
133
# File 'lib/rex/text/rand.rb', line 131

def self.rand_text_alpha_upper(len, bad='')
  rand_base(len, bad, *('A' .. 'Z').to_a)
end

.rand_text_alphanumeric(len, bad = '') ⇒ Object

Generate random bytes of alphanumeric data



136
137
138
139
140
141
142
# File 'lib/rex/text/rand.rb', line 136

def self.rand_text_alphanumeric(len, bad='')
  foo = []
  foo += ('A' .. 'Z').to_a
  foo += ('a' .. 'z').to_a
  foo += ('0' .. '9').to_a
  rand_base(len, bad, *foo )
end

.rand_text_base64(len, bad = '') ⇒ Object

Generate random bytes of base64 data



173
174
175
176
# File 'lib/rex/text/rand.rb', line 173

def self.rand_text_base64(len, bad='')
  foo = Base64.unpack('C*').map{ |c| c.chr }
  rand_base(len, bad, *foo )
end

.rand_text_base64url(len, bad = '') ⇒ Object

Generate random bytes of base64url data



179
180
181
182
# File 'lib/rex/text/rand.rb', line 179

def self.rand_text_base64url(len, bad='')
  foo = Base64Url.unpack('C*').map{ |c| c.chr }
  rand_base(len, bad, *foo )
end

.rand_text_english(len, bad = '') ⇒ Object

Generate random bytes of english-like data



159
160
161
162
163
# File 'lib/rex/text/rand.rb', line 159

def self.rand_text_english(len, bad='')
  foo = []
  foo += (0x21 .. 0x7e).map{ |c| c.chr }
  rand_base(len, bad, *foo )
end

.rand_text_hex(len, bad = '') ⇒ Object

Generate random bytes of alphanumeric hex.



145
146
147
148
149
150
# File 'lib/rex/text/rand.rb', line 145

def self.rand_text_hex(len, bad='')
  foo = []
  foo += ('0' .. '9').to_a
  foo += ('a' .. 'f').to_a
  rand_base(len, bad, *foo)
end

.rand_text_highascii(len, bad = '') ⇒ Object

Generate random bytes of high ascii data



166
167
168
169
170
# File 'lib/rex/text/rand.rb', line 166

def self.rand_text_highascii(len, bad='')
  foo = []
  foo += (0x80 .. 0xff).map{ |c| c.chr }
  rand_base(len, bad, *foo )
end

.rand_text_numeric(len, bad = '') ⇒ Object

Generate random bytes of numeric data



153
154
155
156
# File 'lib/rex/text/rand.rb', line 153

def self.rand_text_numeric(len, bad='')
  foo = ('0' .. '9').to_a
  rand_base(len, bad, *foo )
end

.randomize_space(str) ⇒ Object

Randomize the whitespace in a string



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rex/text/randomize.rb', line 51

def self.randomize_space(str)
  set = ["\x09", "\x20", "\x0d", "\x0a"]
  str.gsub(/\s+/) { |s|
    len = rand(50)+2
    buf = ''
    while (buf.length < len)
      buf << set.sample
    end

    buf
  }
end

.refine(str1, str2) ⇒ Object

Removes noise from 2 Strings and return a refined String version.



101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/rex/text/binary_manipulation.rb', line 101

def self.refine( str1, str2 )
  return str1 if str1 == str2

  # get the words of the first str in an array
  s_words = to_words( str1 )

  # get the words of the second str in an array
  o_words = to_words( str2 )

  # get what hasn't changed (the rdiff, so to speak) as a string
  (s_words - (s_words - o_words)).join
end

.remove_badchars(data, badchars = '') ⇒ Object

Removes bad characters from a string.

Modifies data in place

Parameters:

  • data (#delete)
  • badchars (String) (defaults to: '')

    A list of characters considered to be bad



32
33
34
35
36
37
# File 'lib/rex/text/badchars.rb', line 32

def self.remove_badchars(data, badchars = '')
  return data if badchars.length == 0
  badchars_pat = badchars.unpack("C*").map{|c| "\\x%.2x" % c}.join
  data.gsub!(/[#{badchars_pat}]/n, '')
  data
end

.rol(val, cnt) ⇒ Object

Rotate a 32-bit value to the left by cnt bits

Parameters:

  • val (Integer)

    The value to rotate

  • cnt (Integer)

    Number of bits to rotate by



90
91
92
93
94
95
96
# File 'lib/rex/text/binary_manipulation.rb', line 90

def self.rol(val, cnt)
  bits = [val].pack("N").unpack("B32")[0].split(//)
  1.upto(cnt) do |c|
    bits.push( bits.shift )
  end
  [bits.join].pack("B32").unpack("N")[0]
end

.ror(val, cnt) ⇒ Object

Rotate a 32-bit value to the right by cnt bits

Parameters:

  • val (Integer)

    The value to rotate

  • cnt (Integer)

    Number of bits to rotate by



76
77
78
79
80
81
82
# File 'lib/rex/text/binary_manipulation.rb', line 76

def self.ror(val, cnt)
  bits = [val].pack("N").unpack("B32")[0].split(//)
  1.upto(cnt) do |c|
    bits.unshift( bits.pop )
  end
  [bits.join].pack("B32").unpack("N")[0]
end

.ror13_hash(name) ⇒ Integer

Calculate the ROR13 hash of a given string

Returns:

  • (Integer)


27
28
29
30
31
# File 'lib/rex/text/block_api.rb', line 27

def self.ror13_hash(name)
  hash = 0
  name.unpack("C*").each {|c| hash = ror(hash, 13); hash += c }
  hash
end

.sha1(str) ⇒ Object

Hexidecimal SHA1 digest of the supplied string



33
34
35
# File 'lib/rex/text/hash.rb', line 33

def self.sha1(str)
  Digest::SHA1.hexdigest(str)
end

.sha1_raw(str) ⇒ Object

Raw SHA1 digest of the supplied string



26
27
28
# File 'lib/rex/text/hash.rb', line 26

def self.sha1_raw(str)
  Digest::SHA1.digest(str)
end

.sha2(str) ⇒ Object

Hexidecimal SHA2 digest of the supplied string



47
48
49
# File 'lib/rex/text/hash.rb', line 47

def self.sha2(str)
  Digest::SHA2.hexdigest(str)
end

.sha2_raw(str) ⇒ Object

Raw SHA2 digest of the supplied string



40
41
42
# File 'lib/rex/text/hash.rb', line 40

def self.sha2_raw(str)
  Digest::SHA2.digest(str)
end

.shuffle_a(arr) ⇒ Array

Performs a Fisher-Yates shuffle on an array

Modifies arr in place

Parameters:

  • arr (Array)

    The array to be shuffled

Returns:

  • (Array)


81
82
83
# File 'lib/rex/text/randomize.rb', line 81

def self.shuffle_a(arr)
  arr.shuffle!
end

.shuffle_s(str) ⇒ String

Shuffles a byte stream

Parameters:

  • str (String)

Returns:

  • (String)

    The shuffled result

See Also:



70
71
72
# File 'lib/rex/text/randomize.rb', line 70

def self.shuffle_s(str)
  shuffle_a(str.unpack("C*")).pack("C*")
end

.split_to_a(str, n) ⇒ Object

Split a string by n character into an array



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/rex/text.rb', line 128

def self.split_to_a(str, n)
  if n > 0
    s = str.dup
    until s.empty?
      (ret ||= []).push s.slice!(0, n)
    end
  else
    ret = str
  end
  ret
end

.to_ascii(str = '', type = 'utf-16le', mode = '', size = '') ⇒ Object

Converts a unicode string to standard ASCII text.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/rex/text/unicode.rb', line 251

def self.to_ascii(str='', type = 'utf-16le', mode = '', size = '')
  return '' if not str
  case type
    when 'utf-16le'
      return str.unpack('v*').pack('C*')
    when 'utf-16be'
      return str.unpack('n*').pack('C*')
    when 'utf-32le'
      return str.unpack('V*').pack('C*')
    when 'utf-32be'
      return str.unpack('N*').pack('C*')
    when 'utf-7'
      raise TypeError, 'invalid utf type, not yet implemented'
    when 'utf-8'
      raise TypeError, 'invalid utf type, not yet implemented'
    when 'uhwtfms' # suggested name from HD :P
      raise TypeError, 'invalid utf type, not yet implemented'
    when 'uhwtfms-half' # suggested name from HD :P
      raise TypeError, 'invalid utf type, not yet implemented'
    else
      raise TypeError, 'invalid utf type'
  end
end

.to_bash(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts a raw string into a Bash buffer



72
73
74
# File 'lib/rex/text/lang.rb', line 72

def self.to_bash(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '$\'', '\'\\', "export #{name}=\\\n", '\'')
end

.to_bash_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a Bash-style comment



151
152
153
# File 'lib/rex/text/lang.rb', line 151

def self.to_bash_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end

.to_c(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts a raw string into a C buffer



26
27
28
# File 'lib/rex/text/lang.rb', line 26

def self.to_c(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '"', "unsigned char #{name}[] = \n", '";')
end

.to_c_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a c-style comment



44
45
46
# File 'lib/rex/text/lang.rb', line 44

def self.to_c_comment(str, wrap = DefaultWrap)
  return "/*\n" + wordwrap(str, 0, wrap, '', ' * ') + " */\n"
end

.to_csharp(str, wrap = DefaultWrap, name = "buf") ⇒ Object



30
31
32
33
34
35
36
37
38
39
# File 'lib/rex/text/lang.rb', line 30

def self.to_csharp(str, wrap = DefaultWrap, name = "buf")
  ret = "byte[] #{name} = new byte[#{str.length}] {"
  i = -1;
  while (i += 1) < str.length
    ret << "\n" if i%(wrap/4) == 0
    ret << "0x" << str[i].unpack("H*")[0] << ","
  end
  ret = ret[0..ret.length-2] #cut off last comma
  ret << " };\n"
end

.to_dword(str, wrap = DefaultWrap) ⇒ Object

Creates a comma separated list of dwords



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rex/text/binary_manipulation.rb', line 30

def self.to_dword(str, wrap = DefaultWrap)
  code = str
  alignnr = str.length % 4
  if (alignnr > 0)
    code << "\x00" * (4 - alignnr)
  end
  codevalues = Array.new
  code.split("").each_slice(4) do |chars4|
    chars4 = chars4.join("")
    dwordvalue = chars4.unpack('*V')
    codevalues.push(dwordvalue[0])
  end
  buff = ""
  0.upto(codevalues.length-1) do |byte|
    if(byte % 8 == 0) and (buff.length > 0)
      buff << "\r\n"
    end
    buff << sprintf('0x%.8x, ', codevalues[byte])
  end
  # strip , at the end
  buff = buff.chomp(', ')
  buff << "\r\n"
  return buff
end

.to_ebcdic(str) ⇒ String

Note:

This method will raise in the event of invalid characters

A native implementation of the ASCII to EBCDIC conversion table, since EBCDIC isn’t available to String#encode as of Ruby 2.1

Parameters:

  • str (String)

    An encodable ASCII string

Returns:

  • (String)

    an EBCDIC encoded string



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/rex/text/ebcdic.rb', line 155

def self.to_ebcdic(str)
  new_str = []
  str.each_byte do |x|
    if Iconv_ASCII.index(x.chr)
      new_str << Iconv_EBCDIC[Iconv_ASCII.index(x.chr)]
    else
      raise Rex::Text::IllegalSequence, ("\\x%x" % x)
    end
  end
  new_str.join
end

.to_guid(bytes) ⇒ String

Convert 16-byte string to a GUID string

Examples:

str = "ABCDEFGHIJKLMNOP"
Rex::Text.to_guid(str) #=> "{44434241-4645-4847-494a-4b4c4d4e4f50}"

Parameters:

  • bytes (String)

    16 bytes which represent a GUID in the proper order.

Returns:

  • (String)


112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rex/text.rb', line 112

def self.to_guid(bytes)
  return nil unless bytes
  s = bytes.unpack('H*')[0]
  parts = [
    s[6,  2] + s[4,  2] + s[2, 2] + s[0, 2],
    s[10, 2] + s[8,  2],
    s[14, 2] + s[12, 2],
    s[16, 4],
    s[20, 12]
  ]
  "{#{parts.join('-')}}"
end

.to_hex(str, prefix = "\\x", count = 1) ⇒ String

Returns the escaped hex version of the supplied string

Examples:

Rex::Text.to_hex("asdf") # => "\\x61\\x73\\x64\\x66"

Parameters:

  • count (Integer) (defaults to: 1)

    Number of bytes to put in each escape chunk

  • str (String)

    The string to be converted

  • prefix (String) (defaults to: "\\x")

Returns:

  • (String)

    The escaped hex version of str

Raises:

  • (::RuntimeError)


18
19
20
21
22
23
24
25
26
# File 'lib/rex/text/hex.rb', line 18

def self.to_hex(str, prefix = "\\x", count = 1)
  raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)

  # XXX: Regexp.new is used here since using /.{#{count}}/o would compile
  # the regex the first time it is used and never check again.  Since we
  # want to know how many to capture on every instance, we do it this
  # way.
  return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s| prefix + s }
end

.to_hex_ascii(str, prefix = "\\x", count = 1, suffix = nil) ⇒ String

Returns the string with nonprintable hex characters sanitized to ascii. Similiar to to_hex, but regular ASCII is not translated if count is 1.

Examples:

Rex::Text.to_hex_ascii("\x7fABC\0") # => "\\x7fABC\\x00"

Parameters:

  • suffix (String, nil) (defaults to: nil)

    A string to append to the converted bytes

  • str (String)

    The string to be converted

  • prefix (String) (defaults to: "\\x")
  • count (Integer) (defaults to: 1)

    Number of bytes to put in each escape chunk

Returns:

  • (String)

    The original string with non-printables converted to their escaped hex representation

Raises:

  • (::RuntimeError)


41
42
43
44
45
46
# File 'lib/rex/text/hex.rb', line 41

def self.to_hex_ascii(str, prefix = "\\x", count = 1, suffix=nil)
  raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
  return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s|
    (0x20..0x7e) === s.to_i(16) ? s.to_i(16).chr : prefix + s + suffix.to_s
  }
end

.to_hex_dump(str, width = 16, base = nil) ⇒ Object

Converts a string to a nicely formatted hex dump

Parameters:

  • str (String)

    The string to convert

  • width (Integer) (defaults to: 16)

    Number of bytes to convert before adding a newline

  • base (Integer) (defaults to: nil)

    The base address of the dump



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rex/text/hex.rb', line 54

def self.to_hex_dump(str, width=16, base=nil)
  buf = ''
  idx = 0
  cnt = 0
  snl = false
  lst = 0
  lft_col_len = (base.to_i+str.length).to_s(16).length
  lft_col_len = 8 if lft_col_len < 8

  while (idx < str.length)
    chunk = str[idx, width]
    addr = base ? "%0#{lft_col_len}x  " %(base.to_i + idx) : ''
    line  = chunk.unpack("H*")[0].scan(/../).join(" ")
    buf << addr + line

    if (lst == 0)
      lst = line.length
      buf << " " * 4
    else
      buf << " " * ((lst - line.length) + 4).abs
    end

    buf << "|"

    chunk.unpack("C*").each do |c|
      if (c >	0x1f and c < 0x7f)
        buf << c.chr
      else
        buf << "."
      end
    end

    buf << "|\n"

    idx += width
  end

  buf << "\n"
end

.to_ibm1047(str) ⇒ Object

The next two are the same as the above, except strictly for z/os conversions

strictly for IBM1047 -> ISO8859-1

A native implementation of the IBM1047(EBCDIC) -> ISO8859-1(ASCII) conversion table, since EBCDIC isn’t available to String#encode as of Ruby 2.1 all 256 bytes are defined



193
194
195
196
197
198
199
200
# File 'lib/rex/text/ebcdic.rb', line 193

def self.to_ibm1047(str)
  return str if str.nil?
  new_str = []
  str.each_byte do |x|
    new_str << Iconv_IBM1047[x.ord]
  end
  new_str.join
end

.to_java(str, name = "shell") ⇒ Object

Converts a raw string into a java byte array



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/rex/text/lang.rb', line 79

def self.to_java(str, name = "shell")
  buff = "byte #{name}[] = new byte[]\n{\n"
  cnt = 0
  max = 0
  str.unpack('C*').each do |c|
    buff << ", " if max > 0
    buff << "\t" if max == 0
    buff << sprintf('(byte) 0x%.2x', c)
    max +=1
    cnt +=1

    if (max > 7)
      buff << ",\n" if cnt != str.length
      max = 0
    end
  end
  buff << "\n};\n"
  return buff
end

.to_js_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a javascript-style comment



51
52
53
# File 'lib/rex/text/lang.rb', line 51

def self.to_js_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '// ')
end

.to_mixed_case_array(str) ⇒ Array<String>

Takes a string, and returns an array of all mixed case versions.

Examples:

>> Rex::Text.to_mixed_case_array "abc1"
=> ["abc1", "abC1", "aBc1", "aBC1", "Abc1", "AbC1", "ABc1", "ABC1"]

Parameters:

  • str (String)

    The string to randomize

Returns:

  • (Array<String>)

See Also:



37
38
39
40
41
42
43
44
45
46
# File 'lib/rex/text/randomize.rb', line 37

def self.to_mixed_case_array(str)
  letters = str.each_char.map { |l| [l.downcase, l.upcase] }
  (1 << str.size).times.map do |i| 
    this_str = ""
    ("%0#{str.size}b" % i).each_char.map(&:to_i).each_with_index do |d,i|
      this_str << letters[i][d]
    end
    this_str
  end.uniq
end

.to_num(str, wrap = DefaultWrap) ⇒ Object

Creates a comma separated list of numbers



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/rex/text/binary_manipulation.rb', line 12

def self.to_num(str, wrap = DefaultWrap)
  code = str.unpack('C*')
  buff = ""
  0.upto(code.length-1) do |byte|
    if(byte % 15 == 0) and (buff.length > 0)
      buff << "\r\n"
    end
    buff << sprintf('0x%.2x, ', code[byte])
  end
  # strip , at the end
  buff = buff.chomp(', ')
  buff << "\r\n"
  return buff
end

.to_octal(str, prefix = "\\") ⇒ String

Returns the escaped octal version of the supplied string

Examples:

Rex::Text.to_octal("asdf") # => "\\141\\163\\144\\146"

Parameters:

  • str (String)

    The string to be converted

  • prefix (String) (defaults to: "\\")

Returns:

  • (String)

    The escaped octal version of str



83
84
85
86
87
88
89
90
# File 'lib/rex/text.rb', line 83

def self.to_octal(str, prefix = "\\")
  octal = ""
  str.each_byte { |b|
    octal << "#{prefix}#{b.to_s 8}"
  }

  return octal
end

.to_perl(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts a raw string into a perl buffer



58
59
60
# File 'lib/rex/text/lang.rb', line 58

def self.to_perl(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '" .', "my $#{name} = \n", '";')
end

.to_perl_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a perl-style comment



144
145
146
# File 'lib/rex/text/lang.rb', line 144

def self.to_perl_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end

.to_psh_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a psh-style comment



158
159
160
# File 'lib/rex/text/lang.rb', line 158

def self.to_psh_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end

.to_python(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts a raw string into a python buffer



65
66
67
# File 'lib/rex/text/lang.rb', line 65

def self.to_python(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, "#{name} += b\"", '"', "#{name} =  b\"\"\n", '"')
end

.to_rand_case(str) ⇒ String

Converts a string to random case

Examples:

Rex::Text.to_rand_case("asdf") # => "asDf"

Parameters:

  • str (String)

    The string to randomize

Returns:

  • (String)

See Also:



19
20
21
22
23
24
25
# File 'lib/rex/text/randomize.rb', line 19

def self.to_rand_case(str)
  buf = str.dup
  0.upto(str.length) do |i|
    buf[i,1] = rand(2) == 0 ? str[i,1].upcase : str[i,1].downcase
  end
  return buf
end

.to_raw(str) ⇒ Object

Returns the raw string



70
71
72
# File 'lib/rex/text.rb', line 70

def self.to_raw(str)
  return str
end

.to_ruby(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts a raw string into a ruby buffer



12
13
14
# File 'lib/rex/text/lang.rb', line 12

def self.to_ruby(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '" +', "#{name} = \n", '"')
end

.to_ruby_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a ruby-style comment



19
20
21
# File 'lib/rex/text/lang.rb', line 19

def self.to_ruby_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end

.to_unescape(data, endian = ENDIAN_LITTLE, prefix = '%%u') ⇒ Object

Returns a unicode escaped string for Javascript



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/rex/text/unicode.rb', line 229

def self.to_unescape(data, endian=ENDIAN_LITTLE, prefix='%%u')
  data << "\x41" if (data.length % 2 != 0)
  dptr = 0
  buff = ''
  while (dptr < data.length)
    c1 = data[dptr,1].unpack("C*")[0]
    dptr += 1
    c2 = data[dptr,1].unpack("C*")[0]
    dptr += 1

    if (endian == ENDIAN_LITTLE)
      buff << sprintf("#{prefix}%.2x%.2x", c2, c1)
    else
      buff << sprintf("#{prefix}%.2x%.2x", c1, c2)
    end
  end
  return buff
end

.to_unicode(str = '', type = 'utf-16le', mode = '', size = '') ⇒ Object

Converts standard ASCII text to a unicode string.

Supported unicode types include: utf-16le, utf16-be, utf32-le, utf32-be, utf-7, and utf-8

Providing ‘mode’ provides hints to the actual encoder as to how it should encode the string.

Only UTF-7 and UTF-8 use “mode”.

utf-7 by default does not encode alphanumeric and a few other characters. By specifying the mode of “all”, then all of the characters are encoded, not just the non-alphanumeric set. to_unicode(str, ‘utf-7’, ‘all’)

utf-8 specifies that alphanumeric characters are used directly, eg “a” is just “a”. However, there exist 6 different overlong encodings of “a” that are technically not valid, but parse just fine in most utf-8 parsers. (0xC1A1, 0xE081A1, 0xF08081A1, 0xF8808081A1, 0xFC80808081A1, 0xFE8080808081A1). How many bytes to use for the overlong enocding is specified providing ‘size’. to_unicode(str, ‘utf-8’, ‘overlong’, 2)

Many utf-8 parsers also allow invalid overlong encodings, where bits that are unused when encoding a single byte are modified. Many parsers will ignore these bits, rendering simple string matching to be ineffective for dealing with UTF-8 strings. There are many more invalid overlong encodings possible for “a”. For example, three encodings are available for an invalid 2 byte encoding of “a”. (0xC1E1 0xC161 0xC121).

By specifying “invalid”, a random invalid encoding is chosen for the given byte size. to_unicode(str, ‘utf-8’, ‘invalid’, 2)

utf-7 defaults to ‘normal’ utf-7 encoding utf-8 defaults to 2 byte ‘normal’ encoding



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/rex/text/unicode.rb', line 46

def self.to_unicode(str='', type = 'utf-16le', mode = '', size = '')
  return '' if not str
  case type
    when 'utf-16le'
      return str.unpack('C*').pack('v*')
    when 'utf-16be'
      return str.unpack('C*').pack('n*')
    when 'utf-32le'
      return str.unpack('C*').pack('V*')
    when 'utf-32be'
      return str.unpack('C*').pack('N*')
    when 'utf-7'
      case mode
        when 'all'
          return str.gsub(/./){ |a|
            out = ''
            if 'a' != '+'
              out = encode_base64(to_unicode(a, 'utf-16be')).gsub(/[=\r\n]/, '')
            end
            '+' + out + '-'
          }
        else
          return str.gsub(/[^\n\r\t\ A-Za-z0-9\'\(\),-.\/\:\?]/){ |a|
            out = ''
            if a != '+'
              out = encode_base64(to_unicode(a, 'utf-16be')).gsub(/[=\r\n]/, '')
            end
            '+' + out + '-'
          }
      end
    when 'utf-8'
      if size == ''
        size = 2
      end

      if size >= 2 and size <= 7
        string = ''
        str.each_byte { |a|
          if (a < 21 || a > 0x7f) || mode != ''
            # ugh.	turn a single byte into the binary representation of it, in array form
            bin = [a].pack('C').unpack('B8')[0].split(//)

            # even more ugh.
            bin.collect!{|a_| a_.to_i}

            out = Array.new(8 * size, 0)

            0.upto(size - 1) { |i|
              out[i] = 1
              out[i * 8] = 1
            }

            i = 0
            byte = 0
            bin.reverse.each { |bit|
              if i < 6
                mod = (((size * 8) - 1) - byte * 8) - i
                out[mod] = bit
              else
                byte = byte + 1
                i = 0
                redo
              end
              i = i + 1
            }

            if mode != ''
              case mode
                when 'overlong'
                  # do nothing, since we already handle this as above...
                when 'invalid'
                  done = 0
                  while done == 0
                    # the ghetto...
                    bits = [7, 8, 15, 16, 23, 24, 31, 32, 41]
                    bits.each { |bit|
                      bit = (size * 8) - bit
                      if bit > 1
                        set = rand(2)
                        if out[bit] != set
                          out[bit] = set
                          done = 1
                        end
                      end
                    }
                  end
                else
                  raise TypeError, 'Invalid mode.  Only "overlong" and "invalid" are acceptable modes for utf-8'
              end
            end
            string << [out.join('')].pack('B*')
          else
            string << [a].pack('C')
          end
        }
        return string
      else
        raise TypeError, 'invalid utf-8 size'
      end
    when 'uhwtfms' # suggested name from HD :P
      load_codepage()

      string = ''
      # overloading mode as codepage
      if mode == ''
        mode = 1252 # ANSI - Latan 1, default for US installs of MS products
      else
        mode = mode.to_i
      end
      if @@codepage_map_cache[mode].nil?
        raise TypeError, "Invalid codepage #{mode}"
      end
      str.each_byte {|byte|
        char = [byte].pack('C*')
        possible = @@codepage_map_cache[mode]['data'][char]
        if possible.nil?
          raise TypeError, "codepage #{mode} does not provide an encoding for 0x#{char.unpack('H*')[0]}"
        end
        string << possible[ rand(possible.length) ]
      }
      return string
    when 'uhwtfms-half' # suggested name from HD :P
      load_codepage()
      string = ''
      # overloading mode as codepage
      if mode == ''
        mode = 1252 # ANSI - Latan 1, default for US installs of MS products
      else
        mode = mode.to_i
      end
      if mode != 1252
        raise TypeError, "Invalid codepage #{mode}, only 1252 supported for uhwtfms_half"
      end
      str.each_byte {|byte|
        if ((byte >= 33 && byte <= 63) || (byte >= 96 && byte <= 126))
          string << "\xFF" + [byte ^ 32].pack('C')
        elsif (byte >= 64 && byte <= 95)
          string << "\xFF" + [byte ^ 96].pack('C')
        else
          char = [byte].pack('C')
          possible = @@codepage_map_cache[mode]['data'][char]
          if possible.nil?
            raise TypeError, "codepage #{mode} does not provide an encoding for 0x#{char.unpack('H*')[0]}"
          end
          string << possible[ rand(possible.length) ]
        end
      }
      return string
    else
      raise TypeError, 'invalid utf type'
  end
end

.to_utf8(str) ⇒ String

Note:

This method will discard invalid characters

Converts US-ASCII to UTF-8, skipping over any characters which don’t convert cleanly. This is a convenience method that wraps String#encode with non-raising default paramaters.

Parameters:

  • str (String)

    An encodable ASCII string

Returns:

  • (String)

    a UTF-8 equivalent



222
223
224
# File 'lib/rex/text/unicode.rb', line 222

def self.to_utf8(str)
  str.encode('utf-8', { :invalid => :replace, :undef => :replace, :replace => '' })
end

.to_vbapplication(str, name = "buf") ⇒ Object

Converts a raw string into a vba buffer



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rex/text/lang.rb', line 123

def self.to_vbapplication(str, name = "buf")
  return "#{name} = Array()" if str.nil? or str.empty?

  code  = str.unpack('C*')
  buff = "#{name} = Array("
  maxbytes = 80

  1.upto(code.length) do |idx|
    buff << code[idx].to_s
    buff << "," if idx < code.length - 1
    buff << " _\r\n" if (idx > 1 and (idx % maxbytes) == 0)
  end

  buff << ")\r\n"

  return buff
end

.to_vbscript(str, name = "buf") ⇒ Object

Converts a raw string to a vbscript byte array



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/rex/text/lang.rb', line 102

def self.to_vbscript(str, name = "buf")
  return "#{name}" if str.nil? or str.empty?

  code = str.unpack('C*')
  buff = "#{name}=Chr(#{code[0]})"
  1.upto(code.length-1) do |byte|
    if(byte % 100 == 0)
      buff << "\r\n#{name}=#{name}"
    end
    # exe is an Array of bytes, not a String, thanks to the unpack
    # above, so the following line is not subject to the different
    # treatments of String#[] between ruby 1.8 and 1.9
    buff << "&Chr(#{code[byte]})"
  end

  return buff
end

.to_words(str, strict = false) ⇒ Object

Returns the words in str as an Array.

strict - include only words, no boundary characters (like spaces, etc.)



60
61
62
# File 'lib/rex/text/binary_manipulation.rb', line 60

def self.to_words( str, strict = false )
  strict ? str.scan(/\w+/) : str.split(/\b/)
end

.ungzip(str) ⇒ String

Uncompresses a string using gzip

Parameters:

  • str (String)

    Compressed string to inflate

Returns:

  • (String)

    The uncompressed version of str

Raises:

  • (RuntimeError)


94
95
96
97
98
99
100
101
102
103
# File 'lib/rex/text/compress.rb', line 94

def self.ungzip(str)
  raise RuntimeError, "Gzip support is not present." if (!zlib_present?)

  s = ""
  s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
  gz = Zlib::GzipReader.new(StringIO.new(str, 'rb'))
  s << gz.read
  gz.close
  return s
end

.unicode_filter_decode(str) ⇒ Object



211
212
213
# File 'lib/rex/text/unicode.rb', line 211

def self.unicode_filter_decode(str)
  str.to_s.gsub( /\$U\$([\x20-\x2c\x2e-\x7E]*)\-0x([A-Fa-f0-9]+)/n ){|m| [$2].pack("H*") }
end

.unicode_filter_encode(str) ⇒ Object

A custom unicode filter for dealing with multi-byte strings on a 8-bit console Punycode would have been more “standard”, but it requires valid Unicode chars



203
204
205
206
207
208
209
# File 'lib/rex/text/unicode.rb', line 203

def self.unicode_filter_encode(str)
  if (str.to_s.unpack("C*") & ( LowAscii + HighAscii + "\x7f" ).unpack("C*")).length > 0
    str = "$U$" + str.unpack("C*").select{|c| c < 0x7f and c > 0x1f and c != 0x2d}.pack("C*") + "-0x" + str.unpack("H*")[0]
  else
    str
  end
end

.uri_decode(str) ⇒ Object

Decode a URI encoded string



100
101
102
# File 'lib/rex/text/encode.rb', line 100

def self.uri_decode(str)
  str.gsub(/(%[a-z0-9]{2})/i){ |c| [c[1,2]].pack("H*") }
end

.uri_encode(str, mode = 'hex-normal') ⇒ Object

Encode a string in a manor useful for HTTP URIs and URI Parameters.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/rex/text/encode.rb', line 14

def self.uri_encode(str, mode = 'hex-normal')
  return "" if str == nil

  return str if mode == 'none' # fast track no encoding

  all = /./
  noslashes = /[^\/\\]+/
  # http://tools.ietf.org/html/rfc3986#section-2.3
  normal = /[^a-zA-Z0-9\/\\\.\-_~]+/

  case mode
    when 'hex-all'
      return str.gsub(all) { |s| Rex::Text.to_hex(s, '%') }
    when 'hex-normal'
      return str.gsub(normal) { |s| Rex::Text.to_hex(s, '%') }
    when 'hex-noslashes'
      return str.gsub(noslashes) { |s| Rex::Text.to_hex(s, '%') }
    when 'hex-random'
      res = ''
      str.each_byte do |c|
        b = c.chr
        res << ((rand(2) == 0) ?
          b.gsub(all)   { |s| Rex::Text.to_hex(s, '%') } :
          b.gsub(normal){ |s| Rex::Text.to_hex(s, '%') } )
      end
      return res
    when 'u-all'
      return str.gsub(all) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
    when 'u-normal'
      return str.gsub(normal) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
    when 'u-noslashes'
      return str.gsub(noslashes) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
    when 'u-random'
      res = ''
      str.each_byte do |c|
        b = c.chr
        res << ((rand(2) == 0) ?
          b.gsub(all)   { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) } :
          b.gsub(normal){ |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) } )
      end
      return res
    when 'u-half'
      return str.gsub(all) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms-half'), '%u', 2) }
    else
      raise TypeError, "invalid mode #{mode.inspect}"
  end
end

.wordwrap(str, indent = 0, col = DefaultWrap, append = '', prepend = '') ⇒ Object

Wraps text at a given column using a supplied indention



95
96
97
98
# File 'lib/rex/text.rb', line 95

def self.wordwrap(str, indent = 0, col = DefaultWrap, append = '', prepend = '')
  return str.gsub(/.{1,#{col - indent}}(?:\s|\Z)/){
    ( (" " * indent) + prepend + $& + append + 5.chr).gsub(/\n\005/,"\n").gsub(/\005/,"\n")}
end

.xml_char_encode(str) ⇒ Object

Encode an ASCII string so it’s safe for XML. It’s a wrapper for to_hex_ascii.



93
94
95
# File 'lib/rex/text/encode.rb', line 93

def self.xml_char_encode(str)
  self.to_hex_ascii(str, "&#x", 1, ";")
end

.xor(key, value) ⇒ String

XOR a string against a variable-length key

Parameters:

  • key (String)

    XOR key

  • value (String)

    String to XOR

Returns:

  • (String)

    XOR'd string



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/rex/text/xor.rb', line 9

def self.xor(key, value)
  unless key && value
    raise ArgumentError, 'XOR key and value must be supplied'
  end

  xor_key =
    case key
    when String
      if key.empty?
        raise ArgumentError, 'XOR key must not be empty'
      end

      key
    when Integer
      unless key.between?(0x00, 0xff)
        raise ArgumentError, 'XOR key must be between 0x00 and 0xff'
      end

      # Convert integer to string
      [key].pack('C')
    end

  # Get byte arrays for key and value
  xor_key   = xor_key.bytes
  xor_value = value.bytes

  # XOR value against cycled key
  xor_value.zip(xor_key.cycle).map { |v, k| v ^ k }.pack('C*')
end

.zlib_deflate(str, level = Zlib::BEST_COMPRESSION) ⇒ String

Compresses a string using zlib

Parameters:

  • str (String)

    The string to be compressed

  • level (Integer) (defaults to: Zlib::BEST_COMPRESSION)

    One of the Zlib compression level constants

Returns:

  • (String)

    The compressed version of str



43
44
45
46
47
48
49
50
51
52
# File 'lib/rex/text/compress.rb', line 43

def self.zlib_deflate(str, level = Zlib::BEST_COMPRESSION)
  if self.zlib_present?
    z = Zlib::Deflate.new(level)
    dst = z.deflate(str, Zlib::FINISH)
    z.close
    return dst
  else
    raise RuntimeError, "Gzip support is not present."
  end
end

.zlib_inflate(str) ⇒ String

Uncompresses a string using zlib

Parameters:

  • str (String)

    Compressed string to inflate

Returns:

  • (String)

    The uncompressed version of str



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rex/text/compress.rb', line 59

def self.zlib_inflate(str)
  if(self.zlib_present?)
    zstream = Zlib::Inflate.new
    buf = zstream.inflate(str)
    zstream.finish
    zstream.close
    return buf
  else
    raise RuntimeError, "Gzip support is not present."
  end
end

.zlib_present?Boolean

Returns true if zlib can be used.

Returns:

  • (Boolean)


23
24
25
26
27
28
29
30
# File 'lib/rex/text/compress.rb', line 23

def self.zlib_present?
  begin
    temp = Zlib
    return true
  rescue
    return false
  end
end