Skip to content

Commit 8935e51

Browse files
authored
Add files via upload
1 parent bc1c4bb commit 8935e51

3 files changed

Lines changed: 174 additions & 0 deletions

File tree

JwtAnalyzer.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

JwtAnalyzer.slnx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Solution>
2+
<Project Path="JwtAnalyzer.csproj" />
3+
</Solution>

Program.cs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
using System;
2+
using System.Text;
3+
using System.Text.Json;
4+
using System.Text.Json.Nodes;
5+
using System.Collections.Generic;
6+
7+
class Program
8+
{
9+
static int Main(string[] args)
10+
{
11+
if (args.Length == 0 || Has(args, "-h", "--help"))
12+
{
13+
Help();
14+
return 0;
15+
}
16+
17+
string mode = GetArg(args, "--mode");
18+
string token = GetArg(args, "-t", "--token");
19+
if (string.IsNullOrWhiteSpace(mode) || string.IsNullOrWhiteSpace(token)) return 1;
20+
21+
var parts = token.Split('.');
22+
if (parts.Length < 2) return 1;
23+
24+
var headerJson = Decode(parts[0]);
25+
var payloadJson = Decode(parts[1]);
26+
if (headerJson == null || payloadJson == null) return 1;
27+
28+
if (mode == "read")
29+
{
30+
Console.WriteLine("Header:");
31+
Console.WriteLine(headerJson);
32+
Console.WriteLine();
33+
Console.WriteLine("Payload:");
34+
Console.WriteLine(payloadJson);
35+
return 0;
36+
}
37+
38+
if (mode == "scan")
39+
{
40+
Scan(headerJson, payloadJson, parts.Length == 3, token.Length);
41+
return 0;
42+
}
43+
44+
if (mode == "edit")
45+
{
46+
var header = JsonNode.Parse(headerJson);
47+
var payload = JsonNode.Parse(payloadJson);
48+
49+
if (Has(args, "--set"))
50+
{
51+
var kv = GetArg(args, "--set").Split('=', 2);
52+
if (kv.Length == 2)
53+
{
54+
if (kv[0] == "alg") header[kv[0]] = kv[1];
55+
else payload[kv[0]] = JsonValue.Create(ParseValue(kv[1]));
56+
}
57+
}
58+
59+
if (Has(args, "--remove"))
60+
{
61+
var key = GetArg(args, "--remove");
62+
payload.AsObject().Remove(key);
63+
}
64+
65+
PrintNewToken(header, payload);
66+
return 0;
67+
}
68+
69+
return 0;
70+
}
71+
72+
static void Scan(string headerJson, string payloadJson, bool hasSig, int len)
73+
{
74+
using var h = JsonDocument.Parse(headerJson);
75+
using var p = JsonDocument.Parse(payloadJson);
76+
long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
77+
78+
if (h.RootElement.TryGetProperty("alg", out var alg))
79+
{
80+
var a = alg.GetString();
81+
if (a == "none") Console.WriteLine("VULNERABLE: alg=none");
82+
else Console.WriteLine("alg: " + a);
83+
}
84+
else Console.WriteLine("WARNING: alg missing");
85+
86+
if (!hasSig) Console.WriteLine("WARNING: missing signature");
87+
88+
if (p.RootElement.TryGetProperty("exp", out var exp))
89+
{
90+
if (now > exp.GetInt64()) Console.WriteLine("EXPIRED");
91+
else Console.WriteLine("exp: valid");
92+
}
93+
94+
if (p.RootElement.TryGetProperty("nbf", out var nbf))
95+
if (now < nbf.GetInt64()) Console.WriteLine("NOT VALID YET");
96+
97+
if (p.RootElement.TryGetProperty("iat", out var iat))
98+
if (iat.GetInt64() > now) Console.WriteLine("WARNING: iat future");
99+
100+
if (!p.RootElement.TryGetProperty("iss", out _)) Console.WriteLine("INFO: iss missing");
101+
if (!p.RootElement.TryGetProperty("aud", out _)) Console.WriteLine("INFO: aud missing");
102+
if (len > 4096) Console.WriteLine("WARNING: large token");
103+
}
104+
105+
static void PrintNewToken(JsonNode h, JsonNode p)
106+
{
107+
string eh = Encode(h.ToJsonString());
108+
string ep = Encode(p.ToJsonString());
109+
Console.WriteLine("Modified JWT:");
110+
Console.WriteLine($"{eh}.{ep}.");
111+
}
112+
113+
static string Decode(string s)
114+
{
115+
try
116+
{
117+
s = s.Replace('-', '+').Replace('_', '/');
118+
if (s.Length % 4 == 2) s += "==";
119+
if (s.Length % 4 == 3) s += "=";
120+
return Encoding.UTF8.GetString(Convert.FromBase64String(s));
121+
}
122+
catch { return null; }
123+
}
124+
125+
static string Encode(string j)
126+
{
127+
return Convert.ToBase64String(Encoding.UTF8.GetBytes(j)).TrimEnd('=').Replace('+', '-').Replace('/', '_');
128+
}
129+
130+
static object ParseValue(string v)
131+
{
132+
if (long.TryParse(v, out var l)) return l;
133+
if (bool.TryParse(v, out var b)) return b;
134+
return v;
135+
}
136+
137+
static bool Has(string[] a, params string[] k)
138+
{
139+
foreach (var x in a)
140+
foreach (var y in k)
141+
if (x == y) return true;
142+
return false;
143+
}
144+
145+
static string GetArg(string[] a, params string[] k)
146+
{
147+
for (int i = 0; i < a.Length - 1; i++)
148+
foreach (var y in k)
149+
if (a[i] == y) return a[i + 1];
150+
return null;
151+
}
152+
153+
static void Help()
154+
{
155+
Console.WriteLine("Usage:");
156+
Console.WriteLine("--mode read|scan|edit -t <JWT>");
157+
Console.WriteLine("--set key=value");
158+
Console.WriteLine("--remove key");
159+
Console.WriteLine("-h --help");
160+
}
161+
}

0 commit comments

Comments
 (0)