jwtear 0.1.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 +7 -0
- data/.gitignore +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +58 -0
- data/Rakefile +2 -0
- data/bin/jwtear +117 -0
- data/jwtear.gemspec +22 -0
- data/lib/jwtear.rb +24 -0
- data/lib/jwtear/algorithms.rb +82 -0
- data/lib/jwtear/errors.rb +5 -0
- data/lib/jwtear/extensions.rb +41 -0
- data/lib/jwtear/jwt.rb +117 -0
- data/lib/jwtear/utils.rb +31 -0
- data/lib/jwtear/version.rb +3 -0
- data/modules/bruteforce.rb +39 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4bd6308c71a62710f83b4fe948bb9548de5cebef
|
4
|
+
data.tar.gz: 3c04480e04b3469e40a5cede5a09c8db727e9cbe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca0c937b0abec2482997108633039078c5dc0691b6eedd9fa71a7e2dc68a9a4b61f0b1d3427ac16625b3bd28e20764bfb9b78ef06d48e30c18f8d1319de6556f
|
7
|
+
data.tar.gz: 1914d144b8c6fc0b84b040b132d9dbda8ffa50789148eaec75f621991be9bd38712459a86bc90dc91a0e727364d96bfe87d70f2e54c7cc73617b813f64cebff7
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.idea/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 KING SABRI
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Jwtear
|
2
|
+
Command-line tool and library to parse, create and manipulate JWT tokens for security testing purposes.
|
3
|
+
|
4
|
+
During working on exploiting some JWT-based application I needed some tool to make parsing and manipulating JWT token easier.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
install it yourself as:
|
9
|
+
|
10
|
+
$ gem install jwtear
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
```
|
15
|
+
$> jwtear -h
|
16
|
+
|
17
|
+
|
18
|
+
888888 888 888 88888888888
|
19
|
+
"88b 888 o 888 888
|
20
|
+
888 888 d8b 888 888
|
21
|
+
888 888 d888b 888 888 .d88b. 8888b. 888d888
|
22
|
+
888 888d88888b888 888 d8P Y8b "88b 888P"
|
23
|
+
888 88888P Y88888 888 88888888 .d888888 888
|
24
|
+
88P 8888P Y8888 888 Y8b. 888 888 888
|
25
|
+
888 888P Y888 888 "Y8888 "Y888888 888
|
26
|
+
.d88P v0.1.0
|
27
|
+
.d88P"
|
28
|
+
888P"
|
29
|
+
JWTear - Parse, create and manipulate JWT tokens.
|
30
|
+
|
31
|
+
Help menu:
|
32
|
+
-p, --parse JWT_TOKEN Parse JWT token
|
33
|
+
--generate-token Generate JWT token.
|
34
|
+
--generate-sig Generate JWT signature.
|
35
|
+
--header HEADER JWT header (JSON format). (required for generate-token and generate-sig)
|
36
|
+
eg. {"typ":"JWT","alg":"HS256"} | Supported algorithms: [HS256, RS512, etc]
|
37
|
+
--payload PAYLOAD JWT payload (JSON format). (required for generate-token and generate-sig)
|
38
|
+
eg. {"login":"admin"}
|
39
|
+
--key SECRET Secret Key for symmetric encryption. (required for generate-token and generate-sig)
|
40
|
+
eg. P@ssw0rd
|
41
|
+
-h, --help Show this help message
|
42
|
+
|
43
|
+
Usage:
|
44
|
+
ruby jwtear.rb <OPTIONS>
|
45
|
+
|
46
|
+
Example:
|
47
|
+
ruby jwtear.rb --generate-token --header '{"typ":"JWT","alg":"HS256"}' --payload '{"login":"admin"}' --key 'P@ssw0rd!'
|
48
|
+
ruby jwtear.rb --generate-sig --header '{"typ":"JWT","alg":"HS256"}' --payload '{"login":"admin"}' --key 'P@ssw0rd!'
|
49
|
+
ruby jwtear.rb --parse 'eyJwI...6IfJ9.kxrMS...MjAMm.zEybN...TU2Njk3ZmE3OA'
|
50
|
+
```
|
51
|
+
|
52
|
+
## Contributing
|
53
|
+
|
54
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jwtear.
|
55
|
+
|
56
|
+
## License
|
57
|
+
|
58
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/jwtear
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# JWTear - A command-line tool and library to parse, create and manipulate JWT tokens for security testing purposes.
|
4
|
+
#
|
5
|
+
# @Author: KING SABRI - @KINGSABRI
|
6
|
+
#
|
7
|
+
lib = File.dirname(__FILE__) + '/../lib'
|
8
|
+
mod = File.dirname(__FILE__) + '/../modules'
|
9
|
+
if File.directory?(lib)
|
10
|
+
unless $:.include?(lib)
|
11
|
+
$:.unshift(lib)
|
12
|
+
$:.unshift(mod)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
require 'jwtear'
|
16
|
+
require 'optparse'
|
17
|
+
|
18
|
+
|
19
|
+
options = {}
|
20
|
+
option_parser = OptionParser.new
|
21
|
+
option_parser.banner = "#{"JWTear".bold} - Parse, create and manipulate JWT tokens."
|
22
|
+
option_parser.set_summary_indent ' '
|
23
|
+
option_parser.separator "\nHelp menu:".underline
|
24
|
+
option_parser.on('-p', '--parse JWT_TOKEN' , 'Parse JWT token') {|v| options[:parse] = v}
|
25
|
+
option_parser.on('--generate-token', 'Generate JWT token.') {|v| options[:generate_token] = v}
|
26
|
+
option_parser.on('--generate-sig', 'Generate JWT signature.') {|v| options[:generate_sig] = v}
|
27
|
+
option_parser.on('--header HEADER',
|
28
|
+
'JWT header (JSON format). (required for generate-token and generate-sig)',
|
29
|
+
' eg. {"typ":"JWT","alg":"HS256"} | Supported algorithms: [HS256, RS512, etc]'
|
30
|
+
) {|v| options[:header] = v}
|
31
|
+
option_parser.on('--payload PAYLOAD' ,
|
32
|
+
'JWT payload (JSON format). (required for generate-token and generate-sig)',
|
33
|
+
' eg. {"login":"admin"}'
|
34
|
+
) {|v| options[:payload] = v}
|
35
|
+
option_parser.on('--alg ALGORITHM',
|
36
|
+
'Force algorithm type when generating a new token (ignore the one in header). (optional with generate-token)',
|
37
|
+
' Supported algorithms: [HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512]'
|
38
|
+
) {|v| options[:alg] = v}
|
39
|
+
option_parser.on('--key SECRET',
|
40
|
+
'Secret Key for symmetric encryption. (required for generate-token and generate-sig. Accept password as a string or a file)',
|
41
|
+
' eg. P@ssw0rd | eg. public_key.pem'
|
42
|
+
) {|v| options[:key] = v}
|
43
|
+
# option_parser.on( '-m MODULE', '--module MODULE',
|
44
|
+
# "Use module - WIP",
|
45
|
+
# "Use it without argument to list all modules with its usage"
|
46
|
+
# ) {|v| options[:key] = v}
|
47
|
+
option_parser.on('-h', '--help', 'Show this help message') {puts JWTear::Utils.banner , option_parser; exit!}
|
48
|
+
option_parser.on_tail "\nUsage:\n".underline + "jwtear <OPTIONS>"
|
49
|
+
option_parser.on_tail "\nExample:".underline
|
50
|
+
option_parser.on_tail %Q{jwtear --generate-token --header #{"'".bold}{"typ":"JWT","alg":" "}#{"'".bold} --payload #{"'".bold}{"login":"admin"}#{"'".bold} --key 'P@ssw0rd!'}
|
51
|
+
option_parser.on_tail %Q{jwtear --generate-sig --header #{"'".bold}{"typ":"JWT","alg":"HS256"}#{"'".bold} --payload #{"'".bold}{"login":"admin"}#{"'".bold} --key 'P@ssw0rd!'}
|
52
|
+
option_parser.on_tail %Q{jwtear --parse #{"'".bold}eyJwI...6IfJ9#{'.'.bold}kxrMS...MjAMm#{'.'.bold}zEybN...TU2Njk3ZmE3OA#{"'".bold}\n\n}
|
53
|
+
|
54
|
+
begin
|
55
|
+
option_parser.parse!
|
56
|
+
include JWTear::Utils
|
57
|
+
case
|
58
|
+
when options[:parse]
|
59
|
+
jwt = JWTear::JWT.new(options[:parse])
|
60
|
+
jwt_parsed = jwt.parse
|
61
|
+
puts "-[#{'Hash'.green}]----"
|
62
|
+
puts jwt_parsed
|
63
|
+
puts "-[#{'JSON'.green}]----"
|
64
|
+
puts jwt.json
|
65
|
+
puts ''
|
66
|
+
puts "[+] ".dark_green + "Header (envelope segment):".bold.underline
|
67
|
+
jwt.header.each {|key, value| puts " #{'-'.bold} #{key}: #{value}"}
|
68
|
+
puts "[+] ".dark_green + "Payload (claim segment):".bold.underline
|
69
|
+
jwt.payload.each {|key, value| puts " #{'-'.bold} #{key}: #{value}"}
|
70
|
+
puts "[+] ".dark_green + "Signature (envelope segment) - encoded:".bold.underline
|
71
|
+
puts "#{Base64.urlsafe_encode64(jwt.signature)}"
|
72
|
+
when options[:generate_token] && (options[:header] || options[:payload] || options[:key]).nil?
|
73
|
+
puts '[!] '.red + "Missing mandatory switch(es) '--header/--payload/--alg/--key'"
|
74
|
+
|
75
|
+
when options[:generate_gen] && (options[:header] || options[:payload] || options[:key]).nil?
|
76
|
+
puts '[!] '.red + "Missing mandatory switch(es) '--header/--payload/--key'"
|
77
|
+
|
78
|
+
when options[:generate_token]
|
79
|
+
jwt = JWTear::JWT.new
|
80
|
+
jwt.header = options[:header]
|
81
|
+
jwt.payload = options[:payload]
|
82
|
+
jwt.alg = options[:alg]
|
83
|
+
if options[:key]
|
84
|
+
jwt.key = File.file?(options[:key])? File.read(options[:key]) : options[:key] # read key as a string or from file(eg. pub_key.pem)
|
85
|
+
end
|
86
|
+
token = jwt.generate_token
|
87
|
+
puts "-[#{'Hash'.dark_green}]----"
|
88
|
+
puts jwt.hash
|
89
|
+
puts "-[#{'JSON'.dark_green}]----"
|
90
|
+
puts jwt.json
|
91
|
+
puts ''
|
92
|
+
puts "-[#{'Token'.green}]----"
|
93
|
+
puts token
|
94
|
+
|
95
|
+
when options[:generate_sig]
|
96
|
+
jwt = JWTear::JWT.new
|
97
|
+
data_encoded = encode_header_payload(options[:header], options[:payload])
|
98
|
+
puts "-[#{'Signature'.green}]----"
|
99
|
+
puts encode(jwt.generate_sig(data_encoded, options[:alg], options[:key]).signature)
|
100
|
+
|
101
|
+
else
|
102
|
+
puts JWTear::Utils.banner
|
103
|
+
puts option_parser
|
104
|
+
end
|
105
|
+
rescue OptionParser::MissingArgument => e
|
106
|
+
e.args.each {|arg| puts '[!] '.red + "#{e.reason.capitalize} for '#{arg}' option."}
|
107
|
+
puts option_parser
|
108
|
+
rescue OptionParser::InvalidOption => e
|
109
|
+
puts '[!] '.red + "#{e}"
|
110
|
+
puts option_parser
|
111
|
+
rescue Exception => e
|
112
|
+
puts "[x] ".red + "Unknown Exception: option parser"
|
113
|
+
puts '[!] '.yellow + 'Please report the issue at: https://github.com/KINGSABRI/jwtear/issues'.underline
|
114
|
+
puts e.backtrace
|
115
|
+
puts e.backtrace_locations
|
116
|
+
puts e
|
117
|
+
end
|
data/jwtear.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "jwtear/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "jwtear"
|
7
|
+
spec.version = JWTear::VERSION
|
8
|
+
spec.authors = ["KING SABRI"]
|
9
|
+
spec.email = ["king.sabri@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{JWTear, command-line tool and library to parse, create and manipulate JWT tokens for security testing purposes.}
|
12
|
+
spec.description = %q{JWTear, command-line tool and library to parse, create and manipulate JWT tokens for security testing purposes.}
|
13
|
+
spec.homepage = "https://github.com/KINGSABRI/jwtear"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "bin"
|
18
|
+
spec.executables = ['jwtear']
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# spec.add_dependency ''
|
22
|
+
end
|
data/lib/jwtear.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Standard libraries
|
2
|
+
require 'base64'
|
3
|
+
require 'json'
|
4
|
+
require 'digest'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
# JWTear
|
8
|
+
require_relative 'jwtear/version'
|
9
|
+
require_relative 'jwtear/errors'
|
10
|
+
require_relative 'jwtear/extensions'
|
11
|
+
require_relative 'jwtear/jwt'
|
12
|
+
require_relative 'jwtear/utils'
|
13
|
+
|
14
|
+
|
15
|
+
module JWTear
|
16
|
+
include JWTear::Utils
|
17
|
+
|
18
|
+
String.class_eval do
|
19
|
+
include Extensions::Core::String
|
20
|
+
end
|
21
|
+
# NilClass.class_eval do
|
22
|
+
# include Extensions::Core::NilClass
|
23
|
+
# end
|
24
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module JWTear
|
2
|
+
|
3
|
+
# Algorithms module contains all algorithms that are supported for this lib
|
4
|
+
# @Note if you are looking for production library, please use jwt gem
|
5
|
+
#
|
6
|
+
module Algorithms
|
7
|
+
|
8
|
+
# sha generates SHA signature
|
9
|
+
#
|
10
|
+
# @param data [String]
|
11
|
+
# the data you want to encrypt or make signature for.
|
12
|
+
# @param alg [String]
|
13
|
+
# the algorithm you want. @example: SHA256, SHA384, SHA512
|
14
|
+
# @param key [String]
|
15
|
+
#
|
16
|
+
# @return [String] SHA signature
|
17
|
+
#
|
18
|
+
def sha(data, alg, key)
|
19
|
+
raise AlgorithmRequiresKeyError if key.nil?
|
20
|
+
digit = /[[:digit:]]+/
|
21
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'.sub(digit, alg[digit])), key, data)
|
22
|
+
end
|
23
|
+
|
24
|
+
# rsa generates RSA signature
|
25
|
+
#
|
26
|
+
# @param data [String]
|
27
|
+
# the data you want to encrypt or make signature for.
|
28
|
+
# @param alg [String]
|
29
|
+
# the algorithm you want. @example: RSA256, RSA384, RSA512
|
30
|
+
# @return [Hash]
|
31
|
+
# of public_key, private_key and signature
|
32
|
+
#
|
33
|
+
def rsa(data, alg)
|
34
|
+
rsa_private = OpenSSL::PKey::RSA.generate(2048)
|
35
|
+
rsa_public = @rsa_private.public_key
|
36
|
+
signature = @rsa_private.sign(OpenSSL::Digest.new(alg.sub('RS', 'sha')), data)
|
37
|
+
|
38
|
+
{public_key: rsa_public, private_key: rsa_private, signature: signature}
|
39
|
+
# FIXME: need to sign using public key
|
40
|
+
# cert = File.open('pub_cert.pem').read
|
41
|
+
# @public_key = OpenSSL::PKey::RSA.new(cert)
|
42
|
+
# raise 'Not a public certificate' unless public_key.public?
|
43
|
+
end
|
44
|
+
|
45
|
+
# ecdsa generates ESDSA signature
|
46
|
+
#
|
47
|
+
# @param data [String]
|
48
|
+
# @param alg [String]
|
49
|
+
# @return [String] of ESDSA signature
|
50
|
+
#
|
51
|
+
def ecdsa(data, alg)
|
52
|
+
# TODO:
|
53
|
+
# - fixme
|
54
|
+
# - support P-256 as SHA256
|
55
|
+
ecdsa_key = OpenSSL::PKey::EC.new('prime256v1')
|
56
|
+
ecdsa_key.generate_key
|
57
|
+
ecdsa_public = OpenSSL::PKey::EC.new(ecdsa_key)
|
58
|
+
ecdsa_public.private_key = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# Just None encryption
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
# empty string if none algorithm, yes it happens in JWT
|
65
|
+
def none
|
66
|
+
''
|
67
|
+
end
|
68
|
+
|
69
|
+
# List of supported algorithms
|
70
|
+
#
|
71
|
+
# @return [Hash]
|
72
|
+
#
|
73
|
+
def supported_algorithms
|
74
|
+
{
|
75
|
+
SHA: %w{HS256 HS384 HS512},
|
76
|
+
RSA: %w{RS256 RS384 RS512},
|
77
|
+
ESDSA: %w{ES256 ES384 ES512}
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module JWTear
|
2
|
+
module Extensions
|
3
|
+
module Core
|
4
|
+
module String
|
5
|
+
def red; colorize(self, "\e[1m\e[31m"); end
|
6
|
+
def green; colorize(self, "\e[1m\e[32m"); end
|
7
|
+
def dark_green; colorize(self, "\e[32m"); end
|
8
|
+
def yellow; colorize(self, "\e[1m\e[33m"); end
|
9
|
+
def blue; colorize(self, "\e[1m\e[34m"); end
|
10
|
+
def dark_blue; colorize(self, "\e[34m"); end
|
11
|
+
def purple; colorize(self, "\e[35m"); end
|
12
|
+
def dark_purple; colorize(self, "\e[1;35m"); end
|
13
|
+
def cyan; colorize(self, "\e[1;36m"); end
|
14
|
+
def dark_cyan; colorize(self, "\e[36m"); end
|
15
|
+
def pure; colorize(self, "\e[0m\e[28m"); end
|
16
|
+
def underline; colorize(self, "\e[4m"); end
|
17
|
+
def bold; colorize(self, "\e[1m"); end
|
18
|
+
def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
|
19
|
+
end
|
20
|
+
|
21
|
+
# module NilClass
|
22
|
+
# def puts(type=nil, arg)
|
23
|
+
# case type
|
24
|
+
# when nil
|
25
|
+
# puts arg
|
26
|
+
# when :error
|
27
|
+
# puts '[x] '.red + arg
|
28
|
+
# when :warning
|
29
|
+
# puts '[!] '.yellow + arg
|
30
|
+
# when :success
|
31
|
+
# puts '[x] '.green.bold + arg
|
32
|
+
# when :status
|
33
|
+
# puts '[x] '.green + arg
|
34
|
+
# else
|
35
|
+
# puts arg
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/jwtear/jwt.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'jwtear/algorithms'
|
2
|
+
require 'jwtear/utils'
|
3
|
+
|
4
|
+
module JWTear
|
5
|
+
class JWT
|
6
|
+
include JWTear::Extensions
|
7
|
+
include JWTear::Algorithms
|
8
|
+
include JWTear::Utils
|
9
|
+
|
10
|
+
# @!attribute [rw] token [String] generated or parsed token
|
11
|
+
# @!attribute [rw] header [String] generated or parsed header
|
12
|
+
# @!attribute [rw] payload [String] generated or parsed payload
|
13
|
+
attr_accessor :token, :header, :payload
|
14
|
+
# @!attribute [rw] alg [String] generated or parsed algorithm
|
15
|
+
# @!attribute [rw] key [String] given encryption key
|
16
|
+
# @!attribute [rw] data [String] given or parsed data
|
17
|
+
attr_accessor :alg, :key, :data
|
18
|
+
# @!attribute [r] json [JSON] given or parsed json
|
19
|
+
# @!attribute [r] hash [Hash] hash result of parsing given or generated json
|
20
|
+
attr_reader :json, :hash
|
21
|
+
# @!attribute [r] signature [String] generated or parsed signature
|
22
|
+
# @!attribute [r] rsa_private [String] generated private private key
|
23
|
+
# @!attribute [r] rsa_public [String] generated or given public key
|
24
|
+
attr_reader :signature, :rsa_private, :rsa_public
|
25
|
+
|
26
|
+
def initialize(token='')
|
27
|
+
@token = token
|
28
|
+
@key = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# parse a given token.
|
32
|
+
# The main use of it is to parse and initiate header, payload, type, alg, signature values
|
33
|
+
#
|
34
|
+
# @param token String
|
35
|
+
def parse(token=@token)
|
36
|
+
_token = token.split('.')
|
37
|
+
@header = JSON.parse(Base64.urlsafe_decode64(_token[0]))
|
38
|
+
@type, @alg = @header['type'], @header['alg']
|
39
|
+
@payload = JSON.parse(Base64.urlsafe_decode64(_token[1]))
|
40
|
+
@signature = Base64.urlsafe_decode64(_token[2]) unless (_token[2].nil? or _token[2].empty?)
|
41
|
+
set_hash_and_json
|
42
|
+
end
|
43
|
+
|
44
|
+
# build the hash and Json format from the parsed or generated token
|
45
|
+
def set_hash_and_json
|
46
|
+
@json = "#{@header.to_json}.#{@payload.to_json}.#{Base64.urlsafe_encode64(@signature, padding: false)}"
|
47
|
+
@hash = {header: @header, payload: @payload, signature: Base64.urlsafe_encode64(@signature, padding: false)}
|
48
|
+
end
|
49
|
+
|
50
|
+
# generate signature
|
51
|
+
#
|
52
|
+
# @param data [String]. 'Base64.encode(header)'.'Base64.encode(payload)'>
|
53
|
+
# @param alg [String] supported algorithms: HS256 HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512
|
54
|
+
# @param key String
|
55
|
+
#
|
56
|
+
# @return [String] the generate signature
|
57
|
+
#
|
58
|
+
def generate_sig(data, alg, key)
|
59
|
+
begin
|
60
|
+
case alg
|
61
|
+
when /^HS/
|
62
|
+
@signature = sha(data, alg, key)
|
63
|
+
when /^RS/
|
64
|
+
rsa = rsa(data, alg)
|
65
|
+
@rsa_public = rsa[:public_key]
|
66
|
+
@rsa_private = rsa[:private_key]
|
67
|
+
@signature = rsa[:signature]
|
68
|
+
when /^ES/
|
69
|
+
ecdsa(data, alg)
|
70
|
+
when /none/i
|
71
|
+
none
|
72
|
+
else
|
73
|
+
raise AlgorithmUnknownError
|
74
|
+
end
|
75
|
+
rescue AlgorithmUnknownError
|
76
|
+
puts "[x] ".red + "algorithm cannot be nil, empty or unsupported, Use: '--alg ALGORITHM' option"
|
77
|
+
puts "[!] ".yellow + 'Supported Algorithms:'
|
78
|
+
supported_algorithms.each_pair do |alg_key, alg_val|
|
79
|
+
puts alg_key, alg_val.map{|_alg| " #{_alg}" }
|
80
|
+
end
|
81
|
+
exit!
|
82
|
+
rescue AlgorithmRequiresKeyError
|
83
|
+
puts "[x] ".red + "key cannot be nil or empty, Use: '--key SECRET_KEY' option"
|
84
|
+
exit!
|
85
|
+
rescue Exception => e
|
86
|
+
puts "[x] ".red + "Unknown Exception: generate_sig"
|
87
|
+
puts '[!] '.yellow + 'Please report the issue at: https://github.com/KINGSABRI/jwtear/issues'.underline
|
88
|
+
puts e
|
89
|
+
puts e.backtrace
|
90
|
+
end
|
91
|
+
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
# generate JWT token
|
96
|
+
# by default, generate_token uses the given json header to detect the algorithm. But it also accept to ignore than
|
97
|
+
# and force it to you another algorithm.
|
98
|
+
#
|
99
|
+
# @return [String] the generated token
|
100
|
+
#
|
101
|
+
def generate_token
|
102
|
+
@header = JSON.parse(@header) unless @header.is_a?(Hash)
|
103
|
+
@payload = JSON.parse(@payload) unless @payload.is_a?(Hash)
|
104
|
+
@alg = @header['alg'] if @alg.nil?
|
105
|
+
header = Base64.urlsafe_encode64(@header.to_json, padding: false)
|
106
|
+
payload = Base64.urlsafe_encode64(@payload.to_json, padding: false)
|
107
|
+
data = "#{header}.#{payload}"
|
108
|
+
@signature = generate_sig(data, @alg, @key).signature
|
109
|
+
signature = encode(@signature)
|
110
|
+
token = [header, payload, signature].join('.')
|
111
|
+
parse(token)
|
112
|
+
|
113
|
+
token
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
data/lib/jwtear/utils.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module JWTear
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
def encode(data)
|
5
|
+
Base64.urlsafe_encode64(data, padding: false)
|
6
|
+
end
|
7
|
+
|
8
|
+
def decode(data)
|
9
|
+
Base64.urlsafe_decode64(data)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode_header_payload(header, payload)
|
13
|
+
[header, payload].map {|part| encode part}.join('.')
|
14
|
+
end
|
15
|
+
|
16
|
+
# JWTear's logo
|
17
|
+
def self.banner
|
18
|
+
%Q{\n 888888 888 888 88888888888
|
19
|
+
"88b 888 o 888 888
|
20
|
+
888 888 d8b 888 888
|
21
|
+
888 888 d888b 888 888 .d88b. 8888b. 888d888
|
22
|
+
888 888d88888b888 888 d8P Y8b "88b 888P"
|
23
|
+
888 88888P Y88888 888 88888888 .d888888 888
|
24
|
+
88P 8888P Y8888 888 Y8b. 888 888 888
|
25
|
+
888 888P Y888 888 "Y8888 "Y888888 888
|
26
|
+
.d88P v#{JWTear::VERSION}
|
27
|
+
.d88P"
|
28
|
+
888P" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module JWTear
|
2
|
+
module JWTModule
|
3
|
+
|
4
|
+
class BruteForce
|
5
|
+
|
6
|
+
attr_accessor :token
|
7
|
+
attr_accessor :word_list
|
8
|
+
def initialize(wordlist)
|
9
|
+
check_gem
|
10
|
+
@word_list = File.open(wordlist).
|
11
|
+
each_line(chomp: true).
|
12
|
+
map(&:strip).
|
13
|
+
reject(&:nil?).
|
14
|
+
reject(&:empty?).lazy
|
15
|
+
@token = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_gem
|
19
|
+
begin
|
20
|
+
require 'celluloid'
|
21
|
+
rescue LoadError
|
22
|
+
puts "[x] required gem is missing: please run the following"
|
23
|
+
puts "gem install celluloid"
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def options
|
29
|
+
"'Brute-force signature to get the 'Key/Password'. (required for generate-token and generate-sig)'"
|
30
|
+
end
|
31
|
+
|
32
|
+
def bruteforce
|
33
|
+
puts "I'm burtefocing now!!!!!"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jwtear
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- KING SABRI
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: JWTear, command-line tool and library to parse, create and manipulate
|
14
|
+
JWT tokens for security testing purposes.
|
15
|
+
email:
|
16
|
+
- king.sabri@gmail.com
|
17
|
+
executables:
|
18
|
+
- jwtear
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- ".gitignore"
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE.txt
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- bin/jwtear
|
28
|
+
- jwtear.gemspec
|
29
|
+
- lib/jwtear.rb
|
30
|
+
- lib/jwtear/algorithms.rb
|
31
|
+
- lib/jwtear/errors.rb
|
32
|
+
- lib/jwtear/extensions.rb
|
33
|
+
- lib/jwtear/jwt.rb
|
34
|
+
- lib/jwtear/utils.rb
|
35
|
+
- lib/jwtear/version.rb
|
36
|
+
- modules/bruteforce.rb
|
37
|
+
homepage: https://github.com/KINGSABRI/jwtear
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.6.13
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: JWTear, command-line tool and library to parse, create and manipulate JWT
|
61
|
+
tokens for security testing purposes.
|
62
|
+
test_files: []
|