module Rex::Text

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

Constants

AllChars
Alpha
AlphaNumeric
Base32
Base64
Base64Url
DefaultPatternSets
DefaultWrap
HighAscii
Iconv_ASCII
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

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

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

LowAscii
LowerAlpha
Names_Female
Names_Male
Numerals
Punctuation
States
Surnames

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

TLDs

We are re-opening the module to add these module methods. Breaking them up this way allows us to maintain a little higher degree of organisation and make it easier to find what you're looking for without hanging the underlying calls that we historically rely upon.

UpperAlpha

Constants

VERSION

Public Class Methods

ascii_safe_hex(str, whitespace=false) click to toggle source

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

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

@see hexify @see ::to_hex Converts all the chars

# File lib/rex/text/hex.rb, line 113
def self.ascii_safe_hex(str, whitespace=false)
  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) click to toggle source

Base32 decoder

# File lib/rex/text/base32.rb, line 63
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) click to toggle source

Base32 encoder

# File lib/rex/text/base32.rb, line 38
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 = '') click to toggle source

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

@param data [String] The string to check for bad characters @param badchars [String] A list of characters considered to be bad @return [Fixnum] Index of the first bad character if any exist in data @return [nil] If data contains no bad characters

# File lib/rex/text/badchars.rb, line 16
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, fun) click to toggle source

Calculate the block API hash for the given module/function

@param mod [String] The name of the module containing the target function. @param fun [String] The name of the function.

@return [String] The hash of the mod/fun pair in string format

# File lib/rex/text/block_api.rb, line 15
def self.block_api_hash(mod, fun)
  unicode_mod = (mod.upcase + "\x00").unpack('C*').pack('v*')
  mod_hash = self.ror13_hash(unicode_mod)
  fun_hash = self.ror13_hash(fun + "\x00")
  "0x#{(mod_hash + fun_hash & 0xFFFFFFFF).to_s(16)}"
end
charset_exclude(keepers) click to toggle source

Returns all chars that are not in the supplied set

@param keepers [String] @return [String] All characters not contained in keepers

# File lib/rex/text/badchars.rb, line 43
def self.charset_exclude(keepers)
  excluded_bytes = [*(0..255)] - keepers.unpack("C*")
  excluded_bytes.pack("C*")
end
checksum16_be(str) click to toggle source

@param str [String] Big-endian data to checksum @return [Fixnum] 16-bit checksum

# File lib/rex/text/checksum.rb, line 22
def self.checksum16_be(str)
  (str.unpack("n*").inject(:+) || 0) % 0x10000
end
checksum16_le(str) click to toggle source

@param str [String] Little-endian data to checksum @return [Fixnum] 16-bit checksum

# File lib/rex/text/checksum.rb, line 16
def self.checksum16_le(str)
  (str.unpack("v*").inject(:+) || 0) % 0x10000
end
checksum32_be(str) click to toggle source

@param str [String] Big-endian data to checksum @return [Fixnum] 32-bit checksum

# File lib/rex/text/checksum.rb, line 34
def self.checksum32_be(str)
  (str.unpack("N*").inject(:+) || 0) % 0x100000000
end
checksum32_le(str) click to toggle source

@param str [String] Little-endian data to checksum @return [Fixnum] 32-bit checksum

# File lib/rex/text/checksum.rb, line 28
def self.checksum32_le(str)
  (str.unpack("V*").inject(:+) || 0) % 0x100000000
end
checksum8(str) click to toggle source

@param str [String] Data to checksum @return [Fixnum] 8-bit checksum

# File lib/rex/text/checksum.rb, line 10
def self.checksum8(str)
  (str.unpack("C*").inject(:+) || 0) % 0x100
end
compress(str) click to toggle source

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

@param str [String] The string in which to crunch whitespace @return [String] Just like str, but with repeated whitespace characters

trimmed down to a single space
# File lib/rex/text/compress.rb, line 15
def self.compress(str)
  str.gsub(/\n/m, ' ').gsub(/\s+/, ' ').gsub(/^\s+/, '').gsub(/\s+$/, '')
end
cowsay(text, width=39) click to toggle source

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 |
                ||     ||

@param text [String] The string to cowsay @param width [Fixnum] Width of the cow's cloud. Default's to cowsay(1)'s default, 39.

# File lib/rex/text/silly.rb, line 23
    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) click to toggle source
# File lib/rex/text/base32.rb, line 71
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) click to toggle source

Base64 decoder

# File lib/rex/text/base64.rb, line 19
def self.decode_base64(str)
  str.to_s.unpack("m")[0]
end
decode_base64url(str) click to toggle source

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

# File lib/rex/text/base64.rb, line 35
def self.decode_base64url(str)
  decode_base64(
    str.gsub(/[^a-zA-Z0-9_\-]/, '').
      tr('-_', '+/'))
end
dehex(str) click to toggle source

Convert hex-encoded characters to literals.

@example

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

@see ::hex_to_raw @param str [String]

# File lib/rex/text/hex.rb, line 180
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) click to toggle source

Convert and replace hex-encoded characters to literals.

@param (see dehex)

# File lib/rex/text/hex.rb, line 195
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) click to toggle source
# File lib/rex/text/base32.rb, line 46
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='') click to toggle source

Base64 encoder

# File lib/rex/text/base64.rb, line 12
def self.encode_base64(str, delim='')
  [str.to_s].pack("m").gsub(/\s+/, delim)
end
encode_base64url(str, delim='') click to toggle source

Base64 encoder (URL-safe RFC6920)

# File lib/rex/text/base64.rb, line 26
def self.encode_base64url(str, delim='')
  encode_base64(str, delim).
    tr('+/', '-_').
    gsub('=', '')
end
from_ebcdic(str) click to toggle source

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

@param str [String] an EBCDIC encoded string @return [String] An encodable ASCII string @note This method will raise in the event of invalid characters

# File lib/rex/text/ebcdic.rb, line 172
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) click to toggle source

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

# File lib/rex/text/ebcdic.rb, line 208
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) click to toggle source

Compresses a string using gzip

@param str (see ::zlib_deflate) @param level [Fixnum] Compression level, 1 (fast) to 9 (best) @return (see ::zlib_deflate)

# File lib/rex/text/compress.rb, line 76
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?() click to toggle source

backwards compat for just a bit…

# File lib/rex/text/compress.rb, line 32
def self.gzip_present?
  self.zlib_present?
end
hex_to_raw(str) click to toggle source

Converts a hex string to a raw string

@example

Rex::Text.hex_to_raw("\\x41\\x7f\\x42") # => "A\x7fB"
# 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 = '') click to toggle source

Converts a string to a hex version with wrapping support

# File lib/rex/text/hex.rb, line 124
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) click to toggle source

Decode a string that's html encoded

# File lib/rex/text/encode.rb, line 84
def self.html_decode(str)
  decoded_str = CGI.unescapeHTML(str)
  return decoded_str
end
html_encode(str, mode = 'hex') click to toggle source

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

@param str [String] The string to be encoded @param mode [“hex”,“int”,“int-wide”] @return [String] @raise [TypeError] if mode is not one of the three available modes

# File lib/rex/text/encode.rb, line 68
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) click to toggle source

Hexidecimal MD5 digest of the supplied string

# File lib/rex/text/hash.rb, line 18
def self.md5(str)
  Digest::MD5.hexdigest(str)
end
md5_raw(str) click to toggle source

Raw MD5 digest of the supplied string

# File lib/rex/text/hash.rb, line 11
def self.md5_raw(str)
  Digest::MD5.digest(str)
end
pack_int64le(val) click to toggle source

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

# File lib/rex/text/binary_manipulation.rb, line 68
def self.pack_int64le(val)
  [val & 0x00000000ffffffff, val >> 32].pack("V2")
end
patt2(len, sets = nil) click to toggle source

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.

# File lib/rex/text/pattern.rb, line 52
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) click to toggle source

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.

@param length [Fixnum] @param sets [Array<(String,String,String)>] 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.

@return [String] A pattern of length bytes, in which any 4-byte chunk is

unique

@see ::pattern_offset

# File lib/rex/text/pattern.rb, line 21
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
    begin
      buf << converge_sets(sets, 0, offsets, length)
    end
  end

  # Maximum permutations reached, but we need more data
  if (buf.length < length)
    buf = buf * (length / buf.length.to_f).ceil
  end

  buf[0,length]
end
pattern_offset(pattern, value, start=0) click to toggle source

Calculate the offset to a pattern

@param pattern [String] The pattern to search. Usually the return value

from {.pattern_create}

@param value [String,Fixnum,Bignum] @return [Fixnum] Index of the given value within pattern, if it exists @return [nil] if pattern does not contain value @see ::pattern_create

# File lib/rex/text/pattern.rb, line 79
def self.pattern_offset(pattern, value, start=0)
  if (value.kind_of?(String))
    pattern.index(value, start)
  elsif (value.kind_of?(Fixnum) or value.kind_of?(Bignum))
    pattern.index([ value ].pack('V'), start)
  else
    raise ::ArgumentError, "Invalid class for value: #{value.class}"
  end
end
permute_case(word, idx=0) click to toggle source

Permute the case of a word

# File lib/rex/text/randomize.rb, line 100
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_utf8() click to toggle source

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

@example

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

@return [String]

# File lib/rex/text/rand.rb, line 177
def self.rand_4byte_utf8
  [rand(0x10000..0x10ffff)].pack('U*')
end
rand_base(len, bad, *foo) click to toggle source

Base text generator method

# File lib/rex/text/rand.rb, line 78
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.times { outp << cset[rand(cset.length)] }
  outp.pack("C*")
end
rand_char(bad, chars = AllChars) click to toggle source

Generates a random character.

# File lib/rex/text/rand.rb, line 73
def self.rand_char(bad, chars = AllChars)
  rand_text(1, bad, chars)
end
rand_guid() click to toggle source

Generate a random GUID

@example

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

@return [String]

# File lib/rex/text/rand.rb, line 165
def self.rand_guid
  "{#{[8,4,4,4,12].map {|a| rand_text_hex(a) }.join("-")}}"
end
rand_hostname() click to toggle source

Generate a random hostname

@return [String] A random string conforming to the rules of FQDNs

# File lib/rex/text/rand.rb, line 184
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_address() click to toggle source

Generate a random mail address

# File lib/rex/text/rand.rb, line 223
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_name() click to toggle source

Generate a name

# File lib/rex/text/rand.rb, line 204
def self.rand_name
  if rand(10) % 2 == 0
    Names_Male.sample
  else
    Names_Female.sample
  end
end
rand_name_female() click to toggle source

Generate a female name

# File lib/rex/text/rand.rb, line 218
def self.rand_name_female
  Names_Female.sample
end
rand_name_male() click to toggle source

Generate a male name

# File lib/rex/text/rand.rb, line 213
def self.rand_name_male
  Names_Male.sample
end
rand_state() click to toggle source

Generate a state

# File lib/rex/text/rand.rb, line 194
def self.rand_state()
  States.sample
end
rand_surname() click to toggle source

Generate a surname

# File lib/rex/text/rand.rb, line 199
def self.rand_surname
  Surnames.sample
end
rand_text(len, bad='', chars = AllChars) click to toggle source

Generate random bytes of data

# File lib/rex/text/rand.rb, line 87
def self.rand_text(len, bad='', chars = AllChars)
  foo = chars.split('')
  rand_base(len, bad, *foo)
end
rand_text_alpha(len, bad='') click to toggle source

Generate random bytes of alpha data

# File lib/rex/text/rand.rb, line 93
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='') click to toggle source

Generate random bytes of lowercase alpha data

# File lib/rex/text/rand.rb, line 101
def self.rand_text_alpha_lower(len, bad='')
  rand_base(len, bad, *('a' .. 'z').to_a)
end
rand_text_alpha_upper(len, bad='') click to toggle source

Generate random bytes of uppercase alpha data

# File lib/rex/text/rand.rb, line 106
def self.rand_text_alpha_upper(len, bad='')
  rand_base(len, bad, *('A' .. 'Z').to_a)
end
rand_text_alphanumeric(len, bad='') click to toggle source

Generate random bytes of alphanumeric data

# File lib/rex/text/rand.rb, line 111
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='') click to toggle source

Generate random bytes of base64 data

# File lib/rex/text/rand.rb, line 148
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='') click to toggle source

Generate random bytes of base64url data

# File lib/rex/text/rand.rb, line 154
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='') click to toggle source

Generate random bytes of english-like data

# File lib/rex/text/rand.rb, line 134
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='') click to toggle source

Generate random bytes of alphanumeric hex.

# File lib/rex/text/rand.rb, line 120
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='') click to toggle source

Generate random bytes of high ascii data

# File lib/rex/text/rand.rb, line 141
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='') click to toggle source

Generate random bytes of numeric data

# File lib/rex/text/rand.rb, line 128
def self.rand_text_numeric(len, bad='')
  foo = ('0' .. '9').to_a
  rand_base(len, bad, *foo )
end
randomize_space(str) click to toggle source

Randomize the whitespace in a string

# File lib/rex/text/randomize.rb, line 54
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 ) click to toggle source

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

# File lib/rex/text/binary_manipulation.rb, line 102
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 = '') click to toggle source

Removes bad characters from a string.

Modifies data in place

@param data [#delete] @param badchars [String] A list of characters considered to be bad

# File lib/rex/text/badchars.rb, line 31
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) click to toggle source

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

@param val (see ror) @param cnt (see ror) @return (see ror)

# File lib/rex/text/binary_manipulation.rb, line 91
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) click to toggle source

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

@param val [Fixnum] The value to rotate @param cnt [Fixnum] Number of bits to rotate by

# File lib/rex/text/binary_manipulation.rb, line 77
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) click to toggle source

Calculate the ROR13 hash of a given string

@return [Fixnum]

# File lib/rex/text/block_api.rb, line 26
def self.ror13_hash(name)
  hash = 0
  name.unpack("C*").each {|c| hash = ror(hash, 13); hash += c }
  hash
end
sha1(str) click to toggle source

Hexidecimal SHA1 digest of the supplied string

# File lib/rex/text/hash.rb, line 32
def self.sha1(str)
  Digest::SHA1.hexdigest(str)
end
sha1_raw(str) click to toggle source

Raw SHA1 digest of the supplied string

# File lib/rex/text/hash.rb, line 25
def self.sha1_raw(str)
  Digest::SHA1.digest(str)
end
shuffle_a(arr) click to toggle source

Performs a Fisher-Yates shuffle on an array

Modifies arr in place

@param arr [Array] The array to be shuffled @return [Array]

# File lib/rex/text/randomize.rb, line 84
def self.shuffle_a(arr)
  len = arr.length
  max = len - 1
  cyc = [* (0..max) ]
  for d in cyc
    e = rand(d+1)
    next if e == d
    f = arr[d];
    g = arr[e];
    arr[d] = g;
    arr[e] = f;
  end
  return arr
end
shuffle_s(str) click to toggle source

Shuffles a byte stream

@param str [String] @return [String] The shuffled result @see ::shuffle_a

# File lib/rex/text/randomize.rb, line 73
def self.shuffle_s(str)
  shuffle_a(str.unpack("C*")).pack("C*")
end
split_to_a(str, n) click to toggle source

Split a string by n character into an array

# File lib/rex/text.rb, line 121
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 = '') click to toggle source

Converts a unicode string to standard ASCII text.

# File lib/rex/text/unicode.rb, line 250
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") click to toggle source

Converts a raw string into a Bash buffer

# File lib/rex/text/lang.rb, line 71
def self.to_bash(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '$\', '\\', "export #{name}=\\\n", '\')
end
to_bash_comment(str, wrap = DefaultWrap) click to toggle source

Creates a Bash-style comment

# File lib/rex/text/lang.rb, line 150
def self.to_bash_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end
to_c(str, wrap = DefaultWrap, name = "buf") click to toggle source

Converts a raw string into a C buffer

# File lib/rex/text/lang.rb, line 25
def self.to_c(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '"', "unsigned char #{name}[] = \n", '";')
end
to_c_comment(str, wrap = DefaultWrap) click to toggle source

Creates a c-style comment

# File lib/rex/text/lang.rb, line 43
def self.to_c_comment(str, wrap = DefaultWrap)
  return "/*\n" + wordwrap(str, 0, wrap, '', ' * ') + " */\n"
end
to_csharp(str, wrap = DefaultWrap, name = "buf") click to toggle source
# File lib/rex/text/lang.rb, line 29
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) click to toggle source

Creates a comma separated list of dwords

# File lib/rex/text/binary_manipulation.rb, line 29
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) click to toggle source

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

@param str [String] An encodable ASCII string @return [String] an EBCDIC encoded string @note This method will raise in the event of invalid characters

# File lib/rex/text/ebcdic.rb, line 154
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) click to toggle source

Convert 16-byte string to a GUID string

@example

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

@param bytes [String] 16 bytes which represent a GUID in the proper

order.

@return [String]

# File lib/rex/text.rb, line 105
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) click to toggle source

Returns the escaped hex version of the supplied string

@example

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

@param str (see ::to_octal) @param prefix (see ::to_octal) @param count [Fixnum] Number of bytes to put in each escape chunk @return [String] The escaped hex version of str

# 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) click to toggle source

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

@example

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

@param str (see ::to_hex) @param prefix (see ::to_hex) @param count (see ::to_hex) @param suffix [String,nil] A string to append to the converted bytes @return [String] The original string with non-printables converted to

their escaped hex representation
# 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) click to toggle source

Converts a string to a nicely formatted hex dump

@param str [String] The string to convert @param width [Fixnum] Number of bytes to convert before adding a newline @param base [Fixnum] The base address of the dump

# 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) click to toggle source

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

# File lib/rex/text/ebcdic.rb, line 192
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") click to toggle source

Converts a raw string into a java byte array

# File lib/rex/text/lang.rb, line 78
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) click to toggle source

Creates a javascript-style comment

# File lib/rex/text/lang.rb, line 50
def self.to_js_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '// ')
end
to_mixed_case_array(str) click to toggle source

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

@example

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

@param str [String] The string to randomize @return [Array<String>] @see ::permute_case

# File lib/rex/text/randomize.rb, line 36
def self.to_mixed_case_array(str)
  letters = []
  str.scan(/./).each { |l| letters << [l.downcase, l.upcase] }
  coords = []
  (1 << str.size).times { |i| coords << ("%0#{str.size}b" % i) }
  mixed = []
  coords.each do |coord|
    c = coord.scan(/./).map {|x| x.to_i}
    this_str = ""
    c.each_with_index { |d,i| this_str << letters[i][d] }
    mixed << this_str
  end
  return mixed.uniq
end
to_num(str, wrap = DefaultWrap) click to toggle source

Creates a comma separated list of numbers

# File lib/rex/text/binary_manipulation.rb, line 11
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 = "\\") click to toggle source

Returns the escaped octal version of the supplied string

@example

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

@param str [String] The string to be converted @param prefix [String] @return [String] The escaped octal version of str

# File lib/rex/text.rb, line 76
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") click to toggle source

Converts a raw string into a perl buffer

# File lib/rex/text/lang.rb, line 57
def self.to_perl(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '" .', "my $#{name} = \n", '";')
end
to_perl_comment(str, wrap = DefaultWrap) click to toggle source

Creates a perl-style comment

# File lib/rex/text/lang.rb, line 143
def self.to_perl_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end
to_python(str, wrap = DefaultWrap, name = "buf") click to toggle source

Converts a raw string into a python buffer

# File lib/rex/text/lang.rb, line 64
def self.to_python(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, "#{name} += \"", '"', "#{name} =  \"\"\n", '"')
end
to_rand_case(str) click to toggle source

Converts a string to random case

@example

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

@param str [String] The string to randomize @return [String] @see ::permute_case @see ::to_mixed_case_array

# File lib/rex/text/randomize.rb, line 18
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) click to toggle source

Returns the raw string

# File lib/rex/text.rb, line 63
def self.to_raw(str)
  return str
end
to_ruby(str, wrap = DefaultWrap, name = "buf") click to toggle source

Converts a raw string into a ruby buffer

# File lib/rex/text/lang.rb, line 11
def self.to_ruby(str, wrap = DefaultWrap, name = "buf")
  return hexify(str, wrap, '"', '" +', "#{name} = \n", '"')
end
to_ruby_comment(str, wrap = DefaultWrap) click to toggle source

Creates a ruby-style comment

# File lib/rex/text/lang.rb, line 18
def self.to_ruby_comment(str, wrap = DefaultWrap)
  return wordwrap(str, 0, wrap, '', '# ')
end
to_unescape(data, endian=ENDIAN_LITTLE, prefix='%%u') click to toggle source

Returns a unicode escaped string for Javascript

# File lib/rex/text/unicode.rb, line 228
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 = '') click to toggle source

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

# File lib/rex/text/unicode.rb, line 45
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) click to toggle source

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.

@param str [String] An encodable ASCII string @return [String] a UTF-8 equivalent @note This method will discard invalid characters

# File lib/rex/text/unicode.rb, line 221
def self.to_utf8(str)
  str.encode('utf-8', { :invalid => :replace, :undef => :replace, :replace => '' })
end
to_vbapplication(str, name = "buf") click to toggle source

Converts a raw string into a vba buffer

# File lib/rex/text/lang.rb, line 122
def self.to_vbapplication(str, name = "buf")
  return "#{name} = Array()" if str.nil? or str.empty?

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

  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") click to toggle source

Converts a raw string to a vbscript byte array

# File lib/rex/text/lang.rb, line 101
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 ) click to toggle source

Returns the words in str as an Array.

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

# File lib/rex/text/binary_manipulation.rb, line 59
def self.to_words( str, strict = false )
  splits = str.split( /\b/ )
  splits.reject! { |w| !(w =~ /\w/) } if strict
  splits
end
ungzip(str) click to toggle source

Uncompresses a string using gzip

@param str (see ::zlib_inflate) @return (see ::zlib_inflate)

# File lib/rex/text/compress.rb, line 93
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) click to toggle source
# File lib/rex/text/unicode.rb, line 210
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) click to toggle source

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

# File lib/rex/text/unicode.rb, line 202
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) click to toggle source

Decode a URI encoded string

# File lib/rex/text/encode.rb, line 99
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') click to toggle source

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

# File lib/rex/text/encode.rb, line 13
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 = '') click to toggle source

Wraps text at a given column using a supplied indention

# File lib/rex/text.rb, line 88
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) click to toggle source

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

# File lib/rex/text/encode.rb, line 92
def self.xml_char_encode(str)
  self.to_hex_ascii(str, "&#x", 1, ";")
end
zlib_deflate(str, level = Zlib::BEST_COMPRESSION) click to toggle source

Compresses a string using zlib

@param str [String] The string to be compressed @param level [Fixnum] One of the Zlib compression level constants @return [String] The compressed version of str

# File lib/rex/text/compress.rb, line 42
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) click to toggle source

Uncompresses a string using zlib

@param str [String] Compressed string to inflate @return [String] The uncompressed version of str

# File lib/rex/text/compress.rb, line 58
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?() click to toggle source

Returns true if zlib can be used.

# File lib/rex/text/compress.rb, line 22
def self.zlib_present?
  begin
    temp = Zlib
    return true
  rescue
    return false
  end
end

Protected Class Methods

load_codepage() click to toggle source
# File lib/rex/text.rb, line 159
def self.load_codepage()
  return if (!@@codepage_map_cache.nil?)
  file = File.join(File.dirname(__FILE__),'codepage.map')
  page = ''
  name = ''
  map = {}
  File.open(file).each { |line|
    next if line =~ /^#/
    next if line =~ /^\s*$/
    data = line.split
    if data[1] =~ /^\(/
      page = data.shift.to_i
      name = data.join(' ').sub(/^\(/,'').sub(/\)$/,'')
      map[page] = {}
      map[page]['name'] = name
      map[page]['data'] = {}
    else
      data.each { |entry|
        wide, char = entry.split(':')
        char = [char].pack('H*')
        wide = [wide].pack('H*')
        if map[page]['data'][char].nil?
          map[page]['data'][char] = [wide]
        else
          map[page]['data'][char].push(wide)
        end
      }
    end
  }
  @@codepage_map_cache = map
end