Class: String

Inherits:
Object
  • Object
show all
Defined in:
lib/ctf_party/cgi.rb,
lib/ctf_party/dec.rb,
lib/ctf_party/hex.rb,
lib/ctf_party/rot.rb,
lib/ctf_party/xor.rb,
lib/ctf_party/case.rb,
lib/ctf_party/flag.rb,
lib/ctf_party/leet.rb,
lib/ctf_party/misc.rb,
lib/ctf_party/base64.rb,
lib/ctf_party/binary.rb,
lib/ctf_party/defang.rb,
lib/ctf_party/digest.rb,
lib/ctf_party/network.rb

Constant Summary collapse

@@flag =

The flag configuration hash. See flag=.

{
  prefix: '',
  suffix: '',
  enclosing: ['{', '}'],
  digest: nil
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.flagObject

Show the actual flag configuration. See flag=.



15
16
17
# File 'lib/ctf_party/flag.rb', line 15

def self.flag
  @@flag
end

.flag=(hash) ⇒ Hash

Note:

You can provide the full hash or only the key to update.

Update the flag configuration.

Examples:

String.flag # => {:prefix=>"", :suffix=>"", :enclosing=>["{", "}"], :digest=>nil}
String.flag = {prefix: 'sigsegv', digest: 'md5'}
String.flag # => {:prefix=>"sigsegv", :suffix=>"", :enclosing=>["{", "}"], :digest=>"md5"}
'this_1s_a_fl4g'.flag # => "sigsegv{a5bec9e2a86b6b70d288451eb38dfec8}"

Parameters:

  • hash (Hash)

    flag configuration

Options Hash (hash):

  • :prefix (String)

    prefix of the flag. Default: none.

  • :suffix (String)

    suffix of the flag. Default: none.

  • :enclosing (Array<String>)

    the characters used to surround the flag. Default are curly braces: ‘``. The array must contain exactly 2 elements.

  • :digest (String)

    the hash algorithm to apply on the flag. Default: none. Allowed values: md5, sha1, sha2_256, sha2_384, sha2_512, rmd160.

Returns:

  • (Hash)

    hash of the updated options.



36
37
38
39
# File 'lib/ctf_party/flag.rb', line 36

def self.flag=(hash)
  hash.select! { |k, _v| @@flag.key?(k) }
  @@flag.merge!(hash)
end

Instance Method Details

#alternatecase(shift = 0) ⇒ String

Change one characte on two upcase and the other downcase

Examples:

'SELECT * FROM'.alternatecase # => "sElEcT * FrOm"
'SELECT * FROM'.alternatecase(1) # => "SeLeCt * fRoM"

Parameters:

  • shift (Integer) (defaults to: 0)

    0: 1st character will be downcase, 1: 1st character will be upcase

Returns:

  • (String)

    the case modified string



26
27
28
# File 'lib/ctf_party/case.rb', line 26

def alternatecase(shift = 0)
  chars.each_with_index.map { |c, i| (i + shift).even? ? c.downcase : c.upcase }.join
end

#alternatecase!(shift = 0) ⇒ Object

Change one characte on two upcase and the other downcase in place as described for #alternatecase.



32
33
34
# File 'lib/ctf_party/case.rb', line 32

def alternatecase!(shift = 0)
  replace(alternatecase(shift))
end

#alxor(key) ⇒ String

ASCII XOR with key, padding left the shortest element

Examples:

'hello'.alxor('key') # => "he\a\t\x16"
'key'.alxor('hello') # => "he\a\t\x16"

Parameters:

  • key (String)

    the element to xor the string with

Returns:

  • (String)

    the xored string (ASCII)



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/ctf_party/xor.rb', line 30

def alxor(key)
  b1 = force_encoding('UTF-8')
  b2 = key.force_encoding('UTF-8')
  raise 'The string is not ASCII' unless b1.ascii_only?
  raise 'The key is not ASCII' unless b2.ascii_only?

  b1 = b1.chars.map(&:ord)
  b2 = b2.chars.map(&:ord)
  longest = [b1.length, b2.length].max
  b1 = ([0] * (longest - b1.length)) + b1
  b2 = ([0] * (longest - b2.length)) + b2
  b1.zip(b2).map { |a, b| (a ^ b).chr }.join
end

#alxor!(key) ⇒ Object

ASCII XOR with key (padding left) in place as described for #alxor.



45
46
47
# File 'lib/ctf_party/xor.rb', line 45

def alxor!(key)
  replace(alxor(key))
end

#arxor(key) ⇒ String

ASCII XOR with key, padding right the shortest element

Examples:

'hello'.arxor('key') # => "\x03\x00\x15lo"
'key'.arxor('hello') # => "\x03\x00\x15lo"

Parameters:

  • key (String)

    the element to xor the string with

Returns:

  • (String)

    the xored string (ASCII)



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ctf_party/xor.rb', line 75

def arxor(key)
  b1 = force_encoding('UTF-8')
  b2 = key.force_encoding('UTF-8')
  raise 'The string is not ASCII' unless b1.ascii_only?
  raise 'The key is not ASCII' unless b2.ascii_only?

  b1 = b1.chars.map(&:ord)
  b2 = b2.chars.map(&:ord)
  longest = [b1.length, b2.length].max
  b1 += [0] * (longest - b1.length)
  b2 += [0] * (longest - b2.length)
  b1.zip(b2).map { |a, b| (a ^ b).chr }.join
end

#arxor!(key) ⇒ Object

ASCII XOR with key (padding right) in place as described for #arxor.



90
91
92
# File 'lib/ctf_party/xor.rb', line 90

def arxor!(key)
  replace(arxor(key))
end

#b64?(opts = {}) ⇒ Boolean

Is the string encoded in base64?

Examples:

'SGVsbG8gd29ybGQh'.b64? # => true
'SGVsbG8g@@d29ybGQh'.b64? # => false

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :mode (Symbol)

    Default value: ‘:strict` (`:rfc4648`). Other values are `:rfc2045` or `:urlsafe`.

Returns:

  • (Boolean)

    ‘true` if the string is a valid base64 string, `false` else.

See Also:



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ctf_party/base64.rb', line 69

def b64?(opts = {})
  opts[:mode] ||= :strict
  b64 = false
  # https://www.rexegg.com/regex-ruby.html
  reg1 = %r{\A(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|
            (?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))\Z}xn
  reg3 = /\A(?:[a-zA-Z0-9\-_]{4})*(?:|(?:[a-zA-Z0-9\-_]{3}=)|
          (?:[a-zA-Z0-9\-_]{2}==)|(?:[a-zA-Z0-9\-_]{1}===))\Z/xn
  case opts[:mode]
  when :strict, :rfc4648
    b64 = true if reg1.match?(self)
  when :rfc2045
    b64 = true
    split("\n").each do |s|
      b64 = false unless reg1.match?(s)
    end
  when :urlsafe
    b64 = true if reg3.match?(self)
  else
    raise ArgumentError 'Wrong mode'
  end
  return b64
end

#bin2dec(opts = {}) ⇒ String

Convert a binary string to decimal (binary to hexadecimal then hexadecimal to decimal)

Examples:

'011000100110100101101110011000010111001001111001'.bin2dec # => "108204962968185"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters (see #bin2hex and #hex2dec)

Returns:

  • (String)

    the decimal encoded string



83
84
85
# File 'lib/ctf_party/binary.rb', line 83

def bin2dec(opts = {})
  bin2hex(opts).hex2dec(opts)
end

#bin2dec!(opts = {}) ⇒ Object

Convert a binary string to decimal in place as described for #bin2dec.



88
89
90
# File 'lib/ctf_party/binary.rb', line 88

def bin2dec!(opts = {})
  replace(bin2dec(opts))
end

#bin2hex(opts = {}) ⇒ String

Encode an binary string to a hexadecimal string

Examples:

'11110011'.bin2hex # => "f3"
'11110011'.bin2hex({prefix: '0x', case: :upper}) # => "0xF3"
'0110111001101111011100100110000101101010'.bin2hex(prefixall: '\\x') # => "\\x6e\\x6f\\x72\\x61\\x6a"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the output. Default value is a void string. Example of values: ‘0x`, `x`.

  • :prefixall (String)

    Prefix each byte. Default value is a void string. Example of value: ‘\x`.

  • :case (Symbol)

    Char case of the output. Default value ‘:lower`. Other valid value `:upper`.

Returns:

  • (String)

    the hexadecimal encoded string



226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/ctf_party/hex.rb', line 226

def bin2hex(opts = {})
  opts[:prefix] ||= ''
  opts[:prefixall] ||= ''
  opts[:case] ||= :lower
  # convert
  out = to_i(2).to_s(16)
  # char case management
  out = out.upcase if opts[:case] == :upper
  # adding prefix must be done after case change, complex conditional to avoid cropping when odd byte length
  out = (out.size.odd? ? [out[0]] + out[1..].scan(/.{1,2}/) : out.scan(/.{2}/)).map do |x|
    opts[:prefixall] + x
  end.join
  return opts[:prefix] + out
end

#bin2hex!(opts = {}) ⇒ Object

Encode an binary string to a hexadecimal string in place as described for #bin2hex.

Examples:

a = '11110011'
a.bin2hex!
a # => "f3"


247
248
249
# File 'lib/ctf_party/hex.rb', line 247

def bin2hex!(opts = {})
  replace(bin2hex(opts))
end

#bin2str(opts = {}) ⇒ Object

Alias for #from_bin.



59
60
61
# File 'lib/ctf_party/binary.rb', line 59

def bin2str(opts = {})
  from_bin(opts)
end

#bin2str!(opts = {}) ⇒ Object

Alias for #from_bin!.



74
75
76
# File 'lib/ctf_party/binary.rb', line 74

def bin2str!(opts = {})
  from_bin!(opts)
end

#dec2bin(opts = {}) ⇒ String

Convert a decimal string to binary (decimal to hexadecimal then hexadecimal to binary)

Examples:

'474316169578'.dec2bin # => "0110111001101111011100100110000101101010"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters (see #dec2hex and #hex2bin)

Returns:

  • (String)

    the binary encoded string



97
98
99
# File 'lib/ctf_party/binary.rb', line 97

def dec2bin(opts = {})
  dec2hex(opts).hex2bin(opts)
end

#dec2bin!(opts = {}) ⇒ Object

Convert a decimal string to binary in place as described for #dec2bin.



102
103
104
# File 'lib/ctf_party/binary.rb', line 102

def dec2bin!(opts = {})
  replace(dec2bin(opts))
end

#dec2hex(opts = {}) ⇒ String

Encode an decimal string to a hexadecimal string

Examples:

'255'.dec2hex # => "ff"
'255'.dec2hex({prefix: '0x', case: :upper}) # => "0xFF"
'10'.dec2hex(padding: 2) # => "0a"
'10'.dec2hex(padding: 8) # => "0000000a"
'474316169578'.dec2hex(prefixall: '\\x') # => "\\x6e\\x6f\\x72\\x61\\x6a"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the output. Default value is a void string. Example of values: ‘0x`, `x`.

  • :prefixall (String)

    Prefix each byte. Default value is a void string. Example of value: ‘\x`.

  • :case (Symbol)

    Char case of the output. Default value ‘:lower`. Other valid value `:upper`.

  • :padding (Symbol)

    Minimum size of the hexadecimal display (number of characters). Must be even.

Returns:

  • (String)

    the hexadecimal encoded string

Raises:

  • (ArgumentError)


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ctf_party/hex.rb', line 49

def dec2hex(opts = {})
  opts[:prefix] ||= ''
  opts[:prefixall] ||= ''
  opts[:case] ||= :lower
  opts[:padding] ||= 2
  raise(ArgumentError, 'Padding must be even') if opts[:padding].odd?

  # convert
  out = to_i.to_s(16)
  # padding
  out = ('0' * (opts[:padding] - out.size)) + out if out.size < opts[:padding]
  # char case management
  out = out.upcase if opts[:case] == :upper
  # adding prefix must be done after case change, complex conditional to avoid cropping when odd byte length
  out = (out.size.odd? ? [out[0]] + out[1..].scan(/.{1,2}/) : out.scan(/.{2}/)).map do |x|
    opts[:prefixall] + x
  end.join
  return opts[:prefix] + out
end

#dec2hex!(opts = {}) ⇒ Object

Encode an decimal string to a hexadecimal string in place as described for #dec2hex.

Examples:

a = '255'
a.dec2hex!
a # => "ff"


75
76
77
# File 'lib/ctf_party/hex.rb', line 75

def dec2hex!(opts = {})
  replace(dec2hex(opts))
end

#dec2str(opts = {}) ⇒ Object

Alias for #from_dec.



43
44
45
# File 'lib/ctf_party/dec.rb', line 43

def dec2str(opts = {})
  from_dec(opts)
end

#dec2str!(opts = {}) ⇒ Object

Alias for #from_dec!.



48
49
50
# File 'lib/ctf_party/dec.rb', line 48

def dec2str!(opts = {})
  replace(dec2str(opts))
end

#defang_domain(opts = {}) ⇒ String

Defang the string if it is a domain name

Examples:

'pwn.by'.defang_domain # => pwn[.]by

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid domain name will be defanged. If `unvalid: true`, everything is defanged.

Returns:

  • (String)

    the defanged string if it is a valid domain name or itself else.



157
158
159
160
161
162
163
164
# File 'lib/ctf_party/defang.rb', line 157

def defang_domain(opts = {})
  opts[:unvalid] ||= false
  if domain? || opts[:unvalid] == true
    gsub('.', '[.]')
  else
    self
  end
end

#defang_domain!(opts = {}) ⇒ Object

Defang the string in place, if it is a domain name, as described for #defang_domain.



167
168
169
# File 'lib/ctf_party/defang.rb', line 167

def defang_domain!(opts = {})
  replace(defang_domain(opts))
end

#defang_email(opts = {}) ⇒ String

Defang the string if it is an email address

Examples:

'noraj.rawsec@pwn.by'.defang_email # => noraj[.]rawsec[@]pwn[.]by

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid email address will be defanged. If `unvalid: true`, everything is defanged.

Returns:

  • (String)

    the defanged string if it is an email address or itself else.



202
203
204
205
206
207
208
209
# File 'lib/ctf_party/defang.rb', line 202

def defang_email(opts = {})
  opts[:unvalid] ||= false
  if email? || opts[:unvalid] == true
    gsub('.', '[.]').gsub('@', '[@]')
  else
    self
  end
end

#defang_email!(opts = {}) ⇒ Object

Defang the string in place, if it is a email address, as described for #defang_email.



212
213
214
# File 'lib/ctf_party/defang.rb', line 212

def defang_email!(opts = {})
  replace(defang_email(opts))
end

#defang_ip(opts = {}) ⇒ String

Defang the string if it is an IP address

Examples:

'1.1.1.1'.defang_ip # => 1[.]1[.]1[.]1
'2606:4700:4700::1111'.defang_ip # => '2606[:]4700[:]4700[:][:]1111'

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid IP address will be defanged. If `unvalid: true`, everything is defanged.

Returns:

  • (String)

    the defanged string if it is a valid IP address or itself else.



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ctf_party/defang.rb', line 16

def defang_ip(opts = {})
  opts[:unvalid] ||= false
  if ipv4?
    gsub('.', '[.]')
  elsif ipv6?
    gsub(':', '[:]')
  elsif opts[:unvalid] == true
    gsub('.', '[.]').gsub(':', '[:]')
  else
    self
  end
end

#defang_ip!(opts = {}) ⇒ nil

Defang the string in place, if it is an IP address, as described for #defang_ip.

Examples:

my_str = '127.0.0.1'
my_str.defang_ip!
my_str # => 127[.]0[.]0[.]1

Returns:

  • (nil)


35
36
37
# File 'lib/ctf_party/defang.rb', line 35

def defang_ip!(opts = {})
  replace(defang_ip(opts))
end

#defang_uriString

Defang the string if it is an URI. Will defang dot for any scheme and defang scheme as well for supported ones. Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.

Examples:

'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.defang_uri
# => fxp://ftp[.]ruby-lang[.]org/pub/ruby/3[.]2/ruby-3[.]2[.]0[.]tar[.]xz

Returns:

  • (String)

    the defanged string if it is an URI or itself else.



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
# File 'lib/ctf_party/defang.rb', line 76

def defang_uri
  begin
    uri = URI(self)
  rescue URI::InvalidURIError, URI::InvalidComponentError => e
    puts e
    return gsub('.', '[.]')
  end
  begin
    # temporary fix until backport for ruby 3.0 https://github.com/ruby/ruby/pull/7260
    # rubocop:disable Lint/Void
    URI::WS
    URI::WSS
    # rubocop:enable Lint/Void
  rescue NameError => e
    puts e
    require 'uri/ws'
    require 'uri/wss'
  end
  case uri
  when URI::HTTP, URI::HTTPS, URI::FTP
    uri.scheme = uri.scheme.gsub(/t/i, 'x')
  when URI::WS, URI::WSS
    uri.scheme = uri.scheme.dup.insert(1, 'x')
  when URI::LDAP, URI::LDAPS
    uri.scheme = uri.scheme.dup.insert(2, 'x')
  when URI::MailTo
    uri.scheme = uri.scheme.dup.insert(4, 'x')
    return uri.to_s.gsub('.', '[.]').gsub('@', '[@]')
  end
  uri.to_s.gsub('.', '[.]')
end

#defang_uri!Object

Defang the string in place, if it is an URI, as described for #defang_uri.



109
110
111
# File 'lib/ctf_party/defang.rb', line 109

def defang_uri!
  replace(defang_uri)
end

#domain?Boolean

Is the string a valid domain name? It is a bit lax, for exemple it does not validate if the TLD really exist but still performs more check than many checkers. rubocop:disable Metrics/PerceivedComplexity

Examples:

'pwn.by'.domain? # => true
'a.-b.net'.domain? # => false

Returns:

  • (Boolean)

    ‘true` if the string is a valid domain name, `false` else.



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/ctf_party/network.rb', line 69

def domain?
  return false unless size.between?(1, 255) # max. domain length

  # split each hostname into labels
  labels = split('.')
  return false if labels.size > 127 # max. label number
  return false if labels.size < 2 # min. label number
  return false if labels.first[0] == '.' # cannot start with a dot

  labels.each_with_index do |label, _index|
    return false unless label.size.between?(1, 63) # max. label length
    return false if label[0] == '-' || label[-1] == '-' # label cannot begin or end with hyphen
    # do not set a whitelist for allowed characters ([a-z0-9\-\_]) since there can be
    # Unicode IDN (without punycode transcription)
    # to not deal with punycode translation and validation, let's just do pseudo-validation
    # by checking only for a few illegal ones (blacklist)
    return false if /\p{C}|\p{Z}/.match?(self)
    # skip TLD validity check since the list is large, often change and custom TLD could be used for internal usage
  end
  return false if /\.\./.match?(self) # cannot contain consecutive dots

  # do not check for trailing dot
  true
end

#email?(opts = {}) ⇒ Boolean

Is the string a valid email address?

Examples:

"n#{'o' * 255}raj@pwn.by".email? # => true
"n#{'o' * 255}raj@pwn.by".email?(mode: :lightwithlength) # => false
'"valid"@domain.com'.email?(mode: :rfc5322) # => true
'"valid"@domain.com'.email?(mode: :light) # => false

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :mode (Symbol)

    Default value: ‘:rfc5322`. Other values are `:strict` (`:rfc5322`), `:light` or `:lightwithlength`. “:strict` / `:rfc5322` is the closest thing to RFC 5322. `:light` is a lighter more practical version of RFC 5322 that will be more useful in real life (omits IP addresses, domain-specific addresses, the syntax using double quotes and square brackets). `:lightwithlength` is the same as the light version but with length limit enforcing.

Returns:

  • (Boolean)

    ‘true` if the string is a valid email address, `false` else.

See Also:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ctf_party/network.rb', line 110

def email?(opts = {})
  opts[:mode] ||= :rfc5322
  case opts[:mode]
  when :strict, :rfc5322
    %r{\A(?:[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*|
    "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|
    \\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|
    \[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|
    [a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|
    \\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])\z}ix.match?(self)
  when :light
    %r{\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
    (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
  when :lightwithlength
    %r{\A(?=[a-z0-9@.!#$%&'*+/=?^_‘{|}~-]{6,254}\z)
    (?=[a-z0-9.!#$%&'*+/=?^_‘{|}~-]{1,64}@)[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
    (?:(?=[a-z0-9-]{1,63}\.)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
    (?=[a-z0-9-]{1,63}\z)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
  end
end

#flagString

Format the current string into the configured flag format. See flag= example.

Returns:

  • (String)

    the format flag.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ctf_party/flag.rb', line 44

def flag
  flag = ''
  flag += @@flag[:prefix]
  flag += @@flag[:enclosing][0]
  if @@flag[:digest].nil?
    flag += self
  else
    case @@flag[:digest]
    when 'md5'
      flag += md5
    when 'sha1'
      flag += sha1
    when 'sha2_256'
      flag += sha2_256
    when 'sha2_384'
      flag += sha2_384
    when 'sha2_512'
      flag += sha2_512
    when 'rmd160'
      flag += rmd160
    end
  end
  flag += @@flag[:enclosing][1]
  flag + @@flag[:suffix]
end

#flag!Object

Format the current string into the configured flag format in place as described for #flag.



72
73
74
# File 'lib/ctf_party/flag.rb', line 72

def flag!
  replace(flag)
end

#flag?Boolean

Check if the string respect the defined flag format.

Examples:

String.flag = {prefix: 'flag'}
flag = 'Brav0!'
flag.flag! # => "flag{Brav0!}"
flag.flag? # => true
flag = 'ctf{Brav0!}'
flag.flag? # => false

Returns:

  • (Boolean)

    true if it respects the configured flag format. but it does not check digest used.



86
87
88
89
# File 'lib/ctf_party/flag.rb', line 86

def flag?
  /#{@@flag[:prefix]}#{@@flag[:enclosing][0]}[[:print:]]+
    #{@@flag[:enclosing][1]}#{@@flag[:suffix]}/ox.match?(self)
end

#from_b64(opts = {}) ⇒ String

Decode the string from base64

Examples:

'UnVieQ=='.from_b64 # => "Ruby"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :mode (Symbol)

    Default value: ‘:strict` (`:rfc4648`). Other values are `:rfc2045` or `:urlsafe`.

Returns:

  • (String)

    the Base64 decoded string

See Also:



41
42
43
44
45
46
47
# File 'lib/ctf_party/base64.rb', line 41

def from_b64(opts = {})
  opts[:mode] ||= :strict
  return Base64.strict_decode64(self) if opts[:mode] == :strict ||
                                         opts[:mode] == :rfc4648
  return Base64.decode64(self) if opts[:mode] == :rfc2045
  return Base64.urlsafe_decode64(self) if opts[:mode] == :urlsafe
end

#from_b64!(opts = {}) ⇒ nil

Decode the string from base64 in place as described for #from_b64.

Examples:

a = 'SGVsbG8gd29ybGQh' # => "SGVsbG8gd29ybGQh"
a.from_b64! # => nil
a # => "Hello world!"

Returns:

  • (nil)


55
56
57
# File 'lib/ctf_party/base64.rb', line 55

def from_b64!(opts = {})
  replace(from_b64(opts))
end

#from_bin(opts = {}) ⇒ String

Decode a binary string

Examples:

'011000100110100101101110011000010111001001111001'.from_bin # => "binary"
'010001101001011001110110100001100100111010011110'.from_bin(bitnumbering: :LSB) # => "binary"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :bitnumbering (Symbol)

    Display input with most significant bit first (‘:MSB` default) or least significant bit first (`:LSB`).

Returns:

  • (String)

    the binary decoded string



49
50
51
52
53
54
55
56
# File 'lib/ctf_party/binary.rb', line 49

def from_bin(opts = {})
  opts[:bitnumbering] ||= :MSB
  # convert
  return Array(self).pack('B*') if opts[:bitnumbering] == :MSB
  return Array(self).pack('b*') if opts[:bitnumbering] == :LSB

  raise ArgumentError ':bitnumbering expects :MSB or :LSB'
end

#from_bin!(opts = {}) ⇒ Object

Decode a binary string in place as described for #from_bin.

Examples:

a = "011000100110100101101110011000010111001001111001"
a.from_bin!
a # => "binary"


69
70
71
# File 'lib/ctf_party/binary.rb', line 69

def from_bin!(opts = {})
  replace(from_bin(opts))
end

#from_dec(opts = {}) ⇒ String

Decode a decimal string (decimal to hexadecimal then hexadecimal to string)

Examples:

'1834615104613964215417'.from_dec # => "ctf-party"

Parameters:

Returns:

  • (String)

    the decimal decoded string



23
24
25
# File 'lib/ctf_party/dec.rb', line 23

def from_dec(opts = {})
  dec2hex(opts).from_hex(opts)
end

#from_dec!(opts = {}) ⇒ Object

Decode a decimal string in place as described for #from_dec.



28
29
30
# File 'lib/ctf_party/dec.rb', line 28

def from_dec!(opts = {})
  replace(from_dec(opts))
end

#from_hex(opts = {}) ⇒ String

Decode a hexadecimal string

Examples:

"6e6f72616a".from_hex # => "noraj"
"0x6e6f72616a".from_hex(prefix: '0x') # => "noraj"
"e6f62716a6".from_hex(nibble: :low) # => "noraj"
'\\x6e\\x6f\\x72\\x61\\x6a'.from_hex(prefix: '\\x') # => "noraj"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the input. Default value is a void string. Example of values: ‘0x`, `x`, `\x`.

  • :nibble (Symbol)

    Display input with high nibble first (‘:high` default) or low nibble first (`:low`).

Returns:

  • (String)

    the hexadecimal decoded string



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/ctf_party/hex.rb', line 148

def from_hex(opts = {})
  opts[:prefix] ||= ''
  opts[:nibble] ||= :high
  # remove prefix
  out = gsub(opts[:prefix], '')
  # convert
  return Array(out).pack('H*') if opts[:nibble] == :high
  return Array(out).pack('h*') if opts[:nibble] == :low

  raise ArgumentError ':nibble expects :high or :low'
end

#from_hex!(opts = {}) ⇒ Object

Decode a hexadecimal string in place as described for #from_hex.

Examples:

a = "6e6f72616a"
a.from_hex!
a # => "noraj"


171
172
173
# File 'lib/ctf_party/hex.rb', line 171

def from_hex!(opts = {})
  replace(from_hex(opts))
end

#from_hexipv4(opts = {}) ⇒ String Also known as: from_hexip

Decode a hexadecimal IPv4 string into a dotted decimal one

Examples:

'0100007F'.from_hexipv4(nibble: :low) # => "127.0.0.1"
'0x7f000001'.from_hexipv4(prefix: '0x') # => "127.0.0.1"
'\\x7f\\x00\\x00\\x01'.from_hexipv4(prefix: '\\x') # => "127.0.0.1"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the input. Default value is a void string. Example of values: ‘0x`, `x`, ’\x’.

  • :nibble (Symbol)

    Display input with high nibble first (‘:high` default) or low nibble first (`:low`, used on Unix `/proc/net/tcp`).

Returns:

  • (String)

    the dotted decimal IP



262
263
264
265
266
267
268
269
270
271
# File 'lib/ctf_party/hex.rb', line 262

def from_hexipv4(opts = {})
  opts[:prefix] ||= ''
  opts[:nibble] ||= :high
  # remove prefix
  out = gsub(opts[:prefix], '')
  # convert
  out = out.scan(/.{2}/).map(&:hex2dec)
  out = out.reverse if opts[:nibble] == :low
  out.join('.')
end

#from_hexipv4!(opts = {}) ⇒ Object Also known as: from_hexip!

Decode a hexadecimal IPv4 string into a dotted decimal one in place as described for #from_hexipv4.



277
278
279
# File 'lib/ctf_party/hex.rb', line 277

def from_hexipv4!(opts = {})
  replace(from_hexipv4(opts))
end

#from_hexipv6(opts = {}) ⇒ String

Decode a hexadecimal IPv6 string into a the double-dotted hexadecimal format

Examples:

'000080FE00000000FF005450B6AD1DFE'.from_hexipv6 # => "[fe80::5054:ff:fe1d:adb6]"
'0x000080FE00000000FF005450B6AD1DFE'.from_hexipv6(prefix: '0x') # => "[fe80::5054:ff:fe1d:adb6]"
'00000000000000000000000000000000'.from_hexipv6 # => "[::]"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the input. Default value is a void string. Example of values: ‘0x`, `x`, ’\x’.

Returns:

  • (String)

    the double-dotted hexadecimal format



292
293
294
295
296
297
298
299
300
301
302
# File 'lib/ctf_party/hex.rb', line 292

def from_hexipv6(opts = {})
  opts[:prefix] ||= ''
  # remove prefix
  out = gsub(opts[:prefix], '')
  # convert
  out = out.scan(/.{2}/).reverse.join
  out = out.scan(/.{8}/).reverse.join
  out = out.scan(/.{4}/).map { |x| x.sub(/^0+/, '') }.join(':')
  out = out.sub(/:{3,}/, '::').downcase
  "[#{out}]"
end

#from_hexipv6!(opts = {}) ⇒ Object

Decode a hexadecimal IPv6 string into a the double-dotted hexadecimal format in place as described for #from_hexipv6.



306
307
308
# File 'lib/ctf_party/hex.rb', line 306

def from_hexipv6!(opts = {})
  replace(from_hexipv6(opts))
end

#hex2bin(opts = {}) ⇒ String

Encode an hexadecimal string to a binary string

Examples:

'ab'.hex2bin # => "10101011"
'\xf3'.hex2bin(prefix: '\x') # => "11110011"
'\\x6e\\x6f\\x72\\x61\\x6a'.hex2bin(prefix: '\\x') # => "110111001101111011100100110000101101010"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the input. Default value is a void string. Example of values: ‘0x`, `x`, `\x`.

  • :even (Integer)

    Returns an even number of chars (pad with ‘0`). Default value is a 1. `0` for false and `1` for true.

Returns:

  • (String)

    the binary encoded string



191
192
193
194
195
196
197
198
199
200
201
# File 'lib/ctf_party/hex.rb', line 191

def hex2bin(opts = {})
  opts[:prefix] ||= ''
  opts[:even] ||= 1
  # remove prefix
  out = gsub(opts[:prefix], '')
  # convert
  out = out.to_i(16).to_s(2)
  # padding
  out = "0#{out}" if out.size.odd? && opts[:even] == 1
  return out
end

#hex2bin!(opts = {}) ⇒ Object

Encode an hexadecimal string to a binary string in place as described for #hex2bin.

Examples:

a = 'ff'
a.hex2bin!
a # => => "11111111"


209
210
211
# File 'lib/ctf_party/hex.rb', line 209

def hex2bin!(opts = {})
  replace(hex2bin(opts))
end

#hex2dec(opts = {}) ⇒ String

Encode an hexadecimal string to a decimal string

Examples:

'ff'.hex2dec # => "255"
'\xf3'.hex2dec(prefix: '\x') # => "243"
'6e6f72616a'.hex2dec # => "474316169578"
'\\x6e\\x6f\\x72\\x61\\x6a'.hex2dec(prefix: '\\x') # => "474316169578"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the input. Default value is a void string. Example of values: ‘0x`, `x`, `\x`.

Returns:

  • (String)

    the decimal encoded string



14
15
16
17
18
19
20
# File 'lib/ctf_party/hex.rb', line 14

def hex2dec(opts = {})
  opts[:prefix] ||= ''
  # remove prefix
  out = gsub(opts[:prefix], '')
  # convert
  return out.hex.to_s
end

#hex2dec!(opts = {}) ⇒ Object

Encode an hexadecimal string to a decimal string in place as described for #hex2dec.

Examples:

a = 'ff'
a.hex2dec!
a # => "255"


28
29
30
# File 'lib/ctf_party/hex.rb', line 28

def hex2dec!(opts = {})
  replace(hex2dec(opts))
end

#hex2str(opts = {}) ⇒ Object

Alias for #from_hex.



161
162
163
# File 'lib/ctf_party/hex.rb', line 161

def hex2str(opts = {})
  from_hex(opts)
end

#hex2str!(opts = {}) ⇒ Object

Alias for #from_hex!.



176
177
178
# File 'lib/ctf_party/hex.rb', line 176

def hex2str!(opts = {})
  from_hex!(opts)
end

#htmlescapeString

HTML escape the string

Examples:

'Usage: foo "bar" <baz>'.htmlescape # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"

Returns:

  • (String)

    the HTML escaped string



72
73
74
# File 'lib/ctf_party/cgi.rb', line 72

def htmlescape
  CGI.escapeHTML self
end

#htmlescape!Object

HTML escape the string in place as described for #htmlescape.



77
78
79
# File 'lib/ctf_party/cgi.rb', line 77

def htmlescape!
  replace(htmlescape)
end

#htmlunescapeString

HTML unescape the string

Examples:

"Usage: foo &quot;bar&quot; &lt;baz&gt;".htmlunescape # => "Usage: foo \"bar\" <baz>"

Returns:

  • (String)

    the HTML unescaped string



85
86
87
# File 'lib/ctf_party/cgi.rb', line 85

def htmlunescape
  CGI.unescapeHTML self
end

#htmlunescape!Object

HTML unescape the string in place as described for #htmlunescape.



90
91
92
# File 'lib/ctf_party/cgi.rb', line 90

def htmlunescape!
  replace(htmlunescape)
end

#ip?Boolean

Is the string an IP address?

Examples:

'127.0.0.1'.ip? # => true
'::1'.ip? # => true

Returns:

  • (Boolean)

    ‘true` if the string is a valid IP address, `false` else.



34
35
36
# File 'lib/ctf_party/network.rb', line 34

def ip?
  ipv4? || ipv6?
end

#ipv4?Boolean

Is the string an IPv4?

Examples:

'1.1.1.1'.ipv4? # => true
'127.0.0.300'.ipv4? # => false

Returns:

  • (Boolean)

    ‘true` if the string is a valid IPv4, `false` else.



12
13
14
15
16
# File 'lib/ctf_party/network.rb', line 12

def ipv4?
  IPAddr.new(self).ipv4?
rescue IPAddr::InvalidAddressError
  false
end

#ipv6?Boolean

Is the string an IPv6?

Examples:

'2606:4700:4700::1111'.ipv6? # => true
'fe80::fe80::fe80'.ipv6? # => false

Returns:

  • (Boolean)

    ‘true` if the string is a valid IPv6, `false` else.



23
24
25
26
27
# File 'lib/ctf_party/network.rb', line 23

def ipv6?
  IPAddr.new(self).ipv6?
rescue IPAddr::InvalidAddressError
  false
end

#istripString

Remove leading and trailing whitespace (like #strip) but also all inner whitespace.

Examples:

"\t\n\v\f\r Hello \t\n\v\f\r World !\t\n\v\f\r ".istrip # => "HelloWorld!"
'73 74 72 69 70'.istrip # => "7374726970"

Returns:

  • (String)

    the whitespace-free string



10
11
12
# File 'lib/ctf_party/misc.rb', line 10

def istrip
  strip.gsub(/\s/, '')
end

#istrip!Object

Remove all whitespace in place as described for #istrip.



15
16
17
# File 'lib/ctf_party/misc.rb', line 15

def istrip!
  replace(innerstrip)
end

#leetObject

Transform into leet speak (l337 5p34k)

Examples:

'The quick brown fox jumps over the lazy dog'.leet # => "7h3 qu1ck 8r0wn f0x jump5 0v3r 7h3 14zy d06"
'leet speak'.leet # => "1337 5p34k"


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/ctf_party/leet.rb', line 8

def leet
  tr = {
    'T' => '7',
    'E' => '3',
    'I' => '1',
    'L' => '1',
    'O' => '0',
    'S' => '5',
    'A' => '4',
    'G' => '6',
    'B' => '8'
  }
  tr.merge! tr.transform_keys(&:downcase)
  gsub(/[#{tr.keys.join}]/i, **tr)
end

#leet!Object

Transform into leet speak (l337 5p34k) in place as described for #leet.



26
27
28
# File 'lib/ctf_party/leet.rb', line 26

def leet!
  replace(leet)
end

#md5String

Calculate the md5 hash of the string.

Examples:

'noraj'.md5 # => "556cc23863fef20fab5c456db166bc6e"

Returns:

See Also:



12
13
14
# File 'lib/ctf_party/digest.rb', line 12

def md5
  Digest::MD5.hexdigest self
end

#md5!Object

Calculate the md5 hash of the string in place as described for #md5.

Examples:

a = '\o/' # => "\\o/"
a.md5! # => "881419964e480e66162da521ccc25ebf"
a # => "881419964e480e66162da521ccc25ebf"


21
22
23
# File 'lib/ctf_party/digest.rb', line 21

def md5!
  replace(md5)
end

#randomcaseString

Change the case of characters randomly

Examples:

'SELECT * FROM'.randomcase # => "SElECt * frOm"
'SELECT * FROM'.randomcase # => "selECT * FROm"

Returns:

  • (String)

    the case modified string



9
10
11
# File 'lib/ctf_party/case.rb', line 9

def randomcase
  chars.map { |c| rand(0..1).zero? ? c.downcase : c.upcase }.join
end

#randomcase!Object

Change the case of characters randomly in place as described for #randomcase.



15
16
17
# File 'lib/ctf_party/case.rb', line 15

def randomcase!
  replace(randomcase)
end

#refang_domain(opts = {}) ⇒ String

Refang the string if it is a domain name

Examples:

'pwn[.]by'.refang_domain # => pwn.by

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid domain name will be refanged. If `unvalid: true`, everything is refanged.

Returns:

  • (String)

    the refanged string if it is a valid domain name or itself else.



179
180
181
182
183
184
185
186
187
# File 'lib/ctf_party/defang.rb', line 179

def refang_domain(opts = {})
  opts[:unvalid] ||= false
  re_domain = gsub('[.]', '.')
  if re_domain.domain? || opts[:unvalid] == true
    re_domain
  else
    self
  end
end

#refang_domain!(opts = {}) ⇒ Object

Refang the string in place, if it is a domain name, as described for #refang_domain.



190
191
192
# File 'lib/ctf_party/defang.rb', line 190

def refang_domain!(opts = {})
  replace(refang_domain(opts))
end

#refang_email(opts = {}) ⇒ String

Refang the string if it is an email address

Examples:

'noraj+alias[@]pwn[.]by'.refang_email # => noraj.rawsec@pwn.by

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid email address will be refanged. If `unvalid: true`, everything is refanged.

Returns:

  • (String)

    the refanged string if it is a valid email address or itself else.



224
225
226
227
228
229
230
231
232
# File 'lib/ctf_party/defang.rb', line 224

def refang_email(opts = {})
  opts[:unvalid] ||= false
  re_email = gsub('[.]', '.').gsub('[@]', '@')
  if re_email.email? || opts[:unvalid] == true
    re_email
  else
    self
  end
end

#refang_email!(opts = {}) ⇒ Object

Refang the string in place, if it is a email address, as described for #refang_email.



235
236
237
# File 'lib/ctf_party/defang.rb', line 235

def refang_email!(opts = {})
  replace(refang_email(opts))
end

#refang_ip(opts = {}) ⇒ String

Refang the string if it is an IP address

Examples:

'1[.]1[.]1[.]1'.refang_ip # => 1.1.1.1
'2606[:]4700[:]4700[:][:]1111'.refang_ip # => 2606:4700:4700::1111

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :unvalid (Symbol)

    Default value: ‘false`. If `unvalid: false`, only valid IP address will be refanged. If `unvalid: true`, everything is refanged.

Returns:

  • (String)

    the refanged string if it is a valid IP address or itself else.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ctf_party/defang.rb', line 48

def refang_ip(opts = {})
  opts[:unvalid] ||= false
  re_ipv4 = gsub('[.]', '.')
  re_ipv6 = gsub('[:]', ':')
  if re_ipv4.ipv4?
    re_ipv4
  elsif re_ipv6.ipv6?
    re_ipv6
  elsif opts[:unvalid] == true
    gsub('[.]', '.').gsub('[:]', ':')
  else
    self
  end
end

#refang_ip!(opts = {}) ⇒ nil

Refang the string in place, if it is an IP address, as described for #refang_ip.

Returns:

  • (nil)


65
66
67
# File 'lib/ctf_party/defang.rb', line 65

def refang_ip!(opts = {})
  replace(refang_ip(opts))
end

#refang_uriString

Refang the string if it is an URI. Will refang dot for any scheme and refang scheme as well for supported ones. Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.

Examples:

'hxxp://noraj[.]neverssl[.]com/online/'.refang_uri # => http://noraj.neverssl.com/online/

Returns:

  • (String)

    the refanged string if it is an URI or itself else.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/ctf_party/defang.rb', line 119

def refang_uri
  if %r{://}.match?(self)
    scheme, remains = split('://', 2)
  else
    scheme, remains = split(':', 2)
  end
  case scheme
  when /hxxps?/i, /fxp/i
    scheme.gsub!(/x/i, 't')
  when /wxss?/i, /ldxaps?/i
    scheme.gsub!(/x/i, '')
  when /mailxto/i
    scheme.gsub!(/x/i, '')
    remains.gsub!('[.]', '.')
    remains.gsub!('[@]', '@')
    return scheme.concat(":#{remains}")
  end
  remains.gsub!('[.]', '.')
  if %r{://}.match?(self)
    scheme.concat("://#{remains}")
  else
    scheme.concat(":#{remains}")
  end
end

#refang_uri!Object

Refang the string in place, if it is an URI, as described for #refang_uri.



145
146
147
# File 'lib/ctf_party/defang.rb', line 145

def refang_uri!
  replace(refang_uri)
end

#rmd160String

Calculate the RIPEMD-160 hash of the string.

Examples:

'payload'.rmd160 # => "3c6255c112d409dafdb84d5b0edba98dfd27b44f"

Returns:

  • (String)

    RIPEMD-160 hash

See Also:



104
105
106
# File 'lib/ctf_party/digest.rb', line 104

def rmd160
  Digest::RMD160.hexdigest self
end

#rmd160!Object

Calculate the RIPEMD-160 hash of the string in place as described for #rmd160.

Examples:

pl = 'payload' # => "payload"
pl.rmd160! # => "3c6255c112d409dafdb84d5b0edba98dfd27b44f"
pl # => "3c6255c112d409dafdb84d5b0edba98dfd27b44f"


114
115
116
# File 'lib/ctf_party/digest.rb', line 114

def rmd160!
  replace(rmd160)
end

#rot(opts = {}) ⇒ String

“Encrypt / Decrypt” the string with Caesar cipher. This will shift the alphabet letters by ‘n`, where `n` is the integer key. The same function is used for encryption / decryption.

Examples:

'Hello world!'.rot # => "Uryyb jbeyq!"
'Hello world!'.rot(shift: 11) # => "Spwwz hzcwo!"
'Uryyb jbeyq!'.rot # => "Hello world!"
'Spwwz hzcwo!'.rot(shift: 26-11) # => "Hello world!"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :shift (Integer)

    The shift key. Default value: 13.

Returns:

  • (String)

    the (de)ciphered string

See Also:



16
17
18
19
20
21
22
23
24
# File 'lib/ctf_party/rot.rb', line 16

def rot(opts = {})
  opts[:shift] ||= 13
  alphabet = Array('a'..'z')
  lowercase = alphabet.zip(alphabet.rotate(opts[:shift])).to_h
  alphabet = Array('A'..'Z')
  uppercasecase = alphabet.zip(alphabet.rotate(opts[:shift])).to_h
  encrypter = lowercase.merge(uppercasecase)
  chars.map { |c| encrypter.fetch(c, c) }.join
end

#rot!(opts = {}) ⇒ String

“Encrypt / Decrypt” the string with Caesar cipher in place as described for #rot.

Examples:

a = 'Bonjour le monde !' # => "Bonjour le monde !"
a.rot! # => "Obawbhe yr zbaqr !"
a # => "Obawbhe yr zbaqr !"

Returns:

  • (String)

    the (de)ciphered string as well as changing changing the object in place.



34
35
36
# File 'lib/ctf_party/rot.rb', line 34

def rot!(opts = {})
  replace(rot(opts))
end

#rot13Object

Alias for #rot with default value ( ‘rot(shift: 13)` ).



39
40
41
# File 'lib/ctf_party/rot.rb', line 39

def rot13
  rot
end

#rot13!Object

Alias for #rot! with default value ( ‘rot!(shift: 13)` ).



44
45
46
# File 'lib/ctf_party/rot.rb', line 44

def rot13!
  rot!
end

#rot_allHash

Compute all possibilities with #rot

Examples:

'noraj'.rot_all # => {1=>"opsbk", 2=>"pqtcl", 3=>"qrudm", ... }

Returns:

  • (Hash)

    All possibilities with the shift index as key and the (de)ciphered text as value



53
54
55
# File 'lib/ctf_party/rot.rb', line 53

def rot_all
  (1..26).each_with_object({}) { |i, h| h[i] = rot(shift: i) }
end

#sha1String

Calculate the sha1 hash of the string.

Examples:

'ctf-party'.sha1 # => "5a64f3bc491d0977e1e3578a48c65a89a16a5fe8"

Returns:

See Also:



30
31
32
# File 'lib/ctf_party/digest.rb', line 30

def sha1
  Digest::SHA1.hexdigest self
end

#sha1!Object

Calculate the sha1 hash of the string in place as described for

{String#sha1}.

Examples:

bob = 'alice' # => "alice"
bob.sha1! # => "522b276a356bdf39013dfabea2cd43e141ecc9e8"
bob # => "522b276a356bdf39013dfabea2cd43e141ecc9e8"


40
41
42
# File 'lib/ctf_party/digest.rb', line 40

def sha1!
  replace(sha1)
end

#sha2(opts = {}) ⇒ String

Calculate the sha2 hash of the string.

Examples:

'try harder'.sha2 # => "5321ff2d4b1389b3a350dfe8ca77e3889dc6259bb233ad..."
'try harder'.sha2(bitlen: 512) # => "a7b73a98c095b22e25407b15c4dec128c..."

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :bitlen (Integer)

    Defines the bit lenght of the digest. Default value: 256 (SHA2-256). other valid vales are 384 (SHA2-384) and 512 (SHA2-512).

Returns:

See Also:



54
55
56
57
# File 'lib/ctf_party/digest.rb', line 54

def sha2(opts = {})
  opts[:bitlen] ||= 256
  Digest::SHA2.new(opts[:bitlen]).hexdigest self
end

#sha2!(opts = {}) ⇒ Object

Calculate the sha2 hash of the string in place as described for

{String#sha2}.

Examples:

th = 'try harder' # => "try harder"
th.sha2!(bitlen: 384) # => "bb7f60b9562a19c3a83c23791440af11591c42ede9..."
th # => "bb7f60b9562a19c3a83c23791440af11591c42ede9988334cdfd7efa4261a..."


65
66
67
# File 'lib/ctf_party/digest.rb', line 65

def sha2!(opts = {})
  replace(sha2(opts))
end

#sha2_256Object

Alias for #sha2 with default value ( ‘sha2(bitlen: 256)` ).



70
71
72
# File 'lib/ctf_party/digest.rb', line 70

def sha2_256
  sha2
end

#sha2_256!Object

Alias for #sha2! with default value ( ‘sha2!(bitlen: 256)` ).



75
76
77
# File 'lib/ctf_party/digest.rb', line 75

def sha2_256!
  replace(sha2)
end

#sha2_384Object

Alias for #sha2 with default value ( ‘sha2(bitlen: 384)` ).



80
81
82
# File 'lib/ctf_party/digest.rb', line 80

def sha2_384
  sha2(bitlen: 384)
end

#sha2_384!Object

Alias for #sha2! with default value ( ‘sha2!(bitlen: 384)` ).



85
86
87
# File 'lib/ctf_party/digest.rb', line 85

def sha2_384!
  replace(sha2(bitlen: 384))
end

#sha2_512Object

Alias for #sha2 with default value ( ‘sha2(bitlen: 512)` ).



90
91
92
# File 'lib/ctf_party/digest.rb', line 90

def sha2_512
  sha2(bitlen: 512)
end

#sha2_512!Object

Alias for #sha2! with default value ( ‘sha2!(bitlen: 512)` ).



95
96
97
# File 'lib/ctf_party/digest.rb', line 95

def sha2_512!
  replace(sha2(bitlen: 512))
end

#str2bin(opts = {}) ⇒ Object

Alias for #to_bin.



22
23
24
# File 'lib/ctf_party/binary.rb', line 22

def str2bin(opts = {})
  to_bin(opts)
end

#str2bin!(opts = {}) ⇒ Object

Alias for #to_bin!.



37
38
39
# File 'lib/ctf_party/binary.rb', line 37

def str2bin!(opts = {})
  to_bin!(opts)
end

#str2dec(opts = {}) ⇒ Object

Alias for #to_dec.



33
34
35
# File 'lib/ctf_party/dec.rb', line 33

def str2dec(opts = {})
  to_dec(opts)
end

#str2dec!(opts = {}) ⇒ Object

Alias for #to_dec!.



38
39
40
# File 'lib/ctf_party/dec.rb', line 38

def str2dec!(opts = {})
  replace(str2dec(opts))
end

#str2hex(opts = {}) ⇒ Object

Alias for #to_hex.



117
118
119
# File 'lib/ctf_party/hex.rb', line 117

def str2hex(opts = {})
  to_hex(opts)
end

#str2hex!(opts = {}) ⇒ Object

Alias for #to_hex!.



132
133
134
# File 'lib/ctf_party/hex.rb', line 132

def str2hex!(opts = {})
  to_hex!(opts)
end

#to_b64(opts = {}) ⇒ String

Encode the string into base64

Examples:

'Super lib!'.to_b64 # => "U3VwZXIgbGliIQ=="

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :mode (Symbol)

    Default value: ‘:strict` (`:rfc4648`). Other values are `:rfc2045` or `:urlsafe`.

Returns:

  • (String)

    the Base64 encoded string

See Also:



15
16
17
18
19
20
21
# File 'lib/ctf_party/base64.rb', line 15

def to_b64(opts = {})
  opts[:mode] ||= :strict
  return Base64.strict_encode64(self) if opts[:mode] == :strict ||
                                         opts[:mode] == :rfc4648
  return Base64.encode64(self) if opts[:mode] == :rfc2045
  return Base64.urlsafe_encode64(self) if opts[:mode] == :urlsafe
end

#to_b64!(opts = {}) ⇒ nil

Encode the string into base64 in place as described for #to_b64.

Examples:

myStr = 'Ruby' # => "Ruby"
myStr.to_b64! # => nil
myStr # => "UnVieQ=="

Returns:

  • (nil)


29
30
31
# File 'lib/ctf_party/base64.rb', line 29

def to_b64!(opts = {})
  replace(to_b64(opts))
end

#to_bin(opts = {}) ⇒ String

Encode a string into binary

Examples:

'binary'.to_bin # => "011000100110100101101110011000010111001001111001"
'binary'.to_bin(bitnumbering: :LSB) # => "010001101001011001110110100001100100111010011110"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :bitnumbering (Symbol)

    Display output with most significant bit first (‘:MSB` default) or least significant bit first (`:LSB`).

Returns:

  • (String)

    the binary encoded string



12
13
14
15
16
17
18
19
# File 'lib/ctf_party/binary.rb', line 12

def to_bin(opts = {})
  opts[:bitnumbering] ||= :MSB
  # convert
  return unpack1('B*') if opts[:bitnumbering] == :MSB
  return unpack1('b*') if opts[:bitnumbering] == :LSB

  raise ArgumentError ':bitnumbering expects :MSB or :LSB'
end

#to_bin!(opts = {}) ⇒ Object

Encode a string into binary in place as described for #to_bin.

Examples:

a = 'binary'
a.to_bin!
a # => "011000100110100101101110011000010111001001111001"


32
33
34
# File 'lib/ctf_party/binary.rb', line 32

def to_bin!(opts = {})
  replace(to_bin(opts))
end

#to_dec(opts = {}) ⇒ String

Encode a string into decimal (string to hexadecimal then hexadecimal to decimal)

Examples:

'noraj'.to_dec # => "474316169578"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters (see #to_hex and #hex2dec)

Returns:

  • (String)

    the decimal encoded string



9
10
11
# File 'lib/ctf_party/dec.rb', line 9

def to_dec(opts = {})
  to_hex(opts).hex2dec(opts)
end

#to_dec!(opts = {}) ⇒ Object

Encode a string into decimal in place as described for #to_dec.



14
15
16
# File 'lib/ctf_party/dec.rb', line 14

def to_dec!(opts = {})
  replace(to_dec(opts))
end

#to_hex(opts = {}) ⇒ String

Encode a string into hexadecimal

Examples:

'noraj'.to_hex # => "6e6f72616a"
'noraj'.to_hex(prefix: '0x') # => "0x6e6f72616a"
'noraj'.to_hex(case: :upper) # => "6E6F72616A"
'noraj'.to_hex(nibble: :low) # => "e6f62716a6"
'noraj'.to_hex(prefixall: '\\x') # => "\\x6e\\x6f\\x72\\x61\\x6a"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the output. Default value is a void string. Example of values: ‘0x`, `x`.

  • :prefixall (String)

    Prefix each byte. Default value is a void string. Example of value: ‘\x`.

  • :case (Symbol)

    Char case of the output. Default value ‘:lower`. Other valid value `:upper`.

  • :nibble (Symbol)

    Display output with high nibble first (‘:high` default) or low nibble first (`:low`).

Returns:

  • (String)

    the hexadecimal encoded string



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ctf_party/hex.rb', line 96

def to_hex(opts = {})
  opts[:prefix] ||= ''
  opts[:prefixall] ||= ''
  opts[:case] ||= :lower
  opts[:nibble] ||= :high
  # convert
  out = ''
  case opts[:nibble]
  when :high
    out = unpack1('H*')
  when :low
    out = unpack1('h*')
  end
  # char case management
  out = out.upcase if opts[:case] == :upper
  # adding prefix must be done after case change
  out = out.scan(/.{2}/).map { |x| opts[:prefixall] + x }.join
  return opts[:prefix] + out
end

#to_hex!(opts = {}) ⇒ Object

Encode a string into hexadecimal in place as described for #to_hex.

Examples:

a = 'noraj'
a.to_hex!
a # => "6e6f72616a"


127
128
129
# File 'lib/ctf_party/hex.rb', line 127

def to_hex!(opts = {})
  replace(to_hex(opts))
end

#to_hexipv4(opts = {}) ⇒ String Also known as: to_hexip

Encode a dotted decimal IPv4 into a hexadecimal one

Examples:

'127.0.0.1'.to_hexipv4 # => "7f000001"
'127.0.0.1'.to_hexipv4(nibble: :low) # => "0100007f"
'127.0.0.1'.to_hexipv4(prefixall: '\\x') # => "\\x7f\\x00\\x00\\x01"

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :prefix (String)

    Prefix of the output. Default value is a void string. Example of values: ‘0x`, `x`.

  • :prefixall (String)

    Prefix each byte. Default value is a void string. Example of value: ‘\x`.

  • :case (Symbol)

    Char case of the output. Default value ‘:lower`. Other valid value `:upper`.

  • :nibble (Symbol)

    Display output with high nibble first (‘:high` default) or low nibble first (`:low`, used on Unix `/proc/net/tcp`).

Returns:

  • (String)

    the hexadecimal encoded IP



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/ctf_party/hex.rb', line 325

def to_hexipv4(opts = {})
  opts[:prefix] ||= ''
  opts[:prefixall] ||= ''
  opts[:case] ||= :lower
  opts[:nibble] ||= :high
  # convert
  out = split('.').map { |x| x.dec2hex(padding: 2) }
  out = out.reverse if opts[:nibble] == :low
  out = out.join
  # char case management
  out = out.upcase if opts[:case] == :upper
  # adding prefix must be done after case change
  out = out.scan(/.{2}/).map { |x| opts[:prefixall] + x }.join
  return opts[:prefix] + out
end

#to_hexipv4!(opts = {}) ⇒ Object Also known as: to_hexip!

Encode a dotted decimal IPv4 into a hexadecimal one in place as described for #to_hexipv4.



345
346
347
# File 'lib/ctf_party/hex.rb', line 345

def to_hexipv4!(opts = {})
  replace(to_hexipv4(opts))
end

#ulxor(key) ⇒ String

UTF-8 XOR with key, padding left the shortest element

Examples:

'hello'.ulxor('key') # => "he\a\t\u0016"
'key'.ulxor('hello') # => "he\a\t\u0016"

Parameters:

  • key (String)

    the element to xor the string with

Returns:

  • (String)

    the xored string (UTF-8)



10
11
12
13
14
15
16
17
# File 'lib/ctf_party/xor.rb', line 10

def ulxor(key)
  b1 = unpack('U*')
  b2 = key.unpack('U*')
  longest = [b1.length, b2.length].max
  b1 = ([0] * (longest - b1.length)) + b1
  b2 = ([0] * (longest - b2.length)) + b2
  b1.zip(b2).map { |a, b| a ^ b }.pack('U*')
end

#ulxor!(key) ⇒ Object

UTF-8 XOR with key (padding left) in place as described for #ulxor.



20
21
22
# File 'lib/ctf_party/xor.rb', line 20

def ulxor!(key)
  replace(ulxor(key))
end

#uri?(opts = {}) ⇒ Boolean

Is the string a valid URI?

Examples:

'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.uri? # => true
'a:'.uri? # => false
'a:'.uri?(lax: true) # => true

Parameters:

  • opts (Hash) (defaults to: {})

    optional parameters

Options Hash (opts):

  • :lax (Symbol)

    Default value: ‘false`. When `lax: false`, only URI matching common protocols (ftp http https ldap ldaps mailto ws wss) are recognized, but is still a bit lax (eg. `http://` is seen as valid). When `lax: true`, the parser will accept more types of URI (gopher magnet matrix), but will be very lax and accept nearly anything including `:`.

Returns:

  • (Boolean)

    ‘true` if the string is a valid URI, `false` else.



50
51
52
53
54
55
56
57
58
59
# File 'lib/ctf_party/network.rb', line 50

def uri?(opts = {})
  opts[:lax] ||= false
  strict = URI::DEFAULT_PARSER.make_regexp(%w[ftp http https ldap ldaps mailto ws wss]).match?(self)
  lax = URI::DEFAULT_PARSER.make_regexp.match?(self)
  if opts[:lax] == true
    strict || lax
  else
    strict
  end
end

#urldecodeString

URL-decode the URL string (RFC 2396)

Examples:

'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'.urldecode # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
"'Stop!'%20said%20Fred".urldecode # => "'Stop!' said Fred"
'%27Stop%21%27+said+Fred'.urldecode # => "'Stop!'+said+Fred"

Returns:

  • (String)

    the URL-decoded string



43
44
45
# File 'lib/ctf_party/cgi.rb', line 43

def urldecode
  URI::Parser.new.unescape self
end

#urldecode!Object

URL-decode the string in place as described for #urldecode.



48
49
50
# File 'lib/ctf_party/cgi.rb', line 48

def urldecode!
  replace(urldecode)
end

#urldecode_componentString

URL-decode the URL component string (RFC 3986)

Examples:

'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode_component # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
'%27Stop%21%27%20said%20Fred'.urldecode_component # => "'Stop!' said Fred"

Returns:

  • (String)

    URL-decoded component string



113
114
115
# File 'lib/ctf_party/cgi.rb', line 113

def urldecode_component
  CGI.unescapeURIComponent self
end

#urldecode_component!Object

URL-decode the URL component string (RFC 3986) as described for #urldecode_component.



118
119
120
# File 'lib/ctf_party/cgi.rb', line 118

def urldecode_component!
  replace(urldecode_component)
end

#urldecode_dataString

URL-decode the form data (‘application/x-www-form-urlencoded`) string

Examples:

'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'.urldecode_data # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode_data # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
"'Stop!'%20said%20Fred".urldecode_data => "'Stop!' said Fred"
'%27Stop%21%27+said+Fred'.urldecode_data # => "'Stop!' said Fred"

Returns:

  • (String)

    the URL-decoded string



59
60
61
# File 'lib/ctf_party/cgi.rb', line 59

def urldecode_data
  CGI.unescape self
end

#urldecode_data!Object

URL-decode the string in place as described for #urldecode_data.



64
65
66
# File 'lib/ctf_party/cgi.rb', line 64

def urldecode_data!
  replace(urldecode_data)
end

#urlencodeString

URL-encode the URL string (RFC 2396)

Examples:

'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode # => "http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E"
"'Stop!' said Fred".urlencode # => "'Stop!'%20said%20Fred"

Returns:

  • (String)

    the URL-encoded string



13
14
15
# File 'lib/ctf_party/cgi.rb', line 13

def urlencode
  URI::Parser.new.escape self
end

#urlencode!Object

URL-encode the string in place as described for #urlencode.



18
19
20
# File 'lib/ctf_party/cgi.rb', line 18

def urlencode!
  replace(urlencode)
end

#urlencode_componentString

URL-encode the URL component string (RFC 3986)

Examples:

'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode_component # => "http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E"
"'Stop!' said Fred".urlencode_component # => "%27Stop%21%27%20said%20Fred"

Returns:

  • (String)

    URL-encoded component string



99
100
101
# File 'lib/ctf_party/cgi.rb', line 99

def urlencode_component
  CGI.escapeURIComponent self
end

#urlencode_component!Object

URL-encode the URL component string (RFC 3986) as described for #urlencode_component.



104
105
106
# File 'lib/ctf_party/cgi.rb', line 104

def urlencode_component!
  replace(urlencode_component)
end

#urlencode_dataString

URL-encode form data (‘application/x-www-form-urlencoded`) string

Examples:

"'Stop!' said Fred".urlencode_data # => "%27Stop%21%27+said+Fred"
'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode_data # => "http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E"

Returns:

  • (String)

    the URL-encoded data



27
28
29
# File 'lib/ctf_party/cgi.rb', line 27

def urlencode_data
  CGI.escape self
end

#urlencode_data!Object

URL-encode the data in place as described for #urlencode_data.



32
33
34
# File 'lib/ctf_party/cgi.rb', line 32

def urlencode_data!
  replace(urlencode_data)
end

#urxor(key) ⇒ String

UTF-8 XOR with key, padding right the shortest element

Examples:

'hello'.urxor('key') # => "\u0003\u0000\u0015lo"
'key'.urxor('hello') # => "\u0003\u0000\u0015lo"

Parameters:

  • key (String)

    the element to xor the string with

Returns:

  • (String)

    the xored string (UTF-8)



55
56
57
58
59
60
61
62
# File 'lib/ctf_party/xor.rb', line 55

def urxor(key)
  b1 = unpack('U*')
  b2 = key.unpack('U*')
  longest = [b1.length, b2.length].max
  b1 += [0] * (longest - b1.length)
  b2 += [0] * (longest - b2.length)
  b1.zip(b2).map { |a, b| a ^ b }.pack('U*')
end

#urxor!(key) ⇒ Object

UTF-8 XOR with key (padding right) in place as described for #urxor.



65
66
67
# File 'lib/ctf_party/xor.rb', line 65

def urxor!(key)
  replace(urxor(key))
end