jwtear 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|