ctf-party 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/ctf-party +66 -9
- data/lib/ctf_party/cgi.rb +1 -0
- data/lib/ctf_party/defang.rb +227 -0
- data/lib/ctf_party/hex.rb +4 -2
- data/lib/ctf_party/network.rb +130 -0
- data/lib/ctf_party/version.rb +1 -1
- data/lib/ctf_party.rb +7 -5
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41082df14f844e9d331e06352e00af3ab29af0899ad4a54f911ee6cef946258b
|
4
|
+
data.tar.gz: ffb31de3ffd71d581c277f10ff0be95e9eaf2e75c161df8af1f9b8d415af64fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e09eff292c815cb2a5de04f8ae901a9ccc83ac30f7cd8b3a634b2b0674b32e3cd568cecfca774641afe23953afc1a9987d810655d236bf6f4fede7a2d48c62e2
|
7
|
+
data.tar.gz: 425e78e522566abf5a67650de204e2feea57f800d81f85dd04c87a51c0cbfea1a8096344da8eea61ab9b0a857ef2c511eacb52f97f2e92fb333274897f05b8d9
|
data/bin/ctf-party
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Ruby internal
|
5
|
-
require '
|
5
|
+
require 'shellwords' # for shellescape cmd
|
6
6
|
# Project internal
|
7
7
|
require 'ctf_party'
|
8
8
|
require 'ctf_party/version'
|
@@ -10,11 +10,16 @@ require 'ctf_party/version'
|
|
10
10
|
require 'docopt'
|
11
11
|
|
12
12
|
cmd_whitelist = {
|
13
|
+
# ctf-party commands
|
13
14
|
alternatecase: 'Change one characte on two upcase and the other downcase',
|
14
15
|
bin2hex: 'Encode an binary string to a hexadecimal string',
|
15
16
|
bin2str: 'Alias for from_bin',
|
16
17
|
dec2hex: 'Encode an decimal string to a hexadecimal string',
|
17
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',
|
18
23
|
from_b64: 'Decode the string from base64',
|
19
24
|
from_bin: 'Decode a binary string',
|
20
25
|
from_dec: 'Decode a decimal string (decimal to hexadecimal then hexadecimal to string)',
|
@@ -29,6 +34,10 @@ cmd_whitelist = {
|
|
29
34
|
leet: 'Transform into leet speak (l337 5p34k)',
|
30
35
|
md5: 'Calculate the md5 hash of the string',
|
31
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',
|
32
41
|
rmd160: 'Calculate the RIPEMD-160 hash of the string',
|
33
42
|
rot13: 'Encrypt / Decrypt the string with Caesar cipher with a shift of 13',
|
34
43
|
sha1: 'Calculate the sha1 hash of the string',
|
@@ -45,27 +54,62 @@ cmd_whitelist = {
|
|
45
54
|
to_hex: 'Encode a string into hexadecimal',
|
46
55
|
to_hexip: 'Encode a dotted decimal IP into a hexadecimal one',
|
47
56
|
urldecode: 'URL-decode the string',
|
48
|
-
|
57
|
+
urldecode_component: 'URL-decode the URL component string',
|
58
|
+
urlencode: 'URL-encode the string',
|
59
|
+
urlencode_component: 'URL-encode the URL component string',
|
60
|
+
# native string commands
|
61
|
+
bytesize: 'https://rubyapi.org/3.1/o/string#method-i-bytesize',
|
62
|
+
capitalize: 'https://rubyapi.org/3.1/o/string#method-i-capitalize',
|
63
|
+
chomp: 'https://rubyapi.org/3.1/o/string#method-i-chomp',
|
64
|
+
chop: 'https://rubyapi.org/3.1/o/string#method-i-chop',
|
65
|
+
downcase: 'https://rubyapi.org/3.1/o/string#method-i-downcase',
|
66
|
+
dump: 'https://rubyapi.org/3.1/o/string#method-i-dump',
|
67
|
+
hex: 'https://rubyapi.org/3.1/o/string#method-i-hex',
|
68
|
+
inspect: 'https://rubyapi.org/3.1/o/string#method-i-inspect',
|
69
|
+
length: 'https://rubyapi.org/3.1/o/string#method-i-length',
|
70
|
+
lstrip: 'https://rubyapi.org/3.1/o/string#method-i-lstrip',
|
71
|
+
reverse: 'https://rubyapi.org/3.1/o/string#method-i-reverse',
|
72
|
+
rstrip: 'https://rubyapi.org/3.1/o/string#method-i-rstrip',
|
73
|
+
scrub: 'https://rubyapi.org/3.1/o/string#method-i-scrub',
|
74
|
+
shellescape: 'https://rubyapi.org/3.1/o/string#method-i-shellescape',
|
75
|
+
size: 'https://rubyapi.org/3.1/o/string#method-i-size',
|
76
|
+
squeeze: 'https://rubyapi.org/3.1/o/string#method-i-squeeze',
|
77
|
+
strip: 'https://rubyapi.org/3.1/o/string#method-i-strip',
|
78
|
+
succ: 'https://rubyapi.org/3.1/o/string#method-i-succ',
|
79
|
+
swapcase: 'https://rubyapi.org/3.1/o/string#method-i-swapcase',
|
80
|
+
undump: 'https://rubyapi.org/3.1/o/string#method-i-undump',
|
81
|
+
unicode_normalize: 'https://rubyapi.org/3.1/o/string#method-i-unicode_normalize',
|
82
|
+
upcase: 'https://rubyapi.org/3.1/o/string#method-i-upcase'
|
49
83
|
}
|
50
84
|
|
51
85
|
doc = <<~DOCOPT
|
52
|
-
ctf-party by noraj
|
86
|
+
ctf-party v#{Version::VERSION} by noraj
|
53
87
|
|
54
88
|
Usage:
|
55
|
-
ctf-party <string> <cmd>... [--debug]
|
89
|
+
ctf-party <string> <cmd>... [--row --file] [--debug]
|
56
90
|
ctf-party --list-commands [--debug]
|
57
91
|
ctf-party -h | --help
|
58
92
|
ctf-party --version
|
59
93
|
|
94
|
+
Parameters:
|
95
|
+
<string> The string to manipulate, read from STDIN if equal to "-"
|
96
|
+
<cmd> Command to apply to the string, cf. --list-commands
|
97
|
+
|
60
98
|
Options:
|
61
99
|
-l, --list-commands List available commands (see https://noraj.github.io/ctf-party/yard/String.html)
|
100
|
+
-r, --row Apply the transformation to each row
|
101
|
+
-f, --file Interpret the string as a filename, if file doesn't exist it will still be treated as a string
|
62
102
|
--debug Display arguments
|
63
103
|
-h, --help Show this screen
|
64
104
|
--version Show version
|
65
105
|
|
66
106
|
Examples:
|
67
107
|
ctf-party 'security' to_hex
|
68
|
-
ctf-party 'NzQ2Zjc0NmY=' from_b64
|
108
|
+
ctf-party 'NzQ2Zjc0NmY=' from_b64 hex2bin
|
109
|
+
curl -s https://example.org | ctf-party - htmlescape
|
110
|
+
seq 1 10 | ctf-party - dec2hex hex2bin --row
|
111
|
+
cut -d : -f 1 /etc/passwd | ctf-party - randomcase --row
|
112
|
+
ctf-party /etc/passwd str2hex --row --file
|
69
113
|
DOCOPT
|
70
114
|
|
71
115
|
begin
|
@@ -73,11 +117,24 @@ begin
|
|
73
117
|
# use case 1, using the tool
|
74
118
|
pp args if args['--debug']
|
75
119
|
if args['<string>']
|
120
|
+
args['<string>'] = $stdin.read.chomp if args['<string>'] == '-'
|
121
|
+
args['<string>'] = File.read(args['<string>']) if args['--file'] && File.exist?(args['<string>'])
|
76
122
|
wrong_cmd = args['<cmd>'] - cmd_whitelist.keys.map(&:to_s)
|
77
123
|
if wrong_cmd.empty?
|
78
|
-
|
79
|
-
|
80
|
-
|
124
|
+
if args['--row']
|
125
|
+
output = ''
|
126
|
+
args['<string>'].each_line(chomp: true) do |line|
|
127
|
+
output_line = line
|
128
|
+
args['<cmd>'].each do |cmd|
|
129
|
+
output_line = output_line.public_send(cmd)
|
130
|
+
end
|
131
|
+
output += "#{output_line}\n"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
output = args['<string>']
|
135
|
+
args['<cmd>'].each do |cmd|
|
136
|
+
output = output.public_send(cmd)
|
137
|
+
end
|
81
138
|
end
|
82
139
|
puts output
|
83
140
|
else
|
@@ -85,7 +142,7 @@ begin
|
|
85
142
|
end
|
86
143
|
elsif args['--list-commands']
|
87
144
|
cmd_whitelist.each do |k, v|
|
88
|
-
puts "#{k.to_s.ljust(
|
145
|
+
puts "#{k.to_s.ljust(25)}#{v}"
|
89
146
|
end
|
90
147
|
end
|
91
148
|
# use case 2, help: already handled by docopt
|
data/lib/ctf_party/cgi.rb
CHANGED
@@ -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
|
data/lib/ctf_party/hex.rb
CHANGED
@@ -59,8 +59,10 @@ class String
|
|
59
59
|
out = ('0' * (opts[:padding] - out.size)) + out if out.size < opts[:padding]
|
60
60
|
# char case management
|
61
61
|
out = out.upcase if opts[:case] == :upper
|
62
|
-
# adding prefix must be done after case change
|
63
|
-
out = out.scan(/.{2}/).map
|
62
|
+
# adding prefix must be done after case change, complex conditional to avoid cropping when odd byte lenght
|
63
|
+
out = (out.size.odd? ? [out[0]] + out[1..].scan(/.{1,2}/) : out.scan(/.{2}/)).map do |x|
|
64
|
+
opts[:prefixall] + x
|
65
|
+
end.join
|
64
66
|
return opts[:prefix] + out
|
65
67
|
end
|
66
68
|
|
@@ -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
|
data/lib/ctf_party/version.rb
CHANGED
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/
|
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.
|
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:
|
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.
|
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.
|
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
|