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"
]
Func_Verb =
[
  "get", "set", "put", "describe", "acquire", "release", "initialize", "free",
  "init", "find", "list", "create", "destroy"
]
Func_Subj =
[
  "file", "directory", "dir", "address", "addr", "process", "proc", "user",
  "privileges", "priv", "attribute", "attr", "mutex", "handle", "type"
]
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.46"
@@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:



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

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)


171
172
173
174
175
176
# File 'lib/rex/text/hex.rb', line 171

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

.display_width(str) ⇒ Integer

Function that aims to calculate the display width of the given string. In the future this will be aware of East Asian characters having different display widths. For now it simply returns the string’s length ignoring color codes.

Parameters:

  • str (String)

Returns:

  • (Integer)


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

def self.display_width(str)
  str.gsub(COLOR_CODES_REGEX, '').length
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
# File 'lib/rex/text/hex.rb', line 129

def self.hexify(str, col = DefaultWrap, line_start = '', line_end = '', buf_start = '', buf_end = '')
  if col < line_start.length + 4 + line_end.length
    # raise an exception
    raise ArgumentError.new('insufficient column width')
  end

  ret = buf_start.dup
  ret << line_start if ret.end_with?("\n")
  str.each_char do |char|
    # "\x##".length is 4, check if we're going over the wrap boundary
    if (ret.split("\n").last || '').length + 4 + line_end.length > col
      ret << "#{line_end}\n#{line_start}"
    end
    ret << "\\x" << char.unpack('H*')[0]
  end
  ret << "\n" if ret.split("\n").last.length + buf_end.length > col
  ret << "#{buf_end}\n"
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)


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

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

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

Base text generator method



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

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.



106
107
108
# File 'lib/rex/text/rand.rb', line 106

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

.rand_countryObject

Generate a country code



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

def self.rand_country
  Countries.sample
end

.rand_func_nameObject

Generate a random function name



292
293
294
295
296
# File 'lib/rex/text/rand.rb', line 292

def self.rand_func_name
  verb = rand(9) > 4 ? Func_Verb.sample.capitalize : Func_Verb.sample
  subj = rand(9) > 4 ? Func_Subj.sample.capitalize : Func_Subj.sample
  verb + subj
end

.rand_guidString

Generate a random GUID

Examples:

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

Returns:

  • (String)


199
200
201
# File 'lib/rex/text/rand.rb', line 199

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



218
219
220
221
222
223
224
225
# File 'lib/rex/text/rand.rb', line 218

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



262
263
264
265
266
267
268
269
# File 'lib/rex/text/rand.rb', line 262

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



243
244
245
246
247
248
249
# File 'lib/rex/text/rand.rb', line 243

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



257
258
259
# File 'lib/rex/text/rand.rb', line 257

def self.rand_name_female
  Names_Female.sample
end

.rand_name_maleObject

Generate a male name



252
253
254
# File 'lib/rex/text/rand.rb', line 252

def self.rand_name_male
  Names_Male.sample
end

.rand_password(len = 10, mix_case: true, numbers: true, special_characters: false) ⇒ Object

Generate a strong password of specified length and attributes



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/rex/text/rand.rb', line 272

def self.rand_password(len=10, mix_case:true, numbers:true, special_characters: false)
  allowed_characters=[]
  upper=('A'..'Z').to_a
  lower=('a'..'z').to_a
  number=('0'..'10').to_a
  specials = ((32..47).to_a + (58..64).to_a + (91..96).to_a + (123..126).to_a).pack('U*').chars
  allowed_characters+=upper
  if mix_case
    allowed_characters+=lower
  end
  if numbers
    allowed_characters+=number
  end
  if special_characters
    allowed_characters+=specials
  end
  rand_base(len,'',*allowed_characters)
end

.rand_stateObject

Generate a state



233
234
235
# File 'lib/rex/text/rand.rb', line 233

def self.rand_state()
  States.sample
end

.rand_surnameObject

Generate a surname



238
239
240
# File 'lib/rex/text/rand.rb', line 238

def self.rand_surname
  Surnames.sample
end

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

Generate random bytes of data



121
122
123
124
# File 'lib/rex/text/rand.rb', line 121

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



127
128
129
130
131
132
# File 'lib/rex/text/rand.rb', line 127

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



135
136
137
# File 'lib/rex/text/rand.rb', line 135

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



140
141
142
# File 'lib/rex/text/rand.rb', line 140

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



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

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



182
183
184
185
# File 'lib/rex/text/rand.rb', line 182

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



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

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



168
169
170
171
172
# File 'lib/rex/text/rand.rb', line 168

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.



154
155
156
157
158
159
# File 'lib/rex/text/rand.rb', line 154

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



175
176
177
178
179
# File 'lib/rex/text/rand.rb', line 175

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



162
163
164
165
# File 'lib/rex/text/rand.rb', line 162

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



143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rex/text.rb', line 143

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



142
143
144
# File 'lib/rex/text/lang.rb', line 142

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



221
222
223
# File 'lib/rex/text/lang.rb', line 221

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



114
115
116
# File 'lib/rex/text/lang.rb', line 114

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
40
# File 'lib/rex/text/lang.rb', line 30

def self.to_csharp(str, wrap = DefaultWrap, name = "buf")
  ret = "byte[] #{name} = new byte[#{str.length}] {"
  str.each_char do |char|
    # "0x##,".length is 5, check if we're going over the wrap boundary
    ret << "\n" if ret.split("\n").last.length + 5 > wrap
    ret << "0x" << char.unpack('H*')[0] << ","
  end
  ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
  ret << "\n" if ret.split("\n").last.length + 2 > wrap
  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_golang(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts to a golang style array of bytes



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rex/text/lang.rb', line 45

def self.to_golang(str, wrap = DefaultWrap, name = "buf")
  ret = "#{name} :=  []byte{"
  str.each_char do |char|
    # "0x##,".length is 5, check if we're going over the wrap boundary
    ret << "\n" if ret.split("\n").last.length + 5 > wrap
    ret << "0x" << char.unpack('H*')[0] << ","
  end
  ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
  ret << "\n" if ret.split("\n").last.length + 2 > wrap
  ret << "};\n"
end

.to_golang_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a golang style comment



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

def self.to_golang_comment(str,  wrap = DefaultWrap)
  return "/*\n" + wordwrap(str, 0, wrap, '', '') + "*/\n"
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)


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

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



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rex/text/lang.rb', line 149

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



121
122
123
# File 'lib/rex/text/lang.rb', line 121

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_nim(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts to a nim style array of bytes

Raises:

  • (ArgumentError)


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

def self.to_nim(str, wrap = DefaultWrap, name = "buf")
  raise ArgumentError.new('str can not be empty') if str.empty?

  ret = "var #{name}: array[#{str.length}, byte] = [\n"
  ret << "byte "
  str.each_char do |char|
    # "0x##,".length is 5, check if we're going over the wrap boundary
    ret << "\n" if ret.split("\n").last.length + 5 > wrap
    ret << "0x" << char.unpack('H*')[0] << ","
  end
  ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
  ret << "\n" if ret.split("\n").last.length + 1 > wrap
  ret << "]\n"
end

.to_nim_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a nim style comment



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

def self.to_nim_comment(str,  wrap = DefaultWrap)
  return "#[\n" + wordwrap(str, 0, wrap, '', '') + "]#\n"
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



128
129
130
# File 'lib/rex/text/lang.rb', line 128

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



214
215
216
# File 'lib/rex/text/lang.rb', line 214

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



228
229
230
# File 'lib/rex/text/lang.rb', line 228

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



135
136
137
# File 'lib/rex/text/lang.rb', line 135

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_rust(str, wrap = DefaultWrap, name = "buf") ⇒ Object

Converts to a Rust style array of bytes



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

def self.to_rust(str, wrap = DefaultWrap, name = "buf")
  ret = "let #{name}: [u8; #{str.length}] = ["
  str.each_char do |char|
    # "0x##,".length is 5, check if we're going over the wrap boundary
    ret << "\n" if ret.split("\n").last.length + 5 > wrap
    ret << "0x" << char.unpack('H*')[0] << ","
  end
  ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
  ret << "\n" if ret.split("\n").last.length + 2 > wrap
  ret << "];\n"
end

.to_rust_comment(str, wrap = DefaultWrap) ⇒ Object

Creates a Rust style comment



107
108
109
# File 'lib/rex/text/lang.rb', line 107

def self.to_rust_comment(str, wrap = DefaultWrap)
  return "/*\n" + wordwrap(str, 0, wrap, '', ' * ') + " */\n"
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



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/rex/text/lang.rb', line 193

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

  0.upto(code.length-1) 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



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rex/text/lang.rb', line 172

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