ctf-party 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b19410e0b443bc237d10f61d2f85caff731309e95142c66d5d74897b3b296319
4
- data.tar.gz: b446182ee4883bddcabb9cfa108d62712d74ab004fe9b1f4180db7ae42e4dcd9
3
+ metadata.gz: 41082df14f844e9d331e06352e00af3ab29af0899ad4a54f911ee6cef946258b
4
+ data.tar.gz: ffb31de3ffd71d581c277f10ff0be95e9eaf2e75c161df8af1f9b8d415af64fc
5
5
  SHA512:
6
- metadata.gz: e38e7605cd1bf2bd7d9bcef501c93d6c5e1789a8488a6a150380e364822f24c981f265e319654527e0e804f6bcb7f3c6e2337d39abc54d081c602de43aca6056
7
- data.tar.gz: 4cb5c641ec6cbdc40e35387068c8befc1b658d586bae0a52a8c13cdf5cd93068c05e250d48274810e2f276bb61681bf7be0b862da0699d672b857f47a66c50cc
6
+ metadata.gz: e09eff292c815cb2a5de04f8ae901a9ccc83ac30f7cd8b3a634b2b0674b32e3cd568cecfca774641afe23953afc1a9987d810655d236bf6f4fede7a2d48c62e2
7
+ data.tar.gz: 425e78e522566abf5a67650de204e2feea57f800d81f85dd04c87a51c0cbfea1a8096344da8eea61ab9b0a857ef2c511eacb52f97f2e92fb333274897f05b8d9
data/bin/ctf-party CHANGED
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Ruby internal
5
- require 'pp'
6
5
  require 'shellwords' # for shellescape cmd
7
6
  # Project internal
8
7
  require 'ctf_party'
@@ -17,6 +16,10 @@ cmd_whitelist = {
17
16
  bin2str: 'Alias for from_bin',
18
17
  dec2hex: 'Encode an decimal string to a hexadecimal string',
19
18
  dec2str: 'Alias for from_dec',
19
+ defang_domain: 'Defang domain name',
20
+ defang_email: 'Defang email address',
21
+ defang_ip: 'Defang IP address',
22
+ defang_uri: 'Defang URI',
20
23
  from_b64: 'Decode the string from base64',
21
24
  from_bin: 'Decode a binary string',
22
25
  from_dec: 'Decode a decimal string (decimal to hexadecimal then hexadecimal to string)',
@@ -31,6 +34,10 @@ cmd_whitelist = {
31
34
  leet: 'Transform into leet speak (l337 5p34k)',
32
35
  md5: 'Calculate the md5 hash of the string',
33
36
  randomcase: 'Change the case of characters randomly',
37
+ refang_domain: 'Refang domain name',
38
+ refang_email: 'Refang email address',
39
+ refang_ip: 'Refang IP address',
40
+ refang_uri: 'Refang URI',
34
41
  rmd160: 'Calculate the RIPEMD-160 hash of the string',
35
42
  rot13: 'Encrypt / Decrypt the string with Caesar cipher with a shift of 13',
36
43
  sha1: 'Calculate the sha1 hash of the string',
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'uri'
5
+
6
+ class String
7
+ # Defang the string if it is an IP address
8
+ # @param opts [Hash] optional parameters
9
+ # @option opts [Symbol] :unvalid Default value: `false`.
10
+ # If `unvalid: false`, only valid IP address will be defanged.
11
+ # If `unvalid: true`, everything is defanged.
12
+ # @return [String] the defanged string if it is a valid IP address or itself else.
13
+ # @example
14
+ # '1.1.1.1'.defang_ip # => 1[.]1[.]1[.]1
15
+ # '2606:4700:4700::1111'.defang_ip # => '2606[:]4700[:]4700[:][:]1111'
16
+ def defang_ip(opts = {})
17
+ opts[:unvalid] ||= false
18
+ if ipv4?
19
+ gsub('.', '[.]')
20
+ elsif ipv6?
21
+ gsub(':', '[:]')
22
+ elsif opts[:unvalid] == true
23
+ gsub('.', '[.]').gsub(':', '[:]')
24
+ else
25
+ self
26
+ end
27
+ end
28
+
29
+ # Defang the string in place, if it is an IP address, as described for {String#defang_ip}.
30
+ # @return [nil]
31
+ # @example
32
+ # my_str = '127.0.0.1'
33
+ # my_str.defang_ip!
34
+ # my_str # => 127[.]0[.]0[.]1
35
+ def defang_ip!(opts = {})
36
+ replace(defang_ip(opts))
37
+ end
38
+
39
+ # Refang the string if it is an IP address
40
+ # @param opts [Hash] optional parameters
41
+ # @option opts [Symbol] :unvalid Default value: `false`.
42
+ # If `unvalid: false`, only valid IP address will be refanged.
43
+ # If `unvalid: true`, everything is refanged.
44
+ # @return [String] the refanged string if it is a valid IP address or itself else.
45
+ # @example
46
+ # '1[.]1[.]1[.]1'.refang_ip # => 1.1.1.1
47
+ # '2606[:]4700[:]4700[:][:]1111'.refang_ip # => 2606:4700:4700::1111
48
+ def refang_ip(opts = {})
49
+ opts[:unvalid] ||= false
50
+ re_ipv4 = gsub('[.]', '.')
51
+ re_ipv6 = gsub('[:]', ':')
52
+ if re_ipv4.ipv4?
53
+ re_ipv4
54
+ elsif re_ipv6.ipv6?
55
+ re_ipv6
56
+ elsif opts[:unvalid] == true
57
+ gsub('[.]', '.').gsub('[:]', ':')
58
+ else
59
+ self
60
+ end
61
+ end
62
+
63
+ # Refang the string in place, if it is an IP address, as described for {String#refang_ip}.
64
+ # @return [nil]
65
+ def refang_ip!(opts = {})
66
+ replace(refang_ip(opts))
67
+ end
68
+
69
+ # Defang the string if it is an URI.
70
+ # Will defang dot for any scheme and defang scheme as well for supported ones.
71
+ # Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.
72
+ # @return [String] the defanged string if it is an URI or itself else.
73
+ # @example
74
+ # 'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.defang_uri
75
+ # # => fxp://ftp[.]ruby-lang[.]org/pub/ruby/3[.]2/ruby-3[.]2[.]0[.]tar[.]xz
76
+ def defang_uri
77
+ begin
78
+ uri = URI(self)
79
+ rescue URI::InvalidURIError, URI::InvalidComponentError => e
80
+ puts e
81
+ return gsub('.', '[.]')
82
+ end
83
+ case uri
84
+ when URI::HTTP, URI::HTTPS, URI::FTP
85
+ uri.scheme = uri.scheme.gsub(/t/i, 'x')
86
+ when URI::WS, URI::WSS
87
+ uri.scheme = uri.scheme.dup.insert(1, 'x')
88
+ when URI::LDAP, URI::LDAPS
89
+ uri.scheme = uri.scheme.dup.insert(2, 'x')
90
+ when URI::MailTo
91
+ uri.scheme = uri.scheme.dup.insert(4, 'x')
92
+ return uri.to_s.gsub('.', '[.]').gsub('@', '[@]')
93
+ end
94
+ uri.to_s.gsub('.', '[.]')
95
+ end
96
+
97
+ # Defang the string in place, if it is an URI, as described for {String#defang_uri}.
98
+ def defang_uri!
99
+ replace(defang_uri)
100
+ end
101
+
102
+ # Refang the string if it is an URI.
103
+ # Will refang dot for any scheme and refang scheme as well for supported ones.
104
+ # Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.
105
+ # @return [String] the refanged string if it is an URI or itself else.
106
+ # @example
107
+ # 'hxxp://noraj[.]neverssl[.]com/online/'.refang_uri # => http://noraj.neverssl.com/online/
108
+ def refang_uri
109
+ if %r{://}.match?(self)
110
+ scheme, remains = split('://', 2)
111
+ else
112
+ scheme, remains = split(':', 2)
113
+ end
114
+ case scheme
115
+ when /hxxps?/i, /fxp/i
116
+ scheme.gsub!(/x/i, 't')
117
+ when /wxss?/i, /ldxaps?/i
118
+ scheme.gsub!(/x/i, '')
119
+ when /mailxto/i
120
+ scheme.gsub!(/x/i, '')
121
+ remains.gsub!('[.]', '.')
122
+ remains.gsub!('[@]', '@')
123
+ return scheme.concat(":#{remains}")
124
+ end
125
+ remains.gsub!('[.]', '.')
126
+ if %r{://}.match?(self)
127
+ scheme.concat("://#{remains}")
128
+ else
129
+ scheme.concat(":#{remains}")
130
+ end
131
+ end
132
+
133
+ # Refang the string in place, if it is an URI, as described for {String#refang_uri}.
134
+ def refang_uri!
135
+ replace(refang_uri)
136
+ end
137
+
138
+ # Defang the string if it is a domain name
139
+ # @param opts [Hash] optional parameters
140
+ # @option opts [Symbol] :unvalid Default value: `false`.
141
+ # If `unvalid: false`, only valid domain name will be defanged.
142
+ # If `unvalid: true`, everything is defanged.
143
+ # @return [String] the defanged string if it is a valid domain name or itself else.
144
+ # @example
145
+ # 'pwn.by'.defang_domain # => pwn[.]by
146
+ def defang_domain(opts = {})
147
+ opts[:unvalid] ||= false
148
+ if domain? || opts[:unvalid] == true
149
+ gsub('.', '[.]')
150
+ else
151
+ self
152
+ end
153
+ end
154
+
155
+ # Defang the string in place, if it is a domain name, as described for {String#defang_domain}.
156
+ def defang_domain!(opts = {})
157
+ replace(defang_domain(opts))
158
+ end
159
+
160
+ # Refang the string if it is a domain name
161
+ # @param opts [Hash] optional parameters
162
+ # @option opts [Symbol] :unvalid Default value: `false`.
163
+ # If `unvalid: false`, only valid domain name will be refanged.
164
+ # If `unvalid: true`, everything is refanged.
165
+ # @return [String] the refanged string if it is a valid domain name or itself else.
166
+ # @example
167
+ # 'pwn[.]by'.refang_domain # => pwn.by
168
+ def refang_domain(opts = {})
169
+ opts[:unvalid] ||= false
170
+ re_domain = gsub('[.]', '.')
171
+ if re_domain.domain? || opts[:unvalid] == true
172
+ re_domain
173
+ else
174
+ self
175
+ end
176
+ end
177
+
178
+ # Refang the string in place, if it is a domain name, as described for {String#refang_domain}.
179
+ def refang_domain!(opts = {})
180
+ replace(refang_domain(opts))
181
+ end
182
+
183
+ # Defang the string if it is an email address
184
+ # @param opts [Hash] optional parameters
185
+ # @option opts [Symbol] :unvalid Default value: `false`.
186
+ # If `unvalid: false`, only valid email address will be defanged.
187
+ # If `unvalid: true`, everything is defanged.
188
+ # @return [String] the defanged string if it is an email address or itself else.
189
+ # @example
190
+ # 'noraj.rawsec@pwn.by'.defang_email # => noraj[.]rawsec[@]pwn[.]by
191
+ def defang_email(opts = {})
192
+ opts[:unvalid] ||= false
193
+ if email? || opts[:unvalid] == true
194
+ gsub('.', '[.]').gsub('@', '[@]')
195
+ else
196
+ self
197
+ end
198
+ end
199
+
200
+ # Defang the string in place, if it is a email address, as described for {String#defang_email}.
201
+ def defang_email!(opts = {})
202
+ replace(defang_email(opts))
203
+ end
204
+
205
+ # Refang the string if it is an email address
206
+ # @param opts [Hash] optional parameters
207
+ # @option opts [Symbol] :unvalid Default value: `false`.
208
+ # If `unvalid: false`, only valid email address will be refanged.
209
+ # If `unvalid: true`, everything is refanged.
210
+ # @return [String] the refanged string if it is a valid email address or itself else.
211
+ # @example
212
+ # 'noraj+alias[@]pwn[.]by'.refang_email # => noraj.rawsec@pwn.by
213
+ def refang_email(opts = {})
214
+ opts[:unvalid] ||= false
215
+ re_email = gsub('[.]', '.').gsub('[@]', '@')
216
+ if re_email.email? || opts[:unvalid] == true
217
+ re_email
218
+ else
219
+ self
220
+ end
221
+ end
222
+
223
+ # Refang the string in place, if it is a email address, as described for {String#refang_email}.
224
+ def refang_email!(opts = {})
225
+ replace(refang_email(opts))
226
+ end
227
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'uri'
5
+
6
+ class String
7
+ # Is the string an IPv4?
8
+ # @return [Boolean] `true` if the string is a valid IPv4, `false` else.
9
+ # @example
10
+ # '1.1.1.1'.ipv4? # => true
11
+ # '127.0.0.300'.ipv4? # => false
12
+ def ipv4?
13
+ IPAddr.new(self).ipv4?
14
+ rescue IPAddr::InvalidAddressError
15
+ false
16
+ end
17
+
18
+ # Is the string an IPv6?
19
+ # @return [Boolean] `true` if the string is a valid IPv6, `false` else.
20
+ # @example
21
+ # '2606:4700:4700::1111'.ipv6? # => true
22
+ # 'fe80::fe80::fe80'.ipv6? # => false
23
+ def ipv6?
24
+ IPAddr.new(self).ipv6?
25
+ rescue IPAddr::InvalidAddressError
26
+ false
27
+ end
28
+
29
+ # Is the string an IP address?
30
+ # @return [Boolean] `true` if the string is a valid IP address, `false` else.
31
+ # @example
32
+ # '127.0.0.1'.ip? # => true
33
+ # '::1'.ip? # => true
34
+ def ip?
35
+ ipv4? || ipv6?
36
+ end
37
+
38
+ # Is the string a valid URI?
39
+ # @param opts [Hash] optional parameters
40
+ # @option opts [Symbol] :lax Default value: `false`.
41
+ # When `lax: false`, only URI matching common protocols (ftp http https ldap ldaps mailto ws wss) are recognized,
42
+ # but is still a bit lax (eg. `http://` is seen as valid).
43
+ # When `lax: true`, the parser will accept more types of URI (gopher magnet matrix), but will be very lax and accept
44
+ # nearly anything including `:`.
45
+ # @return [Boolean] `true` if the string is a valid URI, `false` else.
46
+ # @example
47
+ # 'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.uri? # => true
48
+ # 'a:'.uri? # => false
49
+ # 'a:'.uri?(lax: true) # => true
50
+ def uri?(opts = {})
51
+ opts[:lax] ||= false
52
+ strict = URI::DEFAULT_PARSER.make_regexp(%w[ftp http https ldap ldaps mailto ws wss]).match?(self)
53
+ lax = URI::DEFAULT_PARSER.make_regexp.match?(self)
54
+ if opts[:lax] == true
55
+ strict || lax
56
+ else
57
+ strict
58
+ end
59
+ end
60
+
61
+ # Is the string a valid domain name?
62
+ # It is a bit lax, for exemple it does not validate if the TLD really exist but
63
+ # still performs more check than many checkers.
64
+ # @return [Boolean] `true` if the string is a valid domain name, `false` else.
65
+ # @example
66
+ # 'pwn.by'.domain? # => true
67
+ # 'a.-b.net'.domain? # => false
68
+ # rubocop:disable Metrics/PerceivedComplexity
69
+ def domain?
70
+ return false unless size.between?(1, 255) # max. domain length
71
+
72
+ # split each hostname into labels
73
+ labels = split('.')
74
+ return false if labels.size > 127 # max. label number
75
+ return false if labels.size < 2 # min. label number
76
+ return false if labels.first[0] == '.' # cannot start with a dot
77
+
78
+ labels.each_with_index do |label, _index|
79
+ return false unless label.size.between?(1, 63) # max. label length
80
+ return false if label[0] == '-' || label[-1] == '-' # label cannot begin or end with hyphen
81
+ # do not set a whitelist for allowed characters ([a-z0-9\-\_]) since there can be
82
+ # Unicode IDN (without punycode transcription)
83
+ # to not deal with punycode translation and validation, let's just do pseudo-validation
84
+ # by checking only for a few illegal ones (blacklist)
85
+ return false if /\p{C}|\p{Z}/.match?(self)
86
+ # skip TLD validity check since the list is large, often change and custom TLD could be used for internal usage
87
+ end
88
+ return false if /\.\./.match?(self) # cannot contain consecutive dots
89
+
90
+ # do not check for trailing dot
91
+ true
92
+ end
93
+ # rubocop:enable Metrics/PerceivedComplexity
94
+
95
+ # Is the string a valid email address?
96
+ # @param opts [Hash] optional parameters
97
+ # @option opts [Symbol] :mode Default value: `:rfc5322`.
98
+ # Other values are `:strict` (`:rfc5322`), `:light` or `:lightwithlength`.
99
+ # ``:strict` / `:rfc5322` is the closest thing to RFC 5322.
100
+ # `:light` is a lighter more practical version of RFC 5322 that will be more useful in real life (omits IP
101
+ # addresses, domain-specific addresses, the syntax using double quotes and square brackets).
102
+ # `:lightwithlength` is the same as the light version but with length limit enforcing.
103
+ # @see https://stackoverflow.com/questions/22993545/ruby-email-validation-with-regex/75050279#75050279
104
+ # @return [Boolean] `true` if the string is a valid email address, `false` else.
105
+ # @example
106
+ # "n#{'o' * 255}raj@pwn.by".email? # => true
107
+ # "n#{'o' * 255}raj@pwn.by".email?(mode: :lightwithlength) # => false
108
+ # '"valid"@domain.com'.email?(mode: :rfc5322) # => true
109
+ # '"valid"@domain.com'.email?(mode: :light) # => false
110
+ def email?(opts = {})
111
+ opts[:mode] ||= :rfc5322
112
+ case opts[:mode]
113
+ when :strict, :rfc5322
114
+ %r{\A(?:[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*|
115
+ "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|
116
+ \\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|
117
+ \[(?:(?: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]?|
118
+ [a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|
119
+ \\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])\z}ix.match?(self)
120
+ when :light
121
+ %r{\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
122
+ (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
123
+ when :lightwithlength
124
+ %r{\A(?=[a-z0-9@.!#$%&'*+/=?^_‘{|}~-]{6,254}\z)
125
+ (?=[a-z0-9.!#$%&'*+/=?^_‘{|}~-]{1,64}@)[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
126
+ (?:(?=[a-z0-9-]{1,63}\.)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
127
+ (?=[a-z0-9-]{1,63}\z)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
128
+ end
129
+ end
130
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Version
4
- VERSION = '2.2.0'
4
+ VERSION = '2.3.0'
5
5
  end
data/lib/ctf_party.rb CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  # Project internal
4
4
  require 'ctf_party/base64'
5
- require 'ctf_party/rot'
5
+ require 'ctf_party/binary'
6
+ require 'ctf_party/case'
7
+ require 'ctf_party/cgi'
8
+ require 'ctf_party/dec'
9
+ require 'ctf_party/defang'
6
10
  require 'ctf_party/digest'
7
11
  require 'ctf_party/flag'
8
12
  require 'ctf_party/hex'
9
- require 'ctf_party/case'
10
- require 'ctf_party/cgi'
11
- require 'ctf_party/binary'
12
13
  require 'ctf_party/leet'
13
- require 'ctf_party/dec'
14
14
  require 'ctf_party/misc'
15
+ require 'ctf_party/network'
16
+ require 'ctf_party/rot'
15
17
  require 'ctf_party/xor'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ctf-party
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre ZANNI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-28 00:00:00.000000000 Z
11
+ date: 2023-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docopt
@@ -46,11 +46,13 @@ files:
46
46
  - lib/ctf_party/case.rb
47
47
  - lib/ctf_party/cgi.rb
48
48
  - lib/ctf_party/dec.rb
49
+ - lib/ctf_party/defang.rb
49
50
  - lib/ctf_party/digest.rb
50
51
  - lib/ctf_party/flag.rb
51
52
  - lib/ctf_party/hex.rb
52
53
  - lib/ctf_party/leet.rb
53
54
  - lib/ctf_party/misc.rb
55
+ - lib/ctf_party/network.rb
54
56
  - lib/ctf_party/rot.rb
55
57
  - lib/ctf_party/version.rb
56
58
  - lib/ctf_party/xor.rb
@@ -76,14 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
78
  version: 2.7.0
77
79
  - - "<"
78
80
  - !ruby/object:Gem::Version
79
- version: '3.2'
81
+ version: '3.3'
80
82
  required_rubygems_version: !ruby/object:Gem::Requirement
81
83
  requirements:
82
84
  - - ">="
83
85
  - !ruby/object:Gem::Version
84
86
  version: '0'
85
87
  requirements: []
86
- rubygems_version: 3.3.3
88
+ rubygems_version: 3.4.1
87
89
  signing_key:
88
90
  specification_version: 4
89
91
  summary: A CLI tool & library to enhance and speed up script/exploit writing with